翻译自:https://medium.com/0xcc/what-the-heck-is-tcp-port-18800-a16899f0f48f
翻译:聂心明
如果安装Amazon音乐客户端的话,你会怀疑开在18800端口的程序到底是什么:
➜ ~ sudo tcpview
Password:
Proto Local address Remote address Status PID Program name
tcp 0.0.0.0:18800 - LISTEN 35050 Amazon Music Helper
windows?也是一样的
在2014年,有人抱怨这个东西
https://chriscarey.com/blog/2014/10/08/how-to-stop-amazon-music-helper-from-running-in-the-background-osx/
所以它究竟做了什么?
通过快速的检查,我们知道这个端口属于
/Applications/Amazon Music.app/Contents/MacOS/Amazon Music Helper
在accept
处下断点,然后nc 127.1 18800
看看发生了什么:
Process 35050 stopped
* thread #6, stop reason = breakpoint 1.1
frame #0: 0x0000000104855af0 Amazon Music Helper` boost::asio::detail::socket_ops::accept(int, sockaddr*, unsigned long*, boost::system::error_code&)
Amazon Music Helper`boost::asio::detail::socket_ops::accept:
-> 0x104855af0 <+0>: push rbp
(lldb) bt
* thread #6, stop reason = breakpoint 1.1
* frame #0: 0x0000000104855af0 Amazon Music Helper` boost::asio::detail::socket_ops::accept(int, sockaddr*, unsigned long*, boost::system::error_code&)
...
frame #5: 0x0000000104813fe5 Amazon Music Helper` boost::asio::detail::task_io_service::run(boost::system::error_code&) + 165
frame #6: 0x000000010480daea Amazon Music Helper` Morpho::HttpDispatcher::startListening(int) + 1418
frame #7: 0x0000000104897a4c Amazon Music Helper` boost::(anonymous namespace)::thread_proxy(void*) + 156
这个是http服务器?但是我curl失败了
➜ ~ curl localhost:18800/test
curl: (52) Empty reply from server
当服务器需要ssl的时候就会发生这样的事情并且你只要以文本模式发送请求就好。所以,让我们试试不同的payload:
➜ ~ curl https://localhost:18800/test -k
denied
现在它奏效了
幸亏symbols没有在编译的时候被去掉,快速分析后发现,Windows客户端和mac客户端有大量相似的代码,但是msvc已经把所有的symbols全部被移到了pdb里面,以至于代码非常难读。
所以Morpho是代码名
- Morpho::CrossDomainHandler (^/crossdomain[.]xml$)
- Morpho::LaunchHandler (^/morpho)
- Morpho::SystemHandler (^/.+)
每一个处理接口都有一个叫requireOrigin
去检查传递进来的请求:
请求的检查在sym.Morpho::HttpDispatcher::getOriginMatchString_HttpRequest
实现
截图中有太多的代码吗?不要担心,下面是一个简单的伪代码:
regex = RegExp("http(s)?.*[.]amazon[.](com|co[.]uk|de|fr|it|es|co[.]jp|ca|in|com[.]au)(:[0-9]{1,4})?");
if (regex.match(request.headers["origin"]) && regex.match(request.headers["origin"]))
return true;
if (regex.match(request.headers["x-amzn-origin"]))
return true;
return false;
因为它接受自定义的头部x-amzn-origin
,第三方网站很容易伪造这样的请求,除此之外,这个RESTful被暴露在所有的网络接口上,所以如果你是Shodan或者ZoomEye的粉丝,你会得到一些意想不到的惊喜?
我们去看看这些处理程序。
Morpho::SystemHandler
它可以直接接收pathname,先不要关心参数。它会返回系统信息:
➜ ~ curl -H "x-amzn-origin: https://a.amazon.com" -k https://127.1:18800/morpho
{ "version":"7.0.3.1540", "device":"AMZN{pretty_long_uuid_here}", "osType":"osx", "osVersion":"10.14.2" }
Morpho::LaunchHandler
这个的危害性就很大了,如果路径名匹配到了下图中的正则sym._anonymousnamespace_::kLaunchRegEx
,那么它们就会被初始化为:^/((purchase|download|play|cplaunch).*)$
所以,当Amazon Music启动时就会把pathname作为命令行参数
此外,如果http的verb是POST,参数就是斜线加http请求体。比如,下面这个请求:
➜ ~ curl -v -k -H "x-amzn-origin: https://a.amazon.com" -XPOST "https://127.0.0.1:18800/play" --data "boy"
结果就是:
Executable module set to "/Applications/Amazon Music.app/Contents/MacOS/Amazon Music".
Architecture set to: x86_64h-apple-macosx.
(lldb) po [[NSProcessInfo processInfo] arguments]
<__NSArrayI 0x7ff256dfc010>(
/Applications/Amazon Music.app/Contents/MacOS/Amazon Music,
play/boy
)
很幸运,请求的pathname通过了正则检查,然后他们用QProcess::startDetached(QString const&, QStringList const&)
代替了它的兄弟QProcess::startDetached(QString const&)
。为什么?
主程序的执行基于libCEF,它也支持Chromium命令参数。如果有机会我可以直接改变启动参数,就像下面这样:
➜ ~ /Applications/Amazon\ Music.app/Contents/MacOS/Amazon\ Music --no-sandbox --renderer-cmd-prefix="/Applications/Calculator.app/Contents/MacOS/Calculator"
如果是Windows,则可以执行:
"Amazon Music.exe" --no-sandbox --renderer-cmd-prefix="cmd /c calc"
亲爱的Amazon开发者,你已经非常接近可造成蠕虫攻击的远程命令执行漏洞了。幸运的是,这些并没有发生。
还有一件事就是,你不需要一个证书去运行https吗?让我们添加-v 来检查一下
* SSL connection using TLSv1.2 / AES256-GCM-SHA384
* ALPN, server did not agree to a protocol
* Server certificate:
* subject: CN=www.amazonmusiclocal.com
* start date: Nov 12 00:00:00 2018 GMT
* expire date: Oct 18 12:00:00 2019 GMT
* issuer: C=US; O=Amazon; OU=Server CA 1B; CN=Amazon
* SSL certificate verify ok.
所以Amazon Music让域名 www.amazonmusiclocal.com
解析到了本地回环地址上。因为签名是正确的,它们的私钥必然被分发到了客户端里面。它们在这里:
[0x100006e10]> afl~Morpho::HelperServer
0x100076f40 1 31 sym.Morpho::HelperServer::getCert
0x100076f60 1 31 sym.Morpho::HelperServer::getPrivKey
0x100077070 5 234 sym.Morpho::HelperServer::getAesKey
0x100077180 33 609 sym.Morpho::HelperServer::getAesIV
这个密钥和证书被硬编码在初始化器里面,你可以通过自己的努力把他们找出来:
pdf @sym.__GLOBAL__sub_I_helperServerData.cpp
就在几天前,我读到类似的文章,但是主角是Spotify:
实际上,我已经不需要dns劫持了,我们只要把一个播放按钮放入到网页中,然后让受害者去点击,受害者点击之后,就会发送一条请求到本地的控制服务器中。我们甚至不需要Spotify,因为网站之间的授权已经被搞定了,我就可以用互联网来做这样的事情了(有几个技术问题和复杂的告警需要解决)
Spotify会怎么说呢?这是产品本身的设计,它们没有安全问题。我试图进一步去解释,但是他们已经确认这是产品本身的设计,不是什么漏洞。为了公平起见,我把spotilocal.com的证书放在了网上。现在这个证书已经被移除了,所以我猜这本身不是产品设计所期望的事情。
https://medium.com/@Zemnmez/übersicht-remote-code-execution-spotify-takeover-a5f6fd6809d0
现在没法找到实际的利用。但是至少你会扫描局域网,然后去攻击音乐播放器,而且现在你也可以用被信任的证书去调试web。