SCHUTZWERK-SA-2023-003: Authentication Bypass in Visual Planning REST API

Related Vulnerabilities: CVE-2023-49231  
                							

                <!--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 &lt;fulldisclosure () seclists org&gt;


<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 &amp;&amp; 
</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, "%&lt;APIKey&gt;" + apiKey + "&lt;/APIKey&gt;%");
/*  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 &amp; 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>