前言:发现红日安全代码审计小组写了关于php代码审计demo的系列文章,于是跟着一起学习。参考:
[红日安全]代码审计Day1 - in_array函数缺陷
RIPS-PHP-SECURITY-CALENDAR-2017学习记录
漏洞解析
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']);
考察知识点:任意文件上传漏洞
in_array()函数:(PHP 4, PHP 5, PHP 7)
- 功能 :检查数组中是否存在某个值
- 定义 : bool in_array ( mixed $needle , array $haystack [, bool $strict = FALSE ] )
- 在 $haystack 中搜索 $needle ,如果第三个参数 $strict 的值为 TRUE ,则 in_array() 函数会进行强检查,检查 $needle 的类型是否和 $haystack 中的相同。如果找到 $haystack ,则返回 TRUE,否则返回 FALSE。
- 如果 $needle 是字符串,则比较是区分大小写的。
该代码中,in_array()函数没有将第三个参数设置为TRUE进行强检查,导致攻击者可以通过构造文件名来绕过服务端的检测。比如,上传6shell.php,由于目标数组$whitelist
中的元素是数字类型的,所以会发生强制类型转换,文件将被强制转换成数字6,6在range(1, 24)中,绕过了in_array()函数判断,导致任意文件可上传。
实例解析
code:piwigo2.7.1
此处in_array()函数也没有设置第三个参数为TRUE,而$rate
是可以直接和SQL语句拼接的
当$_GET['action']
为 rate
的时候,就会调用文件 include/functions_rate.inc.php 中的rate_picture
方法
然后再看$conf['rate_items']
尝试绕过:将$rate
设置为1,1 and if(ascii(substr((select database()),1,1))=112,1,sleep(3)));#
'INSERT INTO'
.RATE_TABLE.
'(user_id,anonymous_id,element_id,rate,date)
VALUES ('
.$user['id'].','
.'\''.$anonymous_id.'\','
.$image_id.','
.$rate
.',NOW());'
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());
修复建议
- in_array()函数第三个参数设置为TRUE作强检查
- 使用 intval() 函数将变量强转成数字