본문 바로가기

CTFs/Plaid 2014

[Plaid 2014] reversing : hudak

hudak

This Challenge is one of my interesting RE probs what the idea was quiet awesome!


- Static Analysis

Given prob is x86 stripped elf binary.

1
2
zero@ubuntu:~/Desktop$ file hudak
hudak: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked, interpreter stripped
cs

let's open with IDA!


First, we can see password check routine and get string from stdin.

1
2
3
4
5
6
7
8
9
10
11
// - main func
 __printf_chk(1"Enter the password.\n");
 get_string(0&buffer, 8010);
 if ( strlen(&buffer) == 30 ) {
 ....
 }
 
// - get_string func
...
  *(buffer - 1= 0xFFu;
...
cs

As we could see, buffer size is 80 bytes and data is scanned with get_string (using read() internally) func filling last byte with 0xff.

And checking if buffer's length is 30 bytes ( actually 29 bytes because of 0xff )


After comparing length with 30(29), 0x080489F0 func which is calling another func and compares processed final data with hard-coded data by using memcmp() is called.

Hard-corded is 32 bytes length data. like below.

1
2
04 19 19 68 43 41 5B 04  C8 44 43 43 43 40 45 47
68 68 06 5A 52 56 03 56  44 03 5E 06 68 19 00 00
cs

0x08048690 func :

I think that this function just returns index of array ( or pointer ). It means useless


0x8048900 func :

This function works as rotating 1 byte to left 30 times like below

1
2
3
4
5
6
7
8
9
10
// - 0x8048770 func
    if ( len > 0 ) // rotate
    {
      i = 0;
      do
      {
        arr[i] = *(buf + (v7 + i) % len);
        ++i;
      }
      while ( len > i );
cs


1
2
3
4
5
6
7
8
9
10
// Result of 0x8048900 func
// i'll set \xff as - for convience
input[0]  = abcdefghijklmnopqrstuvwxyz012-
input[1]  = bcdefghijklmnopqrstuvwxyz012-a
input[2]  = cdefghijklmnopqrstuvwxyz012-ab
...
input[26= 012-abcdefghijklmnopqrstuvwxyz
input[27= 12-abcdefghijklmnopqrstuvwxyz0
input[28= 2-abcdefghijklmnopqrstuvwxyz01
input[29= -abcdefghijklmnopqrstuvwxyz012
cs


0x8048810 func :

This is the most important function! This function does bubble-sort whole list ( input )

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// - 0x8048810 func
      do
      {
        if ( v10 > 0 )
        {
          v7 = 0;
          do
          {
            v8 = v5[v7 + 1];
            v9 = v5[v7];
            if ( memcmp(v5[v7], v5[v7 + 1], v11) > 0 )
            {
              v5[v7] = v8;
              v5[v7 + 1= v9;
            }
            ++v7;
          }
          while ( v7 != v10 );
        }
        ++v12;
      }
      while ( v11 > v12 );
cs


1
2
3
4
5
6
7
8
9
// -> Result of 0x4048810
input[26= 012-abcdefghijklmnopqrstuvwxyz
input[27= 12-abcdefghijklmnopqrstuvwxyz0
input[28= 2-abcdefghijklmnopqrstuvwxyz01
input[0]  = abcdefghijklmnopqrstuvwxyz012-
input[1]  = bcdefghijklmnopqrstuvwxyz012-a
input[2]  = cdefghijklmnopqrstuvwxyz012-ab
...
input[29= -abcdefghijklmnopqrstuvwxyz012
cs


0x80486E0 func :

Extract last byte of 'processed data' ( above data ) and xor with 0x37.

1
2
3
4
5
6
7
// - 0x80486e0 func
      do
      {
        result[v8 - 1= *(*(v4 + 4 * v8 - 4+ v6) ^ 0x37;
        ++v8;
      }
      while ( v8 != v7 );
cs

Back to 0x80489f0 function, xored data is compared with hard-coded data what i mentioned above.

1
2
// - 0x80489f0 func
  return memcmp(&table, v5, 31u) == 0;
cs

Of course, if 'memcpy(...) == 0' is true, we can see "congrat" message on screen.


Now all we have to do is xor hard-coded with 0x37 ( because xor can be reversible )

let's write following C program.

1
2
3
4
5
6
7
8
9
10
11
#include <stdio.h>
 
unsigned char table[32= {
    0x040x190x190x680x430x410x5B0x040xC80x440x430x43,
    0x430x400x450x470x680x680x060x5A0x520x560x030x56,
    0x440x030x5E0x060x680x190x000x00
};
 
void main() {
    for (int i = 0; i < 32; (i % 16 != 15) ? printf("%#x ", table[i] ^ 0x37) : printf("%#x\n", table[i] ^ 0x37), ++i);
}
cs

1
2
3
4
5
6
// - Hex Result 
0x33 0x2e 0x2e 0x5f 0x74 0x76 0x6c 0x33 0xff 0x73 0x74 0x74 0x74 0x77 0x72 0x70
0x5f 0x5f 0x31 0x6d 0x65 0x61 0x34 0x61 0x73 0x34 0x69 0x31 0x5f 0x2e 0x37 0x37
 
// - String ( 0xff ->'-' )
3.._tvl3-stttwrp__1mea4as4i1_.77
cs

So, The result data will be the last byte of each lists.

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
???????????????????????????????3
???????????????????????????????.
???????????????????????????????.
???????????????????????????????_
???????????????????????????????t
???????????????????????????????v
???????????????????????????????l
???????????????????????????????3
???????????????????????????????-
???????????????????????????????s
???????????????????????????????t
???????????????????????????????t
???????????????????????????????t
???????????????????????????????w
???????????????????????????????r
???????????????????????????????p
???????????????????????????????_
???????????????????????????????_
???????????????????????????????1
???????????????????????????????m
???????????????????????????????e
???????????????????????????????a
???????????????????????????????4
???????????????????????????????a
???????????????????????????????s
???????????????????????????????4
???????????????????????????????i
???????????????????????????????1
???????????????????????????????_
???????????????????????????????.
cs

As we think about it, we can guess first byte of each lists. Because whole lists are bubble-sorted.

Then straight line of 'first bytes' is sorted! So ...

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
.??????????????????????????????3
.??????????????????????????????.
.??????????????????????????????.
1??????????????????????????????_
1??????????????????????????????t
3??????????????????????????????v
3??????????????????????????????l
4??????????????????????????????3
5??????????????????????????????-
_??????????????????????????????s
_??????????????????????????????t
_??????????????????????????????t
_??????????????????????????????t
a??????????????????????????????w
a??????????????????????????????r
e??????????????????????????????p
i??????????????????????????????_
l??????????????????????????????_
m??????????????????????????????1
p??????????????????????????????m
r??????????????????????????????e
s??????????????????????????????a
s??????????????????????????????4
t??????????????????????????????a
t??????????????????????????????s
t??????????????????????????????4
t??????????????????????????????i
v??????????????????????????????1
w??????????????????????????????_
-??????????????????????????????.
cs

And we can also guess the flag's first 2 bytes because each list will rotate and rotate then someday that 2 chars will stick together.

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
3.
..
..
_1
t1
v3
l3
34
-5
s_
t_
wa
ra
pe
_i
_l
1m
mp
er
as
4s
at
st
4t
it
1v
_w
.-
cs

But there are a lot of cases to guess. We need to narrow down the cases.


I think that 30 byte ( include 0xff ) is the final flag then it could be readable.

It means it doesn't start with bytes like '0xff', '.', '_' and ends with 0xff. There is one case which ends with 0xff -> '.-'

With these clues i narrow down the cases like below.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
t1
v3
l3
34
wa
ra
pe
1m
mp
er
as
4s
at
st
4t
it
1v
cs

First 2 bytes would be on that list and last byte is '.'.


With more search, we can guess string with string segment like below.

"??????????????????????????...", last byte is '.' but there are 2 segs '..' and '3.'. I think Using '3.' is improper to make flag than '..'. 

"_was_", there are string segments ( _w , wa, as, st or s_ ). start and end with 'w' is only _w, wa.


I just made 3 chars groups in list like 'was', '...' by following process. Then connect them one by one.

With Following process, i can reach the answer like below.

1
2
3
4
5
6
7
8
9
??????????????????????????...
_was_
_it_was_
1mperat1v3...
 
????????_it_was_1mperat1v3...
??????st_it_was_1mperat1v3... // cannot be 'at'
????34st_it_was_1mperat1v3... // cannot be 'as'
4t_l34st_it_was_1mperat1v3... // already 'at' is used
cs

So the flag is 4t_l34st_it_was_1mperat1v3...


Let's check it out!

1
2
3
4
zero@ubuntu:~/Desktop$ ./hudak
Enter the password.
4t_l34st_it_was_1mperat1v3...
Congratulations! :)
cs

'CTFs > Plaid 2014' 카테고리의 다른 글

[Plaid 2014] pwnable : kappa  (0) 2016.08.27
[Plaid 2014] pwnable : ezhp  (0) 2016.08.27
[Plaid 2014] forensic : zfs  (0) 2016.08.27
[Plaid 2014] forensic : rsa  (0) 2016.08.27
[Plaid 2014] forensic : curlcore  (0) 2016.08.27