TJCTF2020 - Gym

Posted on mar. 02 juin 2020 in CTF

solves : 382

Points: 20

Written by agcdragon

Aneesh wants to acquire a summer bod for beach week, but time is running out. Can you help him create a plan to attain his goal?

nc p1.tjctf.org 8008

gym

We have a small game. The goal is to loose 31 lbs (211-180).

╰─ ./bed9d7b7327958dab4d07b06772a032f3e97455e310956558579e8838762b5e2_gym
I'm currently 211 lbs. Can I be exactly 180? Help me out!
-------------------------
Today is day 1.

Choose an activity:
[1] Eat healthy
[2] Do 50 push-ups
[3] Go for a run.
[4] Sleep 8 hours.

We add the binary to IDA and try to reverse it.

We can show each function and get how many lbs are remove from the total:

eat_healthy

                public eat_healthy
eat_healthy     proc near               ; CODE XREF: main+16E↓p

var_14          = dword ptr -14h
var_4           = dword ptr -4

; __unwind {
                push    rbp
                mov     rbp, rsp
                mov     [rbp+var_14], edi
                mov     [rbp+var_4], 4
                mov     eax, [rbp+var_4]
                pop     rbp
                retn
; } // starts at 95A
eat_healthy     endp

do_pushup

                public do_pushup
do_pushup       proc near               ; CODE XREF: main+183↓p

var_14          = dword ptr -14h
var_4           = dword ptr -4

; __unwind {
                push    rbp
                mov     rbp, rsp
                mov     [rbp+var_14], edi
                mov     [rbp+var_4], 1
                mov     eax, [rbp+var_4]
                pop     rbp
                retn
; } // starts at 96D
do_pushup       endp

go_run

                public go_run
go_run          proc near               ; CODE XREF: main+198↓p

var_14          = dword ptr -14h
var_4           = dword ptr -4

; __unwind {
                push    rbp
                mov     rbp, rsp
                mov     [rbp+var_14], edi
                mov     [rbp+var_4], 2
                mov     eax, [rbp+var_4]
                pop     rbp
                retn
; } // starts at 980
go_run          endp

go_sleep

                public go_sleep
go_sleep        proc near               ; CODE XREF: main+1AB↓p

var_14          = dword ptr -14h
var_4           = dword ptr -4

; __unwind {
                push    rbp
                mov     rbp, rsp
                mov     [rbp+var_14], edi
                mov     [rbp+var_4], 3
                mov     eax, [rbp+var_4]
                pop     rbp
                retn
; } // starts at 993
go_sleep        endp

Nice! We know the value for each action :

Action Value
Eat healthy 4
Do 50 push-ups 1
Go for a run. 2
Sleep 8 hours. 3

A quick check make the thing impossible since we have only 7 days (7 * 4 = 28).

Let's check how the main function is build:

int __cdecl main(int argc, const char **argv, const char **envp)
{
  int v3; // eax
  signed int v5; // [rsp+Ch] [rbp-A4h]
  unsigned int i; // [rsp+10h] [rbp-A0h]
  FILE *stream; // [rsp+18h] [rbp-98h]
  char s; // [rsp+20h] [rbp-90h]
  char v9; // [rsp+60h] [rbp-50h]
  unsigned __int64 v10; // [rsp+A8h] [rbp-8h]

  v10 = __readfsqword(0x28u);
  v5 = 211;
  setbuf(stdout, 0LL);
  setbuf(stdin, 0LL);
  setbuf(stderr, 0LL);
  printf("I'm currently %d lbs. Can I be exactly 180? Help me out!", 211LL);
  for ( i = 1; (signed int)i <= 7; ++i )
  {
    printf("\n-------------------------");
    printf("\nToday is day %d.\n", i);
    printf("\nChoose an activity:");
    printf("\n[1] Eat healthy");
    printf("\n[2] Do 50 push-ups");
    printf("\n[3] Go for a run.");
    printf("\n[4] Sleep 8 hours.");
    puts("\n");
    fgets(&s, 4, stdin);
    v3 = atoi(&s);
    if ( v3 == 2 )
    {
      v5 -= do_pushup(i, 4LL);
      continue;
    }
    if ( v3 > 2 )
    {
      if ( v3 == 3 )
      {
        v5 -= go_run(i, 4LL);
LABEL_12:
        v5 -= go_sleep(i, 4LL);
        continue;
      }
      if ( v3 == 4 )
        goto LABEL_12;
    }
    else if ( v3 == 1 )
    {
      v5 -= eat_healthy(i, 4LL);
    }
  }
  sleep(3u);
  if ( v5 == 180 )
  {
    stream = fopen("flag.txt", "r");
    if ( !stream )
    {
      puts("Flag File is Missing. Contact a moderator if running on server.");
      exit(0);
    }
    fgets(&v9, 64, stream);
    puts("Congrats on reaching your weight goal!");
    printf("Here is your prize: %s\n", &v9);
  }
  else
  {
    puts("I didn't reach my goal :(");
  }
  return 0;
}

Oh! We see something really nice:

      if ( v3 == 3 )
      {
        v5 -= go_run(i, 4LL);
LABEL_12:
        v5 -= go_sleep(i, 4LL);
        continue;
      }

So. If we select the action 3 (Go for a run), the program make a sleep right after. We loose the weight for run and sleep, that makes a total of 5 lbs for each run.

Yes can get the value of 31 as the follow pattern : Run, Run, Run, Run, Run, Sleep and Sleep.

We input these choices and got back the flag: tjctf{w3iGht_l055_i5_d1ff1CuLt}.