Headline
CVE-2023-32322: Merge pull request from GHSA-28j3-84m7-gpjp · Ombi-app/Ombi@b8a8f02
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.
Expand Up
@@ -44,25 +44,33 @@ public IActionResult GetLogFiles()
}
[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();
}
}
}