Tag List
Sign In

IRCWare

IRCWare

Overview

IRCWare is a program that connects to 127.0.0.1:8000 and acts as an IRC Client, when it first connects it sends the following 'commands':

NICK ircware_5115
USER ircware 0 * :ircware
JOIN #secret

Analyzing the program in radare2 we see that it uses no library functions, and does all IO by making syscalls itself:

After connecting to the socket and printing it's opening message, the program enters a loop of reading input into a buffer, and processing the input:

The program accepts the following commands:

Cracking the password

To check if the password is correct, the program first copies 'RJJ3DSCP' into a buffer, then loops over each input of the input password, mutating the performing some obscure checks along the way, if the end of the loop is reached then the password was correct:

To solve this I rewrote the password checking code as a C program:

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

int main(int argc, char **argv) {
  char user_inp[8];
  memcpy(user_inp, argv[1], 8);
  char pw[] = "RJJ3DSCP";
  char pw2[] = "RJJ3DSCP";

  int i = 0;

  while (1) {
    char x = user_inp[i];
    pw2[i] = x;
    if ((x == 0) || (x == 10) || (x == 0xd)) {
      if (i == 8) {
        printf("good\n");
      }
      break;
    }
    if (i >= 8)
      break;

    char y = x;
    if (((0x40 < x) && (x < 0x5b)) && ((y = x + 0x11), 0x5a < y)) {
      y = x - 9;
    }

    if (y != pw[i]) {
      break;
    }

    i += 1;
  }

  printf("bad");
}

And then wrote a wrapper that would find the password using Angr:

import angr
import claripy

input_len = 8

p = angr.Project("a.out", main_opts={"base_addr": 0}, auto_load_libs=False)

input_ = [claripy.BVS(f'inp_{i}', 8) for i in range(input_len)]
input_a = claripy.Concat(*input_, 0)


st = p.factory.entry_state(
        args=["./a.out", input_a],
        add_options={angr.options.ZERO_FILL_UNCONSTRAINED_MEMORY},
        )

sm = p.factory.simulation_manager(st)
sm.explore(find=0x11f8, avoid=0x128b)

for x in sm.found:
    path = x.solver.eval_upto(input_a, 1, cast_to = bytes)
    print(path)

Running this, angr quickly found the flag:

Now we can claim the flag: