Pizazz - 190 (Reversing)

Writeup by r3ndom_

Created: 2015-12-8

Problem

Can you tell me the flag? the output of running this program was:

221.164.100.10.237.97.167.177.205.54.30.53.124.232.78.134.215.10.37.45.30.244.131.235.116.131.237.237.85.27.210.205.35.76.5.5.210.102.157.157.3.96.114.25.91.238.192.

Hint

None

Answer

Overview

Brute force the flag.

Details

Here is all my reversing work on the pizazz function.

tl;dr : They have a dictionary of 0xff bytes (grid) that they then grab variables from and move stuff around after that is then printed as a number. This creates the string.

loc_80484AE:                            ; CODE XREF: main+17j
                mov     eax, [eax+4]    ; get the argv list
                mov     eax, [eax+4]    ; get the first param ptr
                mov     [ebp+var_C], eax ; param is stored in var_c
                mov     [ebp+var_18], 0

loc_80484BE:                            ; DATA XREF: .data:tbl_1641o
                mov     eax, [ebp+var_18]
                lea     edx, [eax+1]
                mov     [ebp+var_18], edx ; var_18++
                mov     edx, [ebp+var_C]
                add     eax, edx        ; eax = input[iter]
                movzx   eax, byte ptr [eax]
                test    al, al          ; eax = eax[0]
                setz    al
                movzx   eax, al         ; eax = eax == 0 ? 1 : 0;
                mov     eax, tbl_1641[eax*4]
                nop                     ; jmp table whoooo

loc_80484DF:                            ; CODE XREF: main+1A5j main+1D7j
                jmp     eax
; ---------------------------------------------------------------------------

loc_80484E1:                            ; DATA XREF: .data:0804A184o
                sub     [ebp+var_18], 1 ; var_18 holds the number of characters
                mov     [ebp+var_14], 0 ; var_14 is the iter

loc_80484EC:                            ; DATA XREF: .data:tbl2_1644o
                mov     edx, [ebp+var_C] ; edx = string
                mov     eax, [ebp+var_14] ; eax = iter
                add     eax, edx        ; eax = input[iter]
                movzx   eax, byte ptr [eax]
                movsx   eax, al
                and     eax, 2          ; eax &= 2
                sar     eax, 1          ; eax >>= 1
                mov     ecx, eax        ; ecx = eax
                mov     edx, [ebp+var_C] ; edx = str
                mov     eax, [ebp+var_14] ; eax = iter
                add     eax, edx        ; eax = input[iter]
                movzx   eax, byte ptr [eax]
                movsx   eax, al
                and     eax, 8          ; eax &= 8
                sar     eax, 2          ; eax >>= 2
                or      ecx, eax        ; ecx |= eax
                mov     edx, [ebp+var_C]
                mov     eax, [ebp+var_14]
                add     eax, edx        ; eax = str[iter]
                movzx   eax, byte ptr [eax]
                movsx   eax, al
                and     eax, 20h        ; eax &= 0x20
                sar     eax, 3          ; eax >>= 3
                or      ecx, eax        ; ecx |= eax
                mov     edx, [ebp+var_C]
                mov     eax, [ebp+var_14]
                add     eax, edx
                movzx   eax, byte ptr [eax] ; eax = input[iter]
                movsx   eax, al
                and     eax, 80h        ; eax &= 0x80
                sar     eax, 4          ; eax >>= 4
                or      eax, ecx        ; eax |= ecx
                mov     [ebp+var_1B], al ; var_1b = eax
                mov     edx, [ebp+var_C]
                mov     eax, [ebp+var_14]
                add     eax, edx
                movzx   eax, byte ptr [eax]
                and     eax, 1          ; eax = 1 & (input[iter])
                mov     ecx, eax        ; ecx = eax
                mov     edx, [ebp+var_C]
                mov     eax, [ebp+var_14]
                add     eax, edx
                movzx   eax, byte ptr [eax]
                movsx   eax, al
                and     eax, 4          ; eax = (4 & input[iter]) >> 1
                sar     eax, 1
                or      ecx, eax        ; ecx |= eax
                mov     edx, [ebp+var_C]
                mov     eax, [ebp+var_14]
                add     eax, edx
                movzx   eax, byte ptr [eax]
                movsx   eax, al
                and     eax, 10h
                sar     eax, 2          ; eax = (0x10 & input[iter]) >> 2
                or      ecx, eax        ; |
                mov     edx, [ebp+var_C]
                mov     eax, [ebp+var_14]
                add     eax, edx
                movzx   eax, byte ptr [eax]
                movsx   eax, al
                and     eax, 40h
                sar     eax, 3          ; eax = (0x40 & input[iter]) >> 3
                or      eax, ecx        ; |
                mov     [ebp+var_19], al
                movzx   edx, [ebp+var_1B]
                movzx   eax, [ebp+var_19]
                shl     edx, 4
                add     eax, edx        ; grid[var_19 + (var_1b << 4)]
                add     eax, offset grid
                movzx   eax, byte ptr [eax]
                movzx   eax, al
                sub     esp, 8
                push    eax
                push    offset format   ; "%d."
                call    _printf
                add     esp, 10h
                movzx   eax, [ebp+var_1B] ; eax = var_1b
                shl     eax, 4          ; eax <<= 1="" 4="" 10="1" add="" eax,="" offset="" grid="" ;="" eax="grid+eax" movzx="" byte="" ptr="" [eax]="" mov="" [ebp+var_1A],="" al="" 1a="grid[var_1b" <<="" 4]="" [ebp+var_10],="" loc_80485DE:="" DATA="" XREF:="" .data:tbl3_1649o="" edx,="" [ebp+var_1B]="" edx="1b" [ebp+var_10]="" lea="" ecx,="" [eax-1]="" ecx="eax" -="" shl="" ebx,="" ebx="" grid[="" _10="" +="" (1b="" 4)="" ]="" (_10="" 1)="" [edx],="" set="" below="" to="" above="" ++_10="" cmp="" 0Fh="" setnle=""> 0xF) ? 1 : 0
                movzx   eax, al
                mov     eax, tbl3_1649[eax*4] ; loop if _10 < 0xF
                jmp     loc_80484DF
; ---------------------------------------------------------------------------

loc_8048625:                            ; DATA XREF: .data:0804A18Co
                movzx   eax, [ebp+var_1B]
                shl     eax, 4
                add     eax, 0Fh
                lea     edx, grid[eax]  ; edx = &grid[ (1b << 4) + 0xf]
                movzx   eax, [ebp+var_1A]
                mov     [edx], al       ; *edx = 1a
                add     [ebp+var_14], 1 ; _14 += 1
                mov     eax, [ebp+var_14]
                cmp     eax, [ebp+var_18]
                setnb   al              ; eax = _14 >= _18 ? 1 : 0
                movzx   eax, al
                mov     eax, tbl2_1644[eax*4]
                jmp     loc_80484DF
loc_8048657:                            ; DATA XREF: .data:0804A194o
                sub     esp, 0Ch
                push    0Ah             ; c
                call    _putchar
                add     esp, 10h
                mov     eax, 0

loc_8048669:
            ; Function end.

So based on that here's a quick brute forcer I wrote. This is possible because each character is only dependant on the characters before it and not after. As such we can just make something that progressively checks each character.

import os
import random
import time
correct = "221.164.100.10.237.97.167.177.205.54.30.53.124.232.78.134.215.10.37.45.30.244.131.235.116.131.237.237.85.27.210.205.35.76.5.5.210.102.157.157.3.96.114.25.91.238.192."
answer = ""
check='flag{a'
invalid_chars = [' ', '&', '\'', '(', ')', '*', '`', '\\', '^', '~', '|', '>', '<', ':', ';', '"', '\t', '\n']
def gen_char(prev):
    num = ord(prev)
    num += 1
    if(num > 127):
        num = 0
    #print num
    while(chr(num) in invalid_chars or num > 255 or num < 1):
        num+=1
        if(num > 127):
            num = 0
    return chr(num)

previous_ch = 'a'
while answer != correct:
    answer = os.popen('./pizazz '+check).read()
    answer = answer[:len(answer)-1]
    if("no " in answer or answer != correct[:len(answer)]):
        previous_ch = check[len(check) - 1:]
        check = check[:len(check) - 1]
        check += gen_char(previous_ch)
    else:
        print check
        check += gen_char(chr(random.randint(0,255)))

print check
print answer
print correct

Run that in the same directory as pizazz on a linux machine and you'll get the flag.

Flag

flag{Z-0rder_curv3s_and_janky_p3rmutati10ns_FTW}

Attempted Decompilation

typedef unsigned char byte;

byte grid[0xff];

byte mod_char(char ch)
{
    byte b0 = (ch & 2) >> 1;
    byte b1 = (ch & 8) >> 2;
    byte b2 = (ch & 0x20) >> 3;
    byte b3 = (ch & 0x80) >> 4;
    byte bres = b0 | b1 | b2 | b3;

    byte c0 = (ch & 1);
    byte c1 = (ch & 4) >> 1;
    byte c2 = (ch & 0x10) >> 2;
    byte c3 = (ch & 0x40) >> 3;
    byte cres = c0 | c1 | c2 | c3;

    int index = cres + (bres << 4);
    byte ret = grid[index];

    byte _1a = grid[bres << 4];
    for (int i = 1; i <= 0xf; ++i)
    {
        grid[(bres << 4) + i - 1] = grid[(bres << 4) + i];
    }
    grid[(bres << 4) + 0xf] = _1a;

    return ret;
}

int get_index(char ch)
{
    byte b0 = (ch & 2) >> 1;
    byte b1 = (ch & 8) >> 2;
    byte b2 = (ch & 0x20) >> 3;
    byte b3 = (ch & 0x80) >> 4;
    byte bres = b0 | b1 | b2 | b3;

    byte c0 = (ch & 1);
    byte c1 = (ch & 4) >> 1;
    byte c2 = (ch & 0x10) >> 2;
    byte c3 = (ch & 0x40) >> 3;
    byte cres = c0 | c1 | c2 | c3;

    int index = cres + (bres << 4);
    return index;
}

int arr[] = { 0x5F4BB48, 0x70D06AB, 0x76E1343, 0x845B466, 0x8C4EAE, 0x2F39F, 0x0F919BD5, 0x0BAE5F7A, 0x40EF15D, 0x4A5A670, 0x0F11A9CF, 0x0C48527, 0x1BEB2D7, 0x0D882E67, 0x857D627, 0x6F965D6, 0x4E9D3B8, 0x0DDCB1D, 0x8E66640, 0x3E1E8D3, 0x4230865, 0x412325D, 0x33DD506, 0x35CDE80, 0x0C059781, 0x0C88B7BA, 0x0F6A4A2F, 0x554C327, 0x1FDFE09, 0x2268560, 0x0F474912, 0x36EED2, 0x2CE7470, 0x9E28B02, 0x8A807AE, 0x27AED1D, 0x0B90B8F3, 0x0C98890D, 0x0DB37A5C, 0x17FF4FA, 0x54ABAA3, 0x10D3B84, 0x0ACBB43D, 0x0BCA9772, 0x47FE39, 0x443CA39, 0x6CFEA0F, 0x1C9987E, 0x0B7CB73F, 0x0B6ADF03, 0x5175B58, 0x0CF58AF3, 0x13B2D49, 0x4DC32B6, 0x7DE45C, 0x63982AF, 0x0FBC129B, 0x0E911269, 0x0C692CAC, 0x0A8F557B, 0x1814029, 0x0C50F6B0, 0x5CC781E, 0x1D16699 };

int main(int argc, char** argv)
{
    if(argc < 2)
    {
        puts(">_>");
        return 1;
    }
    memcpy(grid, arr, sizeof(grid));
    size_t stLen = strlen(argv[1]);
    for(int i = 0; i < stLen; ++i)
    {
        printf_s("%d.", mod_char(argv[1][i]));
    }
    return 0;
}