SQL注入

来源:互联网 发布:windows 查看文件编码 编辑:程序博客网 时间:2024/06/07 01:19

我想告诉你的是一个简单的技术,可以有效地用于现代Web应用程序,比如在NodeJSMongoDB上编写的应用程序实质上,这种技术与SQL注入(SQLI)非常相似,虽然简单得多,因为我们不必完成任何奇怪和复杂的字符串。

nodejs和mongodb

在我继续之前,我想说的是,虽然我在谈论NodeJS,但在下面的示例中,我使用ExpressJS,它是最受欢迎的节点Web框架,也是NodeJS社区中的事实标准。

SQL注入入门

学习SQL注入时学习的第一件事是如何创建真实的语句。让我们考虑下面的示例SQL语句,用于在将用户名和密码提交给应用程序时对用户进行身份验证:

SELECT * FROM users WHERE username = '$username' AND password = '$password'

如果这个语句没有准备好,或者在构建时没有正确处理,攻击者可能会' or 1=1--用户名字段中放置一个或多或少看起来像下图所示的语句,这被称为经由SQLI的经典登录绕过:

SELECT * FROM users WHERE username = '' or 1=1--' AND password = ''

即使在今天,这种经典的攻击及其变体也被广泛用于检测SQL语句处理不当的情况。

MONGODB注入入门

现在,即使SQL注入仍然是一个流行的攻击媒介,它已经不像以前那么普遍了。许多现代Web应用程序选择使用更简单的存储机制,如由MongoDB等NoSQL数据库提供的存储机制。NoSQL数据库不仅保证了简化的开发,而且通过完全消除了SQL语言,并通过JSON和JavaScript中常见的更为简单和结构化的查询机制进行中继,从而提高了安全性。

我们上面用来查询用户登录细节的SQL语句将在MongoDB中这样写:

db.users.find({username: username, password: password});

正如你所看到的,我们不再以字符串的形式处理查询语言,因此人们会认为注入不再可能。当然,就安全而言,情况总是如此,因为有很多因素在起作用。

例如,如果我们假设username字段或参数(如果您喜欢的话)来自反序列化的JSON对象,则上述查询的操纵不仅是可能的,而且是不可避免的。例如,如果提供JSON文档作为应用程序的输入,则攻击者将能够执行与之前仅使用SQL注入相同的登录绕过:

{    "username": {"$gt": ""},    "password": {"$gt": ""}}

请求的实际易受攻击的处理程序将看起来像这样:

app.post('/', function (req, res) {        db.users.find({username: req.body.username, password: req.body.password}, function (err, users) {            // TODO: handle the rest        });});

在上面的ExpressJS处理程序中, 未验证用户名密码字段以确保它们是字符串。因此,当JSON文档反序列化时,这些字段可能包含任何可以用来操纵查询结构的字符串。在MongoDB中,字段$ gt有一个特殊的含义,用作大于比较器。因此,来自数据库的用户名和密码将与空字符串进行比较,""并因此返回一个肯定的结果,即一个真实的陈述。

利用此漏洞的请求看起来或多或少像下面这样。使用此链接休息中打开请求

POST http://target/ HTTP/1.1Content-Type: application/json{    "username": {"$gt": ""},    "password": {"$gt": ""}}

深入研究NODEJS和MONGODB的开发

在上面的例子中,我故意选择使用JSON作为传输机制,因为这使得这个攻击更容易解释。虽然将JSON文档看作通信机制并不罕见,但它并不像url编码的键值对那样普遍,简称为urlencoding。有人会认为,如果你只是使用身份和查询参数在urlencoding格式比你将是安全的。

在ExpressJS中,除了简单的查询字符串外,我们仍然可以实现绕过效果,而不使用JSON。例如,我们可以提交一个请求,如下图所示。使用此链接休息中打开请求

POST http://target/ HTTP/1.1Content-Type: application/x-www-form-urlencodedusername[$gt]=&password[$gt]=

该字符串username[$gt]=qs模块使用的特殊语法(在ExpressJS和body-parser中间件中是默认的)。这个语法相当于使用一个名为$gtmapped to no value的参数来创建一个JavaScript对象/散列实质上,上面的请求将导致一个JavaScript对象,如下图所示:

{    "username": {"$gt": undefined},    "password": {"$gt": undefined}}

如果你比较这个对象和我们在前面例子中使用的对象,你可以看到它们在逻辑上是一样的。

我们再一次击败了身份验证机制作为可能是管理员的数据库中的第一个用户登录。根据这里的官方文档,这个技术可以进一步扩展到更多的MongoDB操作符

通过实例学习

我相信学习新事物的最好方法就是亲身体验。因此,我已经创建了两个在实践中说明这个漏洞的项目。第一个项目使用普通的urlencoded表单值,而第二个项目使用JSON(AngularJS)。

github no-login的截图

这两个项目都可以在我们找到的GitHub门户网站在这里这里你需要码头才能运行它们。我将自己省去详细了解码头工作的细节。只需阅读项目的自述文件以获取更多信息。

测试MONGODB注入

我希望你现在有一个好主意,我们可以针对NodeJS和MongoDB应用程序执行这种攻击。在实践中,在进行人工调查时,使用上述技术及其变化已经取得了巨大的成功。不过,我也是自动化的忠实粉丝,所以对于Websecurify Suite的粉丝,我已经亲自将这些测试合并到了FormfuzzJsonfuzz工具中。

为了简化,我实现了一个新的escapemode命令use_mongodb_payloads一旦你执行了这个命令,模糊器不仅会使用MongoDB特定的有效载荷,而且会对查询进行变异以达到最大的深度。

Formfuzz escapemode

一旦执行了escapemode命令,模糊器将产生类似于下图截图所示的请求。正如您可以清楚地看到的,我们使用Formfuzz模糊在几秒钟内绕过了登录屏幕

Formfuzz MongoDB在模糊行动

我希望这篇文章能帮助你理解如果你一起使用NodeJS和MongoDB,你可能遇到的问题。在后续的文章中,我将深入讨论影响两个平台的其他安全问题。如果您有任何具体问题,请不要犹豫与我联系。我们在这里帮忙。