攻防世界babystack(pwn1)——glibc_all_in_one初体验
文章目录
引入
好久没做pwn题了,找了道简单的ret2libc做做,顺便尝试解决一些历史遗留问题 (其实就是让pwn题使用本地的libc的问题,省流:有突破性进展但没有完全解决)
初步分析
1、checksec
没有PIE,i了i了
2、伪代码分析
直接一个大大的溢出read甩我脸上,而且还是无限循环的read,而且有120字节的溢出空间(0x100-136),完全不需要自己费尽心思去构造乱七八糟的利用链,这种题请务必もっともっと!XD
但是,在main函数的最开始部份存在着一条语句v6=__readfsqword(0x28u)
,这条语句的作用就是把canary字段读到栈中,所以这道题我们需要想到绕开或者泄露canary的方法,不然盲目地栈溢出会引起程序 __stack_chk_fail的报错。这里程序正好 提供了一个puts方法,可以供我们泄露canary。
3、栈分析
addr | var |
---|---|
-0x90 | buf |
-0x8 | var_8 |
0x0 | s |
0x8 | r |
栈结构大致如上,其中var_8就是心心念念的canary,可以清楚看见canary以及返回地址都在栈溢出的覆盖范围内。
解题思路
1、泄露canary
由于题目给出了puts方法,所以可以尝试先把buf与canary之间的空间用字符填满,然后使用puts函数将canary输出。但是canary为了防止栈内容泄露,特地把最低位设置为"\x00",以此让输出函数被截断,防止泄露canary及canary后的栈内容。
所以要是想要输出canary的值,需要使用填充字符把canary的最低位覆盖为"\x00"以外的值。又因为程序是小端程序,所以当我们溢出缓冲区一个字节时,溢出的一个字节正好能覆盖到canary的最后一个字节上,此时,canary将被认为是输入的一部分随着填充字符串被puts函数输出出来。
处理后获得canary
因为调用过puts函数,所以puts的gots表地址和puts表地址是已知的,再加上有充足的溢出空间,所以这里还是请出老演员puts函数来把puts函数的libc装载地址泄露出来。
需要注意的是,由于程序为64位程序,所以puts函数的参数需要通过寄存器传递,所以这里还需要找到一个pop rdi; ret;
的小gadget,这里我使用的是ROPgadget工具进行搜索,具体方法不再赘述。
然后就可以开始构造ROP链,具体如下
payload1 = "a" * 0x88 + p64(canary) + "A"* 0x8 + p64(rdi_addr) + p64(puts_got) + p64(puts_plt) + p64(main_addr