练习记录
复现代码:
https://pan.baidu.com/s/1pHjOVK0Ib-tjztkgBxe3nQ 密码: 59t2
漏洞分析:
进入网站:
http://10.211.55.2:100/day14/index.php
这次的CTF题目考察的是一个SQL注入问题,且解法有两种(PHP版本为5.2.x)。我们先来看一下整个网站的框架。
day 应用部署目录
├─css 存放css静态文件
├─image 存放图片文件
├─config.php 连接mysql的配置文件
├─content.php 留言查看文件
├─do.php 留言文件
├─function.php 全局功能函数
├─global.php 全局过滤文件
├─index.php 主页文件
├─login.php 登录文件
├─logout.php 登出文件
├─register.php 注册文件
├─waf.php WAF文件
在观察程序的过程中,我们明显发现 content.php
文件中存在 变量覆盖
和 SQL注入
漏洞。
include './global.php';
extract($_REQUEST);
$sql = "select * from test.content where id=$message_id";
$arr = select($sql);
但是在程序开头,引入了全局过滤文件global.php
,我们这里还要看看它是如何进行过滤的。
global.php
引用了3个文件
从waf.php
中,我们可以明显看到程序对 GET 、 POST 、 COOKIES 三种数据处理方式不一样。
<?php
foreach ($_GET as $key => $value) {
if ($key != "username"&&strstr($key, "password") == false) {
$_GET[$key] = filtering($value);
}
}
foreach ($_POST as $key => $value) {
if ($key != "username"&&strstr($key, "password") == false) {
$_POST[$key] = filtering($value);
}
}
foreach ($_REQUEST as $key => $value) {
if ($key != "username"&&strstr($key, "password") == false) {
$_REQUEST[$key] = ($value);
}
}
$request_uri = explode("?", $_SERVER['REQUEST_URI']);
if (isset($request_uri[1])) {
$rewrite_url = explode("&", $request_uri[1]);
foreach ($rewrite_url as $key => $value) {
$_value = explode("=", $value);
if (isset($_value[1])) {
$_REQUEST[$_value[0]] = dhtmlspecialchars(addslashes($_value[1]));
}
}
}
foreach ($_POST as $key => $value) {
$_POST[$key] = safe_str($value);
$_GET[$key] = dhtmlspecialchars($value);
}
foreach ($_COOKIE as $key => $value) {
$_COOKIE[$key] = safe_str($value);
$_GET[$key] = dhtmlspecialchars($value);
}
?>
下面,我们分别来看这两种解法。
解法一:
可以通过GET
或 POST
向content.php
文件传递如下payload
获取flag:
message_id=-1/*%00*/union/**/select/**/1,flag,3,4/**/from/**/flag
如果是 GET
方式传递数据的话,数据会经过filtering
函数过滤,而在filtering
函数中,开头的 eregi
检测,我们又可以使用%00
截断绕过,但是下方还有循环替换恶意字符的代码,这里无法绕过。filtering
函数代码如下:
也就是说我们的 payload 经过 filtering
函数处理后变成了下面这样( select 被过滤掉了
):
message_id=-1/*%00*/union/**//**/1,flag,3,4/**/from/**/flag
当我们继续看代码时,会发现下面的代码又把 message_id
变量的值还原了。因为 content.php
文件中有代码: extract($_REQUEST)
,所以这里也就造成了注入。
那如果是 POST
方式传送数据,会先经过filtering
函数处理,然后经过 safe_str
函数。 safe_str
函数主要用了 addslashes
函数过滤数据,可以发现对我们的 payload 并没有影响。 safe_str 函数代码如下:
这里能进行注入的原因,主要是因为超全局数组 $_REQUEST
中的数据,是 $_GET 、 $_POST 、 $_COOKIE
的合集,而且数据是复制过去的,并不是引用。所以对$_GET 、 $_POST
处理并不会影响$_REQUEST
中的数据。
解法二:
第二种解法是通过COOKIE
的方式进行解题。我们会发现程序对COOKIE
数据的处理方式,明显和处理$_GET 、 $_POST
的方式不一样。对 COOKIE
数据的处理方式具体如下:
payload 为:message_id=0 union select 1,2,flag,4 from flag
现在连eregi
函数都不用绕了。