【51CTO.com 独家译稿】一般说来,Web服务在人们心目中一直是那种难以精确定义、解释及运用的小众工具。这实际上是种误解,详情点击此处查看。我也很想通过一些技术及代码实例来消除此种误解。在本文当中,我们将专门讨论SOAP。当然类似JSON及REST也都是比较流行的重要标准,但在这里我们姑且将重点集中在SOAP身上。
简单对象访问协议或简称SOAP,是利用XML架构进行信息(且主要通过HTTP协议实现)交互的一套机制。Web服务协议则是一套相对轻量级的通信机制,在API连接驱动方面功效卓著,常见于移动设备应用程序当中。
要在阅读本指导文章的同时尝试当中涉及的各项操作,大家需要预先安装Jruby、Buby、Savon、Nokogiri gems以及通过下载或购买获得PortSwigger出品的Burp套件。整个讨论过程的基本思路是通过深入挖掘并在一定程度上拓展Burp的某些功能,使得攻击SOAP的流程更易于掌握。
如上所述,SOAP信息通信建立在XML架构的基础之上。这种XML架构可以被定义为WSDL或是"Web服务描述语言"类文件。这种信息描述方式为针对数据的攻击制定及请求形成提供了可资利用的宝贵空间。
SOAP的执行及其参数是颇具价值的信息单位,并且能够从WSDL中提取得出。类似获取电子邮件地址之类的操作可以经由类似"profileid=1000"这种参数及赋值实现。创建这一请求、更改profileid的赋值并将其发送至目标处即能够使我们得到其它用户的电子邮箱地址。
现在我们可以通过在XML标签内部查验响应及获取数据中大值的方式对WSDL进行手动列举,但怎样才能在不创建可重复代码的前提下快速且无缝地达成上述目标呢?
安装 JRuby
$ sudo apt-get install jruby
安装 Savon 及 Buby gems
$ sudo jruby -S gem install buby
$ sudo jruby -S gem install savon
现在我们需要编写一些代码。Savon gem是一款Ruby / JRuby函数库,允许我们创建一套SOAP客户端并使其与Web服务进行交互。首先建立一个名为attack_soap.rb的文件(单击此处获取代码),接着输入以下代码:
一行一行逐步讲解
第1至2行:
这一条是我们的脚本指令,基本上表达的意思是"使用这些函数库"。
第 5行:
接下来我们需要输入代码以获得连入Burp套件及运行工具及代码的权限。在这里,我们定义一套标准的CustomMenuItem。第33行演示了如何将其导入并发挥作用。
第 8至9行:
这里我们创建了一种名为enum_wsdl的函数。该函数在第27行被调用并导入一个URL(rhost对象)。在第9行中大家会看到我们引入了Savon客户端实例并将其赋值与rhost相关联。
第 11至 12行:
这两行的内容都是可选值。第10行为一套用户名及密码都为"guest"的账号提供了授权。第11行则将此信息发送到我们的Burp代理实例中。
第 13至 18行:
第13行确保了之前建立的client.wsdl以及client.wsdl.soap_actions被正确调用。第14行为我们提供了非常美观的紫色*标识以及内容为"可用操作列表:"的状态栏。第15至17行用来重申soap_actions中的数组,并将每项操作"放入"控制台;而在第17行中,我们为整个循环语句画上句号。
第 19至21行:
我们还得为执行出现错误的情况做出补救措施,一旦出问题,第19行的指令能帮我们妥善解决。在第20行的描述中,我们会在遇到错误时向屏幕输出一个红色的 - 标记以示警告。第21行则用于结束整套enum_wsdl函数。
第 23 至24行:
我们在第23行中定义了名为menu_item_clicked的函数。这一点至关重要,因为Burp会调用此函数并遵循特殊的命名规范。而在第33行中,我们设定了在单击菜单选项(指那些可用项)时,该函数正式执行调用操作。
这里谈到的一切,总结起来意味着CustomMenuItem这个类必须具备一组名为menu_item_clicked的函数。请注意这里我们向其传递的是*参数(复数),这意味着该函数能够同时接收到多个对象。
在第24行中我们将一对对象拆分为两个相互独立的个体,分别名为menu_item_caption以及message_info。
第 26 至 31行:
这一对象实际上是一个信息组。每条信息都具有与之关联的特定值。当我们循环访问该组时,通过第26行的指令,我们能够同时访问到这些数值。在第27行中我们借助获取itm对象(此对象确实是一条信息)并访问与之关联的url值的方式达到上述目的。我们调用enum_wsdl函数并向其传递刚刚获得的url值。最后,第28、29及30行用于关闭循环、函数及message_info类。
第33行:
最后还有同样重要的一点--我们需要创建菜单选项。我们采取调用Burp(即&burp指令)中的注册菜单选项函数的办法。我们将在"enumerate wsdl"中可见的菜单选项名称调出,如此一来该类就可以查找menu_item_clicked函数了。
整个工作流程总结如下:
" 在Burp中点击enumerate wsdl / 菜单选项。
" CustomMenuItem.menu_item_clicked 被调用并传递至两个对象处。
" 在 menu_item_clicked当中, enum_wsdl 函数被调用。
" 我们解析WSDL以获取可行操作列表并将其输出至控制台。#p#
脚本运行实例:
$ jruby -S buby -i -B ~/Desktop/burp/burp.jar -r ~/Desktop/attack_soap.rb
下一步是对WSDL提出请求,并利用Burp拦截该请求。举例来说:
拦截发往http://192.168.1.149/WebGoat/services/WSDLScanning?WSDL的请求
点击 "enumerate wsdl"选项进入如下界面:
现在我们已经得到了一份标明所有可用操作的详细列表!
但这还不是终点。我们需要把它当成跳板、继续高歌猛进。将一些编写好的代码提交进去,以提取出可用的参数及赋值。这样我们就可以利用这些值来创建请求。
现在一定要注意,下列代码无法解析全部WSDL内容、也不能"自动"创建正确的请求。事实上它应该被作为一种小规模示例,向大家演示正确代码的效果并提供SOAP请求的可视化直观表现。
现在,我们需要重新审视自己刚刚编写出来的代码,并适当加以补充。下列截图是代码库的前半部分。
第 3行:
我们将利用到Nokogiri函数库。因此,我们得先进行安装。大家务必确保在运行脚本之前执行了下列指令:
$ sudo jruby -S gem install nokogiri
第 24至27行:
在第24行,我们创建了parse_wsdl函数。该函数中包括wsdl XML。第25行中的实例及空白hash被命名为wsdl_element_hash。第26行创建了一个doc对象,由wsdl负责解析并且易于寻获。最后,第27行以<wsdl:message>及</wsdl:message>为标签搜索符合的XML内容。
第 28至29行:
我们对test_m1及test_m2进行了实例化,这样它们就能在循环之外仍被调用(接下来的几行代码非常重要)。这种处理方式的最终目的是通过一项SOAP操作返回作为密钥的hash及参数的实际赋值。
正如大家看到的,在下图中,某项操作请求中有一条参数名为"id"。我们要执行能够获取实名、登录账号等等信息的操作,就先要利用这类操作所调用的参数发出SOAP请求。
从理论层面来说,我们创建的hash应该如下所示:
{
'getFirstName => 'id',
'getLoginCount => 'id',
'getCreditCard' => 'id',
'getLastName' => 'id'
}
第 30至34行:
XML/WSDL文档中那些包含<wsdl:message>标签的部分之前已经被解析(由第27行指令实现)为数组类结构。该对象随即被赋予msg的标签。在第30行中,我们开始循环访问msg数组。第31及32行则是将SOAP操作"请求"(自我们创建该请求时起)与参数/类型进行匹配组合。第33及34行负责剔出相匹配的数据(也就是那些与31及32行中的内容相符的数据),当然没有相符内容的情况除外。在这种情况下,test_m1及test_m2将被设置为"nil"(即'空')。
第 36至38行:
提供完整性检查,如果test_m1与test_m2回馈的内容非"空",就意味着我们已经成功地将XML内容与想要获取的信息表达式相匹配,此时将SOAP操作及其参数导入wsdl_element_hash即可。
第 39至 41行:
如下图所示,我们结束循环语句,返回wsdl_hasl_element的hash对象并关闭parse_wsdl函数。
第 43至46行:
由form_request所调用的函数将实例化,而rhost的赋值(也就是一条完整的URL)将作为输入信息被接收。第44至46行意在根据客户端的具体设置情况正确调整我们自己创建的SOAP客户端。
第 47至48行:
第47行创建一个名为wsdl的对象,这是一条以纯XML形式构成的WSDL。第48行将该XML对象传递至parse_wsdl函数。
第 49至53行:
在第49行中,我们对每一条由WSDL中获取的可用soap操作进行循环访问。第50行则是创建一套条件性设置。如果我们的hash,由parse_wsdl函数所创建,中具备soap_action(itm)操作,则需要生成一条请求。在第51至56行中,我们生成该请求。第52及53行用于提供必要的输入信息。因此getCreditCard指令变为:get_gredit_card这种新形式,id也变为:id。这一点非常重要,因为这是Savon gem 请求所强制要求的形式。
第 54至56行:
我们在此创建了一条动态请求。每样操作都随着各项参数被传递至客户端请求当中。
第 57至61行:
关闭上述循环以及form_request参数。
第 67至70行:
我们建立了一条根据菜单选项点击情况触发的条件语句。如果"enumerate wsdl"被选中,我们就会转向enum_wsdl函数。而如果是"form SOAP request"被选中,触发的则是form_request函数。
第 78行:
在此我们添加另一条自定义菜单选项,名为"form SOAP request",而一旦该选项被选中,不仅会触发WSDL解析,还将自动创建一条SOAP语法并将其发送至我们的拦截代理端以备进一步攻击时使用。#p#
那么当我们一切就绪后,效果究竟如何呢?
这里我们点击form SOAP request选项
此处共计创建了四条SOAP请求(因为我们共有四种可用操作)。
根据对"getCreditCardRequest" wsdl:message的深入分析,可以看到我们已经成功获取到一些可怜虫的信用卡号码。
那么以此为基础,我们能够对创建的SOAP请求进行积极扫描,并通过进一步处理及中继器的帮助加以调整。以往那看似无懈可击的壁垒如今瞬间崩溃殆尽,有了SOAP请求自动解析工具,破解信用卡号码已如探囊取物。大成功!
原文链接:http://resources.infosecinstitute.com/soap-attack-1/
【51CTO.com独家译稿,非经授权谢绝转载!合作媒体转载请注明原文出处及出处!】