TLDR: It is frightening, a patch was made available the same day it was disclosed and everybody should update their servers. 



Butor Portal is affected by a Path Traversal vulnerability leading to pre-authentication arbitrary file downloads. Every file that can be read by the local user running the Butor Portal Web service could be exfiltrated by an anonymous attacker.

With the ability of reading most files on a server, an unauthenticated attacker could not only fully compromise the Butor application, but also the underlying infrastructure such as the database or the LDAP server using credentials stored in plain text in configuration files.

Exploitation of this vulnerability does not require advanced skill and can be automated.


What is Butor Portal and why does it matter?

Butor’s Web Portal, Single Sign On (SSO) and Access management apps are part of an open-source project called the Butor Platform. It is used by various financial institutions in systems hosting security critical processes and information.


Who is affected?

Systems using Butor Portal version 1.0.27 and earlier are affected.


Technical Analysis

In order to serve static files, the Butor Portal uses a Java Servlet. It takes two arguments from query parameters: a file name (h) and a theme name (t). The file name is sanitized while the theme name is not. Both parameters are then concatenated to a path used to determine which static file should be served. The file content is then echoed in the response.

As the theme name parameter is not sanitized, by tampering the request, it is possible to retrieve files outside the intended theme folder.

While a legitimate request should be as follows:

It can be tampered like this to fetch other files:

The following excerpt contains the code that is responsible for this vulnerability. Code sections outside the code path used for exploitation were stripped and important lines of code were highlighted for the sake of clarity.

  1 /**
  2  * Copyright 2013-2018
  3  *
  4  * Licensed under the Apache License, Version 2.0 (the "License");
  5  * you may not use this file except in compliance with the License.
  6  * You may obtain a copy of the License at
  7  *
  8  *
  9  *
 10  * Unless required by applicable law or agreed to in writing, software
 11  * distributed under the License is distributed on an "AS IS" BASIS,
 12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 13  * See the License for the specific language governing permissions and
 14  * limitations under the License.
 15  */
 16 package com.butor.portal.web.servlet;
 44 public class WhiteLabelingServlet extends HttpServlet {
 45     protected Logger logger = LoggerFactory.getLogger(getClass());
 46     private static final long serialVersionUID = -4573847543526921509L;
 47     private Map<Pattern, String> wlMap;
 48     private String resDir;
 49     private String themesByDomain;
 50     private String defaultTheme = "default";
 51     private String applyCommonByDomain;
 53     @Override
 54     public void init(ServletConfig config) {
 72     }
 74     @Override
 75     protected void service(HttpServletRequest request,
 76                            HttpServletResponse response) throws IOException, ServletException {
 77         String c = (String) request.getParameter("c"); // css file
 78         String j = (String) request.getParameter("j"); // js file
 79         String a = (String) request.getParameter("a"); // avatar image
 80         String i = (String) request.getParameter("i"); // image
 81         String h = (String) request.getParameter("h"); // html file
 82         String t = (String) request.getParameter("t"); // theme
 83         String s = request.getServerName();
 85"ServerName={}", s);
 87         if (isNullOrEmpty(t)) {
 88             for (Pattern p : wlMap.keySet()) {
 89                 Matcher matcher = p.matcher(s);
 90                 if (matcher.find()) {
 91                     t = wlMap.get(p);
 92                     break;
 93                 }
 94             }
 95         }
 96         if (t == null) {
 97             t = defaultTheme;
 98         }
100         File comFile = null;
101         File file = null;
102         if (j != null) {
107         } else if (c != null) {
112         } else if (h != null) {
113             t += "/" +extractFilename(h);
114             file = new File(resDir, "theme/" +t);
115             if (h.endsWith(".css")) {
116                 response.setContentType("text/css");
117             } else if (h.endsWith(".js")) {
118                 response.setContentType("text/javascript");
119             } else  if (h.endsWith(".html")) {
120                 response.setContentType("text/html");
121             }
122         } else if (a != null) {
130         } else if (i != null) {
139         } else {
140             //TODO
141         }
143         if (comFile != null && comFile.exists()) {
167         }
169         if (file != null && file.exists()) {
170             FileInputStream fis = new FileInputStream(file);
171             IOUtils.copy(fis, response.getOutputStream());
172             Closeables.close(fis, false);
173         }
174     }
175     private String extractFilename(String name) {
176         if (Strings.isNullOrEmpty(name)) {
177             return null;
178         }
179         // remove any path
180         name = new File(name).getName();
181         // remove any args
182         int pos = name.indexOf("?");
183         if (pos > -1) {
184             name = name.substring(0, pos);
185         }
186         return name;
187     }
188 }

Butor Portal’s WhiteLabelingServlet – Original Code : Source



The biggest difficulty in exploiting this vulnerability is the lack of directory listing. However, it is possible to determine whether a folder exists or not by trying to access it. If it exists, a 500 error will be returned, otherwise a 200 empty response will be returned.

While brute force could be viable, it is a lot more efficient to gather information to determine where the desired files are.

To that extent, various configuration files can be retrieved using relative path traversal, their path can be found here :

Here are a few examples:

Moreover, it is possible to gather a lot more information using the proc Linux virtual file system.


6 Exploitation Tricks for Path Traversals

Here are the essential tricks and steps:

  1. Access /proc/self/environ and /proc/self/cmdline : this will retrieve both the command line arguments and the environment variables that were passed to the java process. You will be able to find the user running the process and its home folder. Look for bash history and keys belonging to that user. Don’t underestimate the known_hosts file, that user might reuse the same password on the servers listed there.
  2. In those variables, it will also be possible to find the absolute path to the application and Catalina’s logs as well as various configuration folders, thus enabling the retrieval of more files. While log files might seem boring at first glance, if the verbosity is high enough, it might be possible to retrieve valuable information. That server will likely be used for SSO, a simple configuration file may contain the keys to the castle.
  3. Access /proc/sys/kernel/pid_max to determine the PID range of the target machine, brute force them through the /proc/{pid}/cmdline endpoint. Thankfully, the vast majority of systems use the 32768 default limit so it is absolutely doable. It will be possible to enumerate every process running on the machine. Most importantly, it will also reveal their command line parameters. It is surprising how many secrets are passed this way. Do not bother with the environ endpoint as it requires root privileges to be accessed.
  4. Multiple endpoints disclose networking information. My favourite one is /proc/self/net/arp, it will allow you to enumerate adjacent machines. While this vulnerability does not allow SSRF, a lot of Path Traversals do, and combined with the disclosed network information, it is possible to skip a good portion of the network discovery and scan hurdles to pivot to other systems.
  5. Access /proc/self/smaps to retrieve very detailed process memory information. While it will seem overwhelming at first, the important part is that libraries loaded in memory alongside their path and version will be exposed.
  6. This should be enough information to download the application itself. While the keys of a castle can be changed, its plans cannot. On complex systems, the software itself may be as valuable as the data it is using, and its exfiltration could enable thorough reverse engineering which could yield more vulnerabilities that could be used later.


Time Line

  • GoSecure Inc. disclosed the vulnerability to Butor Inc. on July 5, 2019
  • Butor Inc. acknowledged and issued a fix on July 5, 2019


Syntax coloration provided by IntelliJ and the Copy as HTML plugin.

Art fromブラックジャックによろしく12. ©佐藤 秀峰


Titan Managed Detection & Response
Next-Generation Antivirus
Endpoint Detection & Response
Network Detection & Response
Inbox Detection & Response
Insider Threat Detection & Response
Managed Firewall
Managed SIEM
Endpoint Security Lifecycle
GoSecure Titan
Titan Software
Email Security
Web Security
ResponderPRO Forensics Toolkit
Advisory Services
Cybersecurity Assessment
Security Compromise Assessment
Ethical Hacking
Incident Response & Forensics
Compliance & Audit
3rd Party Technology

Pin It on Pinterest

Share This