CSCAMP CTF Quals 2014: Elf 2 write-up

Created:2014.11.24, last modified: 2014.11.24 by xorpse
Status: Complete

Running the challenge binary produces no output. Loading it into IDA produces the following disassembly for the main function:

.text:0000000000400746                 mov     [rbp+var_4], edi
.text:0000000000400749                 mov     [rbp+var_10], rsi
.text:000000000040074D                 cmp     [rbp+var_4], 1
.text:0000000000400751                 jg      short loc_40075D
.text:0000000000400753                 mov     edi, 0          ; status
.text:0000000000400758                 call    _exit
.text:000000000040075D ; ---------------------------------------------------------------------------
.text:000000000040075D loc_40075D:                             ; CODE XREF: main+13j
.text:000000000040075D                 mov     rax, [rbp+var_10]
.text:0000000000400761                 add     rax, 8
.text:0000000000400765                 mov     rax, [rax]
.text:0000000000400768                 mov     rdi, rax
.text:000000000040076B                 call    xx
.text:0000000000400770                 mov     edi, eax
.text:0000000000400772                 call    xxyy
.text:0000000000400777                 mov     eax, 0

Since this binary is targeted at 64-bit Linux, arguments to functions are passed via registers (rdi, rsi, etc.). We see the first argument (corresponding to argc) is compared with 1 and if it’s less than or equal the executable exits. Otherwise, the first argument to the process, argv[1], is passed to xx() and the result of that is passed to xxyy().

The function xx() is a wrapper around the C standard library function atoi(); so we see that the first argument to the program must be numeric. xxyy() performs some simple arithmetic operations on the numeric argument and compares the result with 16:

.text:000000000040071D                 mov     [rbp+var_14], edi
.text:0000000000400720                 mov     eax, [rbp+var_14]
.text:0000000000400723                 lea     edx, [rax+3]
.text:0000000000400726                 test    eax, eax
.text:0000000000400728                 cmovs   eax, edx
.text:000000000040072B                 sar     eax, 2
.text:000000000040072E                 mov     [rbp+var_4], eax
.text:0000000000400731                 cmp     [rbp+var_4], 10h
.text:0000000000400735                 jnz     short locret_40073C
.text:0000000000400737                 call    xxyyzz
.text:000000000040073C locret_40073C:                          ; CODE XREF: xxyy+20j
.text:000000000040073C                 leave
.text:000000000040073D                 retn

Which amounts to:

if (input < 0)
  output = input + 3;
  output = input;

output /= 4;

if (output == 16)

Since the expected value is 16, then input should be (4 * 16): 64. With this input xxyyzz() is called, and writes the flag value to the file ‘.flag.txt’:

.text:0000000000400697                 push    rbp
.text:0000000000400698                 mov     rbp, rsp
.text:000000000040069B                 sub     rsp, 10h
.text:000000000040069F                 mov     edx, offset modes ; "w"
.text:00000000004006A4                 mov     eax, offset filename ; ".flag.txt"
.text:00000000004006A9                 mov     rsi, rdx        ; modes
.text:00000000004006AC                 mov     rdi, rax        ; filename
.text:00000000004006AF                 call    _fopen
.text:00000000004006B4                 mov     [rbp+stream], rax
.text:00000000004006B8                 cmp     [rbp+stream], 0
.text:00000000004006BD                 jnz     short loc_4006C9
.text:00000000004006BF                 mov     edi, 0          ; status
.text:00000000004006C4                 call    _exit
.text:00000000004006C9 ; ---------------------------------------------------------------------------
.text:00000000004006C9 loc_4006C9:                             ; CODE XREF: xxyyzz+26j
.text:00000000004006C9                 mov     ecx, offset format ; "Flag: %s"
.text:00000000004006CE                 mov     rax, [rbp+stream]
.text:00000000004006D2                 mov     edx, offset __FUNCTION___3311 ; "xxyyzz"
.text:00000000004006D7                 mov     rsi, rcx        ; format
.text:00000000004006DA                 mov     rdi, rax        ; stream
.text:00000000004006DD                 mov     eax, 0
.text:00000000004006E2                 call    _fprintf
.text:00000000004006E7                 mov     rax, [rbp+stream]
.text:00000000004006EB                 mov     rdi, rax        ; stream
.text:00000000004006EE                 call    _fclose
.text:00000000004006F3                 leave
.text:00000000004006F4                 retn

Thus, the flag is: ‘xxyyzz’.