编者:有时候我会碰到一些叫我瞠目结舌的事.比如这个文章,我发英文原文在我blog上,晚上来的时候居然发现有人把它翻译了.....
翻译:blcakwell (plmm:)
我的一个客户要求我们检查一下给他们的职员和顾客用的内网(企业网)。
这也是大范围安全检测的一部分。尽管对于sql注入的一般概念比较熟悉,
实际上,我们以前没有用过这种方法渗透网络。这次我们完全成功
的进行了渗透,我希望把过程图文并茂的重现。
“sql 注入”是“未核实性/不稳健性”用户输入脆弱性的一个子集
(“缓冲誉出”是另一个不同的子集),
主要思路是确使数据库运行不应该被运行的sql语句,
如果冒然运行了这些语句,其产生的后果是让人惊讶的。(水平有现,没有把作者意思完全写出来)
翻译:blcakwell (plmm:)
我的一个客户要求我们检查一下给他们的职员和顾客用的内网(企业网)。
这也是大范围安全检测的一部分。尽管对于sql注入的一般概念比较熟悉,
实际上,我们以前没有用过这种方法渗透网络。这次我们完全成功
的进行了渗透,我希望把过程图文并茂的重现。
“sql 注入”是“未核实性/不稳健性”用户输入脆弱性的一个子集
(“缓冲誉出”是另一个不同的子集),
主要思路是确使数据库运行不应该被运行的sql语句,
如果冒然运行了这些语句,其产生的后果是让人惊讶的。(水平有现,没有把作者意思完全写出来)
/*无太大关系,幽默的类比*/
有很多关于sql注入的文章,包含一些,甚至更多的细节。
本文主要说明合理的发现问题比攻击的过程要重要。
目标网站
客户的数据库就在上面,但是,我们没有进入之前我们没有任何关于它的源代码。
这是一次“没有把握”的攻击,简单的测探之后显示服务器是微软的iis 6.0运行着asp
并且表明数据库是微软的sql服务器,我们相信这些技术几乎应用于任何sql服务器支持的网络。
登陆页面有着传统的“用户名”“密码”表格单,还有一个“电邮给我”“我的密码”的连接;
后者结果让我们攻入了这个服务器。
当填入一个邮件地址,系统在用户数据库里面这个地址,然后给这个地址发邮件。
而我的邮件地址没有发现,所以不会给我发任何东西。
所以,第一步的测试(sql -ish 这个-ish不清楚)是把填入表单的电邮地址数据加上个单引号(')
目的在于看看是否能构成sql语句字面上的不稳定性。当提交这个有着单引号电邮地址的表单,
我们得到一个500 错误(服务器错误),这表示我们的输入的语法不正确的数据被系统运行了(进行了解析
)。
让我们来推测一下系统是怎么运行我们输入的数据的,情况如下:
select 什么什么什么(一般是表里面的列)注入 //我们不知道是什么
from 哪个哪个表 //我们也不知道是什么
where 什么什么='$email'; //这是我们的推测,具体是不是我们也不知道。
这个$email是用户从表单提交来的,并且更多的查询由双引号设置一个字符串,我们不知道
上面的“什么什么什么”和“哪个哪个表”的具体名字,但是我们知道它们的性质,所以我们
等会儿能有些合理的猜测。
我们输入“什么什么@什么什么'”--注意最后的引号--这个产生出sql语句结构
select 什么什么
from 哪个哪个表
where 什么什么='什么什么@什么什么'';
单这个语句被执行,sql解析发现多余的引号,然后因为句法错误而中断了。而把错误到底能多清楚明白
的显示给用户看,要取决于系统内部错误恢复的过程。但是,一般不同于显示“电邮地址未知”。
如果错误反映出我们的输入导致发现它完全具有不稳定性,那么这个系统攻击时机就成熟了。
where 什么什么='$email'; //这是我们的推测,具体是不是我们也不知道。
这个$email是用户从表单提交来的,并且更多的查询由双引号设置一个字符串,我们不知道
上面的“什么什么什么”和“哪个哪个表”的具体名字,但是我们知道它们的性质,所以我们
等会儿能有些合理的猜测。
我们输入“什么什么@什么什么'”--注意最后的引号--这个产生出sql语句结构
select 什么什么
from 哪个哪个表
where 什么什么='什么什么@什么什么'';
单这个语句被执行,sql解析发现多余的引号,然后因为句法错误而中断了。而把错误到底能多清楚明白
的显示给用户看,要取决于系统内部错误恢复的过程。但是,一般不同于显示“电邮地址未知”。
如果错误反映出我们的输入导致发现它完全具有不稳定性,那么这个系统攻击时机就成熟了。
因为我们填入的数据出现在where这个从句那里,让我们来以slq合法的方式改变一下这个从句的属性
看看会发生什么。通过输入“anything' or 'x'='x,” slq的结果如下:
select 什么什么什么
from 哪个哪个表
where 什么什么什么='anything' or 'x'='x';
由于系统不会象人一样思考这些查询---仅仅是构成语句--我们用的引号就把where从句的一个
部件结合成两个部件,并且那个'x'='x'肯定是合法的不管第一个从句是什么( 有一个更好的
让系统“肯定是合法”的方法,等下我们将介绍)
不象“真实”查询那样,每次应该返回一个项值,将会返回数据库的每个项值。唯一能弄清楚
系统在这样的环境下将有什么反映的方法就是努力的去试。试了之后,我们可能得到如下信
息:
你的登陆信息已经发送到“什么什么@什么什么”
我们最好的猜测而且有效果的输入能让查询的第一个记录能返回。而某人会收到一封“密码遗失”的
信,这将让他惊讶恐惧。
我们现在知道我们有能力控制查询为我们目的服务,虽然我们还不知道查询结构的更多信息。
但是我们已经通过我们不同的输入看到三种不同的结果。
1:“你的登陆信息已经通过电邮发送”
2:“你的电邮地址无法识别”
3: 服务器错误
前两个结果是正确的sql形式,而最后一个是不正确的,而用这个特性,当我们设法试着去猜
你的登陆信息已经发送到“什么什么@什么什么”
我们最好的猜测而且有效果的输入能让查询的第一个记录能返回。而某人会收到一封“密码遗失”的
信,这将让他惊讶恐惧。
我们现在知道我们有能力控制查询为我们目的服务,虽然我们还不知道查询结构的更多信息。
但是我们已经通过我们不同的输入看到三种不同的结果。
1:“你的登陆信息已经通过电邮发送”
2:“你的电邮地址无法识别”
3: 服务器错误
前两个结果是正确的sql形式,而最后一个是不正确的,而用这个特性,当我们设法试着去猜
测查询的结构
是非常有用的。
先验式(纲要)映射
第一步我们必须猜测出一些表内的域名;必须合理的确定查询包含“电邮地址”和“密码”
并且可能存在“美国电邮地址”或者“用户id”或者“电话号码”。我们最好执行 show table
命令,可是我们不知道表的名字。然而没有太多方式让我们等到输出的结果(原文为比喻)。
所以我们将一步一步来,在每一步,我们将运用我们所知道到的来显示整个查询,用我们自己这小部分来
作特别的显示,我们知道查询的尾部是一个电邮地址,所以,我们可以把电邮做为表内域名来猜测一下。
select 什么什么什么
from 那个那个表
是非常有用的。
先验式(纲要)映射
第一步我们必须猜测出一些表内的域名;必须合理的确定查询包含“电邮地址”和“密码”
并且可能存在“美国电邮地址”或者“用户id”或者“电话号码”。我们最好执行 show table
命令,可是我们不知道表的名字。然而没有太多方式让我们等到输出的结果(原文为比喻)。
所以我们将一步一步来,在每一步,我们将运用我们所知道到的来显示整个查询,用我们自己这小部分来
作特别的显示,我们知道查询的尾部是一个电邮地址,所以,我们可以把电邮做为表内域名来猜测一下。
select 什么什么什么
from 那个那个表
where 什么什='x' and email is null; --';
目的是用一个合适的域名(电邮)去构成查询,出是否sql合法或者不合法。我们不关心电邮地址是不是
匹配(这也是我们为什么用空变量 'x'的原因),-- 这个表示sql注释的开始。这是一种有效的方式
去掉最后的引号而且不用理会是不是存在匹配的问题。
如果我们得到服务器错误,这就意味着sql句法错误很有可能是由于不正确的域名导致的。如果我们能得到
然后正确的反映或者结果,那么我们就正确地猜测到名字了。这样我们会得到“电邮未知”或者“密码已经
发送”的结果。
注意,我们用and而不是or去注入,在sql先验性映射阶段,我们不是考虑猜到某个具体的电邮地址,
目的是用一个合适的域名(电邮)去构成查询,出是否sql合法或者不合法。我们不关心电邮地址是不是
匹配(这也是我们为什么用空变量 'x'的原因),-- 这个表示sql注释的开始。这是一种有效的方式
去掉最后的引号而且不用理会是不是存在匹配的问题。
如果我们得到服务器错误,这就意味着sql句法错误很有可能是由于不正确的域名导致的。如果我们能得到
然后正确的反映或者结果,那么我们就正确地猜测到名字了。这样我们会得到“电邮未知”或者“密码已经
发送”的结果。
注意,我们用and而不是or去注入,在sql先验性映射阶段,我们不是考虑猜到某个具体的电邮地址,
我们也不希望很多用户收到由系统发送的诸如“你的密码”这样的电邮。这样将会使大家警觉。
通过用and去注入一个电邮地址,即使电邮地址不正确,我们也能确定查询总是会返回0行(也就是
什么也查不到)
当我们提交后系统给了我们一个“电邮地址未知”的反映。所以现在我们知道电邮地址是存放在以电邮为
域名的这一列了。如果这个方法不起作用,我们可以试着用"电邮_地址"或者 "邮件"或者类似的名字
去试试。当然这要试很多次。
接下来我们将猜测其他的名字:密码,用户号,姓名等等。所有这些我们可以一次做掉。只要不是
“服务器错误”的结果,我们就正确的猜测到了。
通过用and去注入一个电邮地址,即使电邮地址不正确,我们也能确定查询总是会返回0行(也就是
什么也查不到)
当我们提交后系统给了我们一个“电邮地址未知”的反映。所以现在我们知道电邮地址是存放在以电邮为
域名的这一列了。如果这个方法不起作用,我们可以试着用"电邮_地址"或者 "邮件"或者类似的名字
去试试。当然这要试很多次。
接下来我们将猜测其他的名字:密码,用户号,姓名等等。所有这些我们可以一次做掉。只要不是
“服务器错误”的结果,我们就正确的猜测到了。
selcet 什么什么什么
from 那个那个表
where email = 'x' and userid is null; --';
这个的结果,我们会发现几个正确的域名:
1:邮件
2:密码
3:登陆号
4:全名
当然我们等下会进一步了解,但是我们现在还没有过多的发现,因为我们不知道表的名字,
怎么样才能知道表的名字呢?
到表的名字
系统的查询是在表里面进行,但是我们不知道表的名字,有几种方式去弄清楚表的名字。
首先我们用subselect。
格式如下:
select count(*) from 哪个哪个表
将返回表内记录的数量,如果表名不存在,那么这个语句不生效。我们可以用以下语句去弄清楚
表名:
select 电邮,密码,登陆号,全名
from 那个哪个表
where email = 'x' and 1=(select count(*) from 表名); --';
我们并不关心到底有多少记录,只关心表名有或者没有。经过几次猜测我们能确信“member
首先我们用subselect。
格式如下:
select count(*) from 哪个哪个表
将返回表内记录的数量,如果表名不存在,那么这个语句不生效。我们可以用以下语句去弄清楚
表名:
select 电邮,密码,登陆号,全名
from 那个哪个表
where email = 'x' and 1=(select count(*) from 表名); --';
我们并不关心到底有多少记录,只关心表名有或者没有。经过几次猜测我们能确信“member
s”
是数据库里面一个表名。但是它和我们的查询有关系吗?为了弄清楚,我们用table.field来试试,
这个表达式只对查询有关系的部分起作用,即表名是存在的和查询没有关系那么不起作用。
select email, passwd, login_id, full_name
from members
where email = 'x' ail is null; --';
当返回“电邮未知”,这就证实了我们的猜测是正确的,也弄清楚表members和我们需要的是有联系的。
等下我们将看到这个方法的重要性。
寻用户名
是数据库里面一个表名。但是它和我们的查询有关系吗?为了弄清楚,我们用table.field来试试,
这个表达式只对查询有关系的部分起作用,即表名是存在的和查询没有关系那么不起作用。
select email, passwd, login_id, full_name
from members
where email = 'x' ail is null; --';
当返回“电邮未知”,这就证实了我们的猜测是正确的,也弄清楚表members和我们需要的是有联系的。
等下我们将看到这个方法的重要性。
寻用户名
我们已经知道members表的一些情况,但是我们只知道一个用户名,就是我们以前测试时系统发送的“你的
密码”邮件的那个用户,但是我们没有收到这个邮件。我们需要猜测更多的用户名,以便得到更多的信息。
首先,我们去网页上看看,在“关于我们”或者“”这样的页面,往往会列出些相关的用户名。
并且往往还列出电邮地址。总之这里会给我们很多线索,为我们的渗透提供方便。
我们做一个电邮名字或者人称全名或者其他有关信息的查询,每次我们用like名字支持的通配符%来进行。
select email,passwd,login_id,full_name
from members
where email ='x' or full_name like '%Bob%';
密码”邮件的那个用户,但是我们没有收到这个邮件。我们需要猜测更多的用户名,以便得到更多的信息。
首先,我们去网页上看看,在“关于我们”或者“”这样的页面,往往会列出些相关的用户名。
并且往往还列出电邮地址。总之这里会给我们很多线索,为我们的渗透提供方便。
我们做一个电邮名字或者人称全名或者其他有关信息的查询,每次我们用like名字支持的通配符%来进行。
select email,passwd,login_id,full_name
from members
where email ='x' or full_name like '%Bob%';
记住,即使有很多个bob我们也只能得到一个bob的信息,这是like的精确匹配的问题。
最后,我们仅仅需要个正确的电邮地址就能知道我们想要的。
暴力破解密码
有一点可以肯定,在主登陆页面进行暴力破解。系统会设法给予识别和限制。可能关闭登陆页面,
锁定帐户,或者其他方式,这些会阻碍我们的破解。但是,因为它存在输入不没有过滤掉有害成分。
所以,我们有另外一条路饶过这种保护。
我们直接输入包含电邮名和密码的查询而不是仅仅做密码测试。看下面这个例子,我们用“bob@example
”作为我们查询的电邮名来猜测密码。
SELECT email, passwd, login_id, full_name
最后,我们仅仅需要个正确的电邮地址就能知道我们想要的。
暴力破解密码
有一点可以肯定,在主登陆页面进行暴力破解。系统会设法给予识别和限制。可能关闭登陆页面,
锁定帐户,或者其他方式,这些会阻碍我们的破解。但是,因为它存在输入不没有过滤掉有害成分。
所以,我们有另外一条路饶过这种保护。
我们直接输入包含电邮名和密码的查询而不是仅仅做密码测试。看下面这个例子,我们用“bob@example
”作为我们查询的电邮名来猜测密码。
SELECT email, passwd, login_id, full_name
FROM members
WHERE email = 'bob@example' AND passwd = 'hello123';
这是个很清楚而正确的sql语句,因此我们不会看到任何服务器错误,而当我们看到“你的密码已经电邮给你
”的时候,那么我们就到了密码。这个信息泄露出密码是正确的。而我们的确知道了密码。
当然,我们可以编写个perl脚本自动的进行,在我们实际去做这些事情之前,我们来看点别的。
数据库是可读写的
到目前为止,我们除了查询数据库之外没有做其他的事情,而即使一个select是只读的,但是不表示
WHERE email = 'bob@example' AND passwd = 'hello123';
这是个很清楚而正确的sql语句,因此我们不会看到任何服务器错误,而当我们看到“你的密码已经电邮给你
”的时候,那么我们就到了密码。这个信息泄露出密码是正确的。而我们的确知道了密码。
当然,我们可以编写个perl脚本自动的进行,在我们实际去做这些事情之前,我们来看点别的。
数据库是可读写的
到目前为止,我们除了查询数据库之外没有做其他的事情,而即使一个select是只读的,但是不表示
sql也是,sql用分号(;)表示一个语句的结束。但是如果输入不能正确的过滤的话,那么没有什么能
防止我们在查询结尾加上不相关连的我们自己的命令。一个可怕的例子如下:
SELECT email, passwd, login_id, full_name
FROM members
WHERE email = 'x'; DROP TABLE members; --';
在第一部分我们给了一个空的电邮地址---'x'---我们不用管它的返回,我们来看看我们的不相关连的
命令起到什么作用,显然是要完全删除整个members表。这很可怕。
以上表明,我们不仅仅能运行单个sql命令,而且我们还能修改数据库。我能保证这点:)
加入一个新成员
防止我们在查询结尾加上不相关连的我们自己的命令。一个可怕的例子如下:
SELECT email, passwd, login_id, full_name
FROM members
WHERE email = 'x'; DROP TABLE members; --';
在第一部分我们给了一个空的电邮地址---'x'---我们不用管它的返回,我们来看看我们的不相关连的
命令起到什么作用,显然是要完全删除整个members表。这很可怕。
以上表明,我们不仅仅能运行单个sql命令,而且我们还能修改数据库。我能保证这点:)
加入一个新成员
我们已经知道members表的部分结构,这好象存在一种可能的方式加入一个新记录到表中,如果起作用。
我们将能很简单的用新加入的数据登陆。
不用惊讶,加入几行sql命令就可以了,但是没成功之前,我们加入的命令还是存在偶然性的。
SELECT email, passwd, login_id, full_name
FROM members
WHERE email = 'x';
INSERT INTO members ('email','passwd','login_id','full_name')
VALUES ('steve@unixwiz','hello','steve','Steve Friedl');--';
即使我们实际上知道表的名字和域名,但是有几件事情可能阻碍我们成功的进行攻击。
1:在网站上的登陆的地方,我们很可能没有足够的地方填写我们的命令
我们将能很简单的用新加入的数据登陆。
不用惊讶,加入几行sql命令就可以了,但是没成功之前,我们加入的命令还是存在偶然性的。
SELECT email, passwd, login_id, full_name
FROM members
WHERE email = 'x';
INSERT INTO members ('email','passwd','login_id','full_name')
VALUES ('steve@unixwiz','hello','steve','Steve Friedl');--';
即使我们实际上知道表的名字和域名,但是有几件事情可能阻碍我们成功的进行攻击。
1:在网站上的登陆的地方,我们很可能没有足够的地方填写我们的命令
(尽管可以通过脚本程序来实现,但是这不是很方便)
2:网站管理员可能设置了不允许用insert命令向members表加入数据。
3:毫无疑问members表内还有其他域,可能需要初始数据值,那么会导致insert失效。
4:即使我们设法插入新记录,对我们没提供数据值的域系统可能不会自动插入null(空值)。
5:一个合法的“member”除了是members表的一个记录以外,可能和其他的表也有关系,那么
单独加入一个表不会有什么效能。
这些情况,主要是4或者5我们不能十分确定--因为,我们去主登陆页面输入上面的用户名+密码
,会返回一个服务器错误。这表明我们加入的数据没有成功。没有处理正确。
一个可能的方法是去猜测其他的域,但是这是一个长而乏味的过程,我们将要猜测各种各样的域名
2:网站管理员可能设置了不允许用insert命令向members表加入数据。
3:毫无疑问members表内还有其他域,可能需要初始数据值,那么会导致insert失效。
4:即使我们设法插入新记录,对我们没提供数据值的域系统可能不会自动插入null(空值)。
5:一个合法的“member”除了是members表的一个记录以外,可能和其他的表也有关系,那么
单独加入一个表不会有什么效能。
这些情况,主要是4或者5我们不能十分确定--因为,我们去主登陆页面输入上面的用户名+密码
,会返回一个服务器错误。这表明我们加入的数据没有成功。没有处理正确。
一个可能的方法是去猜测其他的域,但是这是一个长而乏味的过程,我们将要猜测各种各样的域名
很难想象系统是怎么组织这些结构的。
所以,我们试着去看看另一个不同的方法。
电邮给我个密码
我们意识到即使我们不能往members表里面加入新的记录,但是我们能修改一个存在的记录。
这样我们将能够进入。
从上面步骤,我们知道bob@example是系统上的一个帐户。我们用sql注入把它更新成我们
的电邮地址。
SELECT email, passwd, login_id, full_name
FROM members
所以,我们试着去看看另一个不同的方法。
电邮给我个密码
我们意识到即使我们不能往members表里面加入新的记录,但是我们能修改一个存在的记录。
这样我们将能够进入。
从上面步骤,我们知道bob@example是系统上的一个帐户。我们用sql注入把它更新成我们
的电邮地址。
SELECT email, passwd, login_id, full_name
FROM members
WHERE email = 'x';
UPDATE members
SET email = 'steve@unixwiz'
WHERE email = 'bob@example';
运行了之后,我们看到“无法识别你的电邮地址”,这是预料中的,由于我们输入的是个空电邮地址(那个
email='x';) ,而更新的电邮地址我们没有注册,这个命令只是悄悄地执行而已。
我们去“我丢失了密码”的连接上更新我们的邮件地址,不久后我们将收到一个电邮:
From: system@example
To: steve@unixwiz
Subject: Intranet login
此邮件发送给你的登陆信息。
UPDATE members
SET email = 'steve@unixwiz'
WHERE email = 'bob@example';
运行了之后,我们看到“无法识别你的电邮地址”,这是预料中的,由于我们输入的是个空电邮地址(那个
email='x';) ,而更新的电邮地址我们没有注册,这个命令只是悄悄地执行而已。
我们去“我丢失了密码”的连接上更新我们的邮件地址,不久后我们将收到一个电邮:
From: system@example
To: steve@unixwiz
Subject: Intranet login
此邮件发送给你的登陆信息。
Your User ID is: bob
Your password is: hello
现在要做的事情就是去登陆了。这个方法比我们用insert来创建一个可能受限制的用户要优越许多。
我们发现企业网站很全面,往往包含所有用户的列表。所以我们有理由相信其他用windows网络的企业
也可能这样。可能他们中的某一些在两个不同的地方用同一个密码。这将让我们很容易得到任何企业网的
密码。要是我们放一个open pptp vpn port (什么东西?不懂)到防火墙上,那么可以直接用这种方式进入。
我们还做了几个帐户的测试但是没有成功。我们不知道是否是“密码不对”或者是“企业网的帐
户名不同于windows的帐户名”。但是我们认为用自动工具来做的话将是容易的事情。
原文以下内容为作者介绍附加知识和深入知识,攻击实例到次为止。
/* 由于网络问题,编辑附加之后不能更新,bbs好象不稳定。所以发在后面。
到此虽然全文还没有翻译完,不过攻击示例部分已经翻译完成,希望对大家
有些须帮助。
我基本上是按直译来翻译的,不敢过多的改原作者的文法结构。他是一句话
我也尽量一句话。所以看起来有点古怪。此外我对sql和入侵手法不是很懂,
也许有的地方没有精确的翻译清楚,所以我更决定保持直译以免变样。
如有不足欢迎大家批评指正。*/
原文以下内容为作者介绍附加知识和深入知识,攻击实例到次为止。
/* 由于网络问题,编辑附加之后不能更新,bbs好象不稳定。所以发在后面。
到此虽然全文还没有翻译完,不过攻击示例部分已经翻译完成,希望对大家
有些须帮助。
我基本上是按直译来翻译的,不敢过多的改原作者的文法结构。他是一句话
我也尽量一句话。所以看起来有点古怪。此外我对sql和入侵手法不是很懂,
也许有的地方没有精确的翻译清楚,所以我更决定保持直译以免变样。
如有不足欢迎大家批评指正。*/
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论