使用Burp测试ASP.NET无Cookie会话
作者:Carrie Roberts & Brian King
注意: 本博客中提到的技术和工具可能已过时,不适用于当前情况。然而,这篇博客仍可作为学习机会,并可能更新或集成到现代工具和技术中。
我们最近测试了一个使用ASP.NET无Cookie会话的Web应用程序。这意味着会话令牌是URL的一部分,如下例所示:
http://www.blackhillsinfosec.com/(S(hd73kdjf780sndyfn23elomzqd5ghwa))/login.html
在这种情况下,会话令牌的形式为(S(LongRandomToken))
,其中LongRandomToken
是一个长的随机生成的字母数字字符串,取代了会话Cookie。
这种实现在使用Burp Suite测试时会导致站点地图混乱,因为变化的令牌使应用程序看起来有无限的内容路径。例如,一个只有一个登录页面的站点地图会因为变化的令牌值而显示为多个不同的路径,如下所示。
混乱的站点地图由于多个令牌
在测试过程中,我们希望有一个“干净”的站点地图,基本上忽略所有令牌值,并将它们映射为好像不存在。此外,我们希望Burp Suite的爬虫和扫描工具继续工作。所以我们想出了以下技巧,继续阅读…
解决方案
使用两个Burp实例。
- 浏览器使用Burp1作为代理。
- Burp1使用Burp2作为代理。
- 在Burp1中创建一个匹配/替换规则,将有问题的令牌从请求URL中提取出来,并将其作为URL参数附加到URL的末尾。
- 在Burp2中创建一个匹配/替换规则,从末尾抓取参数并将其放回。
- 当你想看到漂亮的站点地图时,使用Burp1。
- 当你想看到未经篡改的请求时,使用Burp2。
Burp1监听默认端口8080,我们配置Burp2监听端口8090。
Burp2监听端口8090
然后我们配置Burp1使用Burp2作为上游代理。
现在我们有Web应用程序连接到Burp1,Burp1连接到Burp2,Burp2连接到我们正在测试的ASP.NET服务器。
代理配置
以下是所需的匹配和替换规则。
Burp1匹配/替换规则:
- 匹配:
(.*)/(S\(.*?\)\))/([^ ]*)(.*)
- 替换:
$1/$3\?zzzz=$2$4
这将令牌从URL路径中拉出,并将其作为zzzz参数附加到URL的末尾。不用担心是否已经有URL参数,你只是添加了另一个问号,我们将在发送到Web服务器之前在Burp2代理中撤销这一点。
Burp2匹配/替换规则:
- 匹配:
(\w* /)(.*)\?zzzz=([^ ]*)(.*)
- 替换:
$1$3/$2$4
这有效并创建了一个干净的站点地图,但是…
这只影响通过Burp代理的内容。如果你使用爬虫、扫描器或其他工具,这些规则不适用。对于这第二个问题,我们将使用Burp的宏和会话工具。如果参数有名称,宏就是我们所需要的。但由于它显示为没有名称的裸值,我们将再次需要那个上游的Burp实例。
转到选项 > 会话,并向下滚动到宏部分添加一个。你可以从代理历史中拉取请求,或者现在发送这些请求并捕获它们。你需要一组必要的请求来创建一个新会话——登录步骤。
对于每个需要的URL,配置项目,以便Burp发送正确的输入(例如用户名和密码)并注意响应中的正确内容。通常,你希望它更新Cookie jar,这就足够了。但在这里,没有会话Cookie,我们想要的东西甚至没有名称。
我们配置了第一个项目,以便它发送一个没有令牌的请求,这导致服务器返回HTTP 302到一个有令牌的URL。我们配置Burp从HTTP 302响应中提取令牌。由于实际的令牌没有名称,我们编造了一个新名称,该名称在任何地方都没有使用过。
接下来,我们手动将该参数添加到第二个请求的查询字符串中——只是在GET字符串的末尾输入了“&aaaa=asdf”。然后,我们需要配置该第二个URL,以便它将我们的“asdf”替换为在第一个请求的响应中找到的任何内容。
点击“测试宏”按钮,确保Burp正在提取正确的值并将其放在正确的位置。在第二个项目中查找“派生参数”。在我们的测试中,无法避免它被URL编码。这在这里没问题,因为我们无论如何都要在上游代理中更改它。如果我们只捕获内部括号之间的部分,那会更干净。
在上游代理中,配置一个匹配和替换规则,将该URL重写为应用程序期望的形式。
该规则将类似这样的内容:
GET /(S(3gmt4o45krcb0bfbzvh2ud55))/Pages/default.aspx?locId=1&aaaa=%28S%28awtsga551hn1bb550xmy2n2i%29%29 HTTP/1.1
转换为类似这样的内容:
/(S(awtsga551hn1bb550xmy2n2i))/Pages/default.aspx?locId=1 HTTP/1.1
不过,这有一个问题——它是短暂的。在这个应用程序中没有任何实际称为“aaaa”的参数,更不用说在我们需要它的地方了。如果这是一个正常的、命名的参数,我们就不需要编造一个临时参数名称,也不需要上游代理来重写URL。
这在使用时还会导致一些额外的流量,并且可能会稍微污染站点地图。但对于一次针对一个功能的有针对性扫描,它肯定比必须重新探索站点并在一个不间断的会话上运行扫描要好。