<!--X-Body-Begin-->
<!--X-User-Header-->
<a href="/fulldisclosure/"><img src="/images/fulldisclosure-logo.png" class="l-logo right" alt="fulldisclosure logo" width="80"></a>
<h2 class="m-list"><a href="/fulldisclosure/">Full Disclosure</a>
mailing list archives</h2>
<!--X-User-Header-End-->
<!--X-TopPNI-->
<div class="nav-bar">
<div class="nav-link">
<a href="0"><img src="/images/left-icon-16x16.png" alt="Previous" width="16" height="16"></a>
<a href="date.html#1">By Date</a>
<a href="2"><img src="/images/right-icon-16x16.png" alt="Next" width="16" height="16"></a>
</div>
<div class="nav-link">
<a href="0"><img src="/images/left-icon-16x16.png" alt="Previous" width="16" height="16"></a>
<a href="index.html#1">By Thread</a>
<a href="2"><img src="/images/right-icon-16x16.png" alt="Next" width="16" height="16"></a>
</div>
<form class="nst-search center" action="/search/fulldisclosure">
<input class="nst-search-q" name="q" type="search" placeholder="List Archive Search">
<button class="nst-search-button" title="Search">
<img style="width:100%;aspect-ratio:1/1;" alt="" aria-hidden="true" src="/shared/images/nst-icons.svg#search">
</button>
</form>
</div>
<!--X-TopPNI-End-->
<!--X-MsgBody-->
<!--X-Subject-Header-Begin-->
<h1 class="m-title">SCHUTZWERK-SA-2023-003: Authentication Bypass in Visual Planning REST API</h1>
<hr>
<!--X-Subject-Header-End-->
<!--X-Head-of-Message-->
<em>From</em>: Lennert Preuth via Fulldisclosure <fulldisclosure () seclists org>
<em>Date</em>: Wed, 3 Apr 2024 17:10:14 +0200
<!--X-Head-of-Message-End-->
<!--X-Head-Body-Sep-Begin-->
<hr>
<!--X-Head-Body-Sep-End-->
<!--X-Body-of-Message-->
<pre style="margin: 0em;">-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA512
Title
=====
SCHUTZWERK-SA-2023-003: Authentication Bypass in Visual Planning REST API
Status
======
PUBLISHED
Version
=======
1.0
CVE reference
=============
CVE-2023-49231
Link
====
<a rel="nofollow" href="https://www.schutzwerk.com/advisories/schutzwerk-sa-2023-003/">https://www.schutzwerk.com/advisories/schutzwerk-sa-2023-003/</a>
Text-only version:
<a rel="nofollow" href="https://www.schutzwerk.com/advisories/SCHUTZWERK-SA-2023-003.txt">https://www.schutzwerk.com/advisories/SCHUTZWERK-SA-2023-003.txt</a>
Affected products/vendor
========================
All versions prior to Visual Planning 8 (Build 240207) by STILOG I.S.T.
Summary
=======
</pre><tt>A wildcard injection inside a prepared SQL statement was found in an
</tt><tt>undocumented Visual Planning[0] 8 REST API route. The combination of
</tt><tt>fuzzy matching (via LIKE operator) and user-controlled input allows
</tt><tt>exfiltrating the REST API key based on distinguishable server responses.
</tt><tt>If exploited, attackers are able to gain administrative access to the
</tt><tt>REST API v2.0.
</tt><pre style="margin: 0em;">
Risk
====
</pre><tt>The vulnerability allows attackers to obtain a valid API key for the
</tt><tt>Visual Planning REST API v2.0. With such a key, attackers can use
</tt><tt>corresponding endpoints to exfiltrate company data or upload/download
</tt><tt>files. If no external user management (e.g. LDAP) is configured, the API
</tt><tt>key can also be used for user management tasks including the creation of
</tt><tt>administrative users. Since administrators are allowed to upload modules
</tt><tt>using the Visual Planning Admin Center, a compromise of the underlying
</tt><tt>server is likely.
</tt><pre style="margin: 0em;">
Description
===========
</pre><tt>During a recent red teaming assessment, Visual Planning was identified
</tt><tt>as part of the customers internet-facing assets. The software is
</tt><tt>developed by STILOG I.S.T. and provides resource management and
</tt><tt>scheduling features. A security assessment conducted by SCHUTZWERK found
</tt><tt>an authentication bypass in Visual Planning's administrative REST API
</tt><tt>v2.0.[1]
</tt><pre style="margin: 0em;">
</pre><tt>Corresponding API routes are implemented in the PlanningWSRestV2.java
</tt><tt>file. A comparison between the documentation and implemented routes
</tt><tt>revealed an undocumented route (documentation accessed on 2024-03-05),
</tt><tt>which is externally reachable via a GET request to the /session endpoint.
</tt><pre style="margin: 0em;">
</pre><tt>The following code snippet shows the corresponding undocumented route,
</tt><tt>which takes the value of the apikey header as an argument:
</tt><pre style="margin: 0em;">
vp.jar.src/com/visualplanning/webservice/PlanningWSRestV2.java
/* */ @GET
/* */ @Path("/session")
</pre><tt>/* */ public Response openSession(@HeaderParam("apikey") String
</tt><tt>apikey, @HeaderParam("keepalive") String keepalive) {
</tt><pre style="margin: 0em;">/* 123 */ if (apikey == null || apikey.trim().isEmpty()) {
</pre><tt>/* 124 */ return
</tt><tt>WSResponse.instance().errorApikey((Response.StatusType)Response.Status.FORBIDDEN,
</tt><tt>apikey);
</tt><pre style="margin: 0em;">/* */ }
/* */
/* 127 */ WSSession session = WSSession.existsSession(apikey);
/* 128 */ if (session != null) {
</pre><tt>/* 129 */ return
</tt><tt>WSResponse.instance().error((Response.StatusType)Response.Status.FORBIDDEN,
</tt><tt>"Already opened session for apikey : ", apikey);
</tt><pre style="margin: 0em;">/* */ }
/* */
</pre><tt>/* 132 */ if (WSSession.getSession(apikey, (keepalive != null &&
</tt><tt>Boolean.parseBoolean(keepalive) == true)) == null) {
</tt><tt>/* 133 */ return
</tt><tt>WSResponse.instance().errorApikey((Response.StatusType)Response.Status.FORBIDDEN,
</tt><tt>apikey);
</tt><pre style="margin: 0em;">/* */ }
</pre><tt>/* 135 */ return WSResponse.instance().success("WSSession created
</tt><tt>for apikey : " + apikey);
</tt><pre style="margin: 0em;">/* */ }
</pre><tt>Line 132 shows a call to the getSession(apikey, ...) method of the
</tt><tt>WSSession class. Subsequently, the getSession(..) method will call the
</tt><tt>makeSession(apikey, ..) method of the same class.
</tt><pre style="margin: 0em;">
</pre><tt>The following code snippet shows the makeSession(..) method. Line 646
</tt><tt>contains the vulnerable prepared SQL statement, which is prone to
</tt><tt>wildcard injections[2] due to the usage of the LIKE operator in
</tt><tt>combination with user-controlled input:
</tt><pre style="margin: 0em;">
vp.jar.src/com/visualplanning/webservice/WSSession.java
</pre><tt>/* */ private static WSSession makeSession(String apiKey,
</tt><tt>WSSessionType type) {
</tt><pre style="margin: 0em;">/* 634 */ WSSession wsSession = new WSSession();
</pre><tt>/* 635 */ WebApplicationContext applicationContext =
</tt><tt>WebApplicationContext.getDefaultApplication();
</tt><tt>/* 636 */ UserSession userSession =
</tt><tt>applicationContext.createUserSession();
</tt><pre style="margin: 0em;">/* */
</pre><tt>/* 638 */ DBConnection connection =
</tt><tt>applicationContext.createUserSession().getDBConnection();
</tt><tt>/* 639 */ String databaseName =
</tt><tt>applicationContext.getProperty("Application", "Databasename",
</tt><tt>"VisualPlanning7");
</tt><pre style="margin: 0em;">/* */
/* 641 */ connection.setPoolMode(false);
/* 642 */ connection.setDatabase(databaseName);
/* */
/* */ try {
/* 645 */ if (type == WSSessionType.CLIENT) {
</pre><tt>/* 646 */ String planningQuery = "SELECT XMLContent FROM
</tt><tt>Planning WHERE XMLContent LIKE ?";
</tt><tt>/* 647 */ PreparedStatement stmt =
</tt><tt>connection.createPreparedStatement(planningQuery);
</tt><pre style="margin: 0em;">/* 648 */ stmt.setString(1, "%<APIKey>" + apiKey + "</APIKey>%");
/* 649 */ ResultSet rs = stmt.executeQuery();
/* */
/* 651 */ if (!rs.next()) {
/* 652 */ return null;
/* */ }
</pre><tt>The following GET request demonstrates the behavior of injecting a
</tt><tt>percent sign as wildcard character:
</tt><pre style="margin: 0em;">
GET /vplanning/api/v2/session HTTP/1.1
Host: vp-host
apikey: %
[..]
</pre><tt>The server will respond with a success message, indicating that a
</tt><tt>session was created for the used API key:
</tt><pre style="margin: 0em;">
HTTP/1.1 200
[..]
WSSession created for apikey : %
</pre><tt>Further tests showed that an apikey header payload of '1%' will result
</tt><tt>in a similar success response, if the api key starts with the character
</tt><tt>'1'. A payload with a different non-matching first apikey character like
</tt><tt>'2%' will result in a status code 403 and the error message 'Invalid API
</tt><tt>key (2%)'.
</tt><pre style="margin: 0em;">
</pre><tt>The proof-of-concept script brute_vp_apikey.py[3] was developed in order
</tt><tt>to automate the process of exfiltrating the full apikey. The script can
</tt><tt>be executed as follows against a vulnerable Visual Planning instance and
</tt><tt>to extract the administrative api key:
</tt><pre style="margin: 0em;">
$ python3 brute_vp_apikey.py --url <a rel="nofollow" href="http://127.0.0.1:8080">http://127.0.0.1:8080</a>
Visual Planning API Key: 79d4add3-6995-8cae-976b-4aaaddd90616
Solution/Mitigation
===================
The vendor suggests to update to Visual Planning 8 (Build 240207)
Disclosure timeline
===================
2023-11-01: Vulnerability discovered
2023-11-09: Contact vendor in order to determine security contact
2023-11-10: Received generic sales response from vendor
2023-11-14: Contacted CTO of vendor directly
2023-11-16: Vulnerabilities demonstrated in call with contact at vendor
2023-11-24: CVE assigned by Mitre
2023-11-24: Additional technical details provided to vendor
</pre><tt>2023-12-19: Vendor informed SCHUTZWERK that work on fixing the findings
</tt><tt>is in progress
</tt><tt>2024-01-30: Inquired about mitigation status regarding the reported
</tt><tt>vulnerabilities
</tt><tt>2024-01-30: Vendor informed SCHUTZWERK that some of the issues were
</tt><tt>already fixed
</tt><pre style="margin: 0em;">2024-03-08: Sent advisory drafts to vendor
2024-03-28: Received patch information and release of advisory
Contact/Credits
===============
The vulnerability was discovered by Lennert Preuth of SCHUTZWERK GmbH.
References
==========
[0] <a rel="nofollow" href="https://www.visual-planning.com/en/">https://www.visual-planning.com/en/</a>
</pre><tt>[1]
</tt><tt><a rel="nofollow" href="https://app.swaggerhub.com/apis-docs/VisualPlanning/visual-planning_api_rest_v_2_0_us/2.0-oas3">https://app.swaggerhub.com/apis-docs/VisualPlanning/visual-planning_api_rest_v_2_0_us/2.0-oas3</a>
</tt><tt>[2]
</tt><tt><a rel="nofollow" href="https://owasp.org/www-project-web-security-testing-guide/latest/4-Web_Application_Security_Testing/07-Input_Validation_Testing/05-Testing_for_SQL_Injection#sql-wildcard-injection">https://owasp.org/www-project-web-security-testing-guide/latest/4-Web_Application_Security_Testing/07-Input_Validation_Testing/05-Testing_for_SQL_Injection#sql-wildcard-injection</a>
</tt><pre style="margin: 0em;">[3] <a rel="nofollow" href="https://www.schutzwerk.com/en/43/assets/advisories/brute_vp_apikey.py">https://www.schutzwerk.com/en/43/assets/advisories/brute_vp_apikey.py</a>
Disclaimer
==========
</pre><tt>The information provided in this security advisory is provided "as is"
</tt><tt>and without warranty of any kind. Details of this security advisory may
</tt><tt>be updated in order to provide as accurate information as possible. The
</tt><tt>most recent version of this security advisory can be found at SCHUTZWERK
</tt><tt>GmbH's website ( <a rel="nofollow" href="https://www.schutzwerk.com">https://www.schutzwerk.com</a> ).
</tt><pre style="margin: 0em;">
Additional information
======================
SCHUTZWERK Advisories: <a rel="nofollow" href="https://www.schutzwerk.com/blog/tags/advisories/">https://www.schutzwerk.com/blog/tags/advisories/</a>
SCHUTZWERK Advisory Policy: <a rel="nofollow" href="https://www.schutzwerk.com/en/advisories/">https://www.schutzwerk.com/en/advisories/</a>
-----BEGIN PGP SIGNATURE-----
iQJOBAEBCgA4FiEEgLsg7Oj/wY3LSF87GrXfkTIXLrsFAmYF0QkaHGFkdmlzb3Jp
ZXNAc2NodXR6d2Vyay5jb20ACgkQGrXfkTIXLrvAZhAArh5MI5kM1lTjcIPPMiDS
VXJ51Z39qgcXySyrqrKslnP/2a/pfpakD8g161oOTSK/tt9Yd6L/6O5Vywe7Kx5V
lkVw7bs9J0WCY8aYzJ9RxdALt7HexAG+USgbjFWFajdSNNJ8giBu3P3ZCE8/GbHJ
0bKd8AN88NKL954olnI6qGbbnOr/QXWuIOWAYF9wXLgEk992hszYgt7SJIrFHuX6
2TC4iWOv4+72HQiQ8QYXCAZZVBDr3mUPQRBSJ9AZ3x7mxtJtMg8DyW0OATNe9Qlq
IUO7HFqrPwTQmFKf9whk8QD7/Y9dKTpAjlVzvXe49COqbjOzxmIe7muxwyVlOrqO
J9ZqreOr/ENLUgYDBaTLSTAHdEFNeqRGPK3dG0yiRSi3dtavJwr8PN1L52qTqLzT
C+Yrruu6Ac6pSin1Ea9WaXF+YS1ErRcbZxkRD5pS4s6V4NMkV4bDWlDtraQ0rDfL
AA+TxtA25p34S2MV/b3qAiA66UjrXEb6IJVNx4Rx7X3+gcLgI2w7t3DQEVuPaB3k
ltT1oV6ei7tqeQpn7usHzlfa6lq7Q3PIRpxYAo0g4kp4cVVblLRNWDpZMK+cBj1N
MrGP2f50gbpYej/yYHsXNU2pMfbUPoSq3X8uwVCoLvaBSBWx7I3TM1hl0/3wBi/w
phO+Bauh2QYGX2mFw/mduZM=
=ycwQ
-----END PGP SIGNATURE-----
--
SCHUTZWERK GmbH, Pfarrer-Weiß-Weg 12, 89077 Ulm, Germany
Zertifiziert / Certified ISO 27001, 9001 and TISAX
Phone +49 731 977 191 0
advisories () schutzwerk com / www.schutzwerk.com
Geschäftsführer / Managing Directors:
Jakob Pietzka, Michael Schäfer
Amtsgericht Ulm / HRB 727391
Datenschutz / Data Protection www.schutzwerk.com/datenschutz
</pre><p><strong>Attachment:
<a href="att-1/OpenPGP_signature_asc.bin"><tt>OpenPGP_signature.asc</tt></a></strong>
<em>Description:</em> OpenPGP digital signature</p>
<pre style="margin: 0em;">_______________________________________________
Sent through the Full Disclosure mailing list
<a rel="nofollow" href="https://nmap.org/mailman/listinfo/fulldisclosure">https://nmap.org/mailman/listinfo/fulldisclosure</a>
Web Archives & RSS: <a rel="nofollow" href="https://seclists.org/fulldisclosure/">https://seclists.org/fulldisclosure/</a></pre>
<!--X-Body-of-Message-End-->
<!--X-MsgBody-End-->
<!--X-Follow-Ups-->
<hr>
<!--X-Follow-Ups-End-->
<!--X-References-->
<!--X-References-End-->
<!--X-BotPNI-->
<div class="nav-bar">
<div class="nav-link">
<a href="0"><img src="/images/left-icon-16x16.png" alt="Previous" width="16" height="16"></a>
<a href="date.html#1">By Date</a>
<a href="2"><img src="/images/right-icon-16x16.png" alt="Next" width="16" height="16"></a>
</div>
<div class="nav-link">
<a href="0"><img src="/images/left-icon-16x16.png" alt="Previous" width="16" height="16"></a>
<a href="index.html#1">By Thread</a>
<a href="2"><img src="/images/right-icon-16x16.png" alt="Next" width="16" height="16"></a>
</div>
</div>
<h3 class="m-thread">Current thread:</h3>
<ul class="thread">
<li><strong>SCHUTZWERK-SA-2023-003: Authentication Bypass in Visual Planning REST API</strong> <em>Lennert Preuth via Fulldisclosure (Apr 05)</em>
</li></ul>
<!--X-BotPNI-End-->
<!--X-User-Footer-->
<!--X-User-Footer-End-->
<p>