CVE-2023-32322 (published 2023-05-18T17:15Z)

Ombi is an open source application which allows users to request specific media from popular self-hosted streaming servers. Versions prior to 4.38.2 contain an arbitrary file read vulnerability where an Ombi administrative user may access files available to the Ombi server process on the host operating system. Ombi administrators may not always be local system administrators and so this may violate the security expectations of the system. The arbitrary file read vulnerability was present in `ReadLogFile` and `Download` endpoints in `SystemControllers.cs` as the parameter `logFileName` is not sanitized before being combined with the `Logs` directory. When using `Path.Combine(arg1, arg2, arg3)`, an attacker may be able to escape to folders/files outside of `Path.Combine(arg1, arg2)` by using ".." in `arg3`. In addition, by specifying an absolute path for `arg3`, `Path.Combine` will completely ignore the first two arguments and just return just `arg3`. This vulnerability can lead to information disclosure. The Ombi `documentation` suggests running Ombi as a Service with Administrator privileges. An attacker targeting such an application may be able to read the files of any Windows user on the host machine and certain system files. This issue has been addressed in commit `b8a8f029` and in release version 4.38.2. Users are advised to upgrade. There are no known workarounds for this vulnerability. This issue is also tracked as GHSL-2023-088.\n

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

Weakness information:
cwe_id: CWE-22
cwe_name: Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')
description: The product uses external input to construct a pathname that is intended to identify a file or directory that is located underneath a restricted parent directory, but the product does not properly neutralize special elements within the pathname that can cause the pathname to resolve to a location that is outside of the restricted directory.
extended_description: 
            Many file operations are intended to take place within a restricted directory. By using special elements such as ".." and "/" separators, attackers can escape outside of the restricted location to access files or directories that are elsewhere on the system. One of the most common special elements is the "../" sequence, which in most modern operating systems is interpreted as the parent directory of the current location. This is referred to as relative path traversal. Path traversal also covers the use of absolute pathnames such as "/usr/local/bin" to access unexpected files. This is referred to as absolute path traversal.
         
         

Fix information:
repo_url: https://github.com/Ombi-app/Ombi
commit_details: repo_url: https://github.com/Ombi-app/Ombi
author: Jamie
author_date: 2023-05-17 08:46:19+01:00
msg: Merge pull request from GHSA-28j3-84m7-gpjp
repository: repo_url: https://github.com/Ombi-app/Ombi
repo_name: Ombi-app/Ombi
description: Want a Movie or TV Show on Plex/Emby/Jellyfin? Use Ombi!
repo_language: C#
owner: Ombi-app
file_changes: filename: SystemController.cs
change_type: ModificationType.MODIFY
diff: @@ -44,25 +44,33 @@ namespace Ombi.Controllers.V2
         }
 
         [HttpGet("logs/{logFileName}")]
-        public async Task<IActionResult> ReadLogFile(string logFileName, CancellationToken token)
+        public async Task<IActionResult> ReadLogFile(string logFileName)
         {
-            var logFile = Path.Combine(string.IsNullOrEmpty(Ombi.Helpers.StartupSingleton.Instance.StoragePath) ? _hosting.ContentRootPath : Helpers.StartupSingleton.Instance.StoragePath, "Logs", logFileName);
-            using (var fs = new FileStream(logFile, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
-            using (StreamReader reader = new StreamReader(fs))
+            var logsFolder = Path.Combine(string.IsNullOrEmpty(Ombi.Helpers.StartupSingleton.Instance.StoragePath) ? _hosting.ContentRootPath : Helpers.StartupSingleton.Instance.StoragePath, "Logs");
+            var files = Directory.EnumerateFiles(logsFolder);
+            var matchingFile = files.FirstOrDefault(x => Path.GetFileName(x).Equals(logFileName));
+            if (matchingFile != null)
             {
+                using var fs = new FileStream(matchingFile, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
+                using StreamReader reader = new(fs);
                 return Ok(await reader.ReadToEndAsync());
             }
+            return NotFound();
         }
 
         [HttpGet("logs/download/{logFileName}")]
-        public IActionResult Download(string logFileName, CancellationToken token)
+        public IActionResult Download(string logFileName)
         {
-            var logFile = Path.Combine(string.IsNullOrEmpty(Ombi.Helpers.StartupSingleton.Instance.StoragePath) ? _hosting.ContentRootPath : Helpers.StartupSingleton.Instance.StoragePath, "Logs", logFileName);
-            using (var fs = new FileStream(logFile, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
-            using (StreamReader reader = new StreamReader(fs))
+            var logsFolder = Path.Combine(string.IsNullOrEmpty(Ombi.Helpers.StartupSingleton.Instance.StoragePath) ? _hosting.ContentRootPath : Helpers.StartupSingleton.Instance.StoragePath, "Logs");
+            var files = Directory.EnumerateFiles(logsFolder);
+            var matchingFile = files.FirstOrDefault(x => Path.GetFileName(x).Equals(logFileName));
+            if (matchingFile != null)
             {
+                using var fs = new FileStream(matchingFile, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
+                using StreamReader reader = new(fs);
                 return File(reader.BaseStream, "application/octet-stream", logFileName);
             }
+            return NotFound();
         }
     }
 }
\ No newline at end of file

programming_language: C#