0.前言
UNCTF2021年个人赛的PWN题部分WP。
1.fo
简单的栈溢出,需要绕过canary保护。
gdb调试很快可以算出canary的偏移。
存在后门函数,直接返回到后门函数上即可。
直接上exp:
1 | from pwn import * |
2.sc
简单的ret2shellcode,
没什么好说的,直接上exp:
1 | from pwn import * |
3.ezrop
仅存在NX保护。
hint函数提示我们要修改bss段的权限来进行shellcode。
bss段也确实存在一个全局数组fake_flag共32字节,因此我们的shellcode不能超过32字节。shellcraft生成的shellcode有48字节,因此无法用这个。
存在明显的栈溢出,因此要构建rop链。
mprotect函数共三个参数,根据64位的调用约定至少要用到三个寄存器rdi、rsi、rdx来传递参数。但用ropper查询可用的gatgets时发现没有直接pop rdx,ret的gadget。但程序中有__libc_csu_init,由此想到用通用gatgets来完成rop。
使用的代码片段如下图:
上下分别为gatgets2和gatgets1。
思路为先利用通用gatgets调用read函数将shellcode写入fake_flag,返回到vuln函数;再次利用通用gatgets调用mprotect函数改写bss权限使之可执行,再返回到fake_flag即可getshell。
完整的exp如下:
1 | from pwn import * |
4.magic_abs
查看保护,如下图:
拖入IDA中(部分变量改过名字方便辨认。),发现存在abs函数,
由此联想到应该是整数溢出类题目。
主函数部分要求我们输入三个变量的值:name、age和lucky_number。
之后会对v10变量取lucky_number的绝对值,再将v10加上name_size强制转化为整型赋值给v9,然后判断v9与0的关系,大于0则flag为0,小于0则flag为1。
之后判断flag的值来为tag赋值,再调用record函数。
record函数主体如下图:
可以看出有memcpy函数,存在明显的栈溢出漏洞,且程序中有后门函数,故要想办法返回到后门函数。
结合以上分析如下:
如果flag为0,则tag会被赋值于rand()%10000,这是一个妥妥的随机数,之后memcpy会把name的数据拷贝到dest且从dest[0]开始。但是,如果flag为0,name[10]会被赋值为0,而我们知道memcpy遇到\x00会停止,此时将不够溢出。
因此应控制flag的值为1。
之前说了,flag为1要求v9<0,这也意味着要求v10也小于0,我们知道64位int的取值范围为-2147483648~2147483647,因此abs(-2147483648)看似会得到2147483648,但由于超出了最大长度会溢出到-2147483648,这就可以控制v10等于-2147483648。
而flag等于1会拷贝到从dest[tag]开始的内存,而tag在flag等于1时为rand%(((int)abs32(lucky_number+age)>>age)+1),这个看似还是随机数,但我们可以控制age为2147483647来使得tag=rand%1,此时tag恒为0,从而确保了覆盖的字节数是确定的。
完整的exp如下:
1 | from pwn import * |