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[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x01, 0x00, 0x03, 0x02, 0x05, 0x04, 0x07, 0x06, 0x09, 0x08, 0x0B, 0x0A, 0x0D, 0x0C, 0x0F, 0x0E, 0x02, 0x03, 0x00, 0x01, 0x06, 0x07, 0x04, 0x05, 0x0A, 0x0B, 0x08, 0x09, 0x0E, 0x0F, 0x0C, 0x0D, 0x03, 0x02, 0x01, 0x00, 0x07, 0x06, 0x05, 0x04, 0x0B, 0x0A, 0x09, 0x08, 0x0F, 0x0E, 0x0D, 0x0C, 0x04, 0x05, 0x06, 0x07, 0x00, 0x01, 0x02, 0x03, 0x0C, 0x0D, 0x0E, 0x0F, 0x08, 0x09, 0x0A, 0x0B, 0x05, 0x04, 0x07, 0x06, 0x01, 0x00, 0x03, 0x02, 0x0D, 0x0C, 0x0F, 0x0E, 0x09, 0x08, 0x0B, 0x0A, 0x06, 0x07, 0x04, 0x05, 0x02, 0x03, 0x00, 0x01, 0x0E, 0x0F, 0x0C, 0x0D, 0x0A, 0x0B, 0x08, 0x09, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00, 0x0F, 0x0E, 0x0D, 0x0C, 0x0B, 0x0A, 0x09, 0x08, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x09, 0x08, 0x0B, 0x0A, 0x0D, 0x0C, 0x0F, 0x0E, 0x01, 0x00, 0x03, 0x02, 0x05, 0x04, 0x07, 0x06, 0x0A, 0x0B, 0x08, 0x09, 0x0E, 0x0F, 0x0C, 0x0D, 0x02, 0x03, 0x00, 0x01, 0x06, 0x07, 0x04, 0x05, 0x0B, 0x0A, 0x09, 0x08, 0x0F, 0x0E, 0x0D, 0x0C, 0x03, 0x02, 0x01, 0x00, 0x07, 0x06, 0x05, 0x04, 0x0C, 0x0D, 0x0E, 0x0F, 0x08, 0x09, 0x0A, 0x0B, 0x04, 0x05, 0x06, 0x07, 0x00, 0x01, 0x02, 0x03, 0x0D, 0x0C, 0x0F, 0x0E, 0x09, 0x08, 0x0B, 0x0A, 0x05, 0x04, 0x07, 0x06, 0x01, 0x00, 0x03, 0x02, 0x0E, 0x0F, 0x0C, 0x0D, 0x0A, 0x0B, 0x08, 0x09, 0x06, 0x07, 0x04, 0x05, 0x02, 0x03, 0x00, 0x01, 0x0F, 0x0E, 0x0D, 0x0C, 0x0B, 0x0A, 0x09, 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00 }; unsigned int byte_60C180[] = { 0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80, 0x90, 0xA0, 0xB0, 0xC0, 0xD0, 0xE0, 0xF0, 0x10, 0x00, 0x30, 0x20, 0x50, 0x40, 0x70, 0x60, 0x90, 0x80, 0xB0, 0xA0, 0xD0, 0xC0, 0xF0, 0xE0, 0x20, 0x30, 0x00, 0x10, 0x60, 0x70, 0x40, 0x50, 0xA0, 0xB0, 0x80, 0x90, 0xE0, 0xF0, 0xC0, 0xD0, 0x30, 0x20, 0x10, 0x00, 0x70, 0x60, 0x50, 0x40, 0xB0, 0xA0, 0x90, 0x80, 0xF0, 0xE0, 0xD0, 0xC0, 0x40, 0x50, 0x60, 0x70, 0x00, 0x10, 0x20, 0x30, 0xC0, 0xD0, 0xE0, 0xF0, 0x80, 0x90, 0xA0, 0xB0, 0x50, 0x40, 0x70, 0x60, 0x10, 0x00, 0x30, 0x20, 0xD0, 0xC0, 0xF0, 0xE0, 0x90, 0x80, 0xB0, 0xA0, 0x60, 0x70, 0x40, 0x50, 0x20, 0x30, 0x00, 0x10, 0xE0, 0xF0, 0xC0, 0xD0, 0xA0, 0xB0, 0x80, 0x90, 0x70, 0x60, 0x50, 0x40, 0x30, 0x20, 0x10, 0x00, 0xF0, 0xE0, 0xD0, 0xC0, 0xB0, 0xA0, 0x90, 0x80, 0x80, 0x90, 0xA0, 0xB0, 0xC0, 0xD0, 0xE0, 0xF0, 0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x90, 0x80, 0xB0, 0xA0, 0xD0, 0xC0, 0xF0, 0xE0, 0x10, 0x00, 0x30, 0x20, 0x50, 0x40, 0x70, 0x60, 0xA0, 0xB0, 0x80, 0x90, 0xE0, 0xF0, 0xC0, 0xD0, 0x20, 0x30, 0x00, 0x10, 0x60, 0x70, 0x40, 0x50, 0xB0, 0xA0, 0x90, 0x80, 0xF0, 0xE0, 0xD0, 0xC0, 0x30, 0x20, 0x10, 0x00, 0x70, 0x60, 0x50, 0x40, 0xC0, 0xD0, 0xE0, 0xF0, 0x80, 0x90, 0xA0, 0xB0, 0x40, 0x50, 0x60, 0x70, 0x00, 0x10, 0x20, 0x30, 0xD0, 0xC0, 0xF0, 0xE0, 0x90, 0x80, 0xB0, 0xA0, 0x50, 0x40, 0x70, 0x60, 0x10, 0x00, 0x30, 0x20, 0xE0, 0xF0, 0xC0, 0xD0, 0xA0, 0xB0, 0x80, 0x90, 0x60, 0x70, 0x40, 0x50, 0x20, 0x30, 0x00, 0x10, 0xF0, 0xE0, 0xD0, 0xC0, 0xB0, 0xA0, 0x90, 0x80, 0x70, 0x60, 0x50, 0x40, 0x30, 0x20, 0x10, 0x00 }; 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[4 * m + n] = *(byte_60B080 + (4 * (((signed __int64)m << 8) + *(ptr + (unsigned __int8)(4 * l + m))) + n)); } } sub_4007A9(v18, v18 + 4, v13); sub_4007A9(v18 + 8, v18 + 12, v13 + 4); sub_4007A9(v13, v13 + 4, ptr + 4 * 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 |