TsukuCTF 2023 Writeup
Kawaii Raz0r Bladesでソロ参加し、18位でした。
OSINT
airport
つくしくんは、旅の思い出を振り返っていましたが、この写真はどこの空港かわからなくなりました。
ここはどこの空港か教えてくれませんか?
Flagフォーマットは TsukuCTF23{空港の3レターコード(IATA)} です。
ブログを参考に伊丹空港のレターコードであるITMを入れると正解。
TsukuCTF23{ITM}
castle
この前、お城に行ってこの写真を取ってきたんだ!
どこにあるかわかるかい?
フラグのフォーマットは、TsukuCTF23{緯度_軽度} です。
小数点は第三桁まで有効とします。
Google Lensに投げると姫路にある太陽公園であることが分かる。
Google Mapを参考に緯度経度を調整して提出。
TsukuCTF23{34.886_134.630}
eruption
つくしくんは旅行に行ったときに噴火を見ました。噴火の瞬間を実際に見たのは初めてでしたが、見た日付を覚えていません。
つくしくんが噴火を見た日付を写真の撮影日から特定して教えてください。
撮影場所が日本なのでタイムゾーンはJSTです。フラグの形式は TsukuCTF23{YYYY/MM/DD} です。
Google Lensに投げると、似た画像が掲載されているブログを発見。
どうやらJANOG49 in 鹿児島の開催期間中に噴火したとのことなので、Xで「JANOG 噴火」で検索すると2022年1月28日であることが分かる。
TsukuCTF23{2022/01/28}
location_for_what
とある場所を友達と探索していると、「ここ、何かの映画の聖地だった気がするけど、名前忘れちゃった......」とのこと。
シュッと特定して教えてあげよう!
Flagの形式は TsukuCTF23{映画のタイトル} です。
言の葉の庭だそう。今度見てみようかな。
TsukuCTF23{言の葉の庭}
green_bridge
この写真が撮影されたのはどこですか...?
Flagフォーマットは TsukuCTF23{緯度_経度} です。
端数は少数第4位を四捨五入して小数点以下第3位の精度で回答してください。
Google Lensに投げると、こちらのブログからもみじ谷大橋であることが分かる。
Google Mapで写真の地形を見ながら、それらしい緯度経度を提出すると正解。
TsukuCTF23{36.956_139.880}
perfume
とある施設でいろいろな香水を見かけたが、施設の場所が思い出せない。
この施設の場所を調べ、教えてほしい。
フラグはTsukuCTF23{緯度_経度}であり、小数点第三桁まで有効である。
Google Lensに投げると、こちらのブログから大分香りの博物館であることが分かる。
Google Mapで調べて緯度経度を提出。
TsukuCTF23{33.311_131.488}
mab
mab.main.jpが使用しているレンタルサーバサービスを特定し、そのWebサイトのドメイン名を答えてください。
Flagフォーマットは TsukuCTF23{ドメイン名}です。
nslookupでIPを正引きしてShodanにかけるだけ。
TsukuCTF23{https://lolipop.jp}
tsukushi_estate
つくし君が写真に写っているビルにオフィスを構えたいらしいのだけど、築年数が少し心配......
つくし君の代わりに調査してください!
Flagの形式は TsukuCTF23{築年_月} です。
例えば、2022年3月に出来たビルであれば、 TsukuCTF23{2022_03} になります。
つくし不動産の公式サイトに飛んで、貸オフィスの一覧を見てみると写真と似た物件を発見。
築年月を見て提出。
TsukuCTF23{1983_03}
travel_with_tsukushi
旅が好きなつくしくんは、空港の写真からそれがどこの空港かすぐにわかります。
つくしくんからの挑戦状!
これがどこの空港かわかるかな?
Flagフォーマットは TsukuCTF23{空港の3レターコード(IATA)} です。
クアラルンプールであることが分かるので、クアラルンプール空港のレターコードであるKULを提出して正解。
TsukuCTF23{KUL}
kiZOU
ここは日本で一番のリゾート地!少し歩くと目の前に素敵な像が見えたから写真を撮ったつもりだったんだけど、
見返したら端っこしか写ってない!困ったなぁ、この像についてもっと知りたかったんだけどなぁ。
僕の代わりにこの像について調べてくれないか?
フラグ形式は TsukuCTF23{像を寄贈した人物の名前} です。
画像をよく見ると、au style NAHAという文字が見つかり、那覇のauショップであることが分かる。
また、au style NAHAで検索すると、パレット久茂地に店を構えていることも分かる。
ストリートビューで見てみるとシーサー像を発見。
「パレット久茂地 シーサー像」で検索するが寄贈者は見つからなかったので、Xで改めて調べるとこちらのツイートが見つかる。
TsukuCTF23{上原清善}
big_statue
大きなドリアンだ!どこにあるんだろう??
フラグの形式は TsukuCTF23{緯度_経度} です。
例えば、この像が東京の渋谷駅にある場合、フラグは TsukuCTF23{35.6580_139.7016} となります。
Google Lensに投げても見つからなかったので、画像で見える「榴梿王 利陞」を検索してみると、Lexas Durian KingのFacebookが見つかる。
また、こちらのTikTokから店の前に画像のドリアン像があることが分かる。
よって、ストリートビューからドリアン像の位置の緯度経度を取得する。
TsukuCTF23{1.3623_103.8872}
TrainWindow
夏、騒音、車窓にて。
フラグのフォーマットは、TsukuCTF23{緯度_経度}です。
緯度経度は小数第五位を切り捨てとします。
Google Lensにかけると、熱海であることは分かるが詳細な位置までは分からない。
よって、熱海~網代駅までの路線沿いで画像と似たような風景になる場所をストリートビューを手掛かりに探すとここがヒット。
TsukuCTF23{35.0641_139.0666}
CtrlAltPrtSc
仕事中にCtrl + Alt + PrtScでウィンドウのスクリーンショットを撮ったよ。
つくし君がサボって使用していたサービスの名前を答えよ。 フラグはTsukuCTF23{サービスの名前}の形式です。
サボって利用するサービスということと左上のロゴと文字よりYoutubeと推測するとフラグだった。
これ勘以外の解き方あるんですか
TsukuCTF23{Youtube}
laser
光源の座標を正確に教えてください。
フラグフォーマットは、TsukuCTF23{緯度_経度}です。 小数点以下5位を切り捨てて、小数点以下4桁で答えてください。
範囲を調整しながらGoogle Lensで調べると、こちらのツイートが見つかる。
リプライで梅田換気塔に設置された光源であることが分かる。
こちらのサイトを参考にしながらGoogle Mapから座標を調整して提出。
TsukuCTF23{34.7016_135.4990}
3636
ここはどこ...?
Flagフォーマットは TsukuCTF23{緯度_経度} です。
端数は少数第四位を四捨五入して小数点以下第三位の精度で回答してください。
適当に「3636 電話番号 ed jp」で検索すると、とうみょうこども園がヒットする。
ストリートビューで近辺を探索すると、この場所であることが分かる。
ちょうど看板の場所になるように緯度経度を調整して提出。
TsukuCTF23{37.501_139.928}
Yuki
雪、無音、窓辺にて。
フラグのフォーマットは、TsukuCTF23{緯度_経度}です。
緯度経度は小数第四位を切り捨てとします(精度に注意)。
範囲を調整してGoogle Lensに投げると、定山渓という札幌の温泉地であることが分かる。
観光サイトの宿泊施設をMapなども見ながら調べていくと、定山渓ビューホテルが地形的に画像と近いことが分かる。
また、ホテル内のカフェ サンリバーというカフェの画像が室内の机、椅子と一致していることが分かる。
Google Mapを見ながら緯度経度を調整して提出。
TsukuCTF23{42.968_141.167}
tsukushi_no_kuni
かつて、筑紫国を統治していた国造の一人が乱を起こした。
その子孫の一人が、ある天皇と同一人物である説が提唱されている。
その子孫の名前を TsukuCTF23{} で囲んで答えよ。
「筑紫国 国造 乱」で検索すると磐井の乱が見つかり、筑紫君磐井という人物が起こしていることが分かった。
「筑紫君磐井 子孫 天皇」で適当に複数記事を回ると、このブログで天武天皇についての記載が散見される。
よく分からないが適当に天武天皇で提出するとフラグだった。提唱されているソースが何処なのかは不明。
TsukuCTF23{天武天皇}
free_rider
https://www.fnn.jp/articles/-/608001
私はこのユーチューバーが本当に許せません!
この動画を見たいので、元のYouTubeのURLを教えてください。
また、一番上の画像(「非難が殺到」を含む)の再生位置で指定してください。
フラグフォーマットは、
TsukuCTF23{https://www.youtube.com/watch?v=REDACTED&t=REDACTEDs}
外国人の新幹線無賃乗車動画の元動画のURLを探す問題。
「新幹線 無賃乗車 動画」で検索すると、この記事からFidiasというYoutuberであることが分かる。
元動画のタイトルを知りたいため、「Fidias Japan Travel」で調べるとこの記事から、"I Travelled Across Japan For Free"という動画であることが分かった。
消される前にツイートで拡散されているだろうと推測し、Xで「I Travelled Across Japan For Free」で調べるとツイートが見つかり、動画が消去されていることからこれが元動画のURLであると推測。
次に再生位置を知りたいが、この手の炎上動画は大抵第三者に再投稿されているので、Googleでタイトルを調べると再投稿された動画が見つかる。
問題文の記事と同じ部分は2:56 = 176sであることが分かるため、https://www.youtube.com/watch?v=Dg_TKW3sS1U&t=176sがフラグ。
TsukuCTF23{https://www.youtube.com/watch?v=Dg_TKW3sS1U&t=176s}
river
弟のたくしから、「ボールが川で流されちゃった」と写真と共に、連絡がきた。
この場所はどこだ?
Flagフォーマットは TsukuCTF23{緯度_経度} です。
端数は少数第5位を切り捨てて小数点以下第4位の精度で回答してください。
タコ負けして最近パチ禁をしているはずなのですが、ニューギンの専用駐車場が真っ先に目についたのでこれを手掛かりに見ていく。
ニューギンの会社概要から支店や営業所の住所をGoogle Mapで見ていくと、周りの風景から鹿児島営業所であることが分かる。
Google Mapから緯度経度を調整し、よっしゃあ漢唄を歌いながらフラグを提出。
TsukuCTF23{31.5757_130.5533}
broken display
表示が壊れているサイネージって、写真を撮りたくなりますよね!
正しく表示されているときに書かれている施設名を見つけて提出してください!
フラグ形式: TsukuCTF23{◯◯◯◯◯◯◯◯IYA_◯◯◯◯◯◯S}
後ろの方に日能研と駅のようなものが見える。
よって、〇〇宮かつローマ字表記での文字数が一致する地名 + 駅前に日能研がある場所を探していく。
地名コレクションと日能研の教室案内を見ていくと、西宮が見つかる。
「NISHINOMIYA」で検索すると西宮ガーデンズというショッピングセンターが見つかり、ローマ字表記の文字数が一致するためここであると推測し、提出。
TsukuCTF23{NISHINOMIYA_GARDENS}
stickers
この画像が撮影された場所を教えてください!
Flagフォーマットは TsukuCTF23{緯度_経度} です。
ただし、小数点4桁の精度で答えてください。
Google Lensに投げても何も出てこない。
千社札らしきものが貼られており熱海プリンのプリンカーが写っていることから、熱海の神社を中心に探していくが、全く見つからない。
また、背景に「CI EC」が見えるのでそれらしき企業も探すが何も出てこない。(どうやらFUJITECだったみたいです。)
仕方ないので、もう一度Google Lensを用いて画像 + 熱海で検索すると、熱海七湯 河原湯が見つかる。
Google Mapより緯度経度を調整して提出。
TsukuCTF23{35.0967_139.0747}
RegexCrossword
クロスワードを解いてみて!
これを作った会社の本社の郵便番号をハイフンありで答えてね!!
Google Lensで調べても出てこない。
何らかのグッズ?か備品であると推測し、Xで「正規表現 クロスワード」と検索すると、このツイートが見つかる。
記載されているブログから会津大学の学食のナプキンであることが分かる。
もう一度Xで「会津大学 正規表現 クロスワード ナプキン」で検索すると、このツイートからEyes,Japanが制作したことが分かるので、Google検索で「Eyes,JAPAN」と検索し、出てきた郵便番号がフラグ。
TsukuCTF23{965-0872}
flower_bed
花壇の先にQRコードのキューブがあるようですね。友人曰く、モニュメントの近くに配置されているものらしいです。
こちらのQRコードが示すURLを教えてください! リダイレクト前のURLでお願いします!
Flagの形式は TsukuCTF23{URL} です。例えば、https://sechack365.nict.go.jp がURLなら、
TsukuCTF23{https://sechack365.nict.go.jp} が答えになります。
QRコードが書いてある面に、「〇〇 Prefectual Civil Hall and 〇〇 House Official Site」という文章がある。
Googleで「Prefectual Civil Hall and House Official Site」と調べると、旧福岡県公会堂貴賓館の公式サイトが見つかる。
ただしこのURLがフラグではなかったため、もう少し調査する必要がある。
Google Mapを見てみると、近くにFUKUOKAモニュメントというモニュメントが存在し、問題文からこの近くで撮影されていることが分かる。
与えられた画像ではよく分からなかったが、どうやら立体のモニュメント上にQRコードが存在しているらしく、モニュメントを右側から撮影した画像からQRコードを読み取れれば良さそう。
一応このツイートが見つかるが、解像度が低く読み取れない。
仕方ないので、unlimited:waifu2xで無理やり4倍に拡大させるとうまくQRコードを読み込むことが出来た。
TsukuCTF23{http://www.fukuokaken-kihinkan.jp}
grass_court
しばらく使われていないテニスコートのようだ。
この日本にあるテニスコートの場所はどこだろう。
フラグの形式は TsukuCTF23{緯度_経度}です。
小数点以下5位を切り捨てて、小数点以下4桁で答えてください。
テニスコートだけでは特定出来なさそうなので、後ろにあるパラボラアンテナに注目する。
画像+パラボラアンテナでGoogle Lensで検索すると、水沢VLBI観測所がヒットする。
Google Mapで見てみると、風の又三郎テニスコートとテニスコート前の木の本数からここであると推測し、画像から緯度経度を調整して提出。
TsukuCTF23{39.1350_141.1325}
fiction
「座標を教えてくれ」
フラグフォーマットは、TsukuCTF23{緯度_経度}です。
小数点以下5位を切り捨てて、小数点以下4桁で答えてください。
何故VALORANT?と思いながらGoogle Lensに投げる。
すると、Sunsetというマップであることが分かる。(最近やってないので本当に知らんかった)
fandomを見ると座標である34°2'2" N 118°12'16" Wが見つかる。
どうやら実際の地域をモデル?にしているらしく、Google Mapに座標を張り付けて検索すると緯度経度が分かるので提出。
TsukuCTF23{34.0338_-118.2044}
hunter
名前をメールで聞こうとしたところ、相手のGmailの一部が分からなくなってしまいました。
大変お忙しいところ恐縮ですが、暇なときに調査してください。
qeinijo#iby#@gmail.com
#
が不明な部分です。
なお、外部サービスに短期間で多くのアクセスをしないようにしてください。
正確なメールアドレスが分からないのでEpieosなども使えなさそう。
ということでgmailのメールアドレスに利用可能な文字(小文字アルファベット + 数字 + .)で有り得る37*37=1369通りのメールアドレスのリストを作成する。
GHuntを用いてリスト内のメールアドレスを調べ、有効なアカウントが見つかるまでループさせるスクリプトを作成した。
有効でないメールアドレスは、The target wasn't found.と出力されるだけであり、有効な場合はGoogleの各アクティビティが表示される。
よって、出力内の"Google"という文字の有無で判定させた。
import string ALPHA = string.ascii_lowercase + string.digits + "." email = "" with open("email_list.txt","wt") as f: for a1 in ALPHA: for a2 in ALPHA: email = "qeinijo" + a1 + "iby" + a2 + "@gmail.com" + "\n" f.write(email)
import time import os email_list = [] with open("email_list.txt") as f: for line in f: email_list.append(line.rstrip()) for mail in email_list: print(mail) time.sleep(1) process = os.popen("ghunt email " + mail) ret = process.read() process.close() if "Google" not in ret: continue else: print(ret) break
40~50分ぐらい回すと、qeinijo.iby8@gmail.comが有効なアカウントであり、出力内のName欄にフラグであるTsukuCTF23{GHun7_i5_u5efu1}が見つかる。
TsukuCTF23{GHun7_i5_u5efu1}
twin
ハッカーは独自に収集した大量の個人情報を、とあるWebサイト上で2023年11月23日に投稿した。
我々はこの投稿IDがKL34A01mであるという情報を得た。ハッカーのGitHubアカウントを特定せよ。
ダークウェブ要素は恐らくないであろうこと、ハッカー・投稿・個別IDからPastebinと推測。
Pastebinに飛ぶと投稿が見つかる。
GEMINI6512の他の投稿を見ると、ruby製のクワインが見つかるが、プログラム自体を調べてもあまり意味はなさそう。
githubアカウントを特定出来ればいいので、githubのリポジトリにそのまま投稿されてるのではと推測し、githubで"Tsuine"と検索するとリポジトリがヒット。
そのままgithubアカウントを提出すればOK。
TsukuCTF23{gemini5612}
First Bloodでした:)
Web
basic
保護されていない通信ではパスワードはまる見えダゾ!
e.g. パスワードが Passw0rd! の場合、フラグは TsukuCTF23{Passw0rd!} となります。"
pcapファイルが渡される。
basic認証だろうと当たりをつけてHTTPストリームを見ると、AuthorizationにBase64でエンコードされている認証情報が見つかる。
Cyberchefで復号してパスワードを提出。
TsukuCTF23{2929b0u4}
misc
what_os
とある研究所から、昔にシェル操作を行った紙が送られてきた来たんだが、
なんのOSでシェルを操作しているか気になってな。
バージョンの情報などは必要ないから、OSの名前だけを教えてくれないか?
にしても、データとかではなく紙で送られて来たんだ。一体何年前のOSなんだ。。。
送られてきた紙をダウンロードして確認してほしい。
シェル操作をしている様子のテキストファイルが配布される。
適当にas2 getty glob init msh passwd std0とかで検索すると、unix-jun72というGoogle Code Archiveが見つかる。
UNIX 1st editionってことはUNIX?と推測し提出すると正解だった。
TsukuCTF23{Unix}
build_error
怪盗シンボルより、以下の謎とき挑戦状が届いた。
怪盗シンボルだ!
メールに3つのファイルを添付した。
この3つのファイルを同じディレクトリに置き、makeとシェルに入力し実行するとビルドが走るようになっている。
ビルドを行い、標準出力からフラグを入手するのだ!
追記:ソースコードは秘密
怪盗シンボルはせっかちなので、ビルドできるかチェックしているか不安だ。。。 取りあえずチャレンジしてみよう。
FlagフォーマットはTsukuCTF23{n桁の整数}になります。
Makefile, main.o, one.oというファイルが渡される。
普通にmakeしても失敗するので、オブジェクトファイルをghidraでデコンパイルしてみる。
undefined8 main(void) { int local_34; long local_30; long local_28; long local_20; local_30 = 0xc; local_28 = 0xb; local_20 = 0x4b; one_init(); for (local_34 = 0; local_34 < local_28; local_34 = local_34 + 1) { if (local_34 < local_30) { local_20 = local_20 + 1; } if (local_20 < local_34) { local_28 = local_28 + 1; } local_30 = local_30 + 1; } local_20 = local_20 + local_30 + local_28; if (local_20 == c + a + b) { printf("flag is %ld\n",local_20); } else { puts("please retry"); } return 0; }
void one_init(void) { int local_c; a = 0xc; b = 0xb; c = 0x4b; for (local_c = 0; (ulong)(long)local_c < b; local_c = local_c + 1) { if ((ulong)(long)local_c < a) { c = c + 1; } if (c < (ulong)(long)local_c) { b = b + 1; } a = a + 1; } return; }
ビルド出来るように弄らなくてもそのままPythonでa+b+cを求めた方が楽そうなので再現コードを書いてフラグを求める。
def one_init(a,b,c): a = 0xc b = 0xb c = 0x4b i = 0 for i in range(b): if i < a: c += 1 if c < i: b += 1 a += 1 return a,b,c a,b,c = one_init(0,0,0) flag = a+b+c print("TsukuCTF23{" + str(flag) + "}")
TsukuCTF23{120}
content_sign
どうやら、この画像には署名技術を使っているらしい。
この署名技術は、画像に対しての編集を記録することができるらしい。
署名技術を特定し、改変前の画像を復元してほしい。
Flag形式はTsukuCTF23{<一個前に署名した人の名前>&<署名した時刻(ISO8601拡張形式)>}です。
例えば、一個前に署名した人の名前は「Tsuku」で、署名した時刻が2023/12/09 12:34:56(GMT+0)の場合、
フラグはTsukuCTF23{Tsuku&2023-12-09T12:34:45+00:00}です。
なお、タイムゾーンはGMT+0を使用してください。
exiftoolで与えられたpngファイルを見てみると、c2paという文字が散見される。
どうやら画像の認証を行う技術規格だそう。
c2patoolというツールで署名を見てみると2つ署名が見つかるが、改変前の画像の復元なので時間が早い1つ目の署名を答えれば良い。
1つ目の署名者はTSUKU4_IS_H@CKERであることが分かるので、1つ目の署名の時刻と組み合わせてフラグ。
TsukuCTF23{TSUKU4_IS_H@CKER&2023-12-08T13:00:26+00:00}
Open xINT CTF 2023 Writeup
2年ぶりの記事らしい
今年も開催されるとのことで参戦。オンラインで解ける14問中10問解いて4位でした。
[注意]
個人の情報となりうるもの(個人名、電話番号、アカウント名やそのリンク)は意図的に伏せています。
何か問題が発生した場合は記事の削除および編集を行います。
解けた問題
GEO
Amusement
ここの施設の名前は?
Google画像検索で出てきた。
【お山の #かんらんしゃ】~アトラクション紹介~
— さがみ湖リゾートプレジャーフォレスト (@sagamikoresort) 2020年4月27日
標高420mに立つプレジャーフォレストの大きなシンボル的存在!#ワンちゃん と一緒に乗れるのも特徴♪
運がよければ富士山も見えるかも?!#イルミリオン の時期には美しくライトアップされます。#観覧車 #stayhome #おうち時間 pic.twitter.com/AfVZk8r7Du
mural
この壁画が描かれた建物の位置座標を答えてください。
フラグ形式: 7桁のplus code
(画像出典: https://iranprimer.usip.org/blog/2022/feb/09/irans-revolution-43-politics)
出典の画像をスクショして画像検索すると、Flickrに投稿された写真がヒット。
Enghelab Square, Tehranとあるので、Google Mapで調べて画像の風景と合致する所を調べる。
Flickrの画像をよく見ると左端に駅が写っているのでそれを参考にすると以下の場所あたり。
あとはプラスコードを打つだけなので、適当にGuessingして建物のプラスコードを入れたら正解。
Esta rico!
このお店の電話番号は?
机の上にある料理名で検索しても出なかったので冷蔵庫のシールからGuessingする。
橙色のシールに「055」からはじまる電話番号らしき番号が見えるため、「055 市外局番」で調べる。
すると、「静岡県御殿場市、駿東郡小山町」の市外局番であることが分かる。
また、画像内のレジ付近に「サルチーニャ」(サルティーニャ?)が売っているため、「サルティーニャ」で調べるとボリビアの料理であることが分かる。
よって、「静岡県御殿場市 ボリビア料理」で調べると2番目にホットペッパーグルメのページが出てくる。
店内の様子から画像と一致していることが分かるので、その店の電話番号が正解。
WHOIS
neko
neko.vn の登録日付はいつ?
フラグ形式: yyyy-mm-dd
hint: ほかのサイトで探してみて。
ヒント通り、「vn domain whois」で調べて出てきた下記サイトでwhoisをかけると登録日付が出てくる。
https://vnnic.vn/en/whois-information?lang=en
MISC
Aircraft
この機体のモデル名は?
フラグ形式: [A-Z]+-\d+[A-Z]+
https://1drv.ms/v/s!AmBkM-TKj1UtisAkIbSDFG8xxXWAOg?e=tJ9WkV
4つのプロペラがついた航空機の動画が渡される。
スクショして画像検索したら「C-130」と出たので提出してみたがダメ。
形状は似ているのでおそらく同型機であると予想し、C-130のwikipediaに記載されている機体で映像と似ているものを入れていく。
「C-130J」が正解だった。
AI
REVERSE AI
この生成AI画像は、ある文学作品の冒頭部分を画像イメージにしたものである。この文学作品のタイトルを答えよ。
推測できるような学がないため、「2人の猟師 3匹の白い犬 文学作品」で調べる。
すると、「注文の多い料理店」がヒットしたのでこれが正解。
BUS
BUS
このバスの座標を求めよ。
フラグ形式: Nxx.xxx_Exxx.xxx
ひとまずバスの部分で画像検索すると、日光市営バスであることが分かり、主に足尾JR日光駅線で運行されている車両であることが分かる。
https://www.nikko-kotsu.co.jp/images/localbus/ashiojrnikkosenakakuraasiosen.pdf
また、カーナビ部分に国道122号線の標識が出ており、上記pdfからバスの行先表示をGuessingすると、JR日光駅行である可能性が高い。
よって、足尾JR日光駅線の路線内で、JR日光駅方面に向かう国道122号線の部分をしらみつぶしに探せばよい。
奥の方にある青と赤の旗や、道路上の速度制限表示を参考にしながら似た風景を探すと、以下の場所がヒット。
ピン差しして緯度経度を微調整すれば正解。
SOCIAL
cosplayer
下記のURLに投稿された、恐竜に扮したCCさくらのコスプレイヤーの方は昔、
人間のCCさくらのコスプレイヤーの方と2ショットを撮っています。
人間のCCさくらのコスプレをしていた方のX(Twitter)ユーザ名を答えてください。
https://x.com/MikeCovers/status/979804843543056384?s=20
ツイートより、「card-raptor sakura animeboston2018」で検索すると、一番上にfacebookの投稿が見つかる。
投稿にはご丁寧に恐竜CCさくらのご本人のアカウントが掲載されているので飛ぶ。
次に、写真からタグ付けされている写真を見ると、人間のCCさくらとのツーショット画像の投稿がある。
これも同様に相手のアカウントが掲載されているため飛んでみる。
相手のFBアカウントの投稿にはXのアカウントに関する情報は見当たらなかったため、アイコンをスクショして画像検索したらアカウントを発見出来た。
pet
この場所の開園式を撮影したカメラマンは、
今は引退してゴルフを楽しむなど余生を謳歌している。
そんな彼を長年支えてきたペットの名前は?
とりあえず画像検索してみると、バンクーバーのPortal Parkという公園であることが分かる。
「Vancouver Portal Park Opening Ceremony」で画像検索をかけると、開園式の写真が掲載されたサイトがヒット。
https://searcharchives.vancouver.ca/unidentified-man-speaking-at-portal-park-opening-4
サイト内にこの写真の権利者の氏名が載っているため、「(氏名) photographer」で検索すると、この写真家がオーナーである会社のLinkedinが出てくる。
さらに会社名で検索すると、FBのアカウントが見つかる。
自己紹介欄にゴルフについて言及しているためこれが本人だと推測し、写真欄を見るとペットの誕生日を祝う投稿がある。
その投稿にペットの名前が記載されていたため、これが答え。
CRYPTO
Bitcoin
2021年11月に結婚したIlyaが所有していたとみられるBitcoinのアドレスは?
「Ilya who married in 2021 November」で検索すると、BTCに関する事件で逮捕されたなど記事が散見される。
「2016 bitfinex hack address」で調べると、逮捕前にBTCの送金(資金洗浄?)が行われていた旨の記事が見つかる。
https://cointelegraph.com/news/2-5b-in-stolen-btc-from-bitfinex-hack-awakens
このサイト内にトランザクションの詳細が記載されたツイートへのリンクがあり、Blockstream.infoへのリンクが見つかる。
それを参照し、取引しているアドレスを答えると正解だった。
解けなかった問題
Fireworks
8月の花火大会が開催されている場所をブルートフォースしようとしたら多過ぎたので撤退。
COMPANY
MSTがよく分からず放置してたら終わってた。
RIDE A BUS
あの画像で座標特定出来る人間本当に居るんですかね...
Otokichi
山本音吉の長男(John William Ottoson)が1928年8月に台北で亡くなった事以外何も分からず。
Google CTF 2021 writeup - filestore
哀れな一人チームで参戦。
1完出来ただけ良しとすべきかと思ったけどこの問題だけ321チームにも解かれていたので悩みどころ。
CPPは処理を追っている最中に眠くなったので断念。またwriteupを見て復習したい。
Filestore
問題概要
We stored our flag on this platform, but forgot to save the id. Can you help us restore it?
以下のコードが与えられる。
import os, secrets, string, time from flag import flag def main(): # It's a tiny server... blob = bytearray(2**16) files = {} used = 0 # Use deduplication to save space. def store(data): nonlocal used MINIMUM_BLOCK = 16 MAXIMUM_BLOCK = 1024 part_list = [] while data: prefix = data[:MINIMUM_BLOCK] ind = -1 bestlen, bestind = 0, -1 while True: ind = blob.find(prefix, ind+1) if ind == -1: break length = len(os.path.commonprefix([data, bytes(blob[ind:ind+MAXIMUM_BLOCK])])) if length > bestlen: bestlen, bestind = length, ind if bestind != -1: part, data = data[:bestlen], data[bestlen:] part_list.append((bestind, bestlen)) else: part, data = data[:MINIMUM_BLOCK], data[MINIMUM_BLOCK:] blob[used:used+len(part)] = part part_list.append((used, len(part))) used += len(part) assert used <= len(blob) fid = "".join(secrets.choice(string.ascii_letters+string.digits) for i in range(16)) files[fid] = part_list return fid def load(fid): data = [] for ind, length in files[fid]: data.append(blob[ind:ind+length]) return b"".join(data) print("Welcome to our file storage solution.") # Store the flag as one of the files. store(bytes(flag, "utf-8")) while True: print() print("Menu:") print("- load") print("- store") print("- status") print("- exit") choice = input().strip().lower() if choice == "load": print("Send me the file id...") fid = input().strip() data = load(fid) print(data.decode()) elif choice == "store": print("Send me a line of data...") data = input().strip() fid = store(bytes(data, "utf-8")) print("Stored! Here's your file id:") print(fid) elif choice == "status": print("User: ctfplayer") print("Time: %s" % time.asctime()) kb = used / 1024.0 kb_all = len(blob) / 1024.0 print("Quota: %0.3fkB/%0.3fkB" % (kb, kb_all)) print("Files: %d" % len(files)) elif choice == "exit": break else: print("Nope.") break try: main() except Exception: print("Nope.") time.sleep(1)
考察
storeを選択し文字列を与えると、サーバー上の2**16のバイト列に書き込みが行われる。
「# Use deduplication to save space.」と書いてある部分に着目すると、文字列をstoreする際に先頭16バイトをサーバーに保存されている文字列と重複するかを確認した後、重複するプレフィックス長(最大1024バイト)を求めている。全て重複していなければ新たに保存し、16バイト分の文字列長がusedに加算される。
実験
フラグの形式は「CTF{...}」と分かっており、既にフラグが追加されているのもコードから確認出来るため、実際に「CTF{」という文字を送り付けてstatusを確認してみる。
== proof-of-work: disabled == Welcome to our file storage solution. Menu: - load - store - status - exit status User: ctfplayer Time: Fri Jul 23 02:54:44 2021 Quota: 0.026kB/64.000kB Files: 1 Menu: - load - store - status - exit store Send me a line of data... CTF{ Stored! Here's your file id: B4SoCXVzHwJUphrK Menu: - load - store - status - exit status User: ctfplayer Time: Fri Jul 23 02:54:54 2021 Quota: 0.026kB/64.000kB Files: 2 Menu: - load - store - status - exit
Quotaに着目すると、「CTF{」の保存前と保存後で数値が変わっていない。
よって「CTF{」以降の文字をブルートフォースして数値が変わらないものがフラグの一部分とすればOK。
solver
サーバーでは最初の16バイトしか正しく重複検査できない。
例えば「CTF{hogehogeabcdefg}」というフラグが保存されていた場合、「CTF{hogehogeabcd」までしか期待した重複検査を行わず、「CTF{hogehogeabcda」という文字列を与えても数値が一致してしまう。
開催時は愚直に15文字以上になったら最初に指定するフラグの位置を変えてエスパーしたが、特定したフラグが15文字以上になった場合一文字ずらして送り付けるようにすれば綺麗に求まるので、他の方のwriteupを参考にしつつ書き直した。(とはいえ自分の環境ではタイムアウトが起きたのでどちらにせよ指定するフラグはズラさなければダメだった...。)
from pwn import * import string s = string.printable quota = "0.026kB/64.000kB\n" flag = "CTF{" io = remote('filestore.2021.ctfcompetition.com',1337) ctr = 0 while("}" not in flag): print(flag) for i in range(len(s)): flag_send = flag[ctr::] + s[i] io.sendlineafter("- exit","store") io.sendlineafter("Send me a line of data...",flag_send) io.sendlineafter("- exit","status") io.recvline() io.recvline() io.recvline() quota_server = io.recvline() if(quota == quota_server.decode().replace("Quota: ","")): flag += s[i] break else: quota = quota_server.decode().replace("Quota: ","") #print(quota) if(len(flag) >= 15): ctr += 1 print("flag : %s" % flag)
CTF{CR1M3_0f_d3dup1ic4ti0n}
OS自作入門の環境構築メモ
OS自作入門本を買った。
主に自分が詰まったりした部分をまとめていきます。恐らく随時更新。
環境
WSLの有効化
なんで無効にしてたかすら不明。当然仮想プラットフォームを有効化してやる。
コントロールパネル -> プログラム -> プログラムと機能 -> Windowsの機能の有効化または無効化
ウィンドウを開いたら「仮想マシンプラットフォーム」にチェック。「Windowsハイパーバイザープラットフォーム」にもチェックを入れておくとVirtualBox(6.1.16以降)などと共存できるので吉。
disk.imgのマウントができない
day01において「sudo mount -o loop disk.img mnt」を実行すると「mount: ./mnt: mount failed: Operation not permitted.」というエラーが出る。自分の環境の場合、WSL1のまま動かしていたので2に変えてやる。
コマンドプロンプトかPowerShellで「wsl --set-version Ubuntu-20.04 2」を実行すれば勝手に更新されるが、自分の場合カーネルコンポーネントの更新をサボっていたためにエラーが発生した。更新後再度実行したら無事に終了。下記サイトにエラーの詳細と対処が細かく載っている。
WSL バージョンを変更する方法 | SEECK.JP サポート
QEMU環境で実行時に「Could not connect: Connection refused」が発生する
原理をまだ理解出来ていないが、WSL1とWSL2でネットワーク周りの仕様が変更された事が原因らしい。この場合DISPLAY環境変数を変えてやることで対処可能。
「~/.profile」内の「export DISPLAY=:0.0」を「export DISPLAY=\$(cat /etc/resolv.conf | grep nameserver | awk '{print \$2}'):0.0」に変えて保存。
その後、VcXsrvを起動する際にExtra Settingsにて「-ac」をAdditional parametersに追記してやる。どうやらパブリックアクセスを許可するためのパラメータらしい。
参考↓
パケットからマルウェアを探る(Malware Traffic Analysis - ICEMAIDEN)
この記事は、 大阪工業大学 Advent Calendar 2020の22日目の記事です。
※悪用厳禁。何かしら問題が発生した場合は非公開にする可能性があります。
はじめに
20日目の記事でも挨拶をしましたが、初めましての方は初めまして。しあのすと申します。
今回は最近勉強したパケット解析についての備忘録を兼ねてまとめたいと思います。
マルウェア解析
マルウェア解析の流れとして「表層解析」、「動的解析」、「静的解析」の3段階が存在し、この順番に行われることが定石となっています。
表層解析
ハッシュ値やアンチウイルスソフトの検知などを元に調査を行う。動的解析
仮想環境で実際にマルウェアを動作させ、その動作や記録を元に調査を行う。今回話すパケット解析はこれ。
静的解析
マルウェアのリバースエンジニアリングを行い、そのコードを元に調査を行う。
セキュリティとパケット解析
ネットワーク障害の特定や設計段階の調査のために行われるイメージがありそうなパケット解析ですが、セキュリティ対応としてパケット解析が行われる場合も多いのが現状です。
俗に言うセキュリティアナリストやDFIR担当者が不正侵入防止の調査、またはマルウェアや攻撃者の不正侵入後の原因特定をするためにパケット解析が用いられます。
セキュリティのためのパケット解析はネットワーク設計などの調査とは異なり、攻撃者が制御している機器などのこちらから特定が困難な情報が関わってくるため、限られた情報から全貌を明らかにする必要があります。
Malware Traffic Analysis
実際にマルウェアとの通信をキャプチャした有害なpcapファイル検体の公開及びその解析演習を行うことが出来る Malware-Traffic-Analysis.netというサイトが存在します。
サイトには解析のための基本的なWiresharkのチュートリアルやセキュリティのためのパケット解析のトピックなども載っており、Exercisesには各問模範解答が付属しているため、興味を持った方は一度自力で考えてみても面白いかもしれません。
今回はこのサイトのICEMAIDENを例にパケットから調査を行っていきます。
解析
※解析の際は仮想環境上で外部通信やホストとの共有ファイルを切ったことを確認した上で行うことをおすすめします。解析の途中で出てきた有害なIPやURLは意図的にエスケープしています。この記事を見た後に実際にアクセスして何か被害が生じた場合、一切責任を負いません。
シナリオ LANセグメントデータ: LANセグメント範囲:10.18.20.0/24(10.18.20.0〜10.18.20.255) ドメイン:icemaiden.com ドメインコントローラー:10.18.20.8-Icemaiden-DC LANセグメントゲートウェイ:10.18.20.1 LANセグメントブロードキャストアドレス:10.18.20.255
あなたのタスク pcapとアラートを確認してから、次の質問に答えてください。 問1 : 感染したWindowsホストのIPアドレス、MACアドレス、およびホスト名は何ですか? 問2 : この感染したWindowsホストの被害者のWindowsユーザーアカウント名は何ですか? 問3 : 被害者はどのような種類のマルウェアに感染しましたか? 問4 : pcapからのトラフィックに基づいて、マルウェアはどこから来た可能性がありますか? 問5 : 最初の感染後、被害者はどのタイプのWebページ/ Webサイトにアクセスしたように見えましたか?
問1
pcapと共に与えられるアラートの画像に注目すると、「TROJAN Ursnif」の文字が見つかるのでこれに着目します。
送信先ポートが80番であることからHTTPリクエストと10.18.20.97でフィルターをかけて検索してみます。
10. 18. 20. 97
から8. 208. 24. 139
へのパケットが大量に見つかるため、これがアラートにひっかかったと推測出来ます。よってIPは「10.18.20.97」。
MACアドレスはパケット詳細欄のEthernet II
の欄から特定できます。
Source: Acer_56:9b:cf(00:01:24:56:9b:cf)
とあることから、MACアドレスは「00:01:24:56:9b:cf」。
ホスト名はkerberosの通信から特定します。kerberosのCNAMEレコードにはクライアントの主要な識別子の名前が含まれているので、kerberos.CNameString and ip.addr==10.18.20.97
と入力してフィルターをかけてみます。
CNameString
の値から、ホスト名は「JUANITA-WORK-PC」。
問2
先程の結果のCNameStringの欄で右クリックし、「列として適用(Apply as Column)」を押すと、CNameStringの結果が列として表示されます。
ここで、ユーザーアカウント名はホスト名と違い「$」で終わらないという特性を用いると、ユーザーアカウント名は「momia.juanita」と特定できます。
問3
問1でUrsnifのアラートが出ていることから、マルウェアの種類は「Ursnif」だと考えられます。
さらに、
Wiresharkによるパケット解析講座 6: Ursnif感染の調査を参照すると、http.request
のフィルターをかけた際に上で言及されている特殊なGETやPOSTリクエストが散見されることも分かります。このような根拠からもUrsnifと推測して良いと考えられます。
問4
Ursnifで一度Web検索をかけてみます。
上の記事を参照すると、Ursnifは不正なプログラムによって他のサイトからダウンロードされるか、不正なメールから侵入する場合が殆どだと分かります。
http.request
でフィルターをかけてみると、一番最初にhttp:// mail[.]aol[.]com/
というメールサイトにアクセスしているのが分かります。
また、このメールサイトにアクセスしているのが不審なGET/POSTリクエストが送られる前であることから、(上記URL)において、不正なメールから感染したと考えて良いと思われます。
問5
http・https通信に絞るため、(http.request or ssl.handshake) and !ssdp
というフィルターをかけます。
15228~16215,16315,16436~16493において不審なGET/POSTリクエストが確認された後のパケットを見てみると、~[.]bac[.]com
やbankofamerica
の文字が散見されます。
bac[.]com
でwhoisをかけるとAdminの情報辺りでやはりbankofamerica
の文字が見つかるため、bankofamerica[.]comにアクセスしたと推測出来ます。
Ursnifがバンキングマルウェアとして有名なことからの関連でしょうか。
おわりに
HTTP通信から不審なプログラムをエクスポートしてVirusTotalで検索をかけたり、送信されている暗号化データを復号出来たりするとさらに情報を抜き出すことが可能でしょうが、今の技術力や記事を書く時間的にこの辺りが限界でした。
解析の根拠にも間違いや誤魔化しが多い可能性があるので精進します。
この記事によって少しでもパケット解析やフォレンジックに興味を持って頂ければ幸いです。
WaniCTF writeup(Crypto,Forensics)
25問解いて187人中24位でした。
ForensicsとCryptoに加えてMiscも全完出来たので嬉しかったです。
RevとPwnは精進します。
Crypto
Veni, vidi
SYNT{fvzcyr_pynffvpny_pvcure}
ROT13で復号する。
FLAG{simple_classical_cipher}
exclusive
XORを使った暗号です🔐
encrypt.pyとoutput.pyが与えられる。
key = "REDACTED" flag = "FAKE{this_is_fake_flag}" assert len(key) == len(flag) == 57 assert flag.startswith("FLAG{") and flag.endswith("}") assert key[0:3] * 19 == key def encrypt(s1, s2): assert len(s1) == len(s2) result = "" for c1, c2 in zip(s1, s2): result += chr(ord(c1) ^ ord(c2)) return result ciphertext = encrypt(flag, key) print(ciphertext, end="")
コード中の
assert key[0:3] * 19 == key
から鍵が3文字と分かり、フラグの形式がFLAG{
で始まるので既知平文攻撃が出来る。
with open('output.txt') as c: strings = c.read() known = 'FLAG{' known = known[0:5]*len(strings) key=[] f=[] for c1,c2 in zip(strings,known): key.append(chr(ord(c1)^ord(c2))) key = key[0:3]*19 for c,m in zip(strings,key): f.append(chr(ord(c)^ord(m))) flag = ''.join(f) print(flag)
FLAG{xor_c1ph3r_is_vulnera6le_70_kn0wn_plain7ext_@ttack!}
Basic RSA
RSA暗号の基本的な演算ができますか?
接続するとRSAに関する計算を求められる。
p : 素数1 , q : 素数2 , N : 公開鍵1(p*q) , e : 公開鍵2 , m : 平文 , c : 暗号文
として、
・p,qからN
・m,e,nからc
・p,q,e,cからm
の計算を行って順番に投げつけるとフラグが返ってくる。
最後のp,q,e,cからmを導出するには
phi = (p-1)*(q-1)
d = e^-1 (mod phi)
が必要なので適宜計算する。dに関してはpow(e,-1,phi)で出せば早い。
ターミナルからPythonを起動して計算したのでコードは残ってません。
FLAG{y0uv3_und3rst00d_t3xtb00k_RSA}
LCG crack
安全な暗号は安全な乱数から
server.pyが配布される。
import random import os from Crypto.Util.number import * from const import flag, logo, description, menu class RNG: def __init__(self, seed, a, b, m): self.a = a self.b = b self.m = m self.x = seed % m def next(self): self.x = (self.a * self.x + self.b) % self.m return self.x def show_menu(): print(menu) log(description) while not (choice := input("> ")) in "123": print("Invalid choice.") return int(choice) if __name__ == "__main__": print(logo) seed = random.getrandbits(64) a = random.getrandbits(64) b = random.getrandbits(64) m = getPrime(64, os.urandom) rng = RNG(seed, a, b, m) while True: choice = show_menu() # Print if choice == 1: print(rng.next()) # Guess elif choice == 2: for cnt in range(1, 11): print(f"[{cnt}/10] Guess the next number!") try: guess = int(input("> ")) except ValueError: print("Please enter an integer\n\n\n") continue if guess == rng.next(): print(f"Correct! ") cnt += 1 else: print(f"Wrong... Try again!") break else: print(f"Congratz! {flag}") break # Exit else: print("Bye :)") break
choiceが1の時に次の乱数を取得、2の時に次の乱数を当てるモードになる。
seed,a,b,mが固定されてそうなので逆算すればいけるかと予想したら実装に困ってしまった...。
色々調べてたら次の記事を見つけた。
今回のケースは記事の「A (multiplier) と B ( increment) と M (modulus) が未知である場合」と同じ。
記事からコードを引用させていただきソルバを書いた。
#https://satto.hatenadiary.com/entry/solve-LCG from Crypto.Util.number import inverse, GCD, getRandomNBitInteger from functools import reduce from pwn import * def solve_unknown_modulus(states): diffs = [X_1 - X_0 for X_0, X_1 in zip(states, states[1:])] multiples_of_M = [T_2 * T_0 - T_1 ** 2 for T_0, T_1, T_2, in zip(diffs, diffs[1:], diffs[2:])] M = reduce(GCD, multiples_of_M) return M def solve_unknown_multiplier(states, M): A = (states[2] - states[1]) * inverse((states[1] - states[0]), M) return A def solve_unknown_increment(states, A, M): B = (states[1] - A * states[0]) % M return B state = [] io = remote('lcg.wanictf.org',50001) i=0 while(i<30): io.sendlineafter('> ',"1") app = int(io.readline(),10) print(app) state.append(app) i+=1 print('------------------------') M = solve_unknown_modulus(state) A = solve_unknown_multiplier(state, M) B = solve_unknown_increment(state, A, M) next_value = (A * state[-1] + B) % M print(next_value) io.sendlineafter('> ',"2") io.sendlineafter('> ',str(next_value)) print(io.recvline()) for j in range(9): next_value = (A * next_value + B) % M print(next_value) io.sendlineafter('> ',str(next_value)) print(io.recvline()) print(io.recvline())
FLAG{y0u_sh0uld_buy_l0tt3ry_t1ck3ts}
l0g0n
🕵️♂️
server.pyが与えられる。
from hashlib import pbkdf2_hmac import os from Crypto.Cipher import AES from secret import flag, psk class AES_CFB8: def __init__(self, key): self.block_size = 16 self.cipher = AES.new(key, AES.MODE_ECB) def encrypt(self, plaintext: bytes, iv=bytes(16)): iv_plaintext = iv + plaintext ciphertext = bytearray() for i in range(len(plaintext)): X = self.cipher.encrypt(iv_plaintext[i : i + self.block_size])[0] Y = plaintext[i] ciphertext.append(X ^ Y) return bytes(ciphertext) def key_derivation_function(x): dk = pbkdf2_hmac("sha256", x, os.urandom(16), 100000) return dk def main(): while True: client_challenge = input("Challenge (hex) > ") client_challenge = bytes.fromhex(client_challenge) server_challenge = os.urandom(8) print(f"Server challenge: {server_challenge.hex()}") session_key = key_derivation_function(psk + client_challenge + server_challenge) client_credential = input("Credential (hex) > ") client_credential = bytes.fromhex(client_credential) cipher = AES_CFB8(session_key) server_credential = cipher.encrypt(client_challenge) if client_credential == server_credential: print(f"OK! {flag}") else: print("Authentication Failed... 🥺") if __name__ == "__main__": main()
AES_CFB8と問題名の「l0g0n」からZerologonを思い出す。
動画によると、AES_CFB8ではivを0で固定すると暗号文の先頭バイトが256分の1の確率で0となる。
また、0を暗号化すると0になるため、256回の鍵生成したうち1回は平文と同じ0となる。
ChallengeとCredentialを暗号化した結果を比較して同じであればフラグが取得出来るので、上記の脆弱性にしたがって8Byte分の0をループで送り続けるというソルバを書いた。
from pwn import * io = remote('l0g0n.wanictf.org',50002) while(True): io.sendlineafter('Challenge (hex) > ','0000000000000000') io.sendlineafter('Credential (hex) >','0000000000000000') rcv = io.recvline() if(b'OK!' in rcv): print(rcv) break print('not')
FLAG{4_b@d_IV_leads_t0_CVSS_10.0__z3r01090n}
Forensics
logged_flag
ワニ博士が問題を作っていたので、作っているところをキーロガーで勝手に記録してみました。
先に公開してしまいたいと思います。
(ワニ博士は英字配列のキーボードを使っています)
key_log.txtとsecret.jpgが渡される。
key_log.txtを見る限りechoでフラグをflag.txtに書き込んでそれをsteghideでjpgファイルに埋め込んでいる。
echoのコマンド文がそのまま見れるので頑張ってフラグを取り出すか、「steghide embed」で打ち込んでるパスワードmachikanetamachikanesai
を抜き出して、「steghide extract -sf test.jpg」からパスワードを入力してflag.txtを抜き出す。
11:50:15 [E] 11:50:15 [C] 11:50:15 [H] 11:50:15 [O] 11:50:16 [Space] 11:50:23 [Shift] 11:50:24 [F] 11:50:26 [Shift] 11:50:26 [L] 11:50:27 [Shift] 11:50:27 [A] 11:50:28 [Shift] 11:50:28 [G] 11:50:29 [Shift] 11:50:29 [[] 11:50:31 [K] 11:50:32 [3] 11:50:33 [Y] 11:50:35 [Shift] 11:50:35 [-] 11:50:36 [L] 11:50:36 [0] 11:50:37 [G] 11:50:38 [G] 11:50:38 [3] 11:50:38 [R] 11:50:41 [Shift] 11:50:41 [-] 11:50:41 [1] 11:50:42 [S] 11:50:43 [Shift] 11:50:43 [-] 11:50:44 [V] 11:50:45 [3] 11:50:47 [R] 11:50:47 [Y] 11:50:47 [Shift] 11:50:47 [-] 11:50:49 [D] 11:50:49 [4] 11:50:50 [N] 11:50:51 [G] 11:50:52 [3] 11:50:52 [R] 11:50:53 [0] 11:50:54 [U] 11:50:54 [S] 11:50:55 [Shift] 11:50:55 []]
FLAG{k3y_l0gg3r_1s_v3ry_d4ng3r0us}
chunk_eater
pngの必須チャンクをワニ博士が食べてしまいました!
eaten.pngとPNGフォーマットの解説サイトが渡される。
eaten.jpgをバイナリエディタで開くとPNGの必須チャンクと思われるIHDR
IDAT
IEND
が全てWANI
に書き換わっているので、これらを全て元に戻してやる。最初と最後以外のWANI
は全てIDAT
に書き換えた。
正確に修復出来るとフラグの画像が出てくる。
FLAG{chunk_is_so_yummy!}
zero_size_png
この画像のサイズは本当に0×0ですか?
バイナリエディタで開くと画像の幅(赤)と画像の高さ(青)が0になっている。
ただChunk Type(茶)とCRC(緑)は元から存在している。
CRCはChunk Typeと幅,高さから導出出来るので、CRCから幅と高さを逆算するっぽいな~と思い色々調べてたら見つけた。
zlibのcrc32を使えばxorの実装せずに計算してくれるので楽っぽい。
上記のサイトのコードを引用させていただき幅と高さを求める。
#https://www.programmersought.com/article/80384546662/ import zlib import struct filename = 'dyson.png' with open(filename, 'rb') as f: all_b = f.read() crc32key = int(all_b[29:33].hex(),16) data = bytearray(all_b[12:29]) n = 4095 for w in range(n): width = bytearray(struct.pack('>i', w)) for h in range(n): height = bytearray(struct.pack('>i', h)) for x in range(4): data[x+4] = width[x] data[x+8] = height[x] crc32result = zlib.crc32(data) if crc32result == crc32key: print("Wide is:",end="") print(width.hex()) print("High as:",end="") print(height.hex()) exit(0)
Wide is:00000257 High as:0000030d
後は出力通りに幅と高さを書き換える。
FLAG{Cyclic_Redundancy_CAT}
ALLIGATOR_01
ワニ博士のPCでは,悪意のあるプロセスが実行されているみたいです。
取得したメモリダンプから、”evil.exe”が実行された日時を報告してください。
(注意: スペースはすべて半角のアンダースコアにしてください)
example: FLAG{1234-56-78_99:99:99_UTC+0000}
Memory Forensics三部作。
ALLIGATOR.zipを展開するとALLIGATOR.rawが出てくる。
Volatilityが推奨ツールとして紹介されていたので導入した。
使い方等は下記サイトを参照した。
初動調査としてOSのプロファイルを調べる必要があるので下記コマンドで調べる。
volatility -f ALLIGATOR.raw imageinfo
Volatility Foundation Volatility Framework 2.6 INFO : volatility.debug : Determining profile based on KDBG search... Suggested Profile(s) : Win7SP1x86_23418, Win7SP0x86, Win7SP1x86_24000, Win7SP1x86 AS Layer1 : IA32PagedMemoryPae (Kernel AS) AS Layer2 : FileAddressSpace (/root/Documents/wanictf/for/alligator/ALLIGATOR.raw) PAE type : PAE DTB : 0x185000L KDBG : 0x82754de8L Number of Processors : 1 Image Type (Service Pack) : 1 KPCR for CPU 0 : 0x80b96000L KUSER_SHARED_DATA : 0xffdf0000L Image date and time : 2020-10-26 03:04:49 UTC+0000 Image local date and time : 2020-10-25 20:04:49 -0700
Win7SP0x86で良さそう。pstree
でメモリダンプ取得時に動いていたプロセスが確認出来る。
volatility -f ALLIGATOR.raw --profile=Win7SP0x86 pstree
省略 . 0x84dd6b28:evil.exe 3632 2964 1 21 2020-10-26 03:01:55 UTC+0000 省略
日時が載っているのでこれをフラグ形式にしたらフラグ完成。
FLAG{2020-10-26_03:01:55_UTC+0000}
ALLIGATOR_02
コマンドプロンプトの実行履歴からFLAGを見つけてください。
(ALLIGATOR_01で配布されているファイルを使ってください)
consoles
でcmd.exe で実行されたコマンドの出力を表示出来るらしい。
volatility -f ALLIGATOR.raw --profile=Win7SP0x86 consoles
省略 C:\Users\ALLIGATOR>type C:\Users\ALLIGATOR\Desktop\flag.txt FLAG{y0u_4re_c0n50les_master} C:\Users\ALLIGATOR>
FLAG{y0u_4re_c0n50les_master}
ALLIGATOR_03
Dr.WANIはいつも同じパスワードを使うらしいです。
Dr.WANIのパソコンから入手したパス付のzipファイルを開けて、博士の秘密を暴いてしまいましょう。
(ALLIGATOR_01で配布されているファイルを使ってください)
hashdump
でメモリ上のパスワードハッシュをダンプできる。
SYSTEMとSAMのアドレスがなくてもALLIGATORのパスワードハッシュが出てきたけど本来ならば指定するっぽい。
volatility -f ALLIGATOR.raw --profile=Win7SP0x86 hashdump
Administrator:500:aad3b435b51404eeaad3b435b51404ee:fc525c9683e8fe067095ba2ddc971889::: Guest:501:aad3b435b51404eeaad3b435b51404ee:31d6cfe0d16ae931b73c59d7e0c089c0::: IEUser:1000:aad3b435b51404eeaad3b435b51404ee:fc525c9683e8fe067095ba2ddc971889::: sshd:1001:aad3b435b51404eeaad3b435b51404ee:31d6cfe0d16ae931b73c59d7e0c089c0::: sshd_server:1002:aad3b435b51404eeaad3b435b51404ee:8d0a16cfc061c3359db455d00ec27035::: ALLIGATOR:1003:aad3b435b51404eeaad3b435b51404ee:5e7a211fee4f7249f9db23e4a07d7590:::
5e7a211fee4f7249f9db23e4a07d7590
をhashes.txtに移したらJohn the Ripperなどで復号する。
john hashes.txt --wordlist=/usr/share/wordlists/rockyou.txt --format=NT
Loaded 1 password hash (NT [MD4 256/256 AVX2 8x3]) Warning: no OpenMP support for this hash type, consider --fork=4 Press 'q' or Ctrl-C to abort, almost any other key for status ilovewani (?) 1g 0:00:00:00 DONE (2020-11-25 06:35) 4.166g/s 7149Kp/s 7149Kc/s 7149KC/s iloveyoh2..iloveus5 Use the "--show --format=NT" options to display all of the cracked passwords reliably Session completed
ilovewani
をパスワードとしてwani_secret.zipを解凍するとflag.txtが出てきた。
大阪大学 公式マスコットキャラクター「ワニ博士」 【プロフィール】 名前: ワニ博士(わにはかせ) 誕生日: 5 月 3 日 性別: オス 出身地: 大阪府 豊中市 待兼山町 【性格】 温厚,好奇心旺盛,努力型,お茶目,社交的,たまに天然,賢い 【趣味】 ・阪大キャンパスでコーヒーを飲みながら学生としゃべる ・粉もん屋めぐり ・化石集め。(いつか自分の仲間に会うために) ・CTF: FLAG{The_Machikane_Crocodylidae}
FLAG{The_Machikane_Crocodylidae}
USBドライブにTailsを入れる
タイトル通り。スクショも面倒だったのであまり撮ってません。 入れる前にUSBドライブがフォーマット済か要確認。
① : isoとブート用USB作成ツールを拾ってくる
balenaEtcher - Flash OS images to SD cards & USB drives
② : USBにTailsを入れる
Etcher-Portableを起動して、"Flash from file"にisoファイル、Select TargetにUSBドライブを指定。 後は"Flash!"を押して待つだけ。
③ : BIOS設定
セキュアブートを切ってUSBドライブの優先順位や許可をよしなにしておく。 SurfaceだとUSBブートは最初からONになってた。
後はUSBから起動するだけ。 後は永続化ボリューム作るなり好きにする。(セキュリティ的にはよろしくない)
参考 : Tails - Creating and configuring the Persistent Storage