ASIS CTF Quals 2016: "Catch Me!" writeup

Mon, 09 May 2016 22:29:56 +0200
Tags: reverse, CTF

The following loop decrypts 32 bytes starting from 0x601280 by XORing a 8-bytes cyclic key located at 0x6012a8:

.-> 0x004005d0      4889c2         movq %rax, %rdx
|   0x004005d3      83e207         andl $7, %edx               ; 8-byte key
|   0x004005d6      0fb692a81260.  movzbl 0x6012a8(%rdx), %edx ; 0x6012a8 (key)
|   0x004005dd      309080126000   xorb %dl, 0x601280(%rax)    ; 0x601280 (flag)
|   0x004005e3      4883c001       addq $1, %rax               ; counter
|   0x004005e7      4883f821       cmpq $0x21, %rax
`=< 0x004005eb      75e3           jne 0x4005d0

The XORed memory location (starting at 0x601280) appears to be the flag as this location is printed at the end of code execution:

0x004006d1      be80126000     movl $0x601280, %esi        ; Flag content
0x004006d6      bf3d0d4000     movl $0x400d3d, %edi        ; "Flag: ASIS{%s}."
0x004006db      31c0           xorl %eax, %eax
0x004006dd      e8fefdffff     callq sym.imp.printf

Here is the flag before the XOR decryption (at 0x004005d0):

0x00601280  8729 34c5 55b0 c22d ee60 34d4 55ee 807c  .)4.U..-.`4.U..|
0x00601290  ee2f 3796 3deb 9c79 ee2c 3395 78ed c12b  ./7.=..y.,3.x..+

Now the 8-bytes key is composed of a 4-bytes hash based on the ptrace() return value when process is being traced:

0x0040053e      e8cdffffff     callq sym.imp.ptrace
0x00400543      48c1f83f       sarq $0x3f, %rax            ; ptrace value in rax
0x00400547      83e025         andl $0x25, %eax
0x0040054a      83c00a         addl $0xa, %eax
0x0040054d      8905610d2000   movl %eax, 0x200d61(%rip)   ; [0x6012b4:4]
0x00400560      8b3d4e0d2000   movl 0x200d4e(%rip), %edi   ; [0x6012b4:4]
0x00400566      53             pushq %rbx
0x00400567      e8b4020000     callq 0x400820
0x0040056c      89c3           movl %eax, %ebx
0x0040056e      c1e818         shrl $0x18, %eax
0x00400571      bf340d4000     movl $0x400d34, %edi        ; "ASIS" @ 0x400d34
0x00400576      88052c0d2000   movb %al, 0x200d2c(%rip)    ; [0x6012a8:1] key[0]
0x0040057c      89d8           movl %ebx, %eax
0x0040057e      c1e810         shrl $0x10, %eax
0x00400581      83e0fd         andl $0xfffffffd, %eax
0x00400584      88051f0d2000   movb %al, 0x200d1f(%rip)    ; [0x6012a9:1] key[1]
0x0040058a      89d8           movl %ebx, %eax
0x0040058c      c1e808         shrl $8, %eax
0x0040058f      83e0df         andl $0xffffffdf, %eax
0x00400592      8805120d2000   movb %al, 0x200d12(%rip)    ; [0x6012aa:1] key[2]
0x00400598      89d8           movl %ebx, %eax
0x0040059a      83e0bf         andl $0xffffffbf, %eax
0x0040059d      8805080d2000   movb %al, 0x200d08(%rip)    ; [0x6012ab:1] key[3]

And a 4-bytes data taken from a mysterious shell variable (ASIS):

0x00400704      bf340d4000     movl $0x400d34, %edi        ; "ASIS" @ 0x400d34
0x00400709      e8b2fdffff     callq sym.imp.getenv
0x0040070e      8b00           movl (%rax), %eax
0x00400710      8905960b2000   movl %eax, 0x200b96(%rip)   ; [0x6012ac:4]

As we don't know how to set up this ASIS variable, we simply execute the code and check the XORed flag:

0x00601280  3630 3064 55b0 c22d 5f79 3075 55ee 807c  600dU..-_y0uU..|
0x00601290  5f36 3337 3deb 9c79 5f35 3734 78ed c12b  _637=..y_574x..+

We start discovering some l33t speak, that good!


To inject 4 bytes of ASIS in our key, we need to succeed to another check: provide a CTF variable that, once XORed with the ebx register, gives us the value 0xfeebfeeb:

0x004005ad      bf390d4000     movl $0x400d39, %edi        ; "CTF" @ 0x400d39
0x004005b2      e809ffffff     callq sym.imp.getenv
0x004005b7      3318           xorl (%rax), %ebx
0x004005b9      81fbebfeebfe   cmpl $0xfeebfeeb, %ebx

Analysing ebx at 0x004005b9 helps us to find the XORed value to put in CTF. This value should also be placed in ASIS to display the flag:

export CTF="$(printf "\x0a\xda\xf2\x4f")"
export ASIS="$(printf "\x0a\xda\xf2\x4f")"
ltrace ./Catch_Me.orig 2>/dev/null
Flag: ASIS{600d_j0b_y0u_4r3_63771n6_574r73d}