Socket.io-file NPM模块中的文件类型

2022-10-11 22:10:58 154 0
魁首哥

写在前面的话

在一次渗透测试过程中,我们所面对的应用程序安全系数比较高,没有存在太多的错误配置,因此简单分析并没有发现安全问题。但是深入分析后,我们发现了一个运行在嵌入式设备上的Web应用程序。这个Web应用程序使用了WebSocket来实现服务器和客户端之间的通信,为了使用WebSocket,后端系统可以选择的技术有很多种,而这里使用的是Socket.io。

这个应用程序的主要功能之一就是文件上传,这也是它选择使用Socket.io-file NPM模块的原因。总而言之,这里存在一个路径遍历漏洞,将允许我们上传文件到任意系统路径中,并让Web服务器运行该文件。

如果我们可以修改ssh_config、/etc/passwd或/etc/shadow文件的话,那么这个漏洞就相当于是一个远程代码执行漏洞了,但这只能通过root权限来实现,因此我们需要想办法利用低权限用户来实现远程代码执行。

通过研究之后,我们在Socket.io-file模块中找到了一个文件类型限制绕过漏洞。在该漏洞的帮助下,我们可以绕过模块配置文件中的文件类型限制。这样一来,我们就可以上传任意文件类型,然后通过修改底层配置文件来上传适当的Shell,以实现底层系统的远程代码执行。

除此之外,Socket.io-file的上传功能也存在对输入数据处理和验证逻辑不正确的问题,这些分布在代码的各个地方。而攻击者将能够利用该问题绕过上传文件类型的限制,将所选的文件类型上传到底层系统中。

漏洞描述

Socket.io-file的默认配置下,提供了一个由WebSocket处理的上传功能。当用户尝试通过Web应用程序上传一个文件时,将会创建下列客户端请求以实现文件创建:

 42["socket.io-file::createFile",{"id":"u_0","name":"testfile.mp3","size":1,"chunkSize":10240,"sent":0,"data":{}}]  

为了在底层系统创建该文件,Socket.io-file的index.js代码将会被执行,下列代码将会检测文件的类型并执行后续操作:

 let err = new Error('Not Acceptable file type ' + mimeType + ' of ' + filename + '. Type must be one of these: ' + this.accepts.join(', '));

return sendError(err);

}

else {

self.socket.emit(socket.io-file::complete::${id}, emitObj); self.emit('complete', emitObj);

}

}

else {

self.socket.emit(socket.io-file::complete::${id}, emitObj);

self.emit('complete', emitObj);  

比如说,如果用户上传了一个名为“testfile.mp3”的文件,那么应用程序将创建一个新的.mp3文件,由于钱买你的代码只会在客户端进行检测(WebSocket请求创建之前),那么我们就可以拦截上传请求,并以应用程序修改文件名的方式来修改创建文件的文件类型。下面给出的是漏洞利用样例:

 42["socket.io-file::createFile",{"id":"u_0","name":"testfile.php","size":1,"chunkSize":10240,"sent":0,"data":{}}]  

为了绕过客户端限制,我们还需要将原始文件的文件类型修改问Web应用程序允许的文件类型。拦截请求之后,我们需要将文件类型修改为原始类型(.php),这样服务器端就不会进行检测了。接下来,我们就可以在底层系统创建一个.php文件了,这样也就实现了文件类型检测绕过。

除此之外,我们还可以结合路径遍历漏洞来执行攻击,我们继续往下看。

结合多个漏洞实现RCE

既然我们可以向任意服务器目录上传任意文件,那么我们就可以在特定配置下,在底层系统实现远程代码执行了。

场景1:修改配置文件

首先,我们可以修改配置文件,向Web服务器中添加恶意JavaScript代码库,然后修改index.html来加载恶意js脚本,即添加一个