果然 0CTF 是为神仙准备的,自闭了。
Web
Ghost Pepper
Java Web 没怎么接触过,利用这次学习一下。
参考:
- http://momomoxiaoxi.com/2019/03/26/tctf2019/#ghost-pepper
- https://blog.csdn.net/like98k/article/details/88797218
进去发现要登录,用 chrome 看不出,拿 firefox可以看到提示:
karaf/karaf 登录进去,发现什么也没有,看到是 Jetty,发现有 Jolokia,搜漏洞。
比较简单的一种做法是 karaf 有一个 webconsole,我们可以安装一个进控制台拿 flag。
1 | POST /jolokia/exec HTTP/1.1 |
访问 http://111.186.63.207:31337/system/console/gogo
另一种是通过osgi.core 的 installBundleFromURL 来安装bundle,这部分可以参考@moxiaoxi的wp。
Wallbreaker Easy
赛后看各位大师傅们的 wp,基本都是通过启用新的进程来调用 so,so文件我们可控并通过修改LD_PRELOAD
方式加载来执行命令。这里贴上几个链接。
- https://xz.aliyun.com/t/4589
- http://momomoxiaoxi.com/2019/03/26/tctf2019/
- https://paper.tuisec.win/detail/d4ba64dd4d1dc38
以及柠檬师傅的bypass disable_functions
的 总结。
此外还看到了一种突破 open_basedir
,从而读别人目录下 flag 的操作:https://balsn.tw/ctf_writeup/20190323-0ctf_tctf2019quals/#wallbreaker-easy
还有一种解法相比劫持函数简单一些。在调用 Imagick 将 png、bmp等格式的文件转成 jxr 类型时,会调用系统PATH 路径下的 JxrEncApp
来进行转换。参考
所以我们可以利用 putenv
把 PATH 改到自己的 tmp 路径下,把要执行的命令写到该路径下的 JxrEncApp
里,这样我们在转换的时候就可以执行系统命令了。
exp:
1 | import requests |
Crypto
0CTF的 Crypto 抬手就是论文,真实。
babyrsa
pubkey.py 中发现 RSA 的公钥 e=31337,而 N 是个多项式。
rsa.sage:
1 | #!/usr/bin/env sage |
多项式 RSA 算法,google 了相关论文:http://www.diva-portal.se/smash/get/diva2:823505/FULLTEXT01.pdf
这个题每项都是模2的,所以 p = 2,类似于一般的 RSA 难点是分解大数 N,多项式 RSA 是对多项式 N 进行因式分解(系数模 p )。
我选择使用 Mathematica 来分解(简直神器,用这个工具解了好多密码题…)
1 | Factor[多项式,Modulus->2] |
可以看到 Mathematica 给出了结果:
两个因式的最高次数是 821 和 1227,那么可以计算 s(参照上面提到的论文):
s = (2^821-1) * (2^1227-1)
这个 s 类似于一般 RSA 中的 n 的欧拉值(phi),然后就是求逆元 d 了
1 | from gmpy2 import * |
1 | 28371355076358206651880108899447906576372266284154280282347957145120170645734899523334978078067679493874344060469168599875633378810644150054152285167807343298071802254581411860744158353096011714907819564399402714709858337654437633205741705120012058022068404602368525225166892620782231104596296684392603977673442420869964883518757302131139464582403543008517510576759631853686083804876647805871645437996963908242523987920166730933950556409136138395339773872530985876082852299816804207673785130661047844641798164979597836577807048385040982943227701240014693785196556609759136982566512240594608088626862145862029373010104 |
拿到 d 最后就是解密,sage 脚本:
1 | from sage.all import * |
1 | babyrsa$ sage solve.sage |
zer0lfsr
比赛的时候看到题目就想到了强网杯的 streamgame3,通过多个线性反馈移位寄存器的线性组合来构成一个非线性反馈移位寄存器。首先列一下 x1 x2 x3 对应最后输出的表,发现x1,x2,x3 都有 3/4 的概率与最终输出的结果相同。当时的 streamgame3 每个 LFSR 最多只不过 21 bit,这次的三个 LFSR 都是 48 bit,没法爆破,GG。
这个题的反馈位(抽头)都只有两个,很少,感觉应该有东西。google 了很多论文发现了当抽头数较少时可以采用快速相关攻击
来进行攻击。最经典的是 Meier和Staffelbach提出的算法A和算法B ,但是我没有找到相应的实现脚本… 自己啃论文写脚本写不出,还是太菜了。
从@iromise 师傅那里要来了快速相关攻击的实现:链接
按照 README 安装就好了,需要安装 GNU Scientific Library 。GSL安装参考:http://www.voidcn.com/article/p-hpwbigec-dd.html
我在安装中使用了 sudo 还是出现了没有权限的错误,把文件夹 chmod 777 一下,make clean 后再重新 make。
使用:以这道题第一个 lfsr 为例,输入文件格式如下:
1 | 0.75 |
第一行是之前说的 3/4,第二行是提供的输出比特个数,第三行是 lfsr 状态比特位数,第四行是抽头个数 n,后面 n 行就是抽头的位置,最后一行就是提供的比特流。
这个题有个坑点,题目输出的 keystream 是 utf-8 编码的。。。我直接 python2 open("keystream","rb").read()
发现竟然长度不是 8192…一脸懵逼
感觉 python3 的 byte 类型和 utf-8 编码使用起来很难受,可能是没用惯的原因。
先生成三个输入文件:
1 | data=open("keystream","rb").read() |
然后使用快速相关攻击还原每个 lfsr 的比特流:
1 | gml@gml-virtual-machine ~/CTF/fastcorrattack src/fca ./zer0lfsr/init1 >./zer0lfsr/result1 |
这样 result1、result2、result3 中就会还原出每个 lfsr 的比特流。接下来我们还原初始状态,这部分不懂的可以看一下我的这篇中的2018国赛 oldstreamgame
exp:
1 | import hashlib |
flag{b527e2621131134ec22250cfbca75e8c9f5ae4f40370871fd55910927f66a1b4}
此外也可以使用 z3 约束求解,较为简便。参考: