본문 바로가기

CTF

YISF 2017 본선 풀이(x)

YISF 2017 본선에 나왔던 리버싱 문제 reversing_table-based-aes 입니다.

문제파일 https://github.com/Gyeongje/CTF/tree/master/YISF%202017/Reversing-final


해당 파일은 ELF파일이며 암호화된 16자리 문자열을 복호화하면 플래그가 나올것으로 보이는 문제입니다.



메인함수를 보면 aes 128과 흡사한 암호화내용이 보입니다. 

일단 메인함수에 있는 암호화 내용과 sub_4006A6, sub_4006A6 함수내용에 있는 암호화로 이루어져 있습니다.

암호화는 보통 byte 배열에 있는 값으로 이루어지는데 최대한 비슷하게 프로그램을 짜보았습니다.


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
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include <Windows.h>
 
char *byte_value(char a[]);
char *byte_value2(char a[]);
void sub_4006A6(char *ptr);
void sub_4007A9(char *a1, char *a2, char *a3);
 
unsigned int byte_60C080[] = { 0x000x010x020x030x040x050x060x070x080x090x0A0x0B0x0C0x0D,
0x0E0x0F0x010x000x030x020x050x040x070x060x090x080x0B,
0x0A0x0D0x0C0x0F0x0E0x020x030x000x010x060x070x040x05,
0x0A0x0B0x080x090x0E0x0F0x0C0x0D0x030x020x010x000x070x06,
0x050x040x0B0x0A0x090x080x0F0x0E0x0D0x0C0x040x050x06,
0x070x000x010x020x030x0C0x0D0x0E0x0F0x080x090x0A0x0B,
0x050x040x070x060x010x000x030x020x0D0x0C0x0F0x0E0x090x08,
0x0B0x0A0x060x070x040x050x020x030x000x010x0E0x0F0x0C,
0x0D0x0A0x0B0x080x090x070x060x050x040x030x020x010x00,
0x0F0x0E0x0D0x0C0x0B0x0A0x090x080x080x090x0A0x0B0x0C0x0D,
0x0E0x0F0x000x010x020x030x040x050x060x070x090x080x0B,
0x0A0x0D0x0C0x0F0x0E0x010x000x030x020x050x040x070x06,
0x0A0x0B0x080x090x0E0x0F0x0C0x0D0x020x030x000x010x060x07,
0x040x050x0B0x0A0x090x080x0F0x0E0x0D0x0C0x030x020x01,
0x000x070x060x050x040x0C0x0D0x0E0x0F0x080x090x0A0x0B,
0x040x050x060x070x000x010x020x030x0D0x0C0x0F0x0E0x090x08,
0x0B0x0A0x050x040x070x060x010x000x030x020x0E0x0F0x0C,
0x0D0x0A0x0B0x080x090x060x070x040x050x020x030x000x01,
0x0F0x0E0x0D0x0C0x0B0x0A0x090x080x070x060x050x040x030x020x010x00 };
 
unsigned int byte_60C180[] = { 0x000x100x200x300x400x500x600x700x800x900xA00xB00xC00xD0,
0xE00xF00x100x000x300x200x500x400x700x600x900x800xB00xA0,
0xD00xC00xF00xE00x200x300x000x100x600x700x400x500xA00xB0,
0x800x900xE00xF00xC00xD00x300x200x100x000x700x600x500x40,
0xB00xA00x900x800xF00xE00xD00xC00x400x500x60,
0x700x000x100x200x300xC00xD00xE00xF00x800x900xA00xB0,
0x500x400x700x600x100x000x300x200xD00xC00xF00xE00x900x80,
0xB00xA00x600x700x400x500x200x300x000x100xE00xF00xC00xD0,
0xA00xB00x800x900x700x600x500x400x300x200x100x000xF00xE0,
0xD00xC00xB00xA00x900x800x800x900xA00xB00xC00xD00xE00xF0,
0x000x100x200x300x400x500x600x700x900x800xB0,
0xA00xD00xC00xF00xE00x100x000x300x200x500x400x700x60,
0xA00xB00x800x900xE00xF00xC00xD00x200x300x000x100x600x70,
0x400x500xB00xA00x900x800xF00xE00xD00xC00x300x200x10,
0x000x700x600x500x400xC00xD00xE00xF00x800x900xA00xB0,
0x400x500x600x700x000x100x200x300xD00xC00xF00xE00x900x80,
0xB00xA00x500x400x700x600x100x000x300x200xE00xF00xC0,
0xD00xA00xB00x800x900x600x700x400x500x200x300x000x10,
0xF00xE00xD00xC00xB00xA00x900x800x700x600x500x400x300x200x100x00 };
 
int main()
{
    int i, j, k, l, m, n;
    unsigned char flag[17= "abcdefghijklmnop";
 
    unsigned char *ptr;
    unsigned char v18[16= { 0, };
    unsigned char v13[16= { 0, };
    ptr = flag;
 
    unsigned char *byte_601080 = byte_value("C:/test/reversing_table-based-aes/byte_601080");
    unsigned char *byte_60B080 = byte_value2("C:/test/reversing_table-based-aes/byte_60B080");
    for (j = 1; j < 10; j++)
    {
        sub_4006A6(ptr);
        for (k = 0; k < 16; k++)
            *(ptr + k) = *(byte_601080 + (256 * (16 * (j - 1+ k)) + *(ptr + k));
        for (l = 0; l < 4; l++)
        {
            for (m = 0; m < 4; m++)
            {
                for (n = 0; n < 4; n++)
                {
                    v18[* m + n] = *(byte_60B080 + (* (((signed __int64)m << 8+ *(ptr + (unsigned __int8)(* l + m))) + n));
                }
            }
            sub_4007A9(v18, v18 + 4, v13);
            sub_4007A9(v18 + 8, v18 + 12, v13 + 4);
            sub_4007A9(v13, v13 + 4, ptr + * l);
        }
    }
    sub_4006A6(ptr);
    for (i = 0; i < 16; i++)
    {
        *(ptr + i) = *(byte_601080 + (256 * i + 36864+ *(ptr + i));
    }
 
    for (i = 0; i < 16; i++)
        printf("%02X "*(i + ptr));
    puts("");
    for (i = 0; i < 16; i++)
        printf("%c "*(i + ptr));
    puts("");
 
    free(byte_601080);
    free(byte_60B080);
    return 0;
}
 
char *byte_value(char a[])
{
    FILE *f;
    int n = 0, i = 0;
    char data;
 
    f = fopen(a, "rb");
 
    while (fscanf(f, "%c"&data) != EOF)
        n++;
    fclose(f);
 
    unsigned char *byte_601080 = (char*)malloc(sizeof(char)*(n));
 
    f = fopen(a, "rb");
    while (fscanf(f, "%c"&data) != EOF) {
        byte_601080[i] = data;
        i++;
    }
    fclose(f);
 
    return byte_601080;
}
 
char *byte_value2(char a[])
{
    FILE *f;
    int n = 0, i = 0;
    char data;
 
    f = fopen(a, "rb");
 
    while (fscanf(f, "%c"&data) != EOF)
        n++;
    fclose(f);
 
    unsigned char *byte_60B080 = (char*)malloc(sizeof(char)*(n));
 
    f = fopen(a, "rb");
    while (fscanf(f, "%c"&data) != EOF) {
        byte_60B080[i] = data;
        i++;
    }
 
    fclose(f);
    return byte_60B080;
}
 
void sub_4006A6(char *ptr)
{
    char v2;
    char v3;
    char v4;
    unsigned __int8 v5;
 
    v2 = *(ptr + 1);
    *(ptr + 1= *(ptr + 5);
    *(ptr + 5= *(ptr + 9);
    *(ptr + 9= *(ptr + 13);
    *(ptr + 13= v2;
    v3 = *(ptr + 2);
    *(ptr + 2= *(ptr + 10);
    *(ptr + 10= v3;
    v4 = *(ptr + 6);
    *(ptr + 6= *(ptr + 14);
    *(ptr + 14= v4;
    v5 = *(ptr + 15);
    *(ptr + 15= *(ptr + 11);
    *(ptr + 11= *(ptr + 7);
    *(ptr + 7= *(ptr + 3);
    *(ptr + 3= v5;
}
 
void sub_4007A9(char *a1, char *a2, char *a3)
{
    BYTE *result;
 
    for (int i = 0; i < 4; i++)
    {
        result = (a3 + i);
        *result = byte_60C180[(unsigned __int64)(unsigned __int8)((*(i + a1) & 0xF0+ ((*(i + a2) & 0xF0>> 4))]
            + byte_60C080[(unsigned __int64)(unsigned __int8)(16 * *(i + a1) + (*(a2 + i) & 0xF))];
    }
}
cs


byte_601080, byte_60B080 두개의 바이트 값들은 크기가 너무 큰 관계로 파일로 불러들여 연산을 진행하였습니다

16자리 플래그 평문을 모르는 상황이여서 "abcdefghijklmnop" 라는 임의의 16자리 문자열로 대체해 프로그램을 작성하였습니다

(실제 ELF 프로그램에 abcdefghijklmnop 를 넣고 나온 암호화 내용과 직접 짠 프로그램에서 나온 암호화 내용은 동일합니다)


하지만 복호화 하는 과정에서 일반 byte 값 치환과 sub_4006A6 암호화 함수는 쉽게 복호화 코드를 짤수 있었지만

sub_4007A9 함수 같은 경우에는 역연산이 제 머리로는 한계가 와 진행이 되지 않았습니다.


더이상 역연산이 불가능해 보여 brute force 를 생각해보았지만 만약 대회 상황에서 brute force 를 한다고 가정하면 시간이 너무 오래걸려 대회가 끝나고 한참 지나야 답이 나올거 같아 보였습니다.


이 프로그램 자체는 aes암호화 라는 걸 파일이름으로 이미 힌트를 주었던 상황이기 때문에 aes 암호화에 관한 자료를 더 찾아보고 복호화를 진행해야 겠습니다 (문제풀이 보류)

 

'CTF' 카테고리의 다른 글

제 12회 정보보호올림피아드 예선풀이  (2) 2017.10.30
ASIS CTF Final 2017 Write up (ABC Reversing challenge)  (0) 2017.09.19
YISF 2017 write up  (0) 2017.08.09
DIMICTF 2017 write up  (0) 2017.07.16
[CODEAGATE 2017] Junior write up  (2) 2017.02.15