Pwnable.tw babystack
远程搞我心态🤬,收发改了半天,但漏洞点还是挺细节的。
程式一开始先生成长度0x10的随机数并放在rbp-0x20的位置,并在bss上备份。
之后是菜单选项:
1是login要求我们输入password并根据我们输入的password的长度来和栈中相应位置进行比较。
1 | int __fastcall login(const char *a1) |
这里有2个想法:
1.可以通过strncmp依次比较来爆破出password。2.strncmp(&s, a1, v1),&s是我们的输入,在第一个参数,可通过输入’\x00’直接使其返回为0,login成功。
login之后我们就可以执行2的copy操作:
1 | int __fastcall sub_E76(char *a1) |
为啥是magic copy?除了strcpy有点可疑,但也没明显的漏洞。
看了一遍下来除了爆破出password外没啥想法了🤦
之后一次偶然的尝试在得到password后由于我又多输入’a’*0x50,在copy执行strcpy之后返回主函数发现password被改为’a’了!!!
仔细调试在汇编里发现问题:
1 | login函数的栈帧: |
主调用函数都是main函数,这意味着login()和copy()函数是公用一个栈的!!!!
这样就能解释通了,在login()里输入的’a’会残存在栈里,当copy()再次用到这部分栈是,本是想利用read_n((unsigned __int8 *)&src, 0x3Fu);最多输入0x3f那最后一个就是’\x00’来截断,但实际上栈里该处的位置已经被写入了’a’,可导致在strcpy时main函数的栈溢出。
思路有了,但没地址,肯定有办法泄露的。
想到password是通过strncmp的比较来获得的,且比较的长度可控,那我们也能用相同的办法泄露出stack里的地址。
这里我的思路的login时输入’\x00’+’1’*87,这样既能login成功又能改password为’1’*0x10,但为什么是87个呢,一方面是为了strcpy改password,另一个是由于在输入这么多的长度时,main函数stack里的passwoed(被改了的)后面会写入stdvbuf的地址!(至于为什么会写入这个地址,个人想法可能时执行了对输入流初始相关的操作,还有待研究),那这样的话就能通过再次login来leak出Libc地址。
1 | pwndbg> stack 50 |
如果只是改password,而没向下继续覆盖的话是这样的:
1 | pwndbg> stack 50 |
0x7fac80980a31这个地址看着像Libc里的,但实际上他和Libc的偏移是不固定的。
万事具备了,接下来就是在login时构造好stack,在copy里执行strcpy时将正确的password写入对应位置(退出时会和bss上备份的比较),并改ret_addr为one_gadget🚩
EXP:
1 | from pwn import * |