안녕하세요. POX 2018 REV Generator 출제자입니다.

간단한 라이트업을 작성해보고자 합니다.

[0] 풀어주신 팀 감사합니다. (팀은 비공개)
SOLVE

[1] Binary Information

Arch: amd64-64-little
RELRO: Partial RELRO
Stack : Canary found
NX : NX enabled
PIE : PIE enabled

[2] Concept
데몬(Demon아님)을 이길 전사는 누구인가?

[3] Scenario
DNA와 여성의 성별을 정확하게 맞추어서 악마를 이겨라.

[4] Dynamic Analyse
dy_1
악마를 이기기 위해 'y'를 입력하면 당신의 DNA를 입력하라는 구문이 뜨게 됩니다.
그 다음 성별을 체크하네요. 하지만 여기서 girl이라고 입력하면 Segmentation Fault가 뜨게 됩니다. 형식지정자가 char*가 아니라는 뜻입니다.

dy_2
그래서 숫자를 넣게 되면 이제 이름까지 적으라고 합니다.
입력을 열심히 해봅니다. Segmentation이 뜨죠?
하지만, 중요한건 이 문제는 PWN이 아니라는 것이죠.
그렇다면, 정적분석을 통해 '몇 바이트'를 사용해야하는지 알 수 있겠죠.

[5] Static Analyse

[5-1] 해당 문제는 클래스가 4개 있습니다.
3개의 클래스는 남은 하나의 클래스에 종속됩니다.

구조는 다음과 같습니다.

  • Generator *
  • -> Factory1
  • -> Factory2
  • -> Factory3

Generator는 공장의 모든 결과값을 가지고 있게 됩니다.
Factory1은 전사의 dna를 생성합니다.
Factory2는 전사의 성별을 생성합니다.
Factroy3은 전사의 이름을 생성합니다. 사실상 플래그 포맷입니다.

[5-2] Factory1 분석
class Generator의 set함수에서 세팅할 수 있습니다.

  • cpp code
    dy_3-1
  • pseudo code
    dy_13

*cpp code
dy_5
*pseudo code
dy_6
해당 그림에서 dna를 세팅하는 방법을 알 수 있습니다.

  • cpp code
    dy_7
  • pseudo code
    dy_20

가져온 dna가 정해진 dna 값과 일치하는지 체크하는 부분입니다.
아주 간단한 역연산입니다.

주소로 접근하여 분석을 진행하면 역연산을 추가적으로 알 수 있습니다.

text:000000000000296E                 mov     rax, [rbp+var_F8]
.text:0000000000002975                 mov     rax, [rax]
.text:0000000000002978                 mov     rax, [rax]
.text:000000000000297B                 mov     rdx, [rbp+var_F8]
.text:0000000000002982                 mov     rcx, [rdx+58h]
.text:0000000000002986                 mov     rdx, [rbp+var_F8]
.text:000000000000298D                 mov     rsi, rcx
.text:0000000000002990                 mov     rdi, rdx
.text:0000000000002993                 call    rax  // virtual function
.text:0000000000002995                 mov     rdx, rax
.text:0000000000002998                 mov     rax, 340448D300h
.text:00000000000029A2                 cmp     rdx, rax
.text:00000000000029A5                 setnz   al
.text:00000000000029A8                 test    al, al
.text:00000000000029AA                 jz      short loc_2A28
.text:00000000000029AC                 mov     [rbp+var_E4], 0

[5-3] Factroy2 분석
class Generator의 set함수에서 세팅할 수 있습니다.

  • cpp code
    dy_8
  • pseudo code
    dy_17

성별을 32비트 정수형으로 입력할 수 있게 되어 있습니다.
그리고, 가상함수에서 성별을 만들어서 string에 추가시키는 행위도 볼 수 있습니다.

  • cpp code
    dy_10

  • pseudo code
    dy_14

  • cpp code
    dy_16

  • pseudo code
    dy_15

[5-4] Factory3 분석
char 배열 2개가 선언되어 있고, 초기화가 진행되어 있다.
무엇인지 아직 모르겠지만 string flag를 선언해둔뒤 특정 문자열을 append시키는 것도 볼 수 있다.
이미 정해진 값 "\x6c\x5e\x64"를 연산하는 부분이 있고, arr을 매개변수로 가지고 있는 함수에서 똑같은 연산을 취하는 것으로 보아, compare에 관한 함수이다는 것을 추측할 수 있다.

  • cpp code
    dy_12
  • pseudo code
    dy_19

[5-5] main 분석
DNA와 성별들을 체크하는 부분과 append하는 부분이 많이 보인다.
append는 주어진 문자열의 뒷부분에 추가하는 함수이기 때문에 분석하는데 어려움이 없다.

  • cpp code
    dy_11
  • pseudo code
    dy_18

[6] POC

// Generator POC
// Author c0nstant 


#include <iostream>
#include <string>

static std::string flag;

void lose()
{
	char test[22] = "\x55\x4a\x5d\x7e\x5c\x4a\x50\x5a\x49\x4a\x56\x40\x5a\x41\x44\x40\x48\x4a\x4b\x78\x5";
	for (int i = 0; i < 21; i++)
	{
		test[i] ^= 0x5;
	}
}

void flag_block_first()
{
	flag.append("{");
}
void flag_format()
{
	char pox[4] = "lSd";

	for (int i = 0; i < 3; i++)
	{
		pox[i] -= 0x10;
		pox[i] ^= 0xc;
	}
	flag.append(pox);
}

void find_dna()
{
	// dnaDigit is 16
	// result of condition is 223410180864

	// reverse
	long long int result_dna = 223410180864;
	long long int origin_dna = 0;
	result_dna -= 0x1234;
	result_dna ^= 0xcc;
	result_dna /= 16;
	result_dna /= 1000;
	origin_dna = result_dna;
	std::string DNA = std::to_string(origin_dna);
	flag.append(DNA);
	flag.append("_");
}

void makeGender()
{
	// if you select 1,3,5
	flag.append("girl");
	flag.append("_");
}

void last_flag()
{
	// this is hard cording.
	flag.append("M1ssion_C0mplete");
	flag.append("}");
}

int main()
{
	flag_format();
	flag_block_first();
	find_dna();
	makeGender();
	last_flag();
	std::cout << flag << std::endl;
	return 0;
}

c++ 코드 공부할 겸 만들어 보았었습니다. 다음에도 새로운 문제로 찾아오겠습니다.
코드입니다.

#include <iostream>
#include <string>
#include <time.h>
#include <stdlib.h>
void P(std::string);
void T(std::string);
bool checker(char s);

// concept // 
// generator // 

int64_t newDNA;
class Factory1
{
	int64_t dnaDigit;
	int64_t n;
	int64_t dna;
public:
	Factory1()
	{
		dnaDigit = 16;
		n = 0;
	}
	int64_t set()
	{
		P("what your dna>>");
		std::cin >> n;
		newDNA = n;
		dnaDigit *= 1000;
		n *= dnaDigit;
		return n;
	}

	virtual int64_t controlDna(int64_t dna)
	{
		dna ^= 0xcc;
		dna += 0x1234;
		return dna;
	}
	~Factory1()
	{
	}

};



// gender factory
// girl : 1,3,5
// boy : 2,4,6
class Factory2
{
	int gender;

public:
	Factory2()
	{
		gender = 1;
	}
	int set()
	{
		P("what your gender>>");
		std::cin >> gender;
		return gender;
	}

	virtual std::string makeGenger()
	{
		std::string gen;
		gen.append("girl");
		return gen;
	}

	~Factory2()
	{
	}
};

// name, attack, defence factory
// if your name not "POX" you don't enroll register.
class Factory3
{
	char pox[4] = "\x6c\x53\x64";
	char name[4];
public:
	Factory3() {
		for (int i = 0; i < sizeof(name) / sizeof(name[0]); i++)
			name[i] = 0;
	}
public:
	char* set()
	{
		std::cout << "what your name >> " << std::endl;
		std::cin >> name;
		return name;
	}

	virtual std::string lastflag()
	{
		std::string flag;
		flag.append("M1ssion_C0mplete");
		return flag;
	}

	std::string getFlagformat(char arr[])
	{
		std::string newFlag;
		for (int i = 0; i < 3; i++)
		{
			arr[i] -= 0x10;
			arr[i] ^= 0xc;
		}
		newFlag.append(arr);
		return newFlag;
	}
	std::string checkFormat()
	{
		std::string newFlag;
		for (int i = 0; i < 3; i++)
		{
			pox[i] -= 0x10;
			pox[i] ^= 0xc;
		}
		newFlag.append(pox);
		return newFlag;
	}
};

class Generator : public Factory1, public Factory2, public Factory3
{
public:
	char test[22] = "\x55\x4a\x5d\x7e\x5c\x4a\x50\x5a\x49\x4a\x56\x40\x5a\x41\x44\x40\x48\x4a\x4b\x78\x5";
	int64_t dna;
	int gender;
	char *name;
	char* sex;
	std::string flag;
	Generator()
	{
		dna = 0;
		gender = 0;
	}
	void set()
	{
		name = new char[4];
		dna = Factory1::set();
		gender = Factory2::set();
		name = Factory3::set();

		if (checkGender(gender))
		{

			if (controlDna(dna) != 223410180864)
			{
				for (int i = 0; i < 21; i++)
				{
					// POX{YOU_LOSE_DAEMON}
					test[i] ^= 0x5;
				}
				std::cout << test << std::endl;
			}
			else
			{
				flag = Factory2::makeGenger();
				sex = new char[10];
				strcpy(sex, "girl");
				std::string girl;
				girl.append(sex);
				std::string userFlag = Factory3::getFlagformat(name);
				std::string comFlag = Factory3::checkFormat();
				if (userFlag.compare(comFlag) == 0)
				{
					std::string result;
					result.append(userFlag);
					result.append("{");
					std::string DNA = std::to_string(newDNA);
					result.append(DNA);
					result.append("_");
					result.append(girl);
					result.append("_");
					result.append(Factory3::lastflag());
					result.append("}");
					std::cout << result << std::endl;
				}
				else
				{
					std::string result;
					std::string DNA = std::to_string(newDNA);
					result.append(name);
					result.append("{");
					result.append(DNA);
					result.append("_");
					result.append(girl);
					result.append("_");
					result.append("YOU_LOSE_DAEMON");
					result.append("}");
					std::cout << result << std::endl;
				}

			}
			
		}
	}



	bool checkGender(int gender)
	{
		if (gender == 1 || gender == 3 || gender == 5)
		{
			return true;
		}
		else
			return false;
	}

	~Generator()
	{
		delete sex;
	}

};

void P(std::string arr)
{
	T(arr);
}

void T(std::string arr)
{
	std::cout << arr << std::endl;
}
int main(int argc, char*argv[])
{

	char s;
	P("IN World, POX");
	P("Daemon appeared in the peaceful POX");
	P("In order to beat Daemon, you have to make a proper warrior.");
	P("Can you?");
	std::cin >> s;



	// pass
	if (checker(s))
	{
		Generator ge;
		ge.set();
	}

	// wrong
	else
		return -1;

	return 0;
}


bool checker(char s)
{
	if (s == 'y' || s == 'Y')
		return true;
	else
		return false;
}