一个成功的SQL注入攻击可能导致未经授权访问敏感的数据,比如密码、信用卡详细信息或个人用户信息。近年来,许多引人注目的数据泄露都是SQL注入攻击的结果,导致声誉受损和监管罚款。
在某些情况下,攻击者可以获得进入组织系统的持久后门,从而导致长期的危害,这种危害可能会在很长一段时间内被忽视。
目前存在着各种各样的SQL注入漏洞、攻击和技术,它们出现在不同的情况下。一些常见的SQL注入示例包括:
检索隐藏数据,您可以在其中修改SQL查询以返回其他结果。
颠覆应用程序逻辑,您可以更改查询以干扰应用程序逻辑。
联合攻击,您可以从不同的数据库表中检索数据。
检查数据库,从中可以提取有关数据库版本和结构的信息。
盲SQL注入,其中您控制的查询结果不会在应用程序的响应中返回。
考虑一个显示不同类别产品的购物应用程序。当用户单击礼品类别时,其浏览器会请求URL:
https://insecure-website.com/products?category=Gifts
这会导致应用程序进行SQL查询,以从数据库中检索相关产品的详细信息,查询的原本语句为:
SELECT * FROM products WHERE category = 'Gifts' AND released = 1
此SQL查询要求数据库返回:
规定限制released=1时用于隐藏未发布的产品,并且规定已发布的产品的release=0。
应用程序没有针对SQL注入攻击实施任何防御措施,因此攻击者可以构建如下攻击:
https://insecure-website.com/products?category=Gifts'--
那么SQL请求的语句为:
SELECT * FROM products WHERE category = 'Gifts'--' AND released = 1
这里的关键是双破折号--
是SQL中的注释指示符,这意味着查询的其余部分被解释为注释。
这将有效地删除查询的其余部分,因此它不再包含 AND released=1。这意味着将显示所有产品,包括未发布的产品。
进一步说,攻击者可以使应用程序显示任何类别中的所有产品,包括他们不知道的类别:
https://insecure-website.com/products?category=Gifts'+OR+1=1--
那么SQL请求的语句为:
SELECT * FROM products WHERE category = 'Gifts' OR 1=1--' AND released = 1
修改后的查询将返回类别为礼品或1等于1的所有项目。由于1=1始终为真,因此查询将返回所有项目。
所以,要想查询所有商品,尝试:'+OR+1=1--
或者' or 1=1 --+++
例如:
如果存在一个允许用户登录用户名和密码的应用程序。如果用户提交用户名wiener和密码bluecheese,应用程序将通过执行以下SQL查询来检查凭据:
SELECT * FROM users WHERE username = 'wiener' AND password = 'bluecheese'
如果查询返回用户的详细信息,则登录成功。否则,它将被拒绝。
在这里,攻击者只需使用SQL注释序列(从查询的WHERE子句中删除密码检查),就可以在没有密码的情况下以任何用户的身份登录。例如,提交用户名administrator'--
和空白密码将导致以下查询:
SELECT * FROM users WHERE username = 'administrator'--' AND password = ''
此查询返回用户名为administrator的用户,并将攻击者作为该用户成功登录。
例如:对于POST方法,没有办法回显在URL上,所以我们可以用Burp进行修改
它这样颠覆了应用的逻辑,本来是说要输入账号密码才能进入,这样一来,只需要输入账号而不用输入密码。
如果SQL查询的结果在应用程序的响应中返回,攻击者可以利用SQL注入漏洞从数据库中的其他表检索数据。这是使用UNION关键字完成的,它允许您执行额外的SELECT查询并将结果附加到原始查询。
例如,如果应用程序执行包含用户输入“Gifts”的以下查询:
SELECT name, description FROM products WHERE category = 'Gifts'
然后,攻击者可以提交输入:
' UNION SELECT username, password FROM users--
这将导致应用程序返回所有用户名和密码以及产品的名称和说明。
Union Attacks是一个内容比较多的攻击方法,下次专门拿一个篇幅来讲Union Attacks。
在初步识别SQL注入漏洞之后,通常可以获得有关数据库本身的一些信息。这些信息通常可以为进一步开发铺平道路。
您可以查询数据库的版本详细信息。完成此操作的方式取决于数据库类型,因此您可以根据任何一种技术推断数据库类型。例如,在Oracle上,您可以执行:
SELECT * FROM v$version
您还可以确定存在哪些数据库表,以及它们包含哪些列。例如,在大多数数据库上,可以执行以下查询以列出表:
SELECT * FROM information_schema.tables
SQL注入的许多实例都是盲目漏洞。这意味着应用程序不会返回SQL查询的结果或其响应中任何数据库错误的详细信息。仍然可以利用盲漏洞访问未经授权的数据,但所涉及的技术通常更复杂,也更难执行。
根据漏洞的性质和涉及的数据库,可以使用以下技术来利用盲SQL注入漏洞:
根据单个条件的真实性,您可以更改查询逻辑以触发应用程序响应中的可检测差异。这可能涉及将一个新条件注入到一些布尔逻辑中,或者有条件地触发一个错误,例如被零除。
您可以有条件地触发查询处理中的时间延迟,从而允许您根据应用程序响应所需的时间推断条件的真实性。
您可以使用OAST技术触发带外网络交互。这项技术非常强大,在其他技术不起作用的情况下也能起作用。通常,您可以通过带外通道直接过滤数据,例如,将数据放入您控制的域的DNS查找中。
使用Burp Suite的web漏洞扫描程序可以快速可靠地发现大多数SQL注入漏洞。
通过对应用程序中的每个入口点使用一组系统的测试,可以手动检测SQL注入。这通常涉及:
提交单引号字符并查找错误或其他异常。
提交一些特定于SQL的语法,这些语法的计算结果为入口点的基(原始)值和不同的值,并在生成的应用程序响应中查找系统差异。
提交布尔条件,如OR 1=1和OR 1=2,并查找应用程序响应中的差异。
提交设计用于在SQL查询中执行时触发时间延迟的有效负载,并查找响应时间的差异。
提交设计用于在SQL查询中执行时触发带外网络交互的OAST有效负载,并监控任何产生的交互。
大多数SQL注入漏洞出现在SELECT查询的WHERE子句中。
但是SQL注入漏洞原则上可以发生在查询中的任何位置,也可以发生在不同的查询类型中。SQL注入出现的最常见的其他位置有:
在UPDATE语句中,在更新的值或WHERE子句中。
在INSERT语句中,在插入的值内。
在SELECT语句中,在表或列名中。
在SELECT语句中的ORDER BY子句中。
当应用程序从HTTP请求获取用户输入,并在处理该请求的过程中以不安全的方式将输入合并到SQL查询中时,会出现一阶SQL注入。
在二阶SQL注入(也称为存储SQL注入)中,应用程序从HTTP请求获取用户输入,并将其存储以备将来使用。这通常是通过将输入放入数据库来实现的,但在存储数据的位置不会出现漏洞。稍后,当处理不同的HTTP请求时,应用程序检索存储的数据并以不安全的方式将其合并到SQL查询中。
二阶SQL注入通常出现在开发人员意识到SQL注入漏洞的情况下,因此可以安全地处理输入到数据库中的初始位置。当数据随后被处理时,它被认为是安全的,因为它以前是安全地放入数据库的。此时,数据是以不安全的方式处理的,因为开发人员错误地认为数据是可信的。
SQL语言的一些核心功能在流行的数据库平台上以相同的方式实现,因此许多检测和利用SQL注入漏洞的方法在不同类型的数据库上工作相同。
然而,公共数据库之间也存在许多差异。这意味着检测和利用SQL注入的一些技术在不同平台上的工作方式不同。例如:
字符串连接的语法。
解释。
批处理(或堆叠)查询。
特定于平台的API。
错误消息。
大多数SQL注入实例都可以通过使用参数化查询(也称为准备语句)而不是查询中的字符串连接来防止。
以下代码易受SQL注入攻击,因为用户输入直接连接到查询中:
String query = "SELECT * FROM products WHERE category = '"+ input + "'";
Statement statement = connection.createStatement();
ResultSet resultSet = statement.executeQuery(query);
此代码可以以防止用户输入干扰查询结构的方式轻松重写:
PreparedStatement statement = connection.prepareStatement("SELECT * FROM products WHERE category = ?");
statement.setString(1, input); //将input代表的值赋值给第一个问号代表的参数
ResultSet resultSet = statement.executeQuery();
参数化查询可用于不受信任的输入在查询中显示为数据的任何情况,包括INSERT或UPDATE语句中的where子句和值。它们不能用于处理查询的其他部分中不受信任的输入,例如表或列名,或ORDERBY子句。将不受信任的数据放入查询的这些部分的应用程序功能需要采用不同的方法,例如白名单允许的输入值,或者使用不同的逻辑来交付所需的行为。
为了使参数化查询能够有效防止SQL注入,查询中使用的字符串必须始终是硬编码常量,并且不得包含来自任何来源的任何变量数据。不要试图逐个决定数据项是否受信任,继续在查询中使用字符串连接以查找被认为安全的情况。在数据的可能来源方面很容易出错,或者其他代码中的更改会违反关于哪些数据受到污染的假设。
手机扫一扫
移动阅读更方便
你可能感兴趣的文章