[CISCN2019 华东南赛区]Web4
国赛国赛,复现复现
题解
打开界面顺着给的链接走,会进read路由并且获取参数url=https://www.baidu.com
可以猜出来打一个ssrf,不过具体怎么打倒是没有思路,不过首先还是先用file协议读一下文件吧,然后输入file就直接回显WAF,果然没有这么简单啊
根据路由类型再访问一下index.php之类的路径,发现不存在index.php文件,大概可以猜出来是个python题或者js题之类的,不过还是不知道咋搞啊
国赛国赛,复现复现
打开界面顺着给的链接走,会进read路由并且获取参数url=https://www.baidu.com
可以猜出来打一个ssrf,不过具体怎么打倒是没有思路,不过首先还是先用file协议读一下文件吧,然后输入file就直接回显WAF,果然没有这么简单啊
根据路由类型再访问一下index.php之类的路径,发现不存在index.php文件,大概可以猜出来是个python题或者js题之类的,不过还是不知道咋搞啊
PHP题,感觉好久没见了,buu上也不说明一下这个题给不给源码,导致我盲测了一个多小时受不了了看wp告诉我是有源码的,然后去GitHub翻源码做。。。害人
随便登录一下,发现add,delete,view,export几个基本功能,flag功能获取flag但是要求我是admin,登录名改成admin显然无效,不知道是想让我怎么攻击,很令人在意的就是访问时是?page=add这种形式,妥妥的文件包含,开始用filter读源码,被重定向回去,然后访问add.php,报404,那就估计是有一个次级目录专门放包含的文件,尝试跳目录包含自己,不行,简单的跳目录也不行,最后试了试page=/add都不行。放弃包含,估计是已经写死了所有能包含的内容了,后来看源码的确如此。
文件包含不行也有其他的攻击点,这个note添加进去之后会分配一个随机id,还能回显,这种东西可能会通过数据库维护文件系统,note的标题可能存在二次注入,打了一波过去,无果。。。然后查看note的时候get又会多提交一个参数id,也是一波注入,再打一轮,无果。。。心态爆炸
xxe题目,不常见,感觉好像遇到这种题目都是搜一个payload直接打,不过今天看到一个好文章,可以稍微系统的学习一下,起码理解一下之前打XXE的时候遇到的问题是怎么回事
查看源码可以看到一个js函数
function doLogin(){
var username = $("#username").val();
var password = $("#password").val();
if(username == "" || password == ""){
alert("Please enter the username and password!");
return;
}
var data = "<user><username>" + username + "</username><password>" + password + "</password></user>";
$.ajax({
type: "POST",
url: "doLogin.php",
contentType: "application/xml;charset=utf-8",
data: data,
dataType: "xml",
anysc: false,
success: function (result) {
var code = result.getElementsByTagName("code")[0].childNodes[0].nodeValue;
var msg = result.getElementsByTagName("msg")[0].childNodes[0].nodeValue;
if(code == "0"){
$(".msg").text(msg + " login fail!");
}else if(code == "1"){
$(".msg").text(msg + " login success!");
}else{
$(".msg").text("error:" + msg);
}
},
error: function (XMLHttpRequest,textStatus,errorThrown) {
$(".msg").text(errorThrown + ':' + textStatus);
}
});
}
也不ez吧,学习了一下nodeJS的中间件概念和next函数
const express = require('express');
const bodyParser = require('body-parser');
const saferEval = require('safer-eval'); // 2019.7/WORKER1 找到一个很棒的库
const fs = require('fs');
const app = express();
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
// 2020.1/WORKER2 老板说为了后期方便优化
app.use((req, res, next) => {
if (req.path === '/eval') {
let delay = 60 * 1000;
console.log(delay);
if (Number.isInteger(parseInt(req.query.delay))) {
delay = Math.max(delay, parseInt(req.query.delay));
}
const t = setTimeout(() => next(), delay);
// 2020.1/WORKER3 老板说让我优化一下速度,我就直接这样写了,其他人写了啥关我p事
setTimeout(() => {
clearTimeout(t);
console.log('timeout');
try {
res.send('Timeout!');
} catch (e) {
}
}, 1000);
} else {
next();
}
});
app.post('/eval', function (req, res) {
let response = '';
if (req.body.e) {
try {
response = saferEval(req.body.e);
} catch (e) {
response = 'Wrong Wrong Wrong!!!!';
}
}
res.send(String(response));
});
// 2019.10/WORKER1 老板娘说她要看到我们的源代码,用行数计算KPI
app.get('/source', function (req, res) {
res.set('Content-Type', 'text/javascript;charset=utf-8');
res.send(fs.readFileSync('./index.js'));
});
// 2019.12/WORKER3 为了方便我自己查看版本,加上这个接口
app.get('/version', function (req, res) {
res.set('Content-Type', 'text/json;charset=utf-8');
res.send(fs.readFileSync('./package.json'));
});
app.get('/', function (req, res) {
res.set('Content-Type', 'text/html;charset=utf-8');
res.send(fs.readFileSync('./index.html'))
})
app.listen(80, '0.0.0.0', () => {
console.log('Start listening')
});