• 设为首页
  • 点击收藏
  • 手机版
    手机扫一扫访问
    迪恩网络手机版
  • 关注官方公众号
    微信扫一扫关注
    迪恩网络公众号

PHP SECURITY CALENDAR 2017 (Day 1 - 4)

原作者: [db:作者] 来自: [db:来源] 收藏 邀请

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 Twig\Loader\ArrayLoader([
15       'index.html' => $indexTemplate
16     ]);
17     $this->twig = new Twig\Environment($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

 


鲜花

握手

雷人

路过

鸡蛋
该文章已有0人参与评论

请发表评论

全部评论

专题导读
上一篇:
linux升级php至5.6发布时间:2022-07-10
下一篇:
利用飞儿云PHP框架自带的DNSPOD库做DDNS动态域名解析发布时间:2022-07-10
热门推荐
阅读排行榜

扫描微信二维码

查看手机版网站

随时了解更新最新资讯

139-2527-9053

在线客服(服务时间 9:00~18:00)

在线QQ客服
地址:深圳市南山区西丽大学城创智工业园
电邮:jeky_zhao#qq.com
移动电话:139-2527-9053

Powered by 互联科技 X3.4© 2001-2213 极客世界.|Sitemap