Notice
Recent Posts
Recent Comments
Link
«   2024/10   »
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
Archives
Today
Total
관리 메뉴

수호의 메모장

[dreamhack, rev] Permpkin writeup 본문

Security/Reverse Engineering

[dreamhack, rev] Permpkin writeup

수호-_- 2023. 11. 20. 21:24

https://dreamhack.io/wargame/challenges/981

 

Permpkin

Description chall 바이너리를 실행하여 플래그를 어떠한 연산을 거쳐 나온 결과를 flag1.txt와 flag2.txt로 저장하였습니다. 사용자는 chall 을 실행하여 sample flag를 연산한 후 rev1.txt와 rev2.txt 파일을 생성

dreamhack.io

 

IDA로 main 함수를 열어보면 아래와 같이 되어 있다:

__int64 __fastcall main(int a1, char **a2, char **a3)
{
  size_t v3; // rbx
  size_t v4; // rbx
  char v6[32]; // [rsp+0h] [rbp-B0h] BYREF
  char v7[32]; // [rsp+20h] [rbp-90h] BYREF
  char v8[32]; // [rsp+40h] [rbp-70h] BYREF
  char s[24]; // [rsp+60h] [rbp-50h] BYREF
  FILE *v10; // [rsp+78h] [rbp-38h]
  int v11; // [rsp+84h] [rbp-2Ch]
  FILE *stream; // [rsp+88h] [rbp-28h]
  int v13; // [rsp+90h] [rbp-20h]
  int k; // [rsp+94h] [rbp-1Ch]
  int j; // [rsp+98h] [rbp-18h]
  int i; // [rsp+9Ch] [rbp-14h]

  strcpy(s, "_this_is_sample_flag_");
  strcpy(v8, "this_is_sample_flag");
  strcpy(v7, "CC2A750B63821F45AC20839");
  for ( i = 0; i <= 22; ++i )
    v6[i] = sub_126E((unsigned int)v7[i]);
  v13 = strlen(s);
  sub_11FD(s, 0LL, (unsigned int)(v13 - 1), v6);
  sub_12E7(s, v6);
  stream = fopen("rev1.txt", "wb");
  for ( j = 0; ; ++j )
  {
    v3 = j;
    if ( v3 >= strlen(s) )
      break;
    fprintf(stream, "%d ", (unsigned int)s[j]);
  }
  fclose(stream);
  v11 = strlen(v8);
  sub_11FD(v8, 0LL, (unsigned int)(v11 - 1), v6);
  sub_12E7(v8, v6);
  v10 = fopen("rev2.txt", "wb");
  for ( k = 0; ; ++k )
  {
    v4 = k;
    if ( v4 >= strlen(v8) )
      break;
    fprintf(v10, "%d ", (unsigned int)v8[k]);
  }
  fclose(v10);
  return 0LL;
}

 

핵심만 보자:

 

이를 라벨링 해준다

구조가 좀 보이는가?

 

enc1는 아래와 같이 생겼다:

 

sub_11C9는 swap 함수이다.

 

enc2는 아래와 같다:

__int64 __fastcall enc2(const char *a1, const char *a2)
{
  __int64 result; // rax
  int v3; // [rsp+14h] [rbp-Ch]
  int v4; // [rsp+18h] [rbp-8h]
  int j; // [rsp+1Ch] [rbp-4h]
  signed int k; // [rsp+1Ch] [rbp-4h]
  unsigned int i; // [rsp+1Ch] [rbp-4h]

  v4 = strlen(a2);
  v3 = strlen(a1);
  if ( v3 <= v4 )
  {
    for ( i = 0; ; ++i )
    {
      result = i;
      if ( (int)i >= v3 )
        break;
      a1[i] ^= a2[i];
    }
  }
  else
  {
    for ( j = 0; j < v4; ++j )
      a1[j] ^= a2[j];
    for ( k = v4; ; ++k )
    {
      result = (unsigned int)k;
      if ( k >= v3 )
        break;
      a1[k] ^= a2[k % v4];
    }
  }
  return result;
}

 

 

enc2의 경우 간단한 XOR 연산을 취하고 있는 함수이기에 암호문과 키를 그대로 다시 넣어주면 역산이 된다.

enc1의 역산만 구현해 주면 풀 수 있다.

 

 

code:

#include <Windows.h>
#include <iostream>
using namespace std;


short unsigned int ctype_b_values[] = {
0x0002, // 
0x0002, //
0x0002, //
0x0002, //
0x0002, //
0x0002, //
0x0002, //
0x0002, //
0x0002, //
0x2003, //  
0x2002, //
0x2002, //
0x2002, //
0x2002, //
0x0002, //
0x0002, //
0x0002, //
0x0002, //
0x0002, //
0x0002, //
0x0002, //
0x0002, //
0x0002, //
0x0002, //
0x0002,
0x0002,
0x0002,
0x0002, //
0x0002, //
0x0002, //
0x0002, //
0x0002, //
0x6001, // 
0xc004, //!
0xc004, //"
0xc004, //#
0xc004, //$
0xc004, //%
0xc004, //&
0xc004, //'
0xc004, //(
0xc004, //)
0xc004, //*
0xc004, //+
0xc004, //,
0xc004, //-
0xc004, //.
0xc004, ///
0xd808, //0
0xd808, //1
0xd808, //2
0xd808, //3
0xd808, //4
0xd808, //5
0xd808, //6
0xd808, //7
0xd808, //8
0xd808, //9
0xc004, //:
0xc004, //;
0xc004, //<
0xc004, //=
0xc004, //>
0xc004, //?
0xc004, //@
0xd508, //A
0xd508, //B
0xd508, //C
0xd508, //D
0xd508, //E
0xd508, //F
0xc508, //G
0xc508, //H
0xc508, //I
0xc508, //J
0xc508, //K
0xc508, //L
0xc508, //M
0xc508, //N
0xc508, //O
0xc508, //P
0xc508, //Q
0xc508, //R
0xc508, //S
0xc508, //T
0xc508, //U
0xc508, //V
0xc508, //W
0xc508, //X
0xc508, //Y
0xc508, //Z
0xc004, //[
0xc004, //
0xc004, //]
0xc004, //^
0xc004, //_
0xc004, //`
0xd608, //a
0xd608, //b
0xd608, //c
0xd608, //d
0xd608, //e
0xd608, //f
0xc608, //g
0xc608, //h
0xc608, //i
0xc608, //j
0xc608, //k
0xc608, //l
0xc608, //m
0xc608, //n
0xc608, //o
0xc608, //p
0xc608, //q
0xc608, //r
0xc608, //s
0xc608, //t
0xc608, //u
0xc608, //v
0xc608, //w
0xc608, //x
0xc608, //y
0xc608, //z
0xc004, //{
0xc004, //|
0xc004, //}
0xc004, //~
0x0002, //
0x0000, //€
0x0000, //
0x0000, //‚
0x0000, //ƒ
0x0000, //„
0x0000, //…
0x0000, //†
0x0000, //‡
0x0000, //ˆ
0x0000, //‰
0x0000, //Š
0x0000, //‹
0x0000, //Œ
0x0000, //
0x0000, //Ž
0x0000, //
0x0000, //
0x0000, //‘
0x0000, //’
0x0000, //“
0x0000, //”
0x0000, //•
0x0000, //–
0x0000, //—
0x0000, //˜
0x0000, //™
0x0000, //š
0x0000, //›
0x0000, //œ
0x0000, //
0x0000, //ž
0x0000, //Ÿ
0x0000, // 
0x0000, //¡
0x0000, //¢
0x0000, //£
0x0000, //¤
0x0000, //¥
0x0000, //¦
0x0000, //§
0x0000, //¨
0x0000, //©
0x0000, //ª
0x0000, //«
0x0000, //¬
0x0000, //­
0x0000, //®
0x0000, //¯
0x0000, //°
0x0000, //±
0x0000, //²
0x0000, //³
0x0000, //´
0x0000, //µ
0x0000, //¶
0x0000, //·
0x0000, //¸
0x0000, //¹
0x0000, //º
0x0000, //»
0x0000, //¼
0x0000, //½
0x0000, //¾
0x0000, //¿
0x0000, //À
0x0000, //Á
0x0000, //Â
0x0000, //Ã
0x0000, //Ä
0x0000, //Å
0x0000, //Æ
0x0000, //Ç
0x0000, //È
0x0000, //É
0x0000, //Ê
0x0000, //Ë
0x0000, //Ì
0x0000, //Í
0x0000, //Î
0x0000, //Ï
0x0000, //Ð
0x0000, //Ñ
0x0000, //Ò
0x0000, //Ó
0x0000, //Ô
0x0000, //Õ
0x0000, //Ö
0x0000, //×
0x0000, //Ø
0x0000, //Ù
0x0000, //Ú
0x0000, //Û
0x0000, //Ü
0x0000, //Ý
0x0000, //Þ
0x0000, //ß
0x0000, //à
0x0000, //á
0x0000, //â
0x0000, //ã
0x0000, //ä
0x0000, //å
0x0000, //æ
0x0000, //ç
0x0000, //è
0x0000, //é
0x0000, //ê
0x0000, //ë
0x0000, //ì
0x0000, //í
0x0000, //î
0x0000, //ï
0x0000, //ð
0x0000, //ñ
0x0000, //ò
0x0000, //ó
0x0000, //ô
0x0000, //õ
0x0000, //ö
0x0000, //÷
0x0000, //ø
0x0000, //ù
0x0000, //ú
0x0000, //û
0x0000, //ü
0x0000, //ý
0x0000, //þ
0x0000, //ÿ
0x0020, // 
0x0000, //
0x0000, //
0x0000, //
0x0000, //
0x0000, //
0x0028, //
0x0000, //
0x0043, //
0x0000, //  
0x0029, //
0x0000, //
0x0000, //
0x0000,
0x0000, //
0x0000, //
0x003c, //
0x0000, //
0x003c, //
0x0000, //
0x0000, //
0x0000, //
0x0000, //
0x0000,
0x002d,
0x0000,
0x0000,
0x0000,
0x0000,
0x0000, //
0x0028, //
0x0000, //
0x0052, // 
0x0000, //!
0x0029, //"
0x0000, //#
0x0000, //$
0x0000, //%
0x0000, //&
0x0000, //'
0x0075, //(
0x0000, //)
0x0000, //*
0x0000, //+
0x0000, //,
0x0000, //-
0x002c, //.
0x0000, ///
0x0000, //0
0x0000, //1
0x0000, //2
0x0000, //3
0x003e, //4
0x0000, //5
0x003e, //6
0x0000, //7
0x0000, //8
0x0000, //9
0x0000, //:
0x0000, //;
0x0020, //<
0x0000, //=
0x0031, //>
0x0000, //?
0x002f, //@
0x0000, //A
0x0034, //B
0x0000, //C
0x0020, //D
0x0000, //E
0x0000, //F
0x0000, //G
0x0000, //H
0x0000, //I
0x0020, //J
0x0000, //K
0x0031, //L
0x0000, //M
0x002f, //N
0x0000, //O
0x0032, //P
0x0000, //Q
0x0020, //R
0x0000, //S
0x0000, //T
0x0000, //U
0x0000, //V
0x0000, //W
0x0020, //X
0x0000, //Y
0x0033, //Z
0x0000, //[
0x002f,
0x0000, //]
0x0034, //^
0x0000, //_
0x0020, //`
0x0000, //a
0x0000, //b
0x0000, //c
0x0000, //d
0x0000, //e
0x0041, //f
0x0000, //g
0x0045, //h
0x0000, //i
0x0000, //j
0x0000, //k
0x0000, //l
0x0000, //m
0x0078, //n
0x0000, //o
0x0000, //p
0x0000, //q
0x0000, //r
0x0000, //s
0x0073, //t
0x0000, //u
0x0073, //v
0x0000, //w
0x0000, //x
0x0000, //y
0x0000, //z
0x0000, //{
0x0061, //|
0x0000, //}
0x0065, //~
0x0000, //
};

const short unsigned int** __ctype_b_loc()
{
	static short unsigned int** ret = 0;
	if (ret != 0)
	{
		return (const short unsigned int**)ret;
	}
	int len = sizeof(ctype_b_values) / sizeof(short unsigned int);
	int i;
	short unsigned int* lookupTable = (short unsigned int*)malloc(len * sizeof(short unsigned int));
	for (i = 0; i < len; i++)
	{
		lookupTable[i] = ctype_b_values[i];
	}
	ret = (short unsigned int**)malloc(sizeof(short unsigned int*));
	*ret = lookupTable;
	return (const short unsigned int**)ret;
}

__int64 __fastcall sub_126E(unsigned int a1)
{
	unsigned int v2; // [rsp+1Ch] [rbp-4h]

	v2 = 0;
	if (((*__ctype_b_loc())[a1] & 0x800) != 0)
	{
		return a1 - 40;
	}
	else if (a1 > 0x45)
	{
		if (a1 > 0x4F)
		{
			if (a1 <= 0x59)
				return a1 - 80;
		}
		else
		{
			return a1 - 70;
		}
	}
	else
	{
		return a1 - 60;
	}
	return v2;
}

char* __fastcall swap(char* a1, char* a2)
{
	char* result; // rax
	char v3; // [rsp+1Fh] [rbp-1h]

	v3 = *a1;
	*a1 = *a2;
	result = a2;
	*a2 = v3;
	return result;
}

size_t __fastcall enc1(char *a1, __int64 a2, __int64 a3, const char* a4)
{
	size_t result; // rax
	int i; // [rsp+2Ch] [rbp-14h]

	for (i = 0; ; ++i)
	{
		result = strlen(a4);
		if (i >= result)
			break;
		swap(a1, a1 + a4[i]);
	}
	return result;
}

__int64 __fastcall enc2(char* a1, char* a2)
{
	__int64 result; // rax
	signed int v3; // [rsp+14h] [rbp-Ch]
	signed int v4; // [rsp+18h] [rbp-8h]
	int j; // [rsp+1Ch] [rbp-4h]
	signed int k; // [rsp+1Ch] [rbp-4h]
	unsigned int i; // [rsp+1Ch] [rbp-4h]

	v4 = strlen(a2);
	v3 = strlen(a1);
	if (v3 <= v4)
	{
		for (i = 0; ; ++i)
		{
			result = i;
			if ((int)i >= v3)
				break;
			a1[i] ^= a2[i];
		}
	}
	else
	{
		for (j = 0; j < v4; ++j)
			a1[j] ^= a2[j];
		for (k = v4; ; ++k)
		{
			result = (unsigned int)k;
			if (k >= v3)
				break;
			a1[k] ^= a2[k % v4];
		}
	}
	return result;
}

size_t __fastcall dec1(char* a1, __int64 a2, __int64 a3, const char* a4)
{
	size_t result; // rax
	int i; // [rsp+2Ch] [rbp-14h]
	result = strlen(a4);

	for (i = result - 1; i >= 0; --i) // Start from the end of a4 and move backwards
	{
		swap(a1, a1 + a4[i]); // Undo the swap
	}
	return result;
}


void get_flag()
{
	char key_initialized[32]; // [rsp+0h] [rbp-B0h] BYREF
	char key[32]; // [rsp+20h] [rbp-90h] BYREF
	char plain_2[32]; // [rsp+40h] [rbp-70h] BYREF
	char plain_1[24]; // [rsp+60h] [rbp-50h] BYREF
	int plain_strlen; // [rsp+90h] [rbp-20h]

	string flag = "flag{";
	strcpy(key, "CC2A750B63821F45AC20839");
	for (int i = 0; i <= 22; ++i)
		key_initialized[i] = sub_126E(key[i]);

	char encrypted[] = { 102, 111, 62, 107, 104, 52,100, 96, 103, 104, 79, 61, 126, 111, 88, 57, 90, 60, 108, 61, 127 };
	enc2(encrypted, key_initialized);
	plain_strlen = strlen(encrypted);
	dec1(encrypted, 0LL, (unsigned int)(plain_strlen - 1), key_initialized);
	cout << encrypted << endl;
	flag += encrypted;
	char encrypted2[] = { 52, 50, 99, 104, 127, 127, 120, 89, 122, 84, 121, 107, 124, 115, 52, 102, 104, 63, 99 };
	enc2(encrypted2, key_initialized);
	plain_strlen = strlen(encrypted2);
	dec1(encrypted2, 0LL, (unsigned int)(plain_strlen - 1), key_initialized);
	cout << encrypted2 << endl;
	flag += encrypted2;
	flag += "}";
	cout << flag;
}

int main()
{
	get_flag();
	return 0;
}