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
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}
.