HackTM2020-WriteUp
HackTM2020-WriteUp
假期被“关禁闭”,看到战队发的比赛链接,虽然知道自己很菜,题目不是我可以做的,不过还是大胆尝试了,发现一些题目还比较简单[滑稽脸],这里写一下部分题目的WP。
RSA#1
这是一个简单的RSA爆破题。
题目分析
题目给了两个附件:c
、rsa.py
,其中c
的内容如下:
Public key: |
易知,该文件提供了RSA的公钥:(e,n),以及加密后的flag,我们发现,flag的密文是多个大数,可知是逐字节对flag进行加密的,那么进行简单的爆破即可解密。
再来看看rsa.py
的内容:
import random |
该脚本中是一些RSA的加密、解密函数,其中提供了p和q都是512bit的素数,因此模数n是1024bit的,打消分解n的念头(这里不得不说一下,有些比赛的1024bit以上的模数n在http://factordb.com/ 上是有上传的,有时候可以先拿去分解试试)
我们从enc
函数的加密机制发现,它是对明文进行逐字符进行加密,再次印证了是逐字节爆破,直接爆破flag即可。
解密代码
import string |
RSA#2
题目分析
与上个题目一样,附件中包含两个文件c
、rsa.py
,并且rsa.py
与上题一样:
import random |
但是密文文件c
内容不同,其中给出了逐字节加密的密文列表,但是并未给出公钥:
Public key: |
没有公钥,怎么解密???显然也不是攻击私钥,而是直接对密文进行攻击。
我们看到,密文列表中有1111个密文,一般的flag不可能这么长,而这里给出了这么多密文,并且没有给出公钥,解密思路便很显然:利用字母频率攻击出明文。
这也是密码学常用的攻击方法之一,主要思路是:英文的字母在使用中出现的次数大致满足了一个频率表(参考https://en.wikipedia.org/wiki/Letter_frequency ),我们可以把这1111个密文的出现频率统计出来,然后与字母频率对应,从而攻击出明文。
解密代码
with open('c', 'r') as f: |
The Dragon Sleeps At Night
一道misc题,考脑洞,也考基本知识,多做misc确实能开眼界啊!
题目分析
netcat
连接目标IP之后进入一个游戏盒,秉承misc一大传统:打游戏。
这个题目是一个屠龙的游戏,从图中可以看到,有以下功能:
去商店:这里有从1级到5级的屠龙宝刀,屠龙!拿flag~
去工作:赚钱买刀!屠龙!拿flag~
去龙穴:屠龙!拿flag~
回家:休息,为了屠龙!拿flag~
储藏室:放宝刀
解题关键点:
- 1、这里去工作的话最后拿工资的时候会让输入工作天数,1刀/天,但是每次之多输入三个字符,因此常数的话最多999…怎么办呢?
- 2、回家休息的时候可以输入休息的天数,但是休息会“降低”储藏室中宝刀的级别,1级/天,不过…休息天数正负不限~
这两点就是屠龙的关键。
解题
根据前面的分析,我们需要先去工作赚钱,在结账的时候输入9e9
的话其实就可以得到9 billion刀,这足以买到5级宝刀了。其实就是利用科学计数法绕过限制,CTF中很多题目借用了这一点。
此时去屠龙的话,仍然会失败,因为需要6级宝刀,但是商店没有啊!利用关键点2,我们先买5级宝刀并放在储藏室,然后去睡-1
天,便得到了一把6级宝刀,再去屠龙便能顺利拿到flag了。
Strange PCAP
考察流量包隐写、usb数据分析
题目分析
下载数据包的时候,压缩工具就提示要输入密码,但是是个流量包,直接能打开,输密码干嘛?
用binwalk
分析一下,发现存在压缩包隐写,binwalk -e
提取
但是解压需要密码,那就看看数据包里的内容,发现是usb
数据,估计就是键盘记录或者鼠标记录了
利用常规的方法:把usb数据
提取出来,然后用现有的跑键盘记录的脚本跑出来即可。
先利用tshark提取数据:
tshark -r Strange.pcapng -T fields -e usb.capdata | sed '/^\s*$/d' > usbdata.txt |
发现提取的数据如下:
0000000104000100000000000000 |
直接用脚本跑键盘记录的话,结果如下:
可以看到结果不正常,因为上面的数据有很多冗余数据(长度不是8字节的部分),去掉之后再跑脚本,结果如下:
输入密码,即可拿到flag:
键盘记录脚本
本题用国内的通用脚本解不出来,用国外wp的脚本可以
#经夏风师傅完善过的国外脚本 |
再附一个国内的脚本:
normalKeys = { |
这里再拓展一下,usb流量一般是鼠标流量
或者是键盘流量
,可以参考这里。
提供一位师傅的工具。
My Bank
一道web的条件竞争题目
题目分析
常见的一种题,可以去银行贷款,不过最多贷款600刀,还能去商店买东西,饼干最便宜,但是没法吃,还是买flag吧,但是要1440刀…
分析可知,可以利用条件竞争进行贷款,这样就可以拿到不止600刀的资金,再去买flag即可。
条件竞争可参考:https://blog.csdn.net/qq_36992198/article/details/80007405
解题
1、利用BP解题
- 抓包
- 放到爆破模块,设置空payload,线程设为15
- 借到足够的钱去买flag
首先注册账号并登陆,看一下我们的账户信息:
可以看到,我们还可以借600刀,然后设置借钱为100,BP抓包进行爆破,用13-15个线程即可,结果如下:
然后回到我们的账户处查看利用条件竞争借到的1000刀已经到账:
这里需要多次尝试才能借到足够的钱数,每次结果都可能是不一样的。因为利用BP进行条件竞争的时候有时候会受到网速、服务质量等各种因素的影响,多试几次就好了。
2、BASH脚本
看国外大佬的解题思路学到了一种利用bash脚本进行条件竞争的方式(其实用python也一样),脚本如下:
|
这里利用了一个技巧:在cURL
命令之后附加一个&
使进程移到后台。这样,可以同时发出多个请求,并且不需要编写一个处理多线程的复杂代码。
Draw With Us
一个JWT
攻击题目,进入题目是下图的一个改颜色的web端游戏,给出Hint:Changing your color is the first step towards happiness.
同时题目还给了一个json附件,实现代码都在其中,其中包含关键部分:
- NodeJS Express服务器
- 登录/管理员管理/socket.io
- JWT算法:
HMAC-SHA256
- 管理员用户名:
hacktm
题目分析&一些攻击尝试
破解JWT秘钥
代码中获取flag的函数如下:
app.get("/flag", (req, res) => { |
想要得到flag,就必须满足req.user.id == 0
,那么就需要想办法构造JWT。看国外大佬的WP写的对JWT秘钥进行攻击,但是没有成功。
暴力破解n
下面这段代码给出了req.user.id
的生成算法:
app.post("/init", (req, res) => { |
代码中的p
和q
是用户输入,n
是秘钥。由于md5的结果为32个字符,且target
长度与pwHash
相同,同时toString
暗示n
是数字。adminId
是利用target
计算的,每个字符都经过了XOR
运算。在map()
的迭代中,两个字符相同的结果即为0,最后通过reduce()
会计算出所有数的结果,若0,则req.user.id==0
。
然而,如果哈希值不匹配的话,req.user.id
就会是一个大于0
的数字。
由于reduce()
消除线性搜索推导的可能性,因此无法现实地对此进行暴力破解n
,必须找到另一种方式。
JWT none 攻击
这种攻击方法可参考:https://www.sjoerdlangkemper.nl/2016/09/28/attacking-jwt-authentication/
- 1、替换或者更改JWT有效负载
- 2、更改
id
,如{"id":1374,"iat":1580560256}
->{"id":0,"iat":1580560256}
- 3、删除签名
- 4、更改
{"typ":"JWT","alg":"HS256"}
->"alg": "none"
- 5、提交服务器
但是该方法也不行。
总之,关键点就在于:
- 1、使
req.user.id==0
- 2、为了实现1需要得到
config.n
- 3、可能有其他方式得到
config.n
或者config.p
从下面一段代码可以得到新的思路:
app.get("/serverInfo", (req, res) => { |
应该是利用user.rights
作为访问key直接读取对象的代码,如果可以插入自己的user.rights
,便可以插入n
从而得到config.n
的值。
然后发现另一段更新用户数据的代码:
app.post("/updateUser", (req, res) => { |
但是想要插入rigths
必须绕过isAdmin(user)
的判断,同时还有isValidUser(user)
的判断:
function isAdmin(u) { |
可以利用下面的方式仿造admin
:
var admin = "hacktm"; |
结果满足条件:
"hacKtm".toLowerCase() == "hacktm".toLowerCase() // true |
然后即可插入rigths
,插入的时候需要经过checkRights(rights)
的判断:
function checkRights(arr) { |
我们看到,黑名单中限制了p
和n
的上传,可以通过利用数组作为键的方式绕过:
"rights":[["n"]] |
从而即可读取到n
,然后通过使p==n
,q==1
,即可使req.user.id==0
,从而拿到flag
。
Expoit
参照大佬脚本:
获取n
,p
:
import requests |
获取flag
:
import jwt # pip install pyjwt |
关于node.js
的考核可以参考Pcat师傅分享的题解:https://xz.aliyun.com/t/7177
Bonus!从大佬那拿到了一个画画机器人代码,简单实用!
import sys |
用法
- 1、该脚本利用题目提供的
JSON
像素数据获取一个120*80的PNG图像(比如这个题目就给了包含像素数据的JSON) - 2、生成像素数据:
python main.py "image.png"
- 3、像素数据在
output/
中 - 4、该脚本将输出可以运行的GNU并行命令
这个题目确实学到了很多。
总结
简单的可以做,难的做不出,但是学到很多,继续努力!ヾ(◍°∇°◍)ノ゙
- Post Title: HackTM2020-WriteUp
- Post Author: ggb0n
- Post Link: http://ggb0n.cool/2020/02/04/HackTM2020-WriteUp/
- Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.
1.第五空间pwn题练习
2.虎符CTF两道web学习JS
3.SWPU2019复现
4.RootersCTF复现
5.BSidesSF2019-WriteUp
6.RoarCTF-simple_upload-WriteUp
7.UNCTF-Twice_Insert WriteUp
8.HEBCTF-easy_RSA-WriteUp
1.TCTF2020部分题解
2.第五空间pwn题练习
3.堆溢出-Tcache_Attack
4.堆溢出-Housese_Of_XXX
5.堆溢出基础
6.入坑二进制