icewing

PHP代码审计(二)
接上一次的继续整理。
扫描右侧二维码阅读全文
10
2019/06

PHP代码审计(二)

接上一次的继续整理。

3.3 回调漏洞

0x01 漏洞背景

在 PHP 一些回调函数中,如果函数输入可控,可以利用回调 assert 等方法进行命令执行漏洞

0x02 漏洞代码及分析

  • 漏洞代码 1 :
<?php
  call_user_func($_REQUEST['fun'], $_REQUEST['pass']);
?>
  • 漏洞代码 2 :
<?php
array_map($_REQUEST['fun'], $_REQUEST['pass']);
?>

在 fun 传递可控的情况下,会引起代码执行漏洞

  • 修复建议:
    第一个参数不让用户可控
  • 建议修复代码:
array_map('addslashes', $_REQUEST['pass']);

参考文章:
https://www.leavesongs.com/penetration/php-callback-backdoor.html


4.1 命令执行漏洞

0x01 漏洞背景

exec 、 system 、 shell_exec 、 passthru 等命令执行函数,在传入的命令过滤不严,可导致任意命令执行漏洞,危及服务器。

0x02 漏洞代码及分析

  • 漏洞代码 1 :
<?php
  $url = $_GET['url'];
  $content = system("curl $url");
  echo $content;
?>

直接将可控内容带入命令执行中,导致产生漏洞

  • 漏洞代码 2 :
<?php
if (isset($_REQUEST['ip'])) {
    $target = trim($_REQUEST['ip']);
    $substitutions = array(
        '&' => '',
        ';' => '',
        '|' => '',
        '-' => '',
        '$' => '',
        '(' => '',
        ')' => '',
        '`' => '',
        '||' => '',
    );
    $target = str_replace(array_keys($substitutions) , $substitutions, $target);
    $cmd = shell_exec('ping -c 4 ' . $target);
    echo $target;
    echo "<pre>{$cmd}</pre>";
} ?>

虽然进行了一些过滤,但是过滤不严, %0a 可绕过命令执行

  • 修复建议:
    不要让用户可控的内容带入命令执行中

参考文章:
http://www.freebuf.com/articles/web/137923.html


5.1 普通注入漏洞

0x01 漏洞背景

SQL 注入是攻击者通过把恶意 SQL 命令插入到 Web 表单的输入域或页面请求的查询字符串中,来达到欺骗服务器执行恶意的 SQL 命令的一种攻击方式

0x02 漏洞代码及分析

  • 漏洞代码 1 :
<?php
$mysqli = new mysqli('localhost', 'root', 'root', 'code'); // 数据库连接
$id = !empty($_GET['id']) ? $_GET['id'] : '1';
$data = $mysqli->query("select content from test where id=$id");
if ($data->num_rows !== '0') {
    $arr = $data->fetch_all();
    foreach ($arr as $a) {
        echo ' 内容: ' . $a[0] . '<br>';
    }
}
?>

对于传入的内容未过滤,且 SQL 拼接的时候没有单引号保护

  • 修复建议:
    使用单引号保护并过滤内容
  • 建议修复代码:
$id = !empty($_GET['id']) ? addslashes($_GET['id']) : '1';
$data = $mysqli->query("select content from test where id='$id'");
  • 漏洞代码 2 :
<?php

$mysqli = new mysqli('localhost', 'root', 'root', 'code'); // 数据库连接
$id = !empty($_GET['id']) ? $_GET['id'] : '1';
$data = $mysqli->query("select content from test where id='$id'");
if ($data->num_rows !== '0') {
    $arr = $data->fetch_all();
    foreach ($arr as $a) {
        echo ' 内容: ' . $a[0] . '<br>';
    }
}
?>

即使使用了单引号保护,但是传入内容未过滤,导致 SQL 注入
-修复建议:
参考代码 1 修复

  • 漏洞代码 3 :
<?php

$mysqli = new mysqli('localhost', 'root', 'root', 'code'); // 数据库连接
if (!empty($_POST['content'])) {
    $name = $_POST['name'];
    $content = $_POST['content'];
    if ($mysqli->query("insert into test (content)values('$name','$content')")) {
        echo ' 发言成功 ';
    } else {
        echo ' 发言失败 ';
    }
}
?>

nsert 型注入,差不多的注入方式。

  • 修复建议: 对 SQL 拼接时一定要单引号保护,整数型也不例外,并且传入的值要经过 addslashes 函数过滤。不过最好的方案还是用 PDO 预处理
  • 修复代码:
$name = addslashes($_POST['name']);
$content = addslashes($_POST['content']);
if($mysqli->query("insert into test (content)values('$name','$content')"))

5.2 宽字节注入漏洞

0x01 漏洞背景

宽字节注入发生的位置就是 PHP 发送请求到 MYSQL 时字符集使用 charactersetclient 设置值进行了一次编码

0x02 漏洞代码及分析

  • 漏洞代码 1 :
<?php

$mysqli = new mysqli('localhost', 'root', 'root', 'code'); // 数据库连接
$id = !empty($_GET['id']) ? addslashes($_GET['id']) : '1';
$mysqli->query("SET NAMES 'gbk'");
$data = $mysqli->query("select content from test where id='$id'");
if ($data->num_rows !== '0') {
    $arr = $data->fetch_all();
    foreach ($arr as $a) {
        echo ' 内容: ' . $a[0] . '<br>';
    }
}
?>

执行 SET NAMES 'gbk' 之后会引起宽字节注入漏洞,绕过单引号达到注入效果

  • 修复建议:
    字符集编码设置成 utf8
  • 建议修复代码:
$mysqli->query("SET NAMES 'utf8'");

5.3 字符集漏洞

0x01 漏洞背景

默认情况下, Mysql 的字符集就是 latin1 , Mysql 字段的字符集和 php mysqli 客户端设置的字符集不相同导致可能绕过登录等情况

0x02 漏洞代码及分析

  • 漏洞代码 1 :
<?php

$mysqli = new mysqli('localhost', 'root', 'root', 'code'); // 数据库连接
if (!empty($_POST['username']) && !empty($_POST['password'])) {
    $username = addslashes($_POST['username']);
    $password = addslashes($_POST['password']);
    $data = $mysqli->query("select * from user where username='$username' and password='$password'");
    if ($data->num_rows !== '0') {
        $arr = $data->fetch_row();
        session_start();
        $_SESSION['username'] = $arr[1];
        echo ' 登录成功 ';
    }
}
?>

例如管理员账号是 admin ,注册 admin%c2 ,登录之后就是管理员权限了


6.1 hash 比较绕过

0x01 漏洞背景

=== 在进行比较的时候,会先判断两种字符串的类型是否相等,再比较
== 在进行比较的时候,会先将字符串类型转化成相同,再比较
如果比较一个数字和字符串或者比较涉及到数字内容的字符串,则字符串会被转换成数值并且比较按照数值来进行

0x02 漏洞代码及分析

  • 漏洞代码 1 :
<?php

if (isset($_GET['Username']) && isset($_GET['password'])) {
    $logined = true;
    $Username = $_GET['Username'];
    $password = $_GET['password'];
    if (!ctype_alpha($Username)) {
        $logined = false;
    }
    if (!is_numeric($password)) {
        $logined = false;
    }
    if (md5($Username) != md5($password)) {
        $logined = false;
    }
    if ($logined) {
        echo "successful";
    } else {
        echo "login failed!";
    }
}
?>

0e 在比较的时候会将其视作为科学计数法,所以无论 0e 后面是什么, 0 的多少次方还是 0 。导致弱类型比较绕过

  • 修复建议: 将 == 换成 ===
  • 建议修复代码:
if (md5($Username) !== md5($password)) {

6.2 json 绕过

0x01 漏洞背景

=== 在进行比较的时候,会先判断两种字符串的类型是否相等,再比较
== 在进行比较的时候,会先将字符串类型转化成相同,再比较
如果比较一个数字和字符串或者比较涉及到数字内容的字符串,则字符串会被转换成数值并且比较按照数值来进行

0x02 漏洞代码及分析

  • 漏洞代码 1 :
<?php

if (isset($_POST['message'])) {
    $message = json_decode($_POST['message']);
    $key = "*********";
    if ($message->key == $key) {
        echo "flag";
    } else {
        echo "fail";
    }
} else {
    echo "~~~~";
}
?>

json_decode 之后可以解析成布尔型,可以传入 true 绕过比较

  • 修复建议:
    将 == 换成 ===
  • 建议修复代码:
if ($message->key === $key) {

6.3 array_search 绕过

0x01 漏洞背景

=== 在进行比较的时候,会先判断两种字符串的类型是否相等,再比较
== 在进行比较的时候,会先将字符串类型转化成相同,再比较
如果比较一个数字和字符串或者比较涉及到数字内容的字符串,则字符串会被转换成数值并且比较按照数值来进行

0x02 漏洞代码及分析

  • 漏洞代码 1 :
<?php

if (!is_array($_GET['test'])) {
    exit;
}
$test = $_GET['test'];
for ($i = 0; $i < count($test); $i++) {
    if ($test[$i] === "admin") {
        echo "error";
        exit;
    }
    $test[$i] = intval($test[$i]);
}
if (array_search("admin", $test) === 0) {
    echo "flag";
} else {
    echo "false";
}
?>

传入数组 test[]=0 可以绕过

  • 修复建议:
    将 array_search 第三个参数为 true 则就不能绕过
  • 建议修复代码:
if (array_search("admin", $test, true) === 0) {
最后修改:2019 年 06 月 10 日 04 : 46 PM
生活需要一些仪式感,比如手冲一杯咖啡:)

发表评论