BinaryFileNdh.png

File: 11925.ndh

Once again it is a VM file. We quickly take a look at the hexdump to find the remote port used (4004).

% tail 11925.ndh|hexdump -C
00000000  00 16 b7 0e 00 02 02 04  00 00 02 03 04 03 03 03  |................|
00000010  02 03 01 1a 01 03 00 01  03 01 04 00 01 00 19 04  |................|
00000020  7c fe 04 00 03 00 04 00  02 01 04 01 01 01 04 01  ||...............|
00000030  00 04 30 03 01 03 00 1a  01 03 00 01 03 03 0e 00  |..0.............|
00000040  03 03 18 00 03 02 10 0d  00 1e 0a 00 04 06 00 01  |................|
00000050  0a 03 0a 00 16 ec 03 03  03 00 1a 04 00 01 00 04  |................|
00000060  01 00 05 30 1a 04 00 02  01 04 00 01 00 04 01 00  |...0............|
00000070  02 30 1a 04 00 03 02 04  00 02 01 04 00 01 00 04  |.0..............|
00000080  01 00 03 30 1a 01 03 03  04 00 03 02 04 00 02 01  |...0............|
00000090  04 00 01 00 04 01 00 11  30 03 03 1a 01 03 01 01  |........0.......|
000000a0  03 02 01 03 03 01 03 04  01 03 05 04 02 01 00 00  |................|
000000b0  19 04 b1 ff 18 02 00 ff  ff 11 0f 00 0e 00 00 00  |................|
000000c0  03 05 03 04 03 03 03 02  03 01 1a 04 00 03 00 04  |................|
000000d0  02 01 00 00 04 02 02 02  00 19 04 a8 ff 04 00 04  |................|
000000e0  00 0a 04 04 00 00 03 04  02 01 00 00 04 02 02 00  |................|
000000f0  00 19 04 90 ff 07 00 08  04 04 00 05 08 04 00 00  |................|
00000100  03 04 00 01 08 04 00 02  04 19 04 66 ff 06 00 04  |...........f....|
00000110  05 0b 04 04 07 04 00 04  00 00 05 19 04 f5 fe 04  |................|
00000120  01 00 01 0a 04 07 00 04  05 06 00 08 04 03 05 03  |................|
00000130  04 03 03 03 02 03 01 1a  04 02 00 10 83 19 04 d3  |................|
00000140  fe 07 01 08 32 04 00 05  08 04 02 00 00 00 04 00  |....2...........|
00000150  01 05 04 01 02 36 19 04  19 ff 04 02 00 11 11 04  |.....6..........|
00000160  00 01 05 04 02 02 32 00  19 04 5b fd 06 01 08 32  |......2...[....2|
00000170  1a 04 02 00 11 11 04 02  01 5e 83 04 02 02 00 01  |.........^......|
00000180  19 04 d7 fd 11 0d 00 0a  07 04 02 00 51 83 19 04  |............Q...|
00000190  0a ff 16 09 04 02 00 42  83 19 04 77 fe 1a 0e 00  |.......B...w....|
000001a0  07 07 19 04 92 ff 19 04  c7 ff 1c 50 61 73 73 77  |...........Passw|
000001b0  6f 72 64 20 28 72 65 71  75 69 72 65 64 29 3a 20  |ord (required): |
000001c0  00 73 63 69 74 65 65 6b  2e 6e 75 69 74 64 75 68  |.sciteek.nuitduh|
000001d0  61 63 6b 2e 63 6f 6d 3a  34 30 30 34 00 42 61 64  |ack.com:4004.Bad|
000001e0  20 70 61 73 73 77 6f 72  64 2e 0a 00 62 6b 46 53  | password...bkFS|
000001f0  6d 4a 6c 58 2e 74 78 74  00 5a 6f 6d 66 67 53 63  |mJlX.txt.ZomfgSc|
00000200  69 50 61 64 57 69 6c 6c  52 30 78 78 44 34 46 75  |iPadWillR0xxD4Fu|
00000210  63 6b 31 6e 77 30 52 4c  64 21 21 21 0a 00        |ck1nw0RLd!!!..|
0000021e

There are some weird strings at the end, we look closer...

% strings 11925.ndh             
.NDH
Password (required): 
sciteek.nuitduhack.com:4004
Bad password.
bkFSmJlX.txt
ZomfgSciPadWillR0xxD4Fuck1nw0RLd!!!

It looks like a flag! There is no way that can be true!

% nc sciteek.nuitduhack.com 4004
Password (required): ZomfgSciPadWillR0xxD4Fuck1nw0RLd!!!
You are now authenticated

Yeah well, it was actually that simple, we got the flag, and a nice facepalm because we also reversed it, which was useless here...

Flag: ZomfgSciPadWillR0xxD4Fuck1nw0RLd!!!

Btw, meanwhile, we developped a small disassembler in python. We cracked the rar file and accessed the VM source when we just finished. FU.
We used the instruction set unlocked with the .wav challenge ;)

#!/usr/bin/env python
# -*- coding: utf-8 -*-
 
import sys
from struct import pack, unpack
 
START  = 0x6
STOP   = 0xFFFF
BASE_ADDR = 0x8000
 
OPCODES = { 0x06 : 'ADD',   0x0d : 'AND',   0x19 : 'CALL',      0x18 : 'CMP',   0x0b : 'DEC',
            0x09 : 'DIV',   0x0a : 'INC',   0x1b : 'JMPL',      0x16 : 'JMPS',  0x11 : 'JNZ',
            0x10 : 'JZ',    0x1e : 'JA',    0x1f : 'JB',        0x04 : 'MOV',   0x08 : 'MUL',
            0x02 : 'NOP',   0x0f : 'NOT',   0x0c : 'OR',        0x03 : 'POP',   0x01 : 'PUSH',
            0x1a : 'RET',   0x07 : 'SUB',   0x30 : 'SYSCALL',   0x17 : 'TEST',  0x1d : 'XCHG',
            0x0e : 'XOR'
          }
 
NOFLAG  = ( 'DEC', 'INC', 'JMPL', 'JMPS', 'JNZ', 'JZ', 'JA', 'JB', 'NOP', 'NOT', 'POP', 'RET', 'SYSCALL', 'TEST', 'XCHG' )
 
SPECIAL = ( 'CALL', 'PUSH' )
 
FLAGS   = { 0x00 : 'REG_REG',               0x01 : 'REG_DIRECT8', 
            0x02 : 'REG_DIRECT16',          0x03 : 'REG',
            0x04 : 'DIRECT16',              0x05 : 'DIRECT8',
            0x06 : 'REGINDIRECT_REG',       0x07 : 'REGINDIRECT_DIRECT8',
            0x08 : 'REGINDIRECT_DIRECT16',  0x09 : 'REGINDIRECT_REGINDIRECT',
            0x0a : 'REG_REGINDIRECT'
          }
 
"""
REG_REG                                 => op entre 2 registres
REG_DIRECT8                             => op entre 1 reg et 1 octet
REG_DIRECT16                    => op entre 1 reg et 2 octets
REG                                             => op sur un reg
DIRECT16                                => 2 octets
DIRECT8                                 => 1 octet
REGINDIRECT_REG                 => op entre [reg] et reg
REGINDIRECT_DIRECT8             => op entre [reg] et 1 octet
REGINDIRECT_DIRECT16    => op entre [reg] et 2 octets
REGINDIRECT_REGINDIRECT => op entre [reg] et [reg]
REG_REGINDIRECT                 => op entre reg et [reg]
"""
 
# opcode = 1 byte
# flag = 1 byte
# reg = 1 byte
# DIR8 / DIR16 = 1/2 bytes
 
def get_reg( num ) :
    if num >= 0 and num <= 9 :
        if num == 9 :
            return 'BP'
        elif num == 8 :
            return 'SP'
        else:
            return 'R' + str(num)
    else :
        return '#FAIL' + str(num) # <- c'est moche
 
def reg_reg(reg1, reg2):
    print("%s, %s" % (get_reg(reg1), get_reg(reg2)))
 
def reg_direct8(reg, direct):
    print("%s, BYTE %xh" % (get_reg(reg), direct))
 
def reg_direct16(reg, direct):
    print("%s, SHORT %xh" % (get_reg(reg), direct))
 
def direct16(direct):
    print("SHORT %xh" % direct)
 
def direct8(direct):
    print("BYTE %xh" % direct)
 
def reg(reg):
    print(get_reg(reg))
 
def regindirect_reg(reg1, reg2):
    print("[%s], %s" % (get_reg(reg1), get_reg(reg2)))
 
def regindirect_direct8(reg, direct):
    print("[%s], BYTE %xh" % (get_reg(reg), direct))
 
def regindirect_direct16(reg, direct):
    print("[%s], SHORT %xh" % (get_reg(reg), direct))
 
def regindirect_regindirect(reg1, reg2):
    print("[%s], [%s]" % (get_reg(reg1), get_reg(reg2)))
 
def reg_regindirect(reg1, reg2):
    print("%s, [%s]" % (get_reg(reg1), get_reg(reg2)))
 
def extract(code):
    flag = ord(code[0])
    size = 3 # flag = 1 byte, lval = 1byte, rval = 1+ byte
 
    lval = ord(code[1])
    rval = ord(code[2])
 
    if "DIRECT16" in FLAGS[flag]: # rval = 2 bytes
        size += 1
        rval = int(unpack("<H", code[2:4])[0])
 
    globals()[FLAGS[flag].lower()](lval, rval)
 
    return size
 
# NOFLAGS
 
def disass_DEC(code):
    print get_reg( ord(code[0]) )
    return 1
 
def disass_INC(code):
    print get_reg( ord(code[0]) )
    return 1
 
def disass_JMPL(code):
    print hex( unpack('<h', code[0:2])[0] )
    return 2
 
def disass_JMPS(code):
    print hex(ord(code[0]))
    return 1
 
def disass_JNZ(code):
    print hex( unpack('<h', code[0:2])[0] )
    return 2
 
def disass_JZ(code):
    print hex( unpack('<h', code[0:2])[0] )
    return 2
 
def disass_JA(code):
    print hex( unpack('<h', code[0:2])[0] )
    return 2
 
def disass_JB(code):
    print hex( unpack('<h', code[0:2])[0] )
    return 2
 
def disass_NOP(code):
    print
    return 0
 
def disass_NOT(code):
    print get_reg( ord(code[0]) )
    return 1
 
def disass_POP(code):
    print get_reg( ord(code[0]) )
    return 1
 
def disass_RET(code):
    print
    return 0
 
def disass_SYSCALL(code):
    print "R0 (R1..R4)"
    return 0
 
def disass_TEST(code):
    print get_reg(ord(code[0])) + ', ' + get_reg(ord(code[1]))
    return 2
 
def disass_XCHG(code):
    print get_reg(ord(code[0])) + ', ' + get_reg(ord(code[1]))
    return 2
 
# SPECIALS
 
def disass_CALL(code):
    flag = ord(code[0])
    if FLAGS[flag] is 'REG' :
        print get_reg(ord(code[1]))
        return 2
    elif FLAGS[flag] is 'DIRECT16' :
        #print hex( unpack('<H', code[1:3])[0] )
        offset = unpack('<h',code[1:3])[0]
        print hex( cursor + 3 + 6 + offset ) #3 pour l'instruction, 6 pour le header
        return 3
    else:
        print "<Warning : invalid flag %x>" % flag
 
def disass_PUSH(code):
    flag = ord(code[0])
    if FLAGS[flag] is 'REG' :
        print get_reg(ord(code[1]))
        return 2
    elif FLAGS[flag] is 'DIRECT8' :
        print hex(ord(code[1]))
        return 2
    elif FLAGS[flag] is 'DIRECT16' :
        print hex( unpack('<H', code[1:3])[0] )
        return 3
    else:
        print "<Warning : invalid flag %x>" % flag
 
def die( txt ) :
        print txt
        sys.exit()
 
def get_opcodes_str(code):
    return " ".join("%02x" % ord(code[i]) for i in range(5))
 
def main( argc, argv ) :
 
    f = open( argv[1], 'rb' )
    data = f.read()
    f.close()
 
 
    if "-raw" in argv:
        code = data
    else:
    	if data[:4] != '.NDH' :
        	die( 'Bad ndh header' )
        code = data[START:STOP]
 
    #if data[:4] != '.NDH' :
    #    die( 'Bad ndh header' )
 
    #code = data[START:STOP]
    global cursor
    cursor = 0
 
    while cursor < len(code) :
        opcode = ord(code[cursor])
        cursor += 1
 
        if opcode not in OPCODES :
            print "Warning : skipping unknown opcode %02x" % opcode
            continue
 
        offset = "0x%04x | " % (START + cursor - 1)
        addr = '[' + hex(BASE_ADDR + cursor - 1) + '] '
        opcodes_dump = get_opcodes_str(code[cursor - 1:]) + "\t\t"
 
        sys.stdout.write(offset + addr + opcodes_dump + ' ' + OPCODES[opcode] + ' ')
 
        if OPCODES[opcode] in NOFLAG or OPCODES[opcode] in SPECIAL :
            cursor += globals()[ 'disass_' + OPCODES[opcode] ]( code[cursor:] )
        else :
            cursor += extract( code[cursor:] )
 
if __name__ == '__main__' :
        sys.exit( main( len( sys.argv ), sys.argv ) )