CVE-2023-46730 (published 2023-11-07T18:15Z)

Group-Office is an enterprise CRM and groupware tool. In affected versions there is full Server-Side Request Forgery (SSRF) vulnerability in the /api/upload.php endpoint. The /api/upload.php endpoint does not filter URLs which allows a malicious user to cause the server to make resource requests to untrusted domains. Note that protocols like file:// can also be used to access the server disk. The request result (on success) can then be retrieved using /api/download.php. This issue has been addressed in versions 6.8.15, 6.7.54, and 6.6.177. Users are advised to upgrade. There are no known workarounds for this vulnerability.

CVSS v3 base score: 8.8, HIGH (CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H)

Weakness information:
cwe_id: CWE-918
cwe_name: Server-Side Request Forgery (SSRF)
description: The web server receives a URL or similar request from an upstream component and retrieves the contents of this URL, but it does not sufficiently ensure that the request is being sent to the expected destination.
extended_description: By providing URLs to unexpected hosts or ports, attackers can make it appear that the server is sending the request, possibly bypassing access controls such as firewalls that prevent the attackers from accessing the URLs directly. The server can be used as a proxy to conduct port scanning of hosts in internal networks, use other URLs such as that can access documents on the system (using file://), or use other protocols such as gopher:// or tftp://, which may provide greater control over the contents of requests.
         

Fix information:
repo_url: https://github.com/Intermesh/groupoffice
commit_details: repo_url: https://github.com/Intermesh/groupoffice
author: Merijn Schering
author_date: 2023-11-03 10:50:50+01:00
msg: Fix security issue GHSA-vw6c-h82w-mvfv
repository: repo_url: https://github.com/Intermesh/groupoffice
repo_name: Intermesh/groupoffice
description: Group Office groupware and CRM
repo_language: PHP
owner: Intermesh
file_changes: filename: upload.php
change_type: ModificationType.MODIFY
diff: @@ -22,56 +22,38 @@ try {
 		throw new \go\core\http\Exception(401);
 	}
 
-	if (isset($_GET['url'])) {
-		$tmpFile = \go\core\fs\File::tempFile('tmp');
+	//raise max_execution_time for calculating hash of large files
+	ini_set('max_execution_time', 300);
 
-		try {
-			$httpClient = new Client();
-			$response = $httpClient->download($_GET['url'], $tmpFile);
+	$filename = Request::get()->getHeader('X-File-Name');
+	$filename = Request::headerDecode($filename);
+	$tmpFile = \go\core\fs\File::tempFile($filename);
 
-			$blob = Blob::fromTmp($tmpFile);
-			$blob->name = $response['name'];
-			$blob->type = $response['type'];
-		} catch(\Exception $e) {
-			throw new \Exception("Failed to download from given URL " .  $_GET['url']);
-		}
+	$input = fopen('php://input', "r");
+	$fp = $tmpFile->open("w+");
+	while ($data = fread($input, 4096)) { // 4kb at the time
+		fwrite($fp, $data);
+	}
+	fclose($fp);
+	fclose($input);
+
+	if (\go\core\jmap\Capabilities::get()->maxSizeUpload && $tmpFile->getSize() > \go\core\jmap\Capabilities::get()->maxSizeUpload) {
+		$tmpFile->delete();
+		Response::get()->setStatus(413);
+		Response::get()->output([
+			"error" => "File exceeds maximum size of " . \go\core\jmap\Capabilities::get()->maxSizeUpload . " bytes"
+		]);
+		exit();
+	}
 
+	$blob = Blob::fromTmp($tmpFile);
+	$blob->name = $filename;
+	if (Request::get()->getHeader('X-File-LastModified') == null) {
+		$blob->modifiedAt = new \go\core\util\DateTime();
 	} else {
-
-		//raise max_execution_time for calculating hash of large files
-		ini_set('max_execution_time', 300);
-
-		$filename = Request::get()->getHeader('X-File-Name');
-		$filename = Request::headerDecode($filename);
-		$tmpFile = \go\core\fs\File::tempFile($filename);
-
-		$input = fopen('php://input', "r");
-		$fp = $tmpFile->open("w+");
-		while ($data = fread($input, 4096)) { // 4kb at the time
-			fwrite($fp, $data);
-		}
-		fclose($fp);
-		fclose($input);
-
-		if (\go\core\jmap\Capabilities::get()->maxSizeUpload && $tmpFile->getSize() > \go\core\jmap\Capabilities::get()->maxSizeUpload) {
-			$tmpFile->delete();
-			Response::get()->setStatus(413);
-			Response::get()->output([
-				"error" => "File exceeds maximum size of " . \go\core\jmap\Capabilities::get()->maxSizeUpload . " bytes"
-			]);
-			exit();
-		}
-
-		$blob = Blob::fromTmp($tmpFile);
-		$blob->name = $filename;
-		if (Request::get()->getHeader('X-File-LastModified') == null) {
-			$blob->modifiedAt = new \go\core\util\DateTime();
-		} else {
-			$blob->modifiedAt = new \go\core\util\DateTime('@' . Request::get()->getHeader('X-File-LastModified'));
-		}
+		$blob->modifiedAt = new \go\core\util\DateTime('@' . Request::get()->getHeader('X-File-LastModified'));
 	}
 
-
 	if ($blob->save()) {
 		Response::get()->setStatus(201, 'Created');
 		$response = $blob->toArray();

programming_language: PHP
filename: Settings.php
change_type: ModificationType.MODIFY
diff: @@ -306,8 +306,15 @@ class Settings extends core\Settings {
 	 * The full URL to Group-Office. With trailing /.
 	 * 
 	 * eg. https://my.groupoffice.net/
-	 * 
-	 * @var string 
+	 *
+	 * Alternatively to generate a URL based on the request you can use:
+	 *
+	 * @example
+	 * ```
+	 * Extjs3::get()->getBaseUrl();
+	 * ```
+	 *
+	 * @var string
 	 */
 	public $URL;
 

programming_language: PHP
filename: ImageField.js
change_type: ModificationType.MODIFY
diff: @@ -79,31 +79,6 @@ go.form.ImageField = Ext.extend(Ext.BoxComponent, {
 					});
 				},
 				scope: this
-			}, {
-				iconCls: 'ic-link',
-				text: t("From URL"),
-				handler: function () {
-					Ext.MessageBox.prompt(t("Set Image From URL"), t("Enter URL"), function(btn, url) {
-
-						
-						if(btn != "ok" || !url) {
-							return;
-						}
-
-
-						Ext.Ajax.request({
-							url: go.User.uploadUrl + "?url=" + encodeURIComponent(url),
-							method: "GET",
-							success: function(response) {
-								data = Ext.decode(response.responseText);
-								this.setValue(data.blobId);								
-							},
-							scope: this
-						});
-
-					}, this);
-				},
-				scope: this
 			},
 			{
 				iconCls: 'ic-delete',

programming_language: JavaScript
filename: Extjs3.php
change_type: ModificationType.MODIFY
diff: @@ -179,6 +179,8 @@ class Extjs3 {
 	/**
 	 * Get URL to webclient
 	 *
+	 * eg. https://groupoffice.example.com/groupoffice/
+	 *
 	 * @return string
 	 */
 	public function getBaseUrl() {

programming_language: PHP