Writeup: Secuinside CTF 2013 - PE Time

Information

  • Category: reverse

Description

We think something is hidden to this file…
http://war.secuinside.com/files/PE_time.zip

Writeup

Inside the archive we found a PE (as suggested by challenge title:) and a DLL:

  • PE_time.exe
  • msvcr110.dll

Our first question was why a standard dll were included in the challenge files, so we checked for possible modifications:

1
2
$ cat msvcr110.dll| md5sum
4ba25d2cbe1587a841dcfb8c8c4a6ea6 -

But after googling a minute we noticed that this md5 hash matches with the original DLL’s one, so we simply ignore this DLL for the rest of the analysis :)

Anyway, running PE_time.exe outputs a strange circular window with a background image.

We thought that the image inside the binary could contains “something hidden”, so we extract it using
resource extract.
Once, extracted we checked for evidences of stenography using a couple of scripts
but we didn’t find nothing suspicious.

In order to permanently delete the stenography hypothesis we googled for the original image and finally we notice that there is no difference between PE one and the original one (a pixel per pixel difference resulted in a completely black image).

Well, now its time for a bit of reversing with IDA :)

Once located the event handling routine (sub_4010F0 in my system) we noted that there were some code for handling a event we have no idea how to trigger..
and the body of the this event handling routine look pretty strange due to its algorithmic looking (there was some loop and a string comparison).
So maybe that was a good point where to investigate.

After this discover someone in the group (LMolr) suggested to eliminate the circular region and restore the original window shape.. well, maybe these are not the exact words.. but the meaning is the same :)

So, once found the call ds:SetWindowRgn we adopt the quick and dirty approach: NOP it all :)

The result was a square window with a new button and an input box.. and the button click triggers the strange handling routine! We were on the right way..

Going back to the assembler we notice that the strange loops inside the button handler were some kind of hashing function, and the result of the hashing of the input string were compared with a fixed 4-character value C;@R..
At that the goal were much more clear: we have to reverse the that hash because the original value could be the key.

The hashing algorithm were not to hard to understand, but considering the length of the code (4 chars) we decided to adopt another quick and dirty
approach.. reimplement the hashing function and then do a 2^32 brute force :)

With a bit of Hex-Rays magics we almost got the C code of this function, so the implementation was pretty straight forward..

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
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
#include < stdlib.h >
#include < stdio.h >
/*
BRUTE FORCE 2^32

INPUT 4 BYTE
TARGET "C;@R"
43h ; C
3Bh ; ;
40h ; @
52h ; R
0
Result:
53 45 43 55 –> 43 3b 40 52
‘SECU’ –> ‘C;@R’

*/
char * target = "C;@R";

unsigned char window_text_char0;
unsigned char window_text_char1;
unsigned char window_text_char2;
unsigned char window_text_char3;

void doIt(unsigned char *try) {
int counter_5, counter_4, counter_3, counter_2;
window_text_char0 = try [0];
window_text_char1 = try [1];
window_text_char2 = try [2];
window_text_char3 = try [3];

counter_5 = 5;
do {
window_text_char0 -= counter_5;
window_text_char0 ^= 0× 03;–
counter_5;
} while (counter_5);
counter_4 = 4;
do {
window_text_char1 -= counter_4;
window_text_char1 ^= 0× 04;–
counter_4;
} while (counter_4);
counter_3 = 3;
do {
window_text_char2 -= counter_3;
window_text_char2 ^= 0× 05;–
counter_3;
} while (counter_3);
counter_2 = 2;
do {
window_text_char3 -= counter_2;
window_text_char3 ^= 0× 06;–
counter_2;
} while (counter_2);
}

void printall(unsigned char *
try) {
printf("Results: \n");
printf("(hex) % 0x % 0x % 0x % 0x - > % 0x % 0x % 0x % 0x\ n",
try [0],
try [1],
try [2],
try [3],
window_text_char0, window_text_char1, window_text_char2,
window_text_char3);
printf("(chr) % c % c % c % c - > % c % c % c % c\ n",
try [0],
try [1],
try [2],
try [3],
window_text_char0, window_text_char1, window_text_char2,
window_text_char3);
}
int check() {
if (window_text_char0 == target[0] &&
window_text_char1 == target[1] &&
window_text_char2 == target[2] &&
window_text_char3 == target[3]) {
return 1;
} else {
return 0;
}
}

int main(int argc, char * argv[]) {
unsigned char temp[4];
unsigned int a, b, c, d;
for (a = 0; a <= 255; a++) {
printf(".");
for (b = 0; b <= 255; b++) {
for (c = 0; c <= 255; c++) {
for (d = 0; d <= 255; d++) {
temp[0] = a;
temp[1] = b;
temp[2] = c;
temp[3] = d;
doIt(temp);
if (check()) {
printf("\n");
printall(temp);
exit(0);
}
}
}
}
}
printf("\nSomething wrong..Nothing found!\n");
}

Flag

1
SECU