pwn
[week1] 我把她丢了
首先,先checksec查看保护,可发现got表可覆写,无pie,无canary,栈上不可执行
打开ida,发现vuln
函数内存在栈溢出漏洞,同时发现shell
函数内有system
语句,程序内包含/bin/sh
通过64位传参可知,原system
语句中的内容在call _system
之前传给rdi,因此可以不选用shell
函数的开始地址,转而选择先pop rdi;ret
手动更改rdi为/bin/sh
的地址,再直接转入call _system
,如此执行system("/bin/sh")
exp如下:
[week1] Ret2text
首先,先checksec查看保护,可发现got表可覆写,无pie,无canary,栈上不可执行
发现main
函数中存在栈溢出,同时发现dt_gift
函数
于是经过尝试,可构建payload=b'a'*(0x20+0x8)+p64(gift_addr)
,但此时由于未对齐,不可正确执行,于是在p64(gift_addr)
前插入一个ret
的地址
exp如下:
[week1] echo
echo "$(<flag)"
[week1] shellcode_level0
checksec发现除了canary以外保护全开
IDA可以看到,数据输入buf后执行((void (*)(void))buf)()
,将buf指针转为函数指针后执行函数,由此可注入shellcode(手写shellcode后续学习)后执行
exp如下:
[week1] 彻底失去她
checksec可得64位文件,可覆写got表,无canary和pie,栈上不可执行
在main函数中可看到buf存在栈溢出,双击buf可看到buf不在.bss段中
发现present函数,其内容为system('ls')
,且在IDA中未发现/bin/sh
这题考虑先栈溢出,将返回地址覆盖为read函数地址,通过此函数将/bin/sh
(也可输入cat flag
等)输入.bss段,后手动设置rdi,直接执行present函数中的syscall
通过实验可得,read函数输入内容的存储地址由rsi控制,于是在前往read函数之前,先手动设置rsi为.bss段中的一个地址,即payload = b'A'*(0xA+0x8)+p64(rsi_ret)+p64(bss_addr)+p64(read_plt)+p64(rdi_ret)+p64(bss_addr)+p64(ret_addr)+p64(syscall_addr)
exp如下:
[Week2] 她与你皆失
checksec,可覆写got表,无canary和pie,堆栈上不可执行
IDA中未看到后门函数,字符串中没有/bin/sh,由此可看出为ret2libc
由于glibc-all-in-one中没有题目所给的glibc版本,于是使用libcsearcher
exp如下:
或者不使用LibcSearcher,直接用给出的libc文件
现根据所给的libc文件和ld文件更换glibc
checksec发现保护全开
分析代码可知,程序将本地flag文件的内容存入v6变量中,我们需要在buf中输入格式化字符串,在通过输出来获取flag
首先,我们构建payload = b'%p '*10
依次输出,确定指向flag的地址
可以看到,指向flag的地址为0x556faa7f22a0
,在输出中栈上的指针在第八位出现,于是可写成payload = b'%8$p'
,获取flag可写payload = b'%8$s'
exp如下:
[Week2] shellcode_level1
题目保护全开
第一次读入正好为2字节,而syscall
经过汇编后也为2字节,我们可以先尝试输入payload = asm('''syscall''')
,发现当调用到syscall时,rax正好为0,此时查系统调用表可得,运行read函数,因此IDA中((void (__fastcall *)(_QWORD, void *, __int64))buf)(0LL, buf, 1280LL);
可理解为read(0LL, buf, 1280LL)
,吗???***此点存疑!!!***但反正可以继续输入数据并执行
再次输入时,由于传入的开始写入地址还是在buf头部,于是我们要先塞入两字节,再开始覆盖shellcode,exp如下:
checksec可看到开了canary和NX
IDA分析,考虑可使用格式化字符串修改target变量的值,从而获取flag,可获取到target的地址为0x4040B0
先使用payload = b'AAAAAAAA'+b'%p '*10
来试探AAAAAAAA的地址,可看出AAAAAAAA在第六位出现,即payload = b'AAAAAAAA'+b'%6$p'
由于本题考虑小数据覆盖,于是可使用payload = b'A'+b'%7$p'+b'AAA'+b'BBBBBBBB'
重新检验
结果正确,于是可构建payload = b'A'+b'%7$hhn'+b'A'+p64(target)
exp如下:
[Week2] gift
checksec,file得,此题为静态链接,考虑使用ret2syscall
main函数中存在栈溢出,未发现后门函数和/bin/sh字符串,考虑先syscall调用read函数输入/bin/sh,再返回syscall调用execve执行
exp如下:
[Week3] 你为什么不让我溢出
checksec发现,canary开
IDA中发现vuln函数中存在栈溢出漏洞,read读入可以使用send,puts输出不可使用格式化字符串
经过多轮调试发现,canary位于rbp上方,且最后一字节为\x00,因此需要覆盖一位后输出.
exp如下:
checksec
IDA未发现后门函数,可看出使用了printf,可使用格式化字符串更改printf的GOT表,将其指向system,注意64位程序执行格式化字符串输出时,由于地址经过p64封装后存在\x00
,因此无论是泄露还是修改都需要将地址放在最后,详细可见文章
exp如下:
[Week3] PIE
checksec发现,无法覆写GOT表,无canary,栈上不可执行,开了PIE
main函数中存在栈溢出,此题难点在于不更改返回地址的情况下,只能执行一次栈溢出
考虑更改0x7fd1b7c04d90 (__libc_start_call_main+128)
最后一节数据,使程序能够重载进入main函数,经过调试发现,改为\x28
符合条件
在覆盖后,经过printf,可将更改后的数据打印出来,由此可以计算得出libc加载基址.第二次进入main函数时再次进行栈溢出,由于程序加载基址并未泄露,因此无法使用pwn文件中的ROP,这次考虑直接one_gadget
经过对比可得,可以使用第二条来获取shell,同时vmmap可以看到,在libc段中有可写段,于是可构建payload
exp如下:
也可以考虑用libc中的gadget来构建ROP链
exp如下:
[Week3] stack_in_stack
chechsec
IDA发现一次读写内容仅够覆盖完返回地址,于是考虑栈迁移
可利用这个函数泄露libc基地址
exp如下:
只能执行一次格式化字符串,于是考虑.fini_array挟持,这个东西静态和动态好像不一样,动态的程序.fini_array段貌似只能存放一个数据(IDA里看的),而且进入的流程也有些区别,静态的可以看这个
本题首先打算第一次格式化字符串用来泄露libc和更改.fini_array,第二次进入main函数执行格式化字符串更改printf的got表为system,但想要执行shell,必须再来一次main函数,如果只完成这些部分,并不能第三次进入main函数,于是我们继续往下调试.
如果我们可以更改rax+8(0x403148)的内容为main函数地址,我们可以通过这三条语句再次调用main函数.在IDA中可以看到这条地址下存储的内容:
于是第二次格式化字符串要完成的目标即为:修改0x403148为main函数地址,修改printf的got表为system
exp如下:
[Week4] 没有 canary 我要死了! (远端未打通)
发现保护全开
IDA中发现fork函数和随机数函数
发现后门函数
这一题主要考虑的是fork函数复制进程是一模一样的,由此可以爆破得出canary,而随机数是伪随机数,因此我们可以调用glibc库中的随机数函数来破解
参考文章Python ctypes 使用笔记
exp如下:
[Week4] ezstack
checksec
本题未发现后门函数,考虑利用libc,可以覆写setvbuf的got表为system,可利用ret2csu和出题人给的magic_gadget
exp如下:
crypto
[Week1] helloCrypto
由AES的定义可知,AES是对称加密,由此我们可以从密文直接推得明文,原题给的仅仅是例子,原题后的注释才是真正的数据
exp如下:
[Week1] ez_math
题目如下:
分析可得:
由线性代数知识|A@B|=|A||B|
可得,|B|=|upper||low|=1
,|MAT|=|A||B|=|A|
,因为|A|=flag*(ad-bc)=flag*(point1-point2)
由此可逆向解出flag
exp如下:
[Week1] 你会算md5吗
题目如下:
由此可知,题目对flag按字节做了md5加密,加密后内容存于output列表中,因为md5是非对称的,于是我们可以按字节进行枚举,以此获得每一位flag.
exp如下:
[Week1] 十七倍
题目如下:
我们可以从题目中看到,flag为一个unsigned char
型的数组,随后每位字符*17,查文档可得,由于flag是unsigned char
类型,乘法结果会被截断为8位无符号整数。这意味着,如果乘法结果大于255,它会被模256。所以我们可以按字符来枚举,当符合条件时就填入flag。
exp如下:
[Week1] mid_math
与ez_math同理,直接给出exp:
[Week1] ez_rsa
题目如下:
此为rsa加密,加密过程如下:
算模逆元可以使用gmpy2.invert()
函数,例:gmpy2.invert(4,23)
为6
exp如下:
[Week1] babyrsa
题目如下:
回归定义
由欧拉函数定义可得,r = n-1
,可得exp:
[Week1] babypack
题目如下:
阅读可得,在生成a数组时,每一个数字都比之前所有数字之和大,由此可得exp: