前言
▶ 在前面我已经介绍了AKun Wallpaper的部署,分析了xss漏洞并且讲解了如何修复这些漏洞。如果还没有看过前两篇文章的同学可以先看一下前两篇文章。在这一篇文章中将重点分析任意文件删除漏洞和sql注入漏洞,然后对漏洞进行复现,最后讲解如何修复这些漏洞。
漏洞分析1
▶ 审计过程
▪ 首先看到`doImageAction.php`的第18行,此处存在一个删除文件函数 `unlink()`。该函数的参数 `$fileName`是通过GET方式获取,所以该处所删除的文件可控,所以该处存在任意文件删除漏洞。
▶ 漏洞复现
▪ 为了避免删除正常文件,我在网站根目录下创建了一个文件 `a.php`来做测试。
▪ 然后访问 `http://127.0.0.1/admin/doimageAction.php?action=delImage&fileName=../a.php`,其中`action=delImage`代表要执行删除文件的操作,`fileName=../a.php`表示要删除的文件就是上一级目录中的`a.php`。但是访问后网页后弹出提示框提示删除失败,其实这时候已经成功删除文件了。再次查看文件,发现`a.php`已经不存在了。
▪ 这里提示删除失败是因为没有传入id参数,导致数据库删除图片相应的记录失败。如下图所示,标红路径即本次程序运行路径。
▶ 修复方案
▪ 防止任意文件删除的方法有多种,但是所有方法基本有以下两个特点:
1. 尽量避免从用户端获取文件名。
2. 防止目录跳转。
▪ 所以此处给出两种解决办法:
1. 禁止用户任意传入文件名,通过图片id从数据库中获取图片名称。
2. 禁止目录跳转,只允许删除指定目录中的文件。
▪ 这里选择第二种方法做演示,在删除文件的代码前添加如下代码即可防止任意文件删除。其中 `LIST_IMAGES`是图片存储的目录, `basename()`函数是去除目录,只保留文件名。修改后如下图所示:
$fileName = LIST_IMAGES."/".basename($fileName);
注意:在`doImageAction.php`中37行是循环删除多个文件,在复现此处漏洞的时候传入的参数与前面有所不同,其参数格式为:action=delAllImage&info=id1:filename1,id2:filename2,id3:filename3,但是其修复方式与前面讲述方法一样。
漏洞分析2
▶ 审计过程
▪ 看到 `lib/downImage.php`文件,在该文件中执行流程是:
1. 首先通过GET方式获取一个字符串。
2. 然后将字符串中目录去除,只保留有效文件名部分。
3. 最后下载该文件。
▪ 虽然该漏洞不能任意穿越目录,但是可以下载当前目录中任意文件。该文件存在 `lib`目录中,该目录中存在一些敏感文件。如果这些文件能被用户下载,将会存在巨大的潜在风险。
修复方法可以根据具体业务需求设置白名单。此文件本来是移动端程序下载图片时使用,这里为了简化程序删除了移动端版本,但是`downImage.php`忘记删除了,所以此处删除该文件就可修复,不会影响正常业务。
漏洞分析3
▶ 审计过程
▪ 看到 `lib/mysql.func.php`第24行,此处执行了一条sql语句,顺着这条语句找到数据源。
▪ 数据源是 `core/core.php`的20行处获取,从数据源到sql语句执行的过程中未进行任何安全处理,所以该处大概率存在sql注入漏洞。
▶ 漏洞复现
▪ 上面分析的代码功能就是添加管理员,我们打开添加管理员页面,填写任意数据。
▪ 开启浏览器代理,通过burpsuite抓取数据包。
▪ 将数据包发送到 `Repeater`模块,并构造恶意payload。发送数据包5s后才收到响应包,这说明函数`sleep(5)`已经执行成功。
▶ 修复方案
▪ sql注入的防范方法主要有以下几种:
1. 通过`addslashes`、`mysql_real_escape_string`等函数或开启`magic_quotes_gpc`参数来过滤引号。这种方法在某些情况下可以通过宽字节注入或二次注入绕过限制,也不能有效防范int类型注入。
2. 通过`intval`函数转换防止注入。该函数的作用是将变量转化为int型。这种方法无法对本身含有字符型数据的数据进行处理。
3. 通过黑名单或白名单的方式进行过滤。绕过白名单或黑名单的方法多种多样,难以防范。
4. 采用PDO预编译防止sql注入。这种方法防止sql注入的效果比较好,建议采用这种方法。
▪ 此处如果采用PDO预编译的方法修复漏洞,该程序所有sql语句都要重写,工作量巨大,所以建议开发初期就采用PDO预编译方式操作数据库。此处采用 mysql_real_escape_string函数加上 mysql_set_charset函数对特殊字符转义来防止sql注入。
Q:`mysql_set_charset`的作用是什么?
A:`mysql_set_charset`设置了数据库的编码,同时也记录了当前设置的编码,在后面使用`mysql_real_escape_string`函数时会自动获取这个编码,并通过此编码来转义特殊字符。这样统一了转义时用的编码和数据库编码,便可以防止宽字节注入。
Q:`addslashes`与`mysql_real_escape_string`的区别是什么?
A:`mysql_real_escape_string`会获取数据库字符集并根据数据库字符集转义特殊字符,而`addslashes`会直接使用默认字符集转义特殊字符。另外`addslashes`只会对 `'`、`"`、``、`null` 转义,而`mysql_real_escape_string`同时还会对 `r`、`n`和`x1a`转义。
▪ 将 `lib/mysql.func.php`第13行的 `mysql_query("set names utf8");`替换成下面代码:
mysql_set_charset('utf8');
▪ 然后使用`mysql_real_escape_string`函数对用户传过来的数据进行转义,`lib/mysql.func.php`中20行的 `insert`函数改成:
function insert($table,$data) {
$key = join(",",array_keys($data));
$key = mysql_real_escape_string($key);
$value = join(",", array_values($data));
$value = mysql_real_escape_string($value);
$value = explode(",", $value);
$value = "'".join("','", $value)."'";
$sql = "INSERT INTO {$table}({$key}) VALUES({$value})";
mysql_query($sql);
return mysql_insert_id();
}
▪ 其他sql注入漏洞原理类似,可以用同样的方法修复。
来源 | 刘正波
西柚网安
扫描二维码并关注
网安知识一网打尽
原文始发于微信公众号(西柚网安):AKun Wallpaper 代码审计——实战分析(三)
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论