Assets
- home 18.0k
- device(s) 1.0k
- stock(s) 2.3k
- server 0.1k
- cash 0.6k
Liabilities
- debt 4.0k
- loan 0.0k
My Net: 18.0k
05-12-2021
Expired by:
00000 00:00:00

FooBar CTF 2021 notes

The FooBar 2021 was held by people from NIT Durgapur University. I hoped the event to be beginner friendly. When it comes down to assembler, reversing and binary exploitation, etc, I simply go blind. So this time around, I visited the Underworld to meet some baby monsters.

1. NET_DOT [reverse]

The challenge statement:

Find the flag…
Author: kaki-epithesi
File: win.dll

We have a dynamic-link library file written in the .NET framework. My quick search shortlisted: JetBrains dotPeek, Telerik JustDecompile, and ILSpy. The dotPeek extracted the following C# code with ease.

// Decompiled with JetBrains decompiler
// Assembly: win, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null

using System;

namespace win
{
  internal class Program
  {
    private static int sum_all(string password)
    {
      int num = 0;
      foreach (char ch in password)
        num += (int) ch;
      return num;
    }

    private static int check(int[] values)
    {
      int[] numArray = new int[26]
      {
        2410, 2404, 2430, 2408, 2391, 2381, 2333, 2396, 2369, 2332, 2398, 2422, 2332, 
        2397, 2416, 2370, 2393, 2304, 2393, 2333, 2416, 2376, 2371, 2305, 2377, 2391
      };
      int num = 0;
      for (int index = 0; index < numArray.Length; ++index)
      {
        if (numArray[index] == values[index])
        {
          num = 1;
        }
        else
        {
          num = 0;
          break;
        }
      }
      return num;
    }

    private static void Main(string[] args)
    {
      Console.WriteLine("Hello there mate \nJust enter the flag to check : ");
      string password = Console.ReadLine();
      int[] numArray = new int[26];
      if (password.Length != 26)
      {
        Console.WriteLine("Input length error");
        Console.ReadLine();
      }
      else
      {
        for (int index = 0; index < password.Length; ++index)
          numArray[index] = (int) password[index];
        int[] values = new int[26];
        for (int index = 0; index < 26; ++index)
          values[index] = numArray[index] - (index%2*2 + index%3) ^ Program.sum_all(password);
        if (Program.check(values) == 1)
        {
          Console.WriteLine("Your flag : " + password);
          Console.ReadLine();
        }
        else
        {
          Console.WriteLine("try harder");
          Console.ReadLine();
        }
      }
    }
  }
}

By looking at this code, it is clear that we can simply reverse the logic and reconstruct the correct flag representation.

using System;

namespace Reverse
{
  class Program
  {
    static void Main(string[] args)
    {
      // correct flag syntax ~ "GLUG{...}";
      // values[index] = numArray[index] - (index % 2 * 2 + index % 3) ^ Program.sum_all(password);
      // 2410 = (int) 'G' ^ passwordSum [when the index is 0]
      int passwordSum = ((int)'G' ^ 2410);
      int[] numArray = new int[26];
      int[] values = new int[26]
      { 
        2410, 2404, 2430, 2408, 2391, 2381, 2333, 2396, 2369, 2332, 2398, 2422, 2332,
        2397, 2416, 2370, 2393, 2304, 2393, 2333, 2416, 2376, 2371, 2305, 2377, 2391 
      };

      string flag = "";
      for (int index = 0; index < 26; ++index)
      {
        // values[index] = (numArray[index] - (index % 2 * 2 + index % 3)) ^ passwordSum;
        // values[index] ^ passwordSum = (numArray[index] - (index % 2 * 2 + index % 3));
        numArray[index] = (values[index] ^ passwordSum) + (index % 2 * 2 + index % 3);
        flag += (char)numArray[index];
      }
      Console.WriteLine(flag);
    }
  }
}

This simple C# solution printed out the correct flag as GLUG{d0tn3t_1s_qu1t3_go0d}.


2. Childrev [reverse]

The challenge statement:

The baby has grown up to be very mischievous.
Can you bring him under control?
File: childrev

For this challenge, we received a legit ELF 64-bit executable file. Last time when I visit the Underworld I chickened out in a day or two. I only know that there are few powerful tools to deal with this sort of situation, but they all require a fair bit of assembler familiarity. To me, a low-level programming language is a monster under the bed that does magical things in the Underworld where I am afraid to wander. But this time around I was not alone in there. A new friend of mine, from Germany, shed some light into the darkness. He taught me just enough to find the treasure in time.

$ file ./childrev # show file information
childrev: ELF 64-bit LSB executable, x86-64, version 1 (GNU/Linux), statically linked, ...
$ strings childrev | grep 'GLUG\|UPX' # search strings similar to GLUG or UPX
UPX!P
$Info: This file is packed with the UPX executable packer http://upx.sf.net $
$Id: UPX 3.96 Copyright (C) 1996-2020 the UPX Team. All Rights Reserved. $
UPX!u
UPX!
UPX!

The file is packed with the UPX executable packer. So we need to unpack it, to dig further.

$ upx -d childrev # unpack by upx
                       Ultimate Packer for eXecutables
                          Copyright (C) 1996 - 2020
UPX 3.96        Markus Oberhumer, Laszlo Molnar & John Reiser   Jan 23rd 2020

        File size         Ratio      Format      Name
   --------------------   ------   -----------   -----------
    910136 <-    406024   44.61%   linux/amd64   childrev

Unpacked 1 file.

These days, to do reverse engineering and/or binary analysis people seem to be using: GDB, radare2, IDA, Hopper, and Ghidra, etc. Each of them comes with its advantages/disadvantages and a learning curve. I am still trying to find my grip on some of them.

I liked the visualization that the radare2 tool provides. So let’s take a look at the childrev file using radare2.

r2 ./childrev
[0x00401b90]> aaa # Analyze the file
[x] Analyze all flags starting with sym. and entry0 (aa)
[x] Analyze function calls (aac)
[x] Analyze len bytes of instructions for references (aar)
[x] Check for vtables
[x] Type matching analysis for all functions (aaft)
[x] Propagate noreturn information
[x] Use -AA or aaaa to perform additional experimental analysis.
[0x00401b90]> s main # seek(s) 'main' function
[0x00401e41]> agv # visualize the function
                                      ┌─────────────────────────────────────────────────────┐
                                        0x401e41                                     
                                         ; DATA XREF from entry0 @ 0x401bad                │
                                         ;-- rip:                                          │
                                       171: int main (int argc, char **argv, char **envp); │
                                       ; var int64_t var_30h @ rbp-0x30                    │
                                       ; var uint32_t var_8h @ rbp-0x8                     │
                                       ; var int64_t var_4h @ rbp-0x4                      │
                                       ; var int64_t var_3h @ rbp-0x3                      │
                                       ; var int64_t var_2h @ rbp-0x2                      │
                                       ; var int64_t var_1h @ rbp-0x1                      │
                                       push rbp                                            
                                       mov rbp, rsp                                        
                                       sub rsp, 0x30                                       
                                       ; int64_t arg1                                      │
                                       ; 0x49e170                                          │
                                       ; "ENTER THE FLAG : "                               │
                                       lea rdi, str.ENTER_THE_FLAG_:_                      
                                       mov eax, 0                                          
                                       call sym.__printf;[oa]                              │
                                       lea rax, [var_30h]                                  
                                       mov rsi, rax                                        
                                       ; const char *format                                │
                                       ; "%s"                                              │
                                       lea rdi, [0x0049e182]                               
                                       mov eax, 0                                          
                                       ; int scanf(const char *format)                     │
                                       call sym.__isoc99_scanf;[ob]                        │
                                       ; 'G'                                               │
                                       ; 71                                                │
                                       mov byte [var_1h], 0x47                             
                                       ; 'L'                                               │
                                       ; 76                                                │
                                       mov byte [var_2h], 0x4c                             
                                       ; 'U'                                               │
                                       ; 85                                                │
                                       mov byte [var_3h], 0x55                             
                                       ; 'G'                                               │
                                       ; 71                                                │
                                       mov byte [var_4h], 0x47                             
                                       movsx edi, byte [var_4h]                            
                                       ; int64_t arg5                                      │
                                       movsx ecx, byte [var_3h]                            
                                       ; int64_t arg4                                      │
                                       movsx edx, byte [var_2h]                            
                                       ; int64_t arg2                                      │
                                       movsx esi, byte [var_1h]                            
                                       lea rax, [var_30h]                                  
                                       mov r8d, edi                                        
                                       ; int64_t arg1                                      │
                                       mov rdi, rax                                        
                                       call sym.XOR;[oc]                                   │
                                       mov dword [var_8h], eax                             
                                       cmp dword [var_8h], 0                               
                                       jne 0x401eb8                                        
                                      └─────────────────────────────────────────────────────┘
                                              f t
                                               
                                               └───────────────────────────┐
    ┌─────────────────────────────────────────┘                             
                                                                           
┌───────────────────────────────────────────────────────────────────┐   ┌──────────────────────────────────────────────┐
  0x401eaa                                                              0x401eb8                                    
 ; const char *s                                                   │   │ ; CODE XREF from main @ 0x401ea8             │
 ; 0x49e188                                                        │   │ movsx esi, byte [var_4h]                     │
 ; "USE GHIDRA CUTTER OR IDA , THEN IT WILL BE EASY\n"             │   │ ; int64_t arg4                               │
 lea rdi, str.USE_GHIDRA_CUTTER_OR_IDA___THEN_IT_WILL_BE_EASY_n        movsx ecx, byte [var_3h]                     
 ; int puts(const char *s)                                         │   │ ; int64_t arg3                               │
 call sym.puts;[od]                                                │   │ movsx edx, byte [var_2h]                     │
 jmp 0x401ee5                                                          movsx eax, byte [var_1h]                     
└───────────────────────────────────────────────────────────────────┘    lea rdi, [var_30h]                           
    v                                                                    ; int64_t arg6                               │
                                                                        mov r9, rdi                                  
                                                                        ; int64_t arg5                               │
                                                                        mov r8d, esi                                 
                                                                        ; int64_t arg2                               │
                                                                        mov esi, eax                                 
                                                                        ; int64_t arg1                               │
                                                                        ; 0x49e1b9                                   │
                                                                        ; "YAY U MADE IT \n%c%c%c%c{%s}\n"           │
                                                                        lea rdi, str.YAY_U_MADE_IT__n_c_c_c_c_s_n    
                                                                        mov eax, 0                                   
                                                                        call sym.__printf;[oa]                       │
                                                                       └──────────────────────────────────────────────┘
                                                                           v
                                                                           
    └────────────────────────────────────────────────┐                      
                                                      ┌────────────────────┘
                                                      
                                               ┌──────────────────────────────────┐
                                                 0x401ee5                        
                                                ; CODE XREF from main @ 0x401eb6 │
                                                mov eax, 0                       
                                                leave                            
                                                ret                              
                                               └──────────────────────────────────┘

This main function has 4 blocks with starting addresses of 0x401e41, 0x401eaa, 0x401eb8 and 0x401ee5. The first and last blocks are always executed but the execution of the second or third is conditionally dependent on the first block’s execution. Judging by the content of the second and third blocks, I prefer to go with the third. Let’s take a closer look at what happens near the end of the first block.

call sym.XOR;[oc]         ; calling sym.XOR function 
mov dword [var_8h], eax   ; moving the output of sym.XOR function to var_8h variable
cmp dword [var_8h], 0     ; comparing value of the var_8h variable with 0
jne 0x401eb8              ; jumping if they were not equal.

Here, I commented on the ASM instructions with my baby-educated guesses. So I want the sym.XOR output not to be 0. Let’s see the sym.XOR:

[0x00401e41]> s sym.XOR
[0x00401d3d]> agv
 ┌────────────────────────────────────────────────────────────────────────┐
   0x401d3d                                                              
    ; CALL XREF from main @ 0x401e9c                                     │
  260: sym.XOR (int64_t arg1, int64_t arg2, int64_t arg4, int64_t arg5); │
  ; var int64_t var_258h @ rbp-0x258                                     │
  ; var int64_t var_254h @ rbp-0x254                                     │
  ; var int64_t var_250h @ rbp-0x250                                     │
  ; var int64_t var_24ch @ rbp-0x24c                                     │
  ; var int64_t var_248h @ rbp-0x248                                     │
  ; var int64_t var_240h @ rbp-0x240                                     │
  ; var int64_t var_130h @ rbp-0x130                                     │
  ; var int64_t var_18h @ rbp-0x18                                       │
  ; var signed int64_t var_ch @ rbp-0xc                                  │
  ; var int64_t var_8h @ rbp-0x8                                         │
  ; var signed int64_t var_4h @ rbp-0x4                                  │
  ; arg int64_t arg1 @ rdi                                               │
  ; arg int64_t arg2 @ rsi                                               │
  ; arg int64_t arg4 @ rcx                                               │
  ; arg int64_t arg5 @ r8                                                │
  push rbp                                                               
  mov rbp, rsp                                                           
  sub rsp, 0x260                                                         
  ; arg1                                                                 │
  mov qword [var_248h], rdi                                              
  ; arg4                                                                 │
  mov eax, ecx                                                           
  ; arg5                                                                 │
  mov edi, r8d                                                           
  ; arg2                                                                 │
  mov ecx, esi                                                           
  mov byte [var_24ch], cl                                                
  mov byte [var_250h], dl                                                
  mov byte [var_254h], al                                                
  mov eax, edi                                                           
  mov byte [var_258h], al                                                
  movsx ecx, byte [var_258h]                                             
  movsx edx, byte [var_254h]                                             
  movsx esi, byte [var_250h]                                             
  movsx eax, byte [var_24ch]                                             
  mov edi, eax                                                           
  call sym.gen_key;[oa]                                                  │
  mov qword [var_18h], rax                                               
  mov dword [var_4h], 0                                                  
  jmp 0x401dcf                                                           
 └────────────────────────────────────────────────────────────────────────┘
     v
     
     └───────────────────┐
┌──────────────────────────┐
                         
                  ┌─────────────────────────────────────┐
                    0x401dcf                           
                   ; CODE XREF from sym.XOR @ 0x401d9e │
                   cmp dword [var_4h], 0x21            
                   jle 0x401da0                        
                  └─────────────────────────────────────┘
                        t f
                         
    ┌───────────────────┘ 
                         └───────────────────────┐
                                                 
│┌─────────────────────────────────────────┐   ┌───────────────────────────────────────────┐
││  0x401da0                                    0x401dd5                                 
││ ; CODE XREF from sym.XOR @ 0x401dd3     │   │ lea rax, [var_240h]                       │
││ mov eax, dword [var_4h]                     lea rdx, [0x0049e060]                     
││ movsxd rdx, eax                             ; '"'                                     │
││ mov rax, qword [var_248h]                   ; 34                                      │
││ add rax, rdx                                mov ecx, 0x22                             
││ movzx eax, byte [rax]                       mov rdi, rax                              
││ movsx rax, al                               mov rsi, rdx                              
││ xor rax, qword [var_18h]                    rep movsq qword [rdi], qword ptr [rsi]    
││ mov rdx, rax                                mov dword [var_8h], 0                     
││ mov eax, dword [var_4h]                     mov dword [var_ch], 0                     
││ cdqe                                        jmp 0x401e36                              
││ mov qword [rbp + rax*8 - 0x130], rdx       └───────────────────────────────────────────┘
││ add dword [var_4h], 1                          v
│└─────────────────────────────────────────┘       
    v                                             
                                                 
└────┘                                             
                                                   └────────┐
                ┌─────────────────────────────────────────────┐
                                                            
                                                     ┌─────────────────────────────────────┐
                                                       0x401e36                           
                                                      ; CODE XREF from sym.XOR @ 0x401dff │
                                                      cmp dword [var_ch], 0x21            
                                                      jle 0x401e01                        
                                                     └─────────────────────────────────────┘
                                                           t f
                                                            
                    ┌──────────────────────────────────────┘ 
                                                            └──────────────────────────────────────────────┐
                                                                                                           
                │┌─────────────────────────────────────────┐                                                 
                ││  0x401e01                                                                                
                ││ ; CODE XREF from sym.XOR @ 0x401e3a     │                                                 │
                ││ mov eax, dword [var_ch]                                                                  
                ││ cdqe                                                                                     
                ││ mov rdx, qword [rbp + rax*8 - 0x130]                                                     
                ││ mov eax, dword [var_ch]                                                                  
                ││ cdqe                                                                                     
                ││ mov rax, qword [rbp + rax*8 - 0x240]                                                     
                ││ cmp rdx, rax                                                                             
                ││ jne 0x401e29                                                                             
                │└─────────────────────────────────────────┘                                                 
                        f t                                                                                 
                                                                                                          
                         └───────────────────────────────────────────┐                                     
                        └──┐                                                                               
                                                                                                          
                       ┌──────────────────────────┐               ┌─────────────────────────────────────┐   
                         0x401e20                                 0x401e29                              
                        mov dword [var_8h], 1                    ; CODE XREF from sym.XOR @ 0x401e1e │   │
                        jmp 0x401e32                             mov dword [var_8h], 0                  
                       └──────────────────────────┘                jmp 0x401e3c                           
                           v                                      └─────────────────────────────────────┘   
                                                                     v                                     
                                                                                                          
                      ┌────┘                                                                               
                                                                     └────────────┐                        
                                                                                   ┌──────────────────────┘
                                                                                   
                  ┌─────────────────────────────────────┐                    ┌─────────────────────────────────────┐
                    0x401e32                                                 0x401e3c                           
                   ; CODE XREF from sym.XOR @ 0x401e27 │                    │ ; CODE XREF from sym.XOR @ 0x401e30 │
                   add dword [var_ch], 1                                    mov eax, dword [var_8h]             
                  └─────────────────────────────────────┘                     leave                               
                      v                                                       ret                                 
                                                                            └─────────────────────────────────────┘
                      
                      
                └──────┘

We can see that our exit block is 0x401e3c in the bottom right corner. Just above it, the block 0x401e29 is trying to give us 0. So no go. Looking only at the bottom 6 blocks, we can conclude that it is a loop structure where it compares some values 33 (0x21) times.

if any one of the 33 comparisons fails then we get 0.
if all the comparisons pass then we might get something other than 0.

So now our focus shifts to the values being compared. To look up the actual values that are being compared:

  1. Open up the childrev file in IDA.
  2. Locate the XOR function. (filter functions)
  3. Set breakpoint in the comparison line (F2 on cmp rdx, rax).
  4. Reverse the jne 0x401e29 operation. (75 => 74 edit in hex view & apply patches to the input file).
  5. Look up the rdx and rax register values while debugging.

After 33 step-over button clicks, we recovered the flag string to be GLUG{x0r_and_l0g1c@l_sh1ft_e@sy_r1gh8??}. I am sure that there are more elegant or straightforward ways to get it. But I am not there yet. Perhaps, I need to play more SHENZHEN I/O from Zachtronics.


     

Thanks to those who organized and sponsored the event, my hours spent on it were well worth it.

· CTF, C# decompiler, reverse engineering