はじめに
11/22~11/27に開催されたNFLabs. Cybersecurity Challenge for Students 2023に参加してきました。こういったコンテストにガッツリ参加するのは半年ぶり以上でお試し半分で参加してみました。
結果としては9位ということで、思ったよりいい結果が得られて良かったです。
早速ですが、解けた問題に関してWriteupを書いていきます。
OSINT
[Easy] ntt.com
ntt.comのドメイン名を日本電信電話株式会社(関連企業を含む)が登録する以前に登録していた企業の名前を答えてください。
過去このドメイン名を利用していたサイトを調べるため、Wayback Machineが提供するインターネットアーカイブを利用します。
初めの記録が1997年にあるので見てみます。
答え:National TechTeam, Inc.
余談
インターネットアーカイブの記録では、1998年からNTTの関連会社がドメインを保持していたみたいでした。
[Easy] celebration
カタールW杯のベストゴールのゴールセレブレーションの輪の真後ろで、イギリスのあるプロサッカークラブの横断幕が掲げられていました。 そのクラブの名前にもなっている街の名前をアルファベットで答えてください。
まずカタールW杯のベストゴールが誰でどの試合かを調べます。
調査の結果、ブラジル対セルビア戦のブラジル代表FWリチャーリソン選手のゴールということが分かりました。この記事では73分にそのゴールの瞬間があると書いてあったので、YouTubeで調べてみたところ、ゴールの瞬間はハイライトなどで残っていましたが、ゴールセレブレーションの瞬間はカットされていました。他の動画サイトでも調べてみると、ニコニコ動画にゴールセレブレーションのシーンがあったので見てみましたが、画質が悪いため恐らく答えと思わしき横断幕に書かれている文字が読み取れませんでした。
次にブラジル対セルビアのフルサイズの映像がどこかに残っていないかを調べることにしました。
brazil vs serbia full match
と検索するといくつかのサイトでフルサイズの試合が見ることが出来ます。
問題のゴールセレブレーションの映像を見てみると、MIDDLESBROUGH
と書かれた横断幕が見えます。
調べてみると、イングランド・ミドルズブラに本拠地を置くサッカークラブ、ミドルズブラFCだそうです。
答え:Middlesbrough
[Medium] stranger than fiction
ある著名な元俳優が2022年2月下旬、国会議員のDavid Braun氏を含む5名で撮った動画をSNSにアップロードしました。 その俳優の代表作の第一話冒頭に映っている記念碑の場所を答えてください。 回答は緯度経度を小数点下一桁(下二桁目以降は切り捨て)までお願いします。
まずDavid Braun
という名前を調べてみると、Wikipediaには3人候補が上がりました。その中で国会議員はDavyd Arakhamia
という方で、David Braunという名はペンネームということが書かれていました。
Davyd Arakhamia氏のSNSを調査してみたところFacebookのアカウントがあったので、2022年2月下旬あたりの投稿を調べました。投稿を見たところ、この時期はロシアのウクライナ侵攻が始まった時だということが分かります。
つまり問題文に書かれているある著名な元俳優
というのが、ウクライナ大統領のウォルディミナル・ゼレンスキー
ではないかと予想が付きます。
確認のため、ゼレンスキー大統領のFacebookのアカウントで、2022年2月下旬ごろの投稿を調べるとこの投稿が問題文で取り上げているものに一致していることが分かります。
ゼレンスキー大統領の代表作を調べると国民の僕(しもべ)
という作品が該当するそうです。
国民の僕 第一話冒頭を見てみると問題文通りの記念碑が映っていました。
【1話無料公開!】みるアジアで配信中!『国民のしもべ~ウクライナ大統領~』
Google Lensで調べてみると、ウクライナ キーウにある独立記念碑
だということが分かります。
答え:N50.4,E30.5
[Medium] Repair
まずGoogle Lensで調べてみると、スペインにある教会がKarmacolorという団体に聖ジョージ像の清掃を依頼したところ、団体の代表である美術教師によって勝手に修復され、元の彫刻とは似ても似つかないものにされてしまった事件だということが分かります。
その後教会は改めて修復費を出して元通りにしたようです。
この修復費が答えなわけですが、日本語で調べてもあまりいい記事が無かったので、スペイン語で検索してみました。el San Jorge restaurado(復元された聖ジョージ)
検索の結果、この記事が修復費について書かれていました。
答え:€30.759
余談
修復を勝手にやってしまった美術教師は、実は修復過程をSNS上に動画等で投稿しており、自身の作業の様子を記録に残していました。問題が発覚後、騒ぎが大きくなり現在ではアカウントごと無くなってしまいましたが、Facebook上では当時投稿された動画が残っており、聖ジョージ像に塗料を塗っているシーンが見ることが出来ます。
DFIR
[Easy] flower
会社で管理しているWebサイトにアクセスすると、「We hacked your Web page :)」という文章が表示されるというインシデントが発生しました。あなたはWebサーバを調査したが、不審なログを発見することはできませんでした。 しかし、調査の過程でWebサイトのドメイン名をDNS名前解決した際、本来のIPアドレスとは異なるIPアドレスが返っていることを発見しました。あなたはDNSに問題が発生していると考え、通信経路上で取得していたパケットデータを確認することにしました。 pcapngファイルを解析し、インシデントの原因となる攻撃を行ったと考えられる端末のIPアドレスを解答してください。
添付ファイル:flower.pcapng
Wiresharkでflower.pcapngを開き、統計>IPv4 Statics>All Addressesを見ます。
5つのIPアドレスがパケットに記録されていることが分かります。
パケットを見ていくと、問題文中にあったWe hacked your Web page :)
というページが表示されたと思われるレスポンスのパケットがありました。つまり10.64.3.178
は攻撃者が用意したWebサーバということですね。
次に統計にあるフローグラフを見てみると、パケットの始めのやり取りから以下のことが分かります。
- Client:10.64.3.123
- DNSサーバ:10.64.3.120
- Webサーバ:10.64.3.64(flos.example.test)
また途中からDNSサーバへ大量のリクエストを送っているIP10.64.3.101
があり、恐らく攻撃者によるものだと推測できます。
パケット最後のやり取りを見てみると、flos.example.test
の名前解決でドメインと対応しているIPが10.64.3.178
に変えられているのが分かります。
よって
- 攻撃者:10.64.3.101
- 攻撃者が用意したWebサーバ: 10.64.3.178
答え:10.64.3.101
[Easy]rockyou
あなたの運営しているwebアプリケーションにおいて、不正ログインが発生している可能性があるという報告がありました。それを知った同僚がパケットキャプチャを行ってくれていました。セキュリティ担当であるあなたは、手元にあるデータを用いて不正ログインに関する調査を行うこととなりました。Webサーバのアクセスログとpcapファイルを元に不正ログインされている可能性が高いと思われるユーザのユーザ名を解答してください。
添付ファイル:access.log、output.pcap
ログインが成功した=HTTPレスポンスステータスコードが200、だということに着目してhttp.response.code == 200
でフィルタリングします。
答え:william
[Medium] invader (1)
【導入】
Windowsのサーバーに対して外部から不正アクセスを検知したため、この端末のイベントログを抽出した。
このログを分析し、invader (1) ~ (3)までの3つの問に答えよ。3つの問の解答順序は問わないものとする。
【Q1】
侵入元のIPアドレスを答えよ。
注:192.168.0.0/24以外のIPアドレスはすべて外部のIPアドレスとする。
回答方式:IPアドレスを答える
回答例:192.0.2.2
添付ファイル:eventlogs.zip
端末のログオンについてみたいため、Security.evtx
を開き、イベントID4624
でフィルターをかけます。
また今回は外部からのログオンについてなので、ログオンの種類は3と10で絞り込みます。
各ログオンの種類
ログオンの種類 | ログオンタイトル | 説明 |
---|---|---|
2 | 対話型 | ユーザーがこのコンピューターにログオンしました。 |
3 | ネットワーク | ネットワークからこのコンピューターにログオンしたユーザーまたはコンピューター。 |
4 | パッチ | バッチ ログオンの種類はバッチ サーバーによって使用され、そこではプロセスが直接介入せずにユーザーの代わりに実行される可能性があります。 |
5 | サービス | サービス コントロール マネージャーによってサービスが開始されました。 |
7 | ロックを解除する | このワークステーションのロックが解除されました。 |
8 | NetworkCleartext | ユーザーがネットワークからこのコンピューターにログオンしました。 ユーザーのパスワードは、非ハッシュ化形式で認証パッケージに渡されました。 組み込みの認証では、ネットワーク経由で送信する前に、すべてのハッシュ資格情報がパッケージ化されます。 資格情報は、プレーンテキスト (クリア テキストとも呼ばれます) でネットワークを通過しません。 |
9 | NewCredentials | 送信元が現在のトークンを複製し、送信接続用に新しい資格情報を指定しました。 新しいログオン セッションのローカル ID は同じですが、他のネットワーク接続には異なる資格情報を使用します。 |
10 | RemoteInteractive | ターミナル サービスまたはリモート デスクトップを使用してリモートでこのコンピューターにログオンしたユーザー。 |
11 | CachedInteractive | コンピューターにローカルに保存されたネットワーク資格情報を使用してこのコンピューターにログオンしたユーザー。 資格情報を確認するために、ドメイン コントローラーに接続できませんでした。 |
-
Logon Type:3 2023/10/10 16:40:01
:192.168.81.128 -
Logon Type:10 2023/10/10 16:40:03
:192.168.81.128 -
Logon Type:3 2023/10/10 16:44:54
:192.168.81.128 -
Logon Type:10 2023/10/10 16:44:55
:192.168.81.128
答え:192.168.81.128
[Medium] invader(2)
invader (1) の続き
【Q2】
攻撃者は、侵入後にWindows Defenderの設定を変更し特定のフォルダーを検知の対象外とした。
そのフォルダーを答えよ。
回答方式:フォルダーのフルパスを回答(case insensitive)
回答例:C:\Windows\Tasks\
Windows Desfenderの設定に関してなので、Microsoft-Windows-Windows Defender%4Operational.evtx
を開きます。以下、関連度が高いイベントです。
- イベントID 5001 2023/10/10 16:46:38 リアルタイム保護の無効化
- イベントID 5007 2023/10/10 16:46:39
- Old value: HKLM\SOFTWARE\Microsoft\Windows Defender\SpyNet\SpyNetReporting = 0x2
- New value: HKLM\SOFTWARE\Microsoft\Windows Defender\SpyNet\SpyNetReporting = 0x0
- イベントID 5007 2023/10/10 16:46:40
- Old value: HKLM\SOFTWARE\Microsoft\Windows Defender\SpyNet\SubmitSamplesConsent = 0x1
- New value: HKLM\SOFTWARE\Microsoft\Windows Defender\SpyNet\SubmitSamplesConsent = 0x0
- イベントID 5007 2023/10/10 16:46:54
- Old value:
- New value: HKLM\SOFTWARE\Microsoft\Windows Defender\Exclusions\Paths\C:\ = 0x0
答え:C:\
[Medium] invader(3)
invader (2)の続き
【Q3】
攻撃者は、永続化のためにとあるファイル(実行ファイルまたはスクリプトファイル)をOS起動時に自動的に実行するように設定した。
攻撃者が用意したOS起動時に自動的に実行されるファイルを答えよ。
回答方式:ファイルのフルパスを回答(case insensitive)
回答例:C:\Windows\Tasks\test.exe
Windowsのスケジュールタスクが作成されたイベントを見たいためSecurity.evtx
を開き、イベントID4698でフィルターします。
- イベントID: 4698 2023/10/10 16:50:14
<Actions Context="Author">
<Exec>
<Command>C:\Windows\System32\cmd.exe</Command>
<Arguments>/c C:\Users\Administrator\rtcp.exe</Arguments>
</Exec>
</Actions>
答え:C:\Users\Administrator\rtcp.exe
[Medium] exfildb
あなたはシステム&セキュリティ担当の一員として、Webサイトのインシデント対応におけるログ分析を依頼されました。システム構成および調査対象のログは、exfildb.zipに格納されています。攻撃者にDBの情報が持ち出されたと推測される時間を調査し、日本時間(JST)で mm:hh:ss の形式で解答してください。
例) 持ち出された時間が日本時間で2023年9月6日11時02分05秒の場合、11:02:05と解答してください。
添付ファイル:exfildb.zip
exfildb
├── IDSlog
│ ├── 2021-04-20_1645_nids_log.pcap (Server LAN内のフルパケットキャプチャ 16:45 ~ 18:58)
│ ├── 2021-04-20_nids_et_eve.json (簡易アラート情報)
│ └── 2021-04-20_nids_et_fast.log (アラートの詳細情報)
├── Jumpserver
│ └── 2021-04-20_jump_secure.log (Jumpサーバの認証ログ)
├── Webserver
│ └── 2021-04-20_web_access.log (Webサーバのアクセスログ)
└── systeminfo.pdf (説明資料)
・Webサイトの訪問者はhttp://172.16.193.103にアクセスする
・FWが172.16.193.103:80宛の通信をWebサーバの内部IPアドレスにNAT
.11
├── Web Server
|.12
WAN LAN ├── DB Server
.103 .1 |
Client ──── Internet ──── Firewall ──────────
(172.16.193.0/24) : |.101
NIDS ├── Jump Server
|.201
├── Local Maintenance PC
|
Server LAN
(172.16.10.0/24)
各システムの説明
ホスト名 | IPアドレス | OS | 説明 |
---|---|---|---|
web | 172.16.10.11 | CentOS 7 | 会社のコーポレートサイトを運用しているWebサーバ |
db | 172.16.10.12 | CentOS 7 | コーポレートサイトの情報を管理しているDBサーバ |
jump | 172.16.10.101 | CentOS 7 | Server LAN内のサーバにSSHするための踏み台サーバ |
Local Maintenance | 172.16.10.201 | - | Server LAN内のサーバを操作するためのPCサーバのメンテナンスはここから行っている |
firewall | (LAN)172.16.10.1 (WAN)172.16.192.103 | OPNSense | Server LAN内への通信を制御するためのファイアウォール |
nids | - | Ubuntu 20.04 | Server LANを監視しているIDS(Suricata) |
各種サーバについて
- Webサーバ(172.16.10.11)
- Apache 2.4.6 + PHP 7.4.16 + WordPress 5.7.1で構築
- WordPressには以下二つのプラグインをインストール
- Contact Form 7(version 6.4)
- WP File Manager (version 6.0)
- Jumpサーバ(172.16.10.101)
- SSH でリモートから各サーバのメンテナンスを行うために構築中
- 構築中のため、現在は誰も使用していない
- DBサーバ(172.16.10.12)
- Web サーバのみデータベースへアクセスする
- 以下のデータを格納
- WordPressのサイトデータ
- 問い合わせフォーム(Contact Form 7)で送信されたデータ(個人情報)
前提条件(1)
IDSのアラートを確認したところ大量のアラートが発生していた。
大量のアラートからScan行為などのアラートを取り除いたところ、 16:16:33から16:53:27の間に、Webサーバ、Jumpサーバに対して次に示すようなアラートが上がっていた。
アラートの情報をもとにサーバのイベントログ、パケットログを調査し、攻撃の流れを推測したい。
2021-04-20_1645_nids_log.pcap
をざっくりと見てみると、使われていないはずのJumpサーバとやり取りをしているIPアドレス172.16.193.101
が見つかります。前提条件(2)から、SSH BruteForce Attackでログインに成功した攻撃者と思われます。
攻撃者の活動を見るため、Wiresharkでip.addr == 172.16.193.101
でフィルターをかけてパケットを見ていきます。
WordPressの脆弱性悪用
- 16:47:00 cat /etc/passwd
- 16:48:06 cat whoami
- 16:48:13 cat hostname
- 16:48:19 ip addr
- 16:48:43 ls
- 16:48:47 ls ../
~中略~
- 16:49:02 ls ../../../../../
- 16:49:32 wp-config.phpの閲覧でDBの認証情報が洩れた
その後攻撃者はJump ServerへSSH接続をし、nc
の実行ファイルをJump Serverへ配送しています。
DBの情報を含むであろうwpdb.dump
をftpを用いて持ちだそうと2回試行しているのが分かります。
1回目は失敗しており、2回目で以下のようにwpdb.dumpを持ち出していました。
答え:16:56:28
Web
[Easy] ASCII
友人が授業で作成したWebサイトに脆弱性があるという話になりました。Webアプリケーションを診断して脆弱性を特定し、フラグを入手して解答してください。
指定の問題サーバにアクセスすると以下のような画面が表示されており、フォームに値を入力するとアスキーアートとして表示されるみたいです。
如何にも脆弱性がありそうなフォームなので試しに色々入力してみると、特殊文字(;や&)以降の文字はアスキーアートとして表示されませんでした。
試しにaaa;id
をリクエストしてみると
OSコマンドインジェクションがありましたね。
カレントディレクトリにflag.txtがあるみたいなので見てみます。
答え:NFLABS{1nj3ct_n_unv3il_th3_s3cr3tz}
セキュリティ上の問題とその対策
server.py
のコードを見てみます。
import subprocess
from flask import Flask, render_template, request
app = Flask(__name__)
@app.route("/", methods=["GET", "POST"])
def index():
msg = request.form.get("message", "ASCII Art Generator")
if msg == "":
msg = "ASCII Art Generator"
app.logger.debug("msg: {}".format(msg))
p = subprocess.run(
"figlet -w100 -f big {}".format(msg), shell=True, stdout=subprocess.PIPE
)
return render_template(
"index.html", msg=p.stdout.decode().replace("\n", "
").replace(" ", " ")
)
if __name__ == "__main__":
app.run(host="0.0.0.0", port=80, threaded=True, debug=True)
subprocess.run
の引数にshell=True
を渡してしまうことで、明示的にシェルを呼び出してしまいOSコマンドインジェクションが出来てしまうので、もし明示的に呼び出す場合は必ずエスケープ処理を自分でするべきみたいです。(基本はshell=True
を渡さないことが一番ですね)
[Easy] UniDine
私たちの管理するWebサイトに対し、外部から脆弱性の報告がありました。Webアプリケーションを診断して脆弱性を特定し、フラグを入手して解答してください。
指定されたサーバへアクセスする。
ログインフォームがあったので、挨拶がてらSQLインジェクションしてみる。
すると以下のエラー文が。
Fatal error: Uncaught mysqli_sql_exception: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'a'' at line 1 in /var/www/html/login.php:20 Stack trace: #0 /var/www/html/login.php(20): mysqli_query() #1 {main} thrown in /var/www/html/login.php on line 20
PostgreSQLの書式だったので怒られました。再度MySQLの書式でSQLインジェクションしてみます。
ログインが成功するとメールアドレスにフラグがありました。
答え:NFLABS{l0g1n_h4x_sql_1nj3ct1on}
セキュリティ上の問題とその対策
ログインフォームでSQLインジェクションが成功したことから、login.php
でプレースホルダやエスケープ処理が行われていないことになります。対策としてはプレースホルダやエスケープ処理の実装を行う必要があります。詳しいことはIPAさんが出している 安全なSQLの呼び出し方を参考に。
Dev
[Easy] stegano
ステガノプログラムmain.goを用いてflagを画像の中に隠した。画像からflagを見つけよ。
添付ファイル:main.go、stegano.png
main.go
package main
import (
"bufio"
"fmt"
"image"
"image/color"
"image/png"
"log"
"os"
)
func main() {
reader, err := os.Open("original.png")
if err != nil {
log.Fatal(err)
}
defer reader.Close()
m, _, err := image.Decode(reader)
if err != nil {
log.Fatal(err)
}
bounds := m.Bounds()
im := image.NewRGBA64(image.Rect(0, 0, bounds.Dx()*2, bounds.Dy()*2))
for i := 0; i < bounds.Dx(); i++ {
for j := 0; j < bounds.Dy(); j++ {
c := m.At(i, j)
im.Set(i*2, j*2, c)
im.Set(i*2+1, j*2, c)
im.Set(i*2, j*2+1, c)
im.Set(i*2+1, j*2+1, c)
}
}
file, err := os.Open("flag.txt")
if err != nil {
log.Fatal(err)
}
defer file.Close()
s := bufio.NewScanner(file)
s.Scan()
flag := s.Text()
x := 100
y := 100
for i := 0; i < len(flag); i++ {
r1, g1, b1, a1 := im.At(x*2, y*2).RGBA()
r2, g2, b2, a2 := im.At(x*2+1, y*2).RGBA()
r3, g3, b3, a3 := im.At(x*2, y*2+1).RGBA()
box := []uint8{uint8(r1), uint8(g1), uint8(b1), uint8(r2), uint8(g2), uint8(b2), uint8(r3), uint8(g3)}
for j := 0; j < 8; j++ {
if (flag[i] & byte(1<<j)) != 0 {
if box[j] == 0 {
box[j] = box[j] + 1
} else {
box[j] = box[j] - 1
}
}
}
im.Set(x*2, y*2, color.RGBA{R: box[0], G: box[1], B: box[2], A: uint8(a1)})
im.Set(x*2+1, y*2, color.RGBA{R: box[3], G: box[4], B: box[5], A: uint8(a2)})
im.Set(x*2, y*2+1, color.RGBA{R: box[6], G: box[7], B: uint8(b3), A: uint8(a3)})
x = x + 1
y = (y + int(uint8(b3))) % bounds.Dy()
}
fmt.Println(im)
result, err := os.Create("stegano.png")
if err != nil {
log.Fatal(err)
}
defer result.Close()
if err := png.Encode(result, im); err != nil {
log.Fatal(err)
}
}
ざっくりプログラムを説明すると、まずoriginal.png
の2倍大きい画像を生成します。
(例えば、original.pngの大きさが300x300の時)
その次にoriginal.png
の一つのピクセルを、2倍大きい画像に2x2で複製し、それを画像すべてに適応します。
(例えば、original.pngの左上のピクセルをコピーする時
最後にFlagが書かれたflag.txt
を読み込み、文字を2進数として扱い、右下以外のピクセルにFlagの情報を組み込む、という流れです。
Flagの内容を復元するには、右下とそれ以外のピクセルの値の変化を確認することが必要になります。
from PIL import Image
def main():
original_image = Image.open("stegano.png")
width, height = original_image.size
flag = [0,0,0,0,0,0,0,0]
x, y = 100, 100
for i in range(50):
r1, g1, b1= original_image.getpixel((x * 2, y * 2))
r2, g2, b2= original_image.getpixel((x * 2 + 1, y * 2))
r3, g3, b3 = original_image.getpixel((x * 2, y * 2 + 1))
r4, g4, b4 = original_image.getpixel((x * 2 + 1, y * 2 + 1))
box = [r1, g1, b1, r2, g2, b2, r3, g3]
box2 = [r4, g4, b4,r4, g4, b4,r4, g4]
for j in range(8):
if box2[j] - box[j] == 1:
flag[7-j] = 1
elif box2[j] - box[j] == -1:
flag[7-j] = 1
else:
flag[7-j] = 0
if 1 in flag:
pass
else:
break
print(*flag, sep='', end=' ')
x += 1
y = (y + b3) % (height // 2)
if __name__ == "__main__":
main()
01001110 01000110 01001100 01000001 01000010 01010011 01111011 01001001 01001110 01010000 01110101 01100010 00110110 00110011 01001100 01010110 01000101 01101000 00110100 00110010 01010110 01001110 01100100 01100111 00110100 01001101 01101111 01111101
CyberChef
(プログラムで完結させれば良かったですね...)
答え:NFLABS{INPub63LVEh42VNdg4Mo}
おわりに
Malwareジャンル、PenTestジャンルに関しては1問も解けなかったので他の人のWriteupを参考に勉強させていただこうかと思っています。
6日間とかなりキツかったですが、同時にとても楽しく様々な知識が得られたコンテストでした!