Skip to content

Instantly share code, notes, and snippets.

@ImanHosseini
Last active September 13, 2021 00:04
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ImanHosseini/4b5120f1de7a9fa2ec7c5700e1f66c67 to your computer and use it in GitHub Desktop.
Save ImanHosseini/4b5120f1de7a9fa2ec7c5700e1f66c67 to your computer and use it in GitHub Desktop.

NCORE Writeup

Writeup to ncore challenge CSAW'21 quals. This was my 2nd time authoring a chal @ CSAW and I hope ppl enjoyed it. Security enclaves are the idea behind Intel SGX, which allow for having portions of "private" memory.
User sends byte data, we run sim, send out the results. It's a tiny cpu, hooked up to a ram and a safe-rom, with a key that is initialized per each run, they send us the ram contents and their program gets executed. The idea is that they must bruteforce the key in the ISA of this tiny cpu. As it is a made-up ISA, you have to do the plumbing yourself and assemble together your shellcode.
The main challenge is that the memory ops only support direct accessing, so imagine you have a for loop to read bytes, "R0 <- MEM(i)" looping over i, you cannot put i in a regsiter and increment because in a move instructions you have to specify the address explicitly, i.e. "R0 <- MEM(0)" where the 0 is encoded into the instructions. The solution to this challenge is that well, as it is in Von Neumann architecture, data and instructions live in harmony and well you can have self-modifying code: make a "R0 <- MEM(0)" instruction and then overwrite that 0 with 1, 2,.. as much as you want to loop. (this could've been sidestepped though, by just hardcoding MOVs and getting it with multiple connection)
My solve:
| ENT | JEQ R3,R0,8 | INC R0 | JMP 0 | MOVF R1, 0xBF | MOVFS R0, 0 | MOVT R0, 0xBF | INC R3 | INC R1 | MOVT R1, 9 | MOVT R3, 0xB | JMP 0xA |
I also made (an incomplete) disassembler:

bs_ = open("ram.hex","r").readlines()[0].split()[:-3]
bs = [int(x,16) for x in bs_]
opcodes = {0:"ADD",1:"SUB",2:"AND",3:"OR",4:"RES",5:"MOVF",6:"MOVT",7:"ENT",8:"EXT",9:"JGT",10:"JEQ",11:"JMP",12:"INC",13:"MOVFS"}

for i in range(20):
    b0 = bs[2*i]
    b1 = bs[2*i+1]
    b0s = "{0:08b}".format(b0)
    b1s = "{0:08b}".format(b1)
    opc = int(b0s[-4:],2)
    mnem = "UNK"
    ops = []
    if opc in opcodes:
        mnem = opcodes[opc]
    op1 = str(int(b0s[2:4],2))
    op2 = str(int(b0s[0:2],2))

    if mnem in ["ADD","SUB"]:
        ops.append(op1)
        ops.append(op2)
    if mnem in ["INC"]:
        ops.append(f"R{op1}")
    if mnem == "JMP":
        ops.append(f"{b1}")
    if mnem == "MOVF":
        ops.append(f"R{op1}")
        ops.append(str(int(b1s[::-1],2)))
    if mnem == "MOVT":
        ops.append(f"R{op1}")
        ops.append(f"{b1}")
    print(f"{(2*i):3} : {bs_[2*i]} {bs_[2*i+1]} | {b0s} {b1s} | {mnem} {' '.join(ops)}")

& the flag: flag{d0nT_mESs_wiTh_tHe_sChLAmi}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment