# CSICTF2020 - Blaise

## Description
`I recovered a binary from my teacher's computer. I tried to reverse it but I couldn't.`

## Analysis
First, I ran the code.

d@d:~$ ./blaise

At this point, it was not clear what the executable did or wanted, so I entered random numbers until the process finished. It ended up exiting with no message.

Unsure what the binary did, I decompiled it with Ghidra. Below is the `main` function after some tidying:

int main(void) {
time_t rseed;
ulong x;

setbuf(stdout,(char *)0x0);
setbuf(stdin,(char *)0x0);
setbuf(stderr,(char *)0x0);

rseed = time((time_t *)0x0);
x = display_number(0xf,0x14);
return 0

`main` sets a seed for a random number generator and calls `display_number` (decompiled below).

ulong display_number(int arg1,int arg2)

int x;
uint ret;

x = rand();
ret = arg1 + x % ((arg2 - arg1) + 1);
return (ulong)ret;

`display_number` just uses the random number generator to get a number.

Following the list of functions called in `main`, I looked at `process` (decompiled below).

int process(int x)

long key;
long in_FS_OFFSET;
int local_1c;
int i;
long lVar1;
bool flag;

lVar1 = *(long *)(in_FS_OFFSET + 0x28);
flag = true;
i = 0;
while (i <= x) {
key = C(x,i);
if ((int)key != local_1c) {
flag = false;
i = i + 1;
if (flag) {
system("cat flag.txt");
if (lVar1 != *(long *)(in_FS_OFFSET + 0x28)) {
/* WARNING: Subroutine does not return */
return 0;

I assumed the `__isoc99_scanf()` call wrote into `local_1c`. Usually, there should be parameters given for the `__isoc99_scanf()` (or atleast in IDA).

Assuming the previous, it is clear that we are given a challenge `x` times, where `x` is the randomly generated number from `display_number`. At each iteration, the challenge generates `key` using function call `C(x, i)` and checks that the user input matches. If the `flag` remains `true` after the challenges, we get the flag. If any of the user's answers are incorrect, the `flag` is set to false. So, if we understand how `C` (below) works, we can automate the process of answering the challenges.

long C(int x,int i)

long a;
long b;
long c;

a = f(x);
b = f(i);
c = f(x - i);
return a / (b * c);

I then looked at `f`.

long f(int d)

int i;
long result;

result = 1;
i = 2;
while (i <= d) {
result = i * result;
i = i + 1;
return result;

It turned out that `f` is the factorial function and `C` is nCr, nCk, binomial coefficients, etc...

Understanding the executable better, we wrote the following script.

## Solution
The following script defines a function for computing nCr and uses it to interact and solve the challenges from `./blaise`.

from pwn import *
import operator as op
from functools import reduce

def ncr(n, r):
r = min(r, n-r)
num = reduce(op.mul, range(n, n-r, -1), 1)
den = reduce(op.mul, range(1, r+1), 1)
return num // den

target = remote("chall.csivit.com", 30808)
# local
# target = process("./blaise")

line = int(target.recvline().strip().split()[0])
for i in range(line+1):
result = ncr(line, i)


Running this got us the flag!

d@d:~/$ python3 solver.py
[+] Opening connection to chall.csivit.com on port 30808: Done

Original writeup (https://github.com/dancwpark/ctf_writeups/tree/master/CSICTF2020/Blaise).