2023 ciscn WriteUp


半决赛:我们俩真厉害.jpg
决赛:我们仨真厉害.jpg
HED是南方科技大学COMPASS实验室的CTF战队
初赛
Crypto
day1 基于国密SM2算法的密钥密文分发
虽然可以一步一步调库进行计算,但是由于服务器对 /api/search
的管理不是十分到位,于是我们就可以通过访问 /api/allkey
, /api/quantum
接口,让服务器生成对应的密钥,然后再访问 /api/search
就可以获得服务器密钥明文,然后 /api/check
一下即可。
1 | const BASE_URL = 'http://IP:PORT' |
day1 Sign_in_passwd
base64换表给表
day2 badkey1
翻阅 PyCryptodome 源码,发现唯一可以利用的点是:
1 | if Integer(n).gcd(d) != 1: |
需要构造 d 是 p 的倍数。
$$
\begin{align}
ed &\equiv 1 \pmod{\varphi(n)} \
ed &= k(p-1)(q-1)+1 \
emp &= k(p-1)(q-1)+1 \
em &\equiv 1 \pmod{p-1}
\end{align}
$$
随机生成 p,求出对应的逆元 m。
$$
\begin{align}
emp &= k(p-1)(q-1)+1 \
k(q-1) &= (emp-1)/(p-1) = g
\end{align}
$$
计算得到 g,它的长度大于 512bits。对 g 进行因式分解,找到 g 的小因子,枚举所有可能的因子组合得到可能的 q,检查 q 的长度为 512bits 而且是质数。最后进行 RSA.construct()
来验证解。
1 | from Crypto.Util.number import * |
day2 bb84
阅读材料的大意是:
1 | EPC1 4 2 1 2 |
APD1 到 4 中有且只有一个为 1,并且和 EPC1 相等,则这位可以采用为密钥。
或者 APD1 到 4 中有且只有一个为 1,和 EPC1 不相等,但是在同一个基(如APD1=1,EPC1=2),那么这位需要纠错,纠错之后可以采用。
将整个序列筛选之后得到可用的序列,然后根据线性同余生成真正的密钥。
另外材料中提到了用熵计算安全密钥量,然后把它作为模数。这是一个误导,我在这里卡了很久。因为采用的随机数序列的长度显著多于计算出的安全密钥量,不知道如何选出相应的安全密钥。实际上题目的做法是直接把随机数序列的长度当作安全密钥量,不需要计算熵。
之后就是经典的生成流密码,逐个异或。
1 | import csv |
PWN
day1 烧烤摊儿
静态编译栈溢出 没system没exec 标准ORW
1 | from pwn import * |
day2 funcanary
抢一血没写循环直接展开了
fork爆破canry 板子
然后有ASLR 有win 短跳爆破4bit即可
1 | import struct |
RE
day1 moveAside
一年前做过的题,当时我写的的超级详细题解:
https://github.com/GhostFrankWu/CS315-ComputerSecurity/blob/main/week5/wp.md
第一天结束后发现GitHub统计访客50多
核心就是去混淆之后找到用作jmp的mov指令,还有就是要知道mov混淆似乎一定有逐字节比较的地方,断在这里爆破就行了
1 | from pwn import * |
炫酷的界面(雾
day2 babyRE
撞车队友:
网上随便看了点Snap!的资料,定位到flag判断逻辑,根据secret
简单做一波异或运算还原输入key
即flag
1 | secret = [102, 10, 13, 6, 28, 74, 3, 1, 3, 7, 85, 0, 4, 75, 20, 92, 92, 8, 28, 25, 81, 83, 7, 28, 76, 88, 9, 0, 29, 73, 0, 86, 4, 87, 87, 82, 84, 85, 4, 85, 87, 30] |
1 | d = [(92, 1), (92, -1), (8, -1), (28, -1), (20, 1), (25, -1), (75, 1), (81, -1), (83, -1), (0, 1), (7, -1), (28, -1), |
web
day1 unzip
代码长得和上周春秋杯的题完全一致
题目没给Dockerfile,大概不是历史漏洞,03年之后的zip就不能目录穿越了
创建一个指向文件夹的软链 ln -s /var/www/html www && zip -y x.zip www
然后压缩一个带一句话的www文件夹解压就可以了
day2 dumpit
dump和注入分开 query屏蔽的并不多,但提示要做到rce
dump几乎都是用命令行工具做,果然在dump的地方可以命令拼接
然后发现没权限读flag 弹shell
跑linpeas提权时候在环境变量里出了
MISC
day1 签到
python任意代码 签到
day1 被加密的生产流量
发现 query 中的 word count 不符合定义。之前请求了非常大的数字,后期全部请求 5。
追踪 TCP 流发现,word count 刚好形成了 ascii 字符。将其提取并解码。MMYWMX3GNEYWOXZRGAYDA===
base32 解码得到 c1f_fi1g_1000
。
day2 pyshell
虽然服务器禁止了赋值操作,并且每行的长度也有限制
对于第一个限制,可以用 REPL 中的 _ 来获取上一条语句的值
对于第二个限制,可以分多行输入(此时每输入一行都需要重新 nc 连接)
所以最终 payload 为
1 | '/flag' |
day2 问卷
问卷
半决赛
华南赛区日常主办方不当人,开赛两小时全场0解,主办方赶紧上了一题RE(印象中好像是RC4+UUENCODE),这题出不了的队基本进不了决赛了
然后后来似乎摸出了web和pwn,压线进了决赛
决赛
AWD
孩子第一次打国赛不懂规矩,被老前辈删站+不死🐎打爆了听说比赛场地路由有问题,还能直接日别的队的流量
build
抽象环节,一群人写扫描器,完全不想写于是整了个fofa|zoomeye|hunter的调包器,然后得分就混进了前15
渗透
msf的17-010打过去,环境炸了,遂摇裁判重启
向日葵端口不知道是服务器炸了没起来还是没扫到,痛失top10
CTF
可信计算稳定抽象、AI题只有一题有解也被密码姐姐A出来了,算是没掉分
2023 ciscn WriteUp