> For the complete documentation index, see [llms.txt](https://sansong.gitbook.io/cyber/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://sansong.gitbook.io/cyber/capture-the-flag-ctf/writeups/2024/nanocombattant-404ctf-2024.md).

# Nanocombattant @404CTF 2024

Playing with Nanomites

## TL;DR

This challenge uses an anti-debug technique called nanomites. A parent process spawns 2 children and controls their execution. If a debugger is used in one of the children, the program stops. The input characters are checked independently which helps a lot in solving it by counting calls to <mark style="color:blue;">`PTRACE_SETREGS`</mark>.

## Description

`reverse`  `46 validations`  <mark style="color:red;">`hard`</mark>

{% hint style="success" %}
Entrez dans l'arène

Le CHAUSSURE, cette fameuse entité pionnière dans le domaine du sport de combat a ouvert un tournoi pour tous les chat-diateurs qui souhaiteraient se mesurer au reste du monde. Il est l'heure d'aller se confronter dans l'arène, à un détail près... Une vérification est opérée à l'entrée, mais impossible de vous souvenir du mot de passe ! Retrouvez-le.

\
`Author: Narcisse`
{% endhint %}

You can download the challenge from this archive.

{% file src="/files/HOUA1pytmSegdY3FUUu5" %}

## Solution

{% hint style="info" %}
Functions shown in this writeup have already been reversed. Variables and functions have been renamed and IDA's decompiler errors have been patched. Non useful code lines have also been removed for a better understanding.
{% endhint %}

### Overview

We need to find the password to get into the arena.

Here is the code of <mark style="color:blue;">`main`</mark>:

```c
__int64 __fastcall main(int a1, char **a2, char **a3) {

  memset(input, 0, 256);
  puts("=================================================================================");
  puts(aBienvenueDansL);
  puts("_____                                                                       _____");
  puts(asc_938);
  puts(" |||                                                                         ||| ");
  puts(" |||          ~Qu'est-ce que tu peux faire contre le 404 CROU~               ||| ");
  puts(aOnALaM);
  puts(" |||                                                                         ||| ");
  puts(asc_B70);
  puts(&byte_D48);
  __printf_chk();
  __isoc99_scanf("%255s", input);
  if ( strlen((const char *)input) != 19 )
    fail();
  check_input((__int64)input);
  result = 0LL;

  return result;
}
```

It calls <mark style="color:blue;">`fail`</mark> if the input length is not 19.

```c
void __noreturn fail() {
  puts("Crois-tu pouvoir me fumister si facilement ?!?");
  exit(105);
}
```

If the length is correct it calls <mark style="color:blue;">`check_input`</mark>.

Here is the code of <mark style="color:blue;">`check_input`</mark>:

```c
unsigned __int64 __fastcall check_input(__int64 input) {

  buffer1 = mmap(0LL, (unsigned int)n, 7, 33, -1, 0LL);
  memcpy(buffer1, &unk_4EC0, (unsigned int)n);  
  buffer2 = mmap(0LL, (unsigned int)len, 7, 34, -1, 0LL);
  memcpy(buffer2, &unk_4CE0, (unsigned int)len);
  v3 = fork();
  if ( v3 < 0 ) {   
    __printf_chk();
    exit(1);
  }
  first_child_pid = v3;
  if ( !v3 )                                
    first_child_func((void (__fastcall *)(__int64))buffer1, input);
  v5 = fork();                                 
  second_child_pid = v5;
  if ( v5 < 0 ) {                                             
    __printf_chk();
    exit(1);
  }
  if ( !v5 )                                    
    second_child_func((void (*)(void))buffer2);
  cpt = 0;
  while ( waitpid(first_child_pid, &stat_loc, 0) != -1 && (stat_loc & 0x7F) != 0 ) {
    if ( (_BYTE)stat_loc == 127 && BYTE1(stat_loc) == 5 ) {
      father_second_child_func(second_child_pid, (__int64)buffer2, cpt, (__int64)buffer1);
      ptrace(PTRACE_CONT, first_child_pid, 0LL, 0LL);
      v8 = father_first_child_func(first_child_pid, (__int64)buffer1);
      cpt++;
      if ( v8 == -1 )
        fail();
      ptrace(PTRACE_CONT, first_child_pid, 0LL, 0LL);
    }
    if ( cpt == 19 ) {
      success();
      break;
    }
  }

  return result;
}
```

It starts by filling up 2 buffers with data stored in memory (<mark style="color:blue;">`unk_4EC0`</mark> & <mark style="color:blue;">`unk_4CE0`</mark>). We'll come back to this later.

```c
  buffer1 = mmap(0LL, (unsigned int)n, 7, 33, -1, 0LL);
  memcpy(buffer1, &unk_4EC0, (unsigned int)n);  
  buffer2 = mmap(0LL, (unsigned int)len, 7, 34, -1, 0LL);
  memcpy(buffer2, &unk_4CE0, (unsigned int)len);
```

Then it spawns a child process with <mark style="color:blue;">`fork`</mark> and the child calls a function that takes 2 parameters:

* the first buffer filled earlier <mark style="color:blue;">`buffer1`</mark>
* the input

```c
  v3 = fork(); // spawn child process
  if ( v3 < 0 ) {  
    // fork failed
    __printf_chk();
    exit(1);
  }
  first_child_pid = v3;
  if ( !v3 )
    // inside child process                                
    first_child_func((void (__fastcall *)(__int64))buffer1, input);
```

The same thing is done for a second child process. Except this time, the function called by the second child takes the second buffer <mark style="color:blue;">`buffer2`</mark> as parameter.

```c
  v5 = fork();  // spawn second child process                               
  second_child_pid = v5;
  if ( v5 < 0 ) {  
    // fork failed                                           
    __printf_chk();
    exit(1);
  }
  if ( !v5 ) 
    // inside second child process                                   
    second_child_func((void (*)(void))buffer2);
```

Then a counter <mark style="color:blue;">`cpt`</mark> is initialized and a while loop starts.

```c
  // inside father process
  cpt = 0;
  while ( waitpid(first_child_pid, &stat_loc, 0) != -1 && (stat_loc & 0x7F) != 0 ) {
    if ( (_BYTE)stat_loc == 127 && BYTE1(stat_loc) == 5 ) {
      father_scnd_child_func(scnd_child_pid, (__int64)buffer2, cpt, (__int64)buffer1);
      ptrace(PTRACE_CONT, first_child_pid, 0LL, 0LL);
      v8 = father_first_child_func(first_child_pid, (__int64)buffer1);
      cpt++;
      if ( v8 == -1 )
        fail();
      ptrace(PTRACE_CONT, first_child_pid, 0LL, 0LL);
    }
    if ( cpt == 19 ) {
      success();
      break;
    }
  }
```

We can see that inside the loop <mark style="color:blue;">`success`</mark> is called if <mark style="color:blue;">`cpt == 19`</mark>.

```c
int success() {
  return puts(aBienvenueDansL_0);
}

// .rodata:0000000000000D00 aBienvenueDansL_0 "Bienvenue dans l'arene frere d'arme !"
```

Now remember that the input must be of length 19. It looks like this loop is checking each input character to validate them. Let's look closer.

The first line is typical of nanomites on Linux:

```c
waitpid(first_child_pid, &stat_loc, 0) != -1 && (stat_loc & 0x7F) != 0
```

The father process is paused until the first child's state changes. So now the execution flow goes to its children processes.

### **Children processes**

Let's see what happens inside the children. We already saw that each child calls a function with respectively <mark style="color:blue;">`buffer1`</mark> and <mark style="color:blue;">`buffer2`</mark> as parameter. The first child's function also takes the input.

These functions are similar. They call <mark style="color:blue;">`ptrace`</mark> with the request <mark style="color:blue;">`PTRACE_TRACEME`</mark> to be traced by their father. If the father fails to attach itself to them it means that another process is already tracing them: probably a debugger. In this case the program terminates.

If the father can attach itself both function execute the code of respectively <mark style="color:blue;">`buffer1`</mark> and <mark style="color:blue;">`buffer2`</mark>.

Here is the code for the first child's function:

```c
void first_child_func(void (__fastcall *buffer)(__int64), __int64 input) {
  
  if ( (unsigned int)ptrace(PTRACE_TRACEME, 0LL, 0LL, 0LL) != -1 ) {
    buffer(input);
    exit(0);
  }
  // call to ptrace failed => debugger detected
  puts(aArr);
  exit(66);
}

// .rodata:0000000000000A18 aArr "Arrêtez de me suivre, pleutre!"
```

And for the second one:

```c
void second_child_func(void (*buffer)(void)) {

  if ( (unsigned int)ptrace(PTRACE_TRACEME, 0LL, 0LL, 0LL) != -1 ) {
    buffer();
    exit(0);
  }
  // call to ptrace failed => debugger detected
  puts(aArr);
  exit(66);
}

// .rodata:0000000000000A18 aArr "Arrêtez de me suivre, pleutre!"
```

### Shellcodes overview

Now let's see what the code stored inside these buffers does.

Here is the code inside <mark style="color:blue;">`buffer1`</mark>:

```c
loc_4EC0:                                ; DATA XREF: check_input+54↑o
                 int     3               ; Trap to Debugger
                 scasb                   ; input in rdi
                 db      41h
                 mov     r15, 5C133D7A0020CD9Fh
                 rol     bh, 0Eh
                 sal     byte ptr [rdi+826E6D5h], 0CCh
                 js      short near ptr loc_4F1C+2
                 test    eax, 3D45E070h
                 movsb
                 jb      short near ptr unk_4E7B
                 xor     ah, [rbx+56D327D5h]
                 test    [rdi-36F78AE8h], ecx

                 db    6

                 int     3               ; Trap to Debugger
                 sbb     [rbx], ch
                 test    eax, 91A4E503h
                 cmp     eax, 38E18196h
                 out     dx, eax

                 db  9Bh
                 db  61h ; a

                 sbb     al, 9Fh
                 int     3               ; Trap to Debugger
                 lahf

                 db 0D4h

                 db      64h
                 out     dx, eax
                 xchg    eax, edi

                 db  27h

                 sal     dword ptr [rsi+63h], cl
                 xchg    eax, ebx
                 xor     dh, cl
                 fmul    dword ptr [rdi]
                 mov     dh, 9Eh
                 cli

loc_4F12:                               ; CODE XREF: loc_4F30↓j
                 adc     edi, ecx
                 sub     al, 0CCh
                 sbb     [rcx], ch
                 in      al, dx
                 xor     al, 0F1h

loc_4F1C:                               ; CODE XREF: loc_4ED7↑j
                 mov     eax, ds:6F15FDD27E7B76ADh
                 mov     ds:42CC5DD1E221E882h, eax

                 db 0C6h

                 cld
                 loopne  loc_4F12
                 and     esp, [rbp+3A455C1Dh]
                 mov     word ptr [rdx-45667222h], es
                 cmp     eax, 68F0D94Ah
                 stosb
                 int     3               ; Trap to Debugger
                 nop
                 nop
                 [...many nop instructions...]
                 nop
                 int     3               ; Trap to Debugger
                 nop
```

Here is the code inside <mark style="color:blue;">`buffer2`</mark>:

```c
loc_4CE0:                                ; DATA XREF: check_input+92↑o
                 int     3               ; Trap to Debugger
                 test    rdx, rdx       
                 jle     short loc_4D00  ; SIGTRAP
                 mov     rdx, rdx
                 mov     eax, 0
                 jmp     short $+2       


loc_4CF0:                                ; CODE XREF: .data:0000000000004CEE↑j
                                         ; .data:0000000000004CFE↓j
                 movzx   ecx, byte ptr [rsi+rax] ; 
                 xor     [rdi+rax], cl
                 add     rax, 1
                 cmp     rax, rdx
                 jnz     short loc_4CF0 

loc_4D00:                                ; CODE XREF: .data:0000000000004CE4↑j
                 int     3
```

Without looking too deep into them for now we see that they use the instruction <mark style="color:blue;">`int 3`</mark> to create software interrupts. When this instruction is called, the child's state changes and the father process takes control back.

So each child does some things (we'll dive into it later) and often gives control back to the father. What does the father do then ?

### **Children monitoring**

Back to the while loop. At this point, the second line of the loop is executed after the first child executes its first <mark style="color:blue;">`int 3`</mark> instruction. The first child is now paused.

```c
while ( waitpid(first_child_pid, &stat_loc, 0) != -1 && (stat_loc & 0x7F) != 0 ) {
    if ( (_BYTE)stat_loc == 127 && BYTE1(stat_loc) == 5 ) {
      father_second_child_func(second_child_pid);
      ptrace(PTRACE_CONT, first_child_pid, 0LL, 0LL); 
      v8 = father_first_child_func(first_child_pid, (__int64)buffer1);
      cpt++;
      if ( v8 == -1 )
        fail();
      ptrace(PTRACE_CONT, first_child_pid, 0LL, 0LL); 
    }
    if ( cpt == 19 ) {
      success();
      break;
    }
  }
```

The first line checks if the first child was stopped by a <mark style="color:blue;">`SIGTRAP`</mark> (code 5).

```c
if ( (_BYTE)stat_loc == 127 && BYTE1(stat_loc) == 5 )
```

Then it calls a function involving the second child process and resumes the first child with <mark style="color:blue;">`ptrace`</mark> and the request <mark style="color:blue;">`PTRACE_CONT`</mark>.

```c
father_second_child_func(second_child_pid);
ptrace(PTRACE_CONT, first_child_pid, 0LL, 0LL); // first child resumes
```

Let's dive into this <mark style="color:blue;">`father_second_child_func`</mark>:

```c
unsigned __int64 __fastcall father_second_child_func(unsigned int pid, __int64 buffer2, int cpt, __int64 buffer1) {

  while ( 1 ) {
    v6 = pid;
    // father waits for child 2 to change state
    if ( waitpid(pid, &stat_loc, 0) == -1 || (stat_loc & 0x7F) == 0 )
      break;
    // child 2 stopped by SIGTRAP
    if ( (_BYTE)stat_loc == 127 && BYTE1(stat_loc) == 5 ) {
      // get child 2 registers
      ptrace(PTRACE_GETREGS, pid, 0LL, regs);
      if ( rip_reg != buffer2 + 1 ) {     
        rip_reg = buffer2;    // set rip to the start of buffer2 code for the next character to be checked
        ptrace(PTRACE_SETREGS, pid, 0LL, regs);
        v6 = 7LL;
        // child 2 resume
        ptrace(PTRACE_CONT, pid, 0LL, 0LL);     
                                                // escape func
        break;
      }
      v7 = dword_4C80[cpt];                     
      v8 = dword_4D40[v7] + 1LL;
      rdi_reg = v8 + buffer1;
      if ( cpt <= 5 || cpt == 18 )
        rsi_reg = (__int64)&unk_4F60 + v8;     
      if ( (unsigned int)(cpt - 6) > 5 ) {
        if ( cpt > 11 )
          rsi_reg = (__int64)&unk_4D80 + v8;    
      }
      else {
        rsi_reg = (__int64)&unk_4E20 + v8;     
      }
      rdx_reg = dword_4D10[v7] - 1;
      // change child 2 registers
      ptrace(PTRACE_SETREGS, pid, 0LL, regs);
      // child 2 resume
      ptrace(PTRACE_CONT, pid, 0LL, 0LL);       
    }
  }

  return canary_overflowed;
}
```

The father is paused and waits this time for its second child to change state. Once the second child executes its first <mark style="color:blue;">`int 3`</mark> instruction the father grabs its register with <mark style="color:blue;">`PTRACE_GETREGS`</mark>.

Then it performs this check:

```c
if ( rip_reg != buffer2 + 1 ) {
    // do something
    break;
}
else {
    // do something else
}
```

It checks if the <mark style="color:blue;">`rip`</mark> register of the second child is pointing to **0x4CE1**.

```c
.data:0x04CE0    loc_4CE0:                            
.data:0x04CE0                 int     3               
.data:0x04CE1   here --->     test    rdx, rdx       
.data:0x04CE4                 jle     short loc_4D00  
.data:0x04CE6                 mov     rdx, rdx
.data:0x04CE9                 mov     eax, 0
.data:0x04CEE                 jmp     short $+2       
```

So basically it checks if this is the first **SIGTRAP** for the second child (if <mark style="color:blue;">`rip`</mark> points to the next instruction to execute (<mark style="color:blue;">`test  rdx, rdx`</mark>). If it is, it sets rip to the beggining of child 2's shellcode for the next character and resumes child 2 with <mark style="color:blue;">`PTRACE_CONT`</mark>.

If this isn't the first **SIGTRAP**, some operations are done and child 2's <mark style="color:blue;">`rsi`</mark>, <mark style="color:blue;">`rdi`</mark> and <mark style="color:blue;">`rdx`</mark> are modified.

Whatever is going on here, the second shellcode doesn't seem to interact with the input. Let's move on and look at the function called after this one: <mark style="color:blue;">`father_first_child_func`</mark>.

```c
__pid_t __fastcall father_first_child_func(unsigned int pid, __int64 buffer1, int cpt) {

  while ( 1 ) {
    p_stat_loc = (__int64)&stat_loc;
    v7 = pid;
    // father waits for child 1 to change state
    result = waitpid(pid, &stat_loc, 0);        
    if ( result == -1 )
      break;
    result = stat_loc;
    if ( (stat_loc & 0x7F) == 0 )
      break;
    // child 1 stopped by SIGTRAP
    if ( (_BYTE)stat_loc == 127 && BYTE1(stat_loc) == 5 ) { 
      p_stat_loc = pid;
      v7 = 12;
      ptrace(PTRACE_GETREGS, pid, 0LL, regs);
      result = -1;
      // check if ZF = 1
      if ( (eflags_reg & 0x40) != 0 ) {          
        rip_reg = dword_4D40[dword_4C80[cpt + 1]] + buffer1;
        p_stat_loc = pid;
        v7 = 13;
        ptrace(PTRACE_SETREGS, pid, 0LL, regs);
        result = 0;
      }
      break;
    }
  }
  
  return result;
}
```

The father is paused again and waits for the first child. Once it gets control back, it accesses its registers and checks if the zero flag is set:

```c
result = -1;
if ( (eflags_reg & 0x40) != 0 ) {
    // do something
    result = 0;
    break;
}
[...]

return result;
```

If not, the function terminates and returns <mark style="color:blue;">`-1`</mark> which results in a call to <mark style="color:blue;">`fail`</mark> inside <mark style="color:blue;">`check_input`</mark>:

```c
v8 = father_first_child_func(first_child_pid, (__int64)buffer1);
cpt++;
if ( v8 == -1 )
    fail();
```

The zero flag must be set. If it is the case this block is executed:

```c
rip_reg = dword_4D40[dword_4C80[cpt + 1]] + buffer1;
p_stat_loc = pid;
v7 = 13;
ptrace(PTRACE_SETREGS, pid, 0LL, regs);
result = 0;
```

Now this is interesting ! If the character being checked is correct, <mark style="color:blue;">`ptrace`</mark> is called with the request <mark style="color:blue;">`PTRACE_SETREGS`</mark>. So if use <mark style="color:blue;">`strace`</mark> to see calls to <mark style="color:blue;">`ptrace`</mark> we can try different characters and count occurrences of <mark style="color:blue;">`PTRACE_SETREGS`</mark>. Then, the right character will be the one with the most occurrences. This will work since each character is being check individualy.

### Bruteforce the flag

```py
import subprocess

def execute_program(i, j):
    global found, max_count, best_char_candidate

    # Execute $ strace ./nanocombattant
    process = subprocess.Popen(['strace', './nanocombattant'], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)

    # Send input to the program
    user_input = found + "a"*(19-len(found))
    string_list = list(user_input)
    string_list[i] = chr(j)
    user_input = "".join(string_list)
    
    # Retreive strace output
    out, err = process.communicate(user_input)

    # Count motif occurences
    count = err.count("PTRACE_SETREGS")
    
    char = ""
    if count > max_count:
        #print("({}: char, count): ({}; {})".format(i, chr(j), count))
        best_char_candidate = chr(j)
        max_count = count

    # Close the process
    process.terminate()
    
    return char

if __name__ == "__main__":
    found = ""
    # Bruteforce the flag
    for i in range(19):
        max_count = 0
        best_char_candidate = ""
        for j in range(32, 127):
            execute_program(i, j)
        found += best_char_candidate
    print("flag: ", found)
```

**404CTF{fi3r\_n4n0comb4ttant}**

## Appendix

To make the code of <mark style="color:blue;">`father_first_child_func`</mark> and <mark style="color:blue;">`father_second_child_func`</mark>  more understandable I mapped the local variables with the registers (see [here](/cyber/rev/anti-debugging/nanomites.md)).

{% hint style="success" %}
Mapping of registers and local variables for <mark style="color:blue;">`father_first_child_func`</mark>
{% endhint %}

<div align="center"><img src="https://github.com/SamNzo/CTFs/blob/main/404CTF/reverse/img/nanocombattants_father_child1.drawio.png?raw=true" alt="" width="500"></div>

{% hint style="success" %}
Mapping of registers and local variables for <mark style="color:blue;">`father_second_child_func`</mark>
{% endhint %}

<div align="center"><img src="https://github.com/SamNzo/CTFs/blob/main/404CTF/reverse/img/nanocombattants_father_child2.drawio.png?raw=true" alt="" width="500"></div>
