• PHP SECURITY CALENDAR 2017 (Day 1


    Day 1 - Wish List(in_array函数缺陷)

    靶场是红日安全的 https://www.ripstech.com/php-security-calendar-2017/ PHP SECURITY CALENDAR 2017

    起因是最近在学一点内网渗透,问秦学长要个工具,他问:“源码审计你做了吗”,我说:“没有”,他:“可以开始了”,我:“好的”

    虽然我人菜但还是很听话的嘛,源码审计只在 ctf 做题的时候会看一下,还没有专门找时间训练过,而且觉得自己并没有做到熟读源码,只是开发系统的时候现学现卖一点。小黄同学推荐了红日安全的靶场,那就学起来吧(顺便再记一些可能和漏洞无关但是源码涉及到的php函数,眼熟久了就会用了嘻嘻)

    源码是这样的

    class Challenge {
      const UPLOAD_DIRECTORY = './solutions/';
      private $file;
      private $whitelist;
    
      public function __construct($file) {
        $this->file = $file;
        $this->whitelist = range(1, 24);
      }
    
      public function __destruct() {
        if (in_array($this->file['name'], $this->whitelist)) {
          move_uploaded_file(
            $this->file['tmp_name'],
            self::UPLOAD_DIRECTORY . $this->file['name']
          );
        }
      }
    }
    
    $challenge = new Challenge($_FILES['solution']);

      在访问PHP类中的成员变量或方法时,如果被引用的变量或者方法被声明成const(定义常量)或者static(声明静态),那么就必须使用操作符::,反之如果被引用的变量或者方法没有被声明成const或者static,那么就必须使用操作符->。

      move_uploaded_file 将上传的文件移动到新位置。

      这是一个任意文件上传漏洞,而导致这一漏洞的发生则是不安全的使用 in_array() 函数来检测上传的文件名。由于该函数并未将第三个参数设置为 true ,这导致攻击者可以通过构造的文件名来绕过服务端的检测,例如文件名为 7shell.php 。因为PHP在使用 in_array() 函数判断时,会将 7shell.php 强制转换成数字7,而数字7在 range(1,24) 数组中,最终绕过 in_array() 函数判断,导致任意文件上传漏洞。(这里之所以会发生强制类型转换,是因为目标数组中的元素为数字类型,进行弱比较。如果第三个参数设置为 true ,还会比较前两个参数的类型是否相同)

    (*)修复

    这个漏洞的原因是弱类型比较问题,那么就可以使用强匹配进行修复。例如将 in_array() 函数的第三个参数设置为 true ,或者使用 intval() 函数将变量强转成数字,又或者使用正则匹配来处理变量。

    参考:

    https://xz.aliyun.com/t/2451

    Day 2 - Twig(filter_var函数缺陷)

    源代码是这样的

     1 // composer require "twig/twig"
     2 require 'vendor/autoload.php';
     3 
     4 class Template {
     5   private $twig;
     6 
     7   public function __construct() {
     8     $indexTemplate = '<img ' .
     9       'src="https://loremflickr.com/320/240">' .
    10       '<a href="{{link|escape}}">Next slide &raquo;</a>';
    11 
    12     // Default twig setup, simulate loading
    13     // index.html file from disk
    14     $loader = new TwigLoaderArrayLoader([
    15       'index.html' => $indexTemplate
    16     ]);
    17     $this->twig = new TwigEnvironment($loader);
    18   }
    19 
    20   public function getNexSlideUrl() {
    21     $nextSlide = $_GET['nextSlide'];
    22     return filter_var($nextSlide, FILTER_VALIDATE_URL);
    23   }
    24 
    25   public function render() {
    26     echo $this->twig->render(
    27       'index.html',
    28       ['link' => $this->getNexSlideUrl()]
    29     );
    30   }
    31 }
    32 
    33 (new Template())->render();

    这道题考察XSS(跨站脚本攻击)漏洞。虽然题目代码分别用了 escape 和 filter_var 两个过滤方法试图保证传入的是一个真正的url,但是还是可以被攻击者绕过。在代码第10行中,程序使用 Twig 模板引擎定义的 escape 过滤器来过滤link,而实际上这里的 escape 过滤器,是用PHP内置函数 htmlspecialchars 来实现的

    htmlspecialchars  将特殊字符转换为 HTML 实体

    第二处过滤在第22行,这里用了 filter_var 函数来过滤 nextSlide 变量,且用了 FILTER_VALIDATE_URL 过滤器来判断是否是一个合法的url

    filter_var 使用特定的过滤器过滤一个变量

    这段源码可以用一段简单的 demo 来理解

    <?php
        $url = filter_var($_GET['url'],FILTER_VALIDATE_URL);  
        $url = htmlspecialchars($url);
        echo "<a href='$url'>Next slide</a>";
    ?>

     使用 payload :?url=javascript://comment%250aalert(1) ,可以执行 alert 函数

    这里的 // 在JavaScript中表示单行注释,所以后面的内容均为注释,但是使用字符 %0a ,该字符为换行符,所以 alert 语句与注释符 // 不在同一行,就能执行。当然,这里还要对 % 百分号编码成 %25 ,因为程序将浏览器发来的payload:javascript://comment%250aalert(1) 先解码成:javascript://comment%0aalert(1) 存储在变量 $url 中,然后用户点击 a 标签链接就会触发 alert 函数。

    (*)修复

     XSS漏洞,最好的方式就是过滤关键词,将特殊字符进行HTML实体编码替换

    参考:

    https://xz.aliyun.com/t/2457

    Day 3 - Snow Flake(实例化任意对象漏洞)

    源码是这样的

     1 function __autoload($className) {
     2   include $className;
     3 }
     4 
     5 $controllerName = $_GET['c'];
     6 $data = $_GET['d'];
     7 
     8 if (class_exists($controllerName)) {
     9   $controller = new $controllerName($data['t'], $data['v']);
    10   $controller->render();
    11 } else {
    12   echo 'There is no page with this name';
    13 }
    14 
    15 class HomeController {
    16   private $template;
    17   private $variables;
    18 
    19   public function __construct($template, $variables) {
    20     $this->template = $template;
    21     $this->variables = $variables;
    22   }
    23 
    24   public function render() {
    25     if ($this->variables['new']) {
    26       echo 'controller rendering new response';
    27     } else {
    28       echo 'controller rendering old response';
    29     }
    30   }
    31 }

    文件包含漏洞,代码第8行中使用了 class_exists() 函数来判断用户传过来的控制器是否存在,默认情况下,如果程序存在 __autoload 函数,那么在使用 class_exists() 函数就会自动调用本程序中的 __autoload 函数,这题的文件包含漏洞就出现在这个地方。攻击者可以使用路径穿越来包含任意文件,当然使用路径穿越符号的前提是 PHP5~5.3(包含5.3版本)版本之间才可以。例如类名为: ../../../../etc/passwd 的查找,将查看passwd文件内容

    代码第9行中,我们发现实例化类的类名和传入类的参数均在用户的控制之下。攻击者可以通过该漏洞,调用PHP代码库的任意构造函数。即使代码本身不包含易受攻击的构造函数,我们也可以使用PHP的内置类 SimpleXMLElement 来进行 XXE 攻击,进而读取目标文件的内容,甚至命令执行(前提是安装了PHP拓展插件expect)

    SimpleXMLElement 用来表示XML文档中的元素,为PHP的内置类

    这篇文章 http://www.manongjc.com/article/24000.html 介绍了XXE使用实例、应用技巧、基本知识点总结和需要注意事项

    (*)修复

    PHP中XXE漏洞的修复,我们可以过滤关键词,如: ENTITY 、 SYSTEM 等,另外,还可以通过禁止加载XML实体对象的方式,来防止XXE漏洞,代码如下

    libxml_disable_entity_loader(true);

    参考:

    https://xz.aliyun.com/t/2459

    Day 4 - False Beard(strpos使用不当引发漏洞)

    源码是这样的

     1 class Login {
     2   public function __construct($user, $pass) {
     3     $this->loginViaXml($user, $pass);
     4   }
     5 
     6   public function loginViaXml($user, $pass) {
     7     if (
     8       (!strpos($user, '<') || !strpos($user, '>')) &&
     9       (!strpos($pass, '<') || !strpos($pass, '>'))
    10     ) {
    11       $format = '<?xml version="1.0"?>' .
    12         '<user v="%s"/><pass v="%s"/>';
    13       $xml = sprintf($format, $user, $pass);
    14       $xmlElement = new SimpleXMLElement($xml);
    15       // Perform the actual login.
    16       $this->login($xmlElement);
    17     }
    18   }
    19 }
    20 
    21 new Login($_POST['username'], $_POST['password']);

    代码第11行和第12行,程序通过格式化字符串的方式,使用 xml 结构存储用户的登录信息。实际上这样很容易造成数据注入。然后第21行实例化 Login 类,并在第16行处调用 login 方法进行登陆操作。在进行登录操作之前,代码在第8行和第9行使用 strpos 函数来防止输入的参数含有 < 和 > 符号,猜测开发者应该是考虑到非法字符注入问题

    strpos 函数返回查找到的子字符串的下标。如果字符串开头就是我们要搜索的目标,则返回下标 0 ;如果搜索不到,则返回 false 。在这道题目中,开发者只考虑到 strpos 函数返回 false 的情况,却忽略了匹配到的字符在首位时会返回 0 的情况,因为 false 和 0 的取反均为 true 。这样我们就可以在用户名和密码首字符注入 < 符号,从而注入xml数据

    strpos 查找字符串首次出现的位置

    sprintf 返回一个格式化字符串

    如果构造 payload:

    user=<"><injected-tag%20property="&pass=<injected-tag>

    strpos 函数的返回结果是这样的

    <?php
    $user = '<"><injected-tag property=" ';
    $pass = '<injected-tag>';
    var_dump(strpos($user, '<'));    //int 0
    var_dump(!strpos($user, '<'));   //boolean true
    var_dump(strpos($user, '>'));    //int 2
    var_dump(!strpos($user, '<'));   //boolean false
    
    var_dump(
        (!strpos($user, '<')) || !strpos($user, '>')) && (!strpos($user, '<')) || !strpos($user, '>'))
    )    //boolean true
         //相当于var_dump((true || false) && (true || false))
    ?>

    很明显是可以注入xml数据的

    (*)修复

    这个漏洞主要是开发人员对 strpos 函数理解不够造成的,区分开 0 和 false 即可避免,cms中还没有这个函数造成的漏洞,ctf题目里可能遇到

    参考:

    https://xz.aliyun.com/t/2467

  • 相关阅读:
    缓存淘汰算法系列(二)
    Working Set缓存算法(转)
    缓存淘汰算法系列(一)
    面对强制加班,程序员们,你们该怎么做
    浅谈设计模式之工厂类模式由简单到复杂的演变
    报童、钱包和迪米特法则(设计模式迪米特原则经典论文翻译)
    记一次nginx热升级踩的坑
    mysql的瑞士军刀Percona Toolkit的安装及使用。
    linux下通过grep分析慢日志的前后几行
    Linux下LDAP统一认证解决方案
  • 原文地址:https://www.cnblogs.com/wkzb/p/12464884.html
Copyright © 2020-2023  润新知