THMにあるルーム「Block」を解いていきたいと思います
1 2つのファイル
lsass.DMPとtraffic.pcapngが渡されます。
今回はこの2つのファイルをもとにフラグを獲得していきます。
2 traffic.pcapngの解析
まずパケットからなにか情報がないか探します
Q1.当サーバに最初にアクセスしたユーザ名はなんですか?
wiresharkでパケットを確認してみるとsession setup requestというシーケンスがあります。
Session Setup Request, NTLMSSP_AUTH, User: WORKGROUP\????
といった文字列からなんというユーザがログインしたか確認できます。
Q4.当サーバにアクセスした2人目のユーザは誰ですか?
Q1と同様に見つけることができます。
3 lsass.DMPの解析
今度はメモリダンプファイルから質問の答えを見つけていきます。
Q2.Q1のユーザのパスワードはなんですか?
今回はpypykatzというツールを使います。
まずは導入していきます。
python -m venv ~/ctf-env
source ~/ctf-env/bin/activate
pip install pypykatz
導入できたら先ほど見つけたユーザたちの情報を探します。
~/ctf-env/bin/pypykatz lsa minidump lsass.DMP |grep -a 15 "さっき見つけたユーザ名"
== MSV ==
Username: ???
Domain: BLOCK
LM: NA
NT: ???
SHA1: ccd27b4bf489ffda2251897ef86fdb488f248aef
DPAPI: 3d618a1fffd6c879cd0b056910ec0c3100000000
NTの欄に入ってるハッシュが今回聞かれているパスワードです。
ここで出てきたハッシュをクラックしていきます。
今回はjohnを使用します。
まずはjohnにハッシュ値を渡すためのファイルを作っていきます。
echo "さっき出た`NT`内のハッシュ値" > john.hash
クラックしていきます。
john --format=NT --wordlist=/usr/share/wordlist/rockyou.txt john.hash
これでQ2のパスワードが判明します。
Q5.2人目のユーザのハッシュ値はなんですか?
/ctf-env/bin/pypykatz lsa minidump lsass.DMP | grep -A 15 "2人目のユーザ名"
ここで出てくるNTの値がユーザのハッシュ値になります。
Q3.最初のユーザがアクセスできたフラグはなんですか?
今回はパケットキャプチャファイル内のDecrypt SMB3というパケットの中身を見たいのでwiresharkにインポートするための鍵を作っていきます。
まず鍵を導き出すためのpythonスクリプトを作成します。
#!/usr/bin/env python3
import hmac
import hashlib
import argparse
from Cryptodome.Cipher import ARC4
def ntlmv2_hash(nt_hash: bytes, username: str, domain: str) -> bytes:
identity = (username.upper() + domain).encode('utf-16-le')
return hmac.new(nt_hash, identity, hashlib.md5).digest()
def calc_key_exchange_key(ntlmv2_hash: bytes, ntproofstr: bytes) -> bytes:
return hmac.new(ntlmv2_hash, ntproofstr, hashlib.md5).digest()
def decrypt_session_key(key_exchange_key: bytes, encrypted_session_key: bytes) -> bytes:
cipher = ARC4.new(key_exchange_key)
return cipher.decrypt(encrypted_session_key)
def main():
parser = argparse.ArgumentParser()
parser.add_argument("-u", "--user", required=True)
parser.add_argument("-d", "--domain", required=True)
parser.add_argument("-n", "--ntproofstr", required=True)
parser.add_argument("-k", "--key", required=True)
parser.add_argument("-H", "--nthash", required=True)
args = parser.parse_args()
nt_hash = bytes.fromhex(args.nthash)
ntproofstr = bytes.fromhex(args.ntproofstr)
encrypted_session_key = bytes.fromhex(args.key)
v2hash = ntlmv2_hash(nt_hash, args.user, args.domain)
kek = calc_key_exchange_key(v2hash, ntproofstr)
random_session_key = decrypt_session_key(kek, encrypted_session_key)
print(f"NTLMv2 Hash: {v2hash.hex()}")
print(f"Key Exchange Key: {kek.hex()}")
print(f"Random Session Key: {random_session_key.hex()}")
if __name__ == "__main__":
main()
今回はcalc_sesskey.pyというファイル名で保存します。
次に-n -k -Hに当てはまるハッシュ値をパケットキャプチャファイルないから見つけ出します。
先ほどから使っているSession Setup Requestというパケットに全てあります。
まずはntproofstr
SMB2 (Server Message Block Protocol version 2), Session Setup Request, MessageId 3
Session Setup Request (0x01)
Security Blob […]: a182020c30820208a28201f0048201ec4e544c4d535350000300000018001800580000003...
GSS-API Generic Security Service Application Program Interface
Simple Protected Negotiation
negTokenTarg
NTLM Secure Service Provider
NTLM Response […]: 16e816dead16d4ca7d5d6dee4a015c140101000000000000abce46bf0905da01da0...
NTLMv2 Response […]: 16e816dead16d4ca7d5d6dee4a015c140101000000000000abce46bf0905da01da0...
NTProofStr: 16e816dead16d4ca7d5d6dee4a015c14
1人目のユーザの-nの値を見つけ出すことができました。メモしておきます。
次は-kの値を見つけ出していきます。
今度はsession key
SMB2 (Server Message Block Protocol version 2), Session Setup Request, MessageId 3
Session Setup Request (0x01)
Security Blob […]: a182020c30820208a28201f0048201ec4e544c4d535350000300000018001800580000003...
GSS-API Generic Security Service Application Program Interface
Simple Protected Negotiation
negTokenTarg
NTLM Secure Service Provider
Session Key: fde53b54cb676b9bbf0fb1fbef384698
session keyを見つけ出すことができました。同様に-kとしてメモしておきます。
続いて-Nです。
今度はnthash
pypykatzで確認
~/ctf-env/bin/pypykatz lsa minidump lsass.DMP |grep -A 15 "最初のユーザ名"
== MSV ==
Username: mreal...
Domain: BLOCK
LM: NA
NT: 3f29138a04a...c04028bf381
SHA1: 91374e6e58d7b523376e3b1eb04ae5440e678717
DPAPI: 87c8e56bc4714d4c5659f254771559a800000000
NTの値が-Nに入る値です。
実際にpythonスクリプトを動かして鍵を導き出したいと思います。
python3 calc_sesskey_v2.py -u mrealman -d WORKGROUP -n 16e816dead16d4c...5d6dee4a015c14 -k fde53b54cb676b9...0fb1fbef384698 -H 1f9175a51621166...a8143b0f36ab44
出力結果がこちらになります。
NTLMv2 Hash: 110fd571fec8b...728e3d4d6f32f0a
Key Exchange Key: 17e09b2c9b920...9a4382898f50159
Random Session Key: 20a642c086ef7...26277bf1d0cff8c
今回使用するのはRandom Session Keyです。
続いてSession IDを取得します
SMB2 (Server Message Block Protocol version 2), Session Setup Request, MessageId 3
SMB2 Header
Session Id: 0x0000100000000041 Acct:mrealman Domain:WORKGROUP Host:DRAGON
Session IDを見つけました。
これを16進数文字列でコピーします。
必要な要素が取れたので実際にwiresharkにインポートします
[編集]
↓
[設定]
↓
[Protocols]
↓
[SMB2]
↓
[編集]
ここで先ほど見つけたSession ID Session Keyを入力します。
入力した適用してOK
パケットキャプチャファイルを確認します。
Decrypted SMB3の中身が復号されていることが確認できます。
やり取りされたであろうファイルを出力していきます。
[ファイル]
↓
[オブジェクトをエクスポート]
↓
[SMB]
client156.csvというファイルが出てきました。
これを一度作業ディレクトリ内に保存します。
作業ディレクトリに戻ってファイルの中身を確認してみます。
cat %5cclients156.csv
first_name,last_name,password
Jewell,Caseri,eS8/y*t?8$
Abey,Sigward,yB0{g_>KezO
Natassia,Freeth,tS2<1Fef9tiF
Verina,Wainscoat,kT8/2uEMH
Filia,Sommerling,oE9.2c?Sce
Farris,Busst,THM{...}
Bat,Oakes,gE0%f@'qw}s%
Verina,Jedrachowicz,wK4~4L\O
Caril,Wolfarth,yQ3$Ji0~f7aB>F{
Bordie,Baume,iM1}"x)yP'`2|S
,,
フラグが確認できました。
Q6.2人目のユーザがアクセスできたフラグはなんですか?
先ほどの最初のユーザと同じ手順でフラグを獲得することができます。
4 Blockを通してわかったこと
パスワードすら不要で、lsass.DMPのNTハッシュ、パケットキャプチャファイル内のNTLM認証情報だけからSMB3の暗号化トラフィックが解けてしまった。
ハッシュ値の計算は完全にAI任せだったのだが、SMB3のハッシュの計算の仕組みをよく理解できる面白い問題だった。