Wednesday, September 23, 2015

CSAW CTF - RE200 - Hacking Time

For this challenge we got a NES ROM to reverse engineer.
HackingTime_03e852ace386388eb88c39a02f88c773.nes: iNES ROM dump, 2x16k PRG, 1x8k CHR, [Vert.]
I used FCEUX emulator to run the ROM file. The game asks for a password after few messages



The ROM memory could be viewed using Hex viewer, provided as part of FCEUX debug tools. I supplied a password ABCDABCDABCDABCDABCDABCD and found this is memory



Then set read memory access breakpoint for address 0x5 i.e. first byte of string. Now on continuing the game, the breakpoint is hit



The program counter is at 0x82F7, so we know what part of code to analyze. Then I found the Nintendo Entertainment System (NES) ROM loader module for IDA Pro, for analyzing the challenge ROM.
ROM:82F1 algorithm:                              ; CODE XREF: main_function+1C7
ROM:82F1                 LDY     #0
ROM:82F3                 LDA     #0
ROM:82F5                 STA     VAL
ROM:82F7
ROM:82F7 process_loop:                           ; CODE XREF: algorithm+44
ROM:82F7                 LDA     5,Y             ; LDA INPUTKEY,A
ROM:82FA                 TAX                     ; X = A
ROM:82FB                 ROL     A               ; ROL A,1
ROM:82FC                 TXA                     ; A = X
ROM:82FD                 ROL     A               ; ROL A, 1
ROM:82FE                 TAX                     ; X = A
ROM:82FF                 ROL     A               ; ROL A, 1
ROM:8300                 TXA                     ; A = X
ROM:8301                 ROL     A               ; ROL A,1
ROM:8302                 TAX                     ; X = A
The PC 0x82F7, takes us to the actual validation algorithm used. The algorithm processes one byte at a time using multiple rotate operations and couple of XOR's with hardcoded arrays values. Good reference to instruction set is found here. The algorithm was rewritten in python and bruteforce gave the solution
import string

CHECKA = [0x70, 0x30, 0x53, 0xa1, 0xd3, 0x70, 0x3f, 0x64, 0xb3, 0x16,
          0xe4, 0x04, 0x5f, 0x3a, 0xee, 0x42, 0xb1, 0xa1, 0x37, 0x15,
          0x6e, 0x88, 0x2a, 0xab]
CHECKB = [0x20, 0xac, 0x7a, 0x25, 0xd7, 0x9c, 0xc2, 0x1d, 0x58, 0xd0,
          0x13, 0x25, 0x96, 0x6a, 0xdc, 0x7e, 0x2e, 0xb4, 0xb4, 0x10,
          0xcb, 0x1d, 0xc2, 0x66, 0x3b]

CF = 0
def ROR(REG): 
    global CF
    if CF: REG |= 0x100
    CF = REG & 1
    REG  >>= 1
    return REG
    
def ROL(REG):
    global CF
    REG <<= 1
    if CF: REG |= 1
    CF = 1 if (REG > 0xFF) else 0
    return REG & 0xFF

STACK = 0
ADDR_3B = 0
KEY = ''

for Y in range(24):
    for A in string.uppercase+string.digits:
        C = A
        VAL_3B = ADDR_3B
        A = ord(A)  # ROM:82F7                 LDA     $5,Y  
        X = A       # ROM:82FA                 TAX
        A = ROL(A)  # ROM:82FB                 ROL     A
        A = X       # ROM:82FC                 TXA
        A = ROL(A)  # ROM:82FD                 ROL     A
        X = A       # ROM:82FE                 TAX 
        A = ROL(A)  # ROM:82FF                 ROL     A
        A = X       # ROM:8300                 TXA   
        A = ROL(A)  # ROM:8301                 ROL     A 
        X = A       # ROM:8302                 TAX     
        A = ROL(A)  # ROM:8303                 ROL     A
        A = X       # ROM:8304                 TXA      
        A = ROL(A)  # ROM:8305                 ROL     A
        STACK = A   # ROM:8306                 PHA 
        A = VAL_3B  # ROM:8307                 LDA     ROLL 
        X = A       # ROM:8309                 TAX
        A = ROR(A)  # ROM:830A                 ROR     A 
        A = X       # ROM:830B                 TXA  
        A = ROR(A)  # ROM:830C                 ROR     A
        X = A       # ROM:830D                 TAX  
        A = ROR(A)  # ROM:830E                 ROR     A
        A = X       # ROM:830F                 TXA 
        A = ROR(A)  # ROM:8310                 ROR     A
        VAL_3B = A  # ROM:8311                 STA     ROLL
        A = STACK   # ROM:8313                 PLA
        CF = 0      # ROM:8314                 CLC 
        A = (A + VAL_3B) & 0xFF # ROM:8315     ADC     ROLL
        A = A ^ CHECKA[Y]   # ROM:8317     EOR     $955E,Y
        VAL_3B = A  # ROM:831A                 STA     ROLL
        X = A       # ROM:831C                 TAX 
        A = ROL(A)  # ROM:831D                 ROL     A
        A = X       # ROM:831E                 TXA
        A = ROL(A)  # ROM:831F                 ROL     A
        X = A       # ROM:8320                 TAX
        A = ROL(A)  # ROM:8321                 ROL     A
        A = X       # ROM:8322                 TXA
        A = ROL(A)  # ROM:8323                 ROL     A 
        X = A       # ROM:8324                 TAX
        A = ROL(A)  # ROM:8325                 ROL     A
        A = X       # ROM:8326                 TXA
        A = ROL(A)  # ROM:8327                 ROL     A
        X = A       # ROM:8328                 TAX    
        A = ROL(A)  # ROM:8329                 ROL     A 
        A = X       # ROM:832A                 TXA      
        A = ROL(A)  # ROM:832B                 ROL     A
        A = A ^ CHECKB[Y]   # ROM:832C         EOR     $9576,Y
        if A == 0:
            KEY += C
            ADDR_3B = VAL_3B
            break
        else: 
            VAL_3B = 0
print KEY
The flag is NOHACK4UXWRATHOFKFUHRERX

No comments :

Post a Comment