【红日Day12-CTF】htmlentities造成的SQL注入

练习记录

复现代码:

index.php

<?php
require 'config.php';

if(isset($_REQUEST['username'])){
    if(preg_match("/(?:\w*)\W*?[a-z].*(R|ELECT|OIN|NTO|HERE|NION)/i", $_REQUEST['username'])){
        die("Attack detected!!!");
    }
}

if(isset($_REQUEST['password'])){
    if(preg_match("/(?:\w*)\W*?[a-z].*(R|ELECT|OIN|NTO|HERE|NION)/i", $_REQUEST['password'])){
        die("Attack detected!!!");
    }
}

function clean($str){
    if(get_magic_quotes_gpc()){
        $str=stripslashes($str);
    }
    return htmlentities($str, ENT_QUOTES);
}

$username = @clean((string)$_GET['username']);
$password = @clean((string)$_GET['password']);


$query='SELECT * FROM ctf.users WHERE name=\''.$username.'\' AND pass=\''.$password.'\';';

#echo $query;

$result=mysql_query($query);
while($row = mysql_fetch_array($result))
{
    echo "<tr>";
    echo "<td>" . $row['name'] . "</td>";
    echo "</tr>";
}

?>

config.php

<?php
$mysql_server_name="localhost";
$mysql_database="day12";    /** 数据库的名称 */
$mysql_username="root";  /** MySQL数据库用户名 */
$mysql_password="root";  /** MySQL数据库密码 */
$conn = mysql_connect($mysql_server_name, $mysql_username,$mysql_password,'utf-8');
?>
搭建CTF环境使用的sql语句

#
# Structure for table "users"
#
CREATE database day12;
use day12;
DROP TABLE IF EXISTS `users`;
CREATE TABLE `users` (
  `Id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) DEFAULT NULL,
  `pass` varchar(255) DEFAULT NULL,
  `flag` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`Id`)
) ENGINE=MyISAM AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;

#
# Data for table "users"
#

/*!40000 ALTER TABLE `users` DISABLE KEYS */;
INSERT INTO `users` VALUES (1,'admin','qwer!@#zxca','hrctf{sql_Inject1on_Is_1nterEst1ng}');
/*!40000 ALTER TABLE `users` ENABLE KEYS */;

漏洞分析:

进入网站:

http://10.211.55.2:100/day12/index.php

从index.php代码 第27行

$query='SELECT * FROM ctf.users WHERE name=\''.$username.'\' AND pass=\''.$password.'\';';

很明显,这道题考查sql注入,但是这里有两个考察点,我们分别来看一下。

第一部分

第23行第24行 针对GET 方式获取到的usernamepassword进行了处理,

$username = @clean((string)$_GET['username']);
$password = @clean((string)$_GET['password']);

处理函数为clean 。该函数在 第16-20行 处定义

function clean($str){
    if(get_magic_quotes_gpc()){
        $str=stripslashes($str);
    }
    return htmlentities($str, ENT_QUOTES);
}

函数的主要功能就是使用 htmlentities函数处理变量中带有的特殊字符,而这里加入了 htmlentities函数的可选参数ENT_QUOTES ,因此这里会对 单引号双引号等特殊字符进行转义处理。由于这里的注入是字符型的,需要闭合单引号或者逃逸单引号,因此这里需要绕过这个函数。我们可以通过下面这个例子观察 clean 函数的处理效果:
在这里插入图片描述
题目 选中这行 是进入数据库查询,并且返回 name 列字段的值。而这里的sql语句是这样的:

$query='SELECT * FROM ctf.users WHERE name=\''.$username.'\' AND pass=\''.$password.'\';';

那我们如果输入的usernameadminpasswordadmin,自然就构成了正常要执行的sql语句。
在这里插入图片描述
这道题的问题就在于可以引入反斜杠,也就是转义符,官方针对 转义符 是这么解释的。

比如,如果你希望匹配一个 “*” 字符,就需要在模式中写为 *。 这适用于一个字符在不进行转义会有特殊含义的情况下。

这里我们看个简单的例子理解一下这个转义符号。
在这里插入图片描述
转义符号会让当前的特殊符号失去它的作用,这道题由于可以引入反斜杠,也就是转义符号,来让

扫描二维码关注公众号,回复: 8943736 查看本文章
$query='SELECT * FROM ctf.users WHERE name=\''.$username.'\' AND pass=\''.$password.'\';';

username后面的 '失效,只要这个'失效,就能闭合pass=后面的'。最后组合的payload就如下图所示
在这里插入图片描述
所以实际上目前 name的值是admin\' AND pass= ,这时候 password的值是一个可控的输入点,我们可以通过这个值来构造 sql的 联合查询 ,并且注释掉最后的 单引号
在这里插入图片描述
最后我们看看在mysql中执行的结果。
在这里插入图片描述

第二部分

好了第一部分我们其实已经成功构造好了payload,但是回头来看看题目,题目第5、6行第11、12行 有两个正则表达式,作用就是如果参数中带有 or、and 、union等数据,就退出,并输出 Attack detected!!!
在这里插入图片描述
这里当然我们可以正面硬刚这个正则表达式。但是这里我们来聊一个比较有趣的解法。
我们看到是通过request方式传入数据,而php中 REQUEST变量默认情况下包含了 GET ,POSTCOOKIE的数组。在 php.ini配置文件中,有一个参数 variables_order,这参数有以下可选项目

; variables_order
; Default Value: “EGPCS”
; Development Value: “GPCS”
; Production Value: “GPCS”

这些字母分别对应的是 E: EnvironmentG:GetP:PostC:CookieS:Server。这些字母的出现顺序,表明了数据的加载顺序。而php.ini中这个参数默认的配置是 GPCS,也就是说如果以 POSTGET方式传入相同的变量,那么用REQUEST获取该变量的值将为 POST该变量的值。
在这里插入图片描述
我们举个简单的例子方便大家理解:

在这里插入图片描述
我们可以看到这里的 post方式传入的数据覆盖了get方式传入的数据,因此这里最后的payload如下:

http://10.211.55.2:100/day12/index.php?username=\&password= union select 1,flag ,3,4 from day12.users%23

POST:

username=0&password=1

在这里插入图片描述

发布了35 篇原创文章 · 获赞 19 · 访问量 5187

猜你喜欢

转载自blog.csdn.net/zhangpen130/article/details/104039117