| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 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 |
- dreamhack
- 드림핵
- AWS 아키텍처 분석
- reversing.kr
- operating system
- AWS 인프라 분석
- 침입 차단 시스템(IPS)
- IAM Federation
- AWS 보안 아키텍처 분석
- terraform
- reversing
- network
- AWS 사고 사례 분석
- AWS 침해사고 사례 분석
- AWS 인프라 아키텍처
- AWS
- C
- AWS 3 Tier Architecture
- programmers
- 프로그래머스
- 네트워크
- AWS Active Directory
- AWS 보안 사고 사례 모음
- AWS IAM Role
- TryHackMe
- python
- AWS 침해 사고 사례 분석
- Amazon S3
- 리버싱
- 운영체제
- Today
- Total
lhywk 님의 블로그
[Dreamhack] Stop before stops! 본문
문제
무슨 뜻일까요? 궁금해진 카루가 프로그램을 분석해봅니다.
플래그를 알려주는 기능이 숨겨져 있었군요.
영문자, 숫자, 특수문자를 적절히 사용하여 플래그를 획득해 봅시다.
문제 풀이

문제에 주어진 바이너리를 실행하면 에러 문구가 출력됩니다.
IDA를 통해 소스코드를 분석해 보겠습니다.
int __fastcall main(int argc, const char **argv, const char **envp)
{
__int64 v4; // rax
__int64 v5; // rax
__int64 v6; // rax
__int64 v7; // rax
int v8; // ebx
__int64 v9; // rax
unsigned int v10; // eax
__int64 v11; // rax
char v12; // bl
char v13; // r12
bool v14; // r13
__int64 v15; // rax
__int64 v16; // rax
_DWORD v18[12]; // [rsp+10h] [rbp-28D0h] BYREF
_QWORD v19[3]; // [rsp+40h] [rbp-28A0h] BYREF
char v20; // [rsp+5Fh] [rbp-2881h] BYREF
_BYTE v21[88]; // [rsp+60h] [rbp-2880h] BYREF
_BYTE v22[8]; // [rsp+B8h] [rbp-2828h] BYREF
_BYTE v23[5008]; // [rsp+C0h] [rbp-2820h] BYREF
_BYTE v24[5008]; // [rsp+1450h] [rbp-1490h] BYREF
_BYTE v25[32]; // [rsp+27E0h] [rbp-100h] BYREF
_BYTE v26[32]; // [rsp+2800h] [rbp-E0h] BYREF
_BYTE v27[32]; // [rsp+2820h] [rbp-C0h] BYREF
_BYTE v28[47]; // [rsp+2840h] [rbp-A0h] BYREF
char v29; // [rsp+286Fh] [rbp-71h] BYREF
_BYTE v30[36]; // [rsp+2870h] [rbp-70h] BYREF
unsigned int v31; // [rsp+2894h] [rbp-4Ch]
__int64 v32; // [rsp+2898h] [rbp-48h]
_QWORD *v33; // [rsp+28A0h] [rbp-40h]
int v34; // [rsp+28ACh] [rbp-34h]
const char *v35; // [rsp+28B0h] [rbp-30h]
unsigned int *v36; // [rsp+28B8h] [rbp-28h]
v35 = "`~!@$%^*+-_=:;?<>";
if ( argc == 2 )
{
if ( strlen(argv[1]) == 24 && (unsigned __int8)std::operator==<char>(&vlkjbkldsajfksdkfl2[abi:cxx11], argv[1]) )
{
v4 = std::operator<<<std::char_traits<char>>(&std::cout, "Congratulations! The flag is: ");
std::ostream::operator<<(v4, &std::endl<char,std::char_traits<char>>);
v5 = std::operator<<<std::char_traits<char>>(&std::cout, "DH{");
v6 = std::operator<<<char>(v5, &lkjasvhkjsldhkl[abi:cxx11]);
v7 = std::operator<<<std::char_traits<char>>(v6, "}");
std::ostream::operator<<(v7, &std::endl<char,std::char_traits<char>>);
return 0;
}
LABEL_10:
v9 = std::operator<<<std::char_traits<char>>(&std::cout, "Argument error occured! Aborting...");
std::ostream::operator<<(v9, &std::endl<char,std::char_traits<char>>);
return 1;
}
if ( argc != 3 )
goto LABEL_10;
std::random_device::random_device((std::random_device *)v24);
v10 = std::random_device::operator()(v24);
std::mersenne_twister_engine<unsigned long,32ul,624ul,397ul,31ul,2567483615ul,11ul,4294967295ul,7ul,2636928640ul,15ul,4022730752ul,18ul,1812433253ul>::mersenne_twister_engine(
v23,
v10);
std::uniform_int_distribution<int>::uniform_int_distribution(v22, 3, 7);
v34 = std::uniform_int_distribution<int>::operator()<std::mersenne_twister_engine<unsigned long,32ul,624ul,397ul,31ul,2567483615ul,11ul,4294967295ul,7ul,2636928640ul,15ul,4022730752ul,18ul,1812433253ul>>(
v22,
v23);
std::deque<char>::deque(v21);
v20 = 0;
v18[0] = 1;
v18[1] = 2;
v18[2] = 3;
v18[3] = 4;
v18[4] = 5;
v18[5] = 6;
v18[6] = 7;
v18[7] = 8;
v18[8] = 9;
v18[9] = 10;
v19[1] = 10;
v19[0] = v18;
v33 = v19;
v36 = (unsigned int *)std::initializer_list<int>::begin(v19);
v32 = std::initializer_list<int>::end(v33);
while ( v36 != (unsigned int *)v32 )
{
v31 = *v36;
if ( (int)v31 > v34 )
{
generate_random_string[abi:cxx11](v25);
std::string::operator=(&vlkjbkldsajfksdkfl2[abi:cxx11], v25);
std::string::~string(v25);
}
std::ostream::put((std::ostream *)&std::cout, 91);
std::ios_base::width((std::ios_base *)&unk_D208, 2);
std::ios::fill(&unk_D208, 48);
v11 = std::ostream::operator<<(&std::cout, v31);
std::operator<<<std::char_traits<char>>(v11, "] Input a character >> ");
std::operator>><char,std::char_traits<char>>(&std::cin, &v20);
if ( (unsigned __int64)std::deque<char>::size(v21) > 2 )
std::deque<char>::pop_front(v21);
std::deque<char>::push_back(v21, &v20);
v12 = 0;
v13 = 0;
v14 = 0;
if ( (unsigned __int64)std::deque<char>::size(v21) > 2 )
{
std::deque<char>::begin(v27, v21);
std::deque<char>::end(v28, v21);
std::allocator<char>::allocator(&v29);
v12 = 1;
std::string::basic_string<std::_Deque_iterator<char,char &,char *>,void>(v26, v27, v28, &v29);
v13 = 1;
if ( std::string::find(&charstr, v26, 0) != -1 )
v14 = 1;
}
if ( v13 )
std::string::~string(v26);
if ( v12 )
std::allocator<char>::~allocator(&v29);
if ( v14 )
{
v15 = std::operator<<<std::char_traits<char>>(&std::cout, "\n##### Bruteforce attack is not allowed! Aborting...");
std::ostream::operator<<(v15, &std::endl<char,std::char_traits<char>>);
v8 = 1;
goto LABEL_28;
}
std::string::basic_string(v30, &vlkjbkldsajfksdkfl2[abi:cxx11]);
find_in_str((unsigned int)v20, v30);
std::string::~string(v30);
++v36;
}
v16 = std::operator<<<std::char_traits<char>>(&std::cout, "\n##### Max input times reached! Shutting down...");
std::ostream::operator<<(v16, &std::endl<char,std::char_traits<char>>);
v8 = 0;
LABEL_28:
std::deque<char>::~deque(v21);
std::random_device::~random_device((std::random_device *)v24);
return v8;
}
전체 소스코드입니다.
여기서 플래그를 출력해 주는 곳의 소스코드를 분석하겠습니다.
if ( argc == 2 )
{
if ( strlen(argv[1]) == 24 && (unsigned __int8)std::operator==<char>(&vlkjbkldsajfksdkfl2[abi:cxx11], argv[1]) )
{
v4 = std::operator<<<std::char_traits<char>>(&std::cout, "Congratulations! The flag is: ");
std::ostream::operator<<(v4, &std::endl<char,std::char_traits<char>>);
v5 = std::operator<<<std::char_traits<char>>(&std::cout, "DH{");
v6 = std::operator<<<char>(v5, &lkjasvhkjsldhkl[abi:cxx11]);
v7 = std::operator<<<std::char_traits<char>>(v6, "}");
std::ostream::operator<<(v7, &std::endl<char,std::char_traits<char>>);
return 0;
}
LABEL_10:
v9 = std::operator<<<std::char_traits<char>>(&std::cout, "Argument error occured! Aborting...");
std::ostream::operator<<(v9, &std::endl<char,std::char_traits<char>>);
return 1;
}
1. argc == 2 인자를 1개 받습니다.
2. if ( strlen(argv[1]) == 24 && (unsigned __int8)std::operator==<char>(&vlkjbkldsajfksdkfl2[abi:cxx11], argv[1]) )
인자의 문자열 길이는 24자이어야 하고 vlkjbkldsajfksdkfl2 값과 같아야 합니다.
3. 조건을 만족할 경우 플래그를 출력합니다.
그럼 여기서 vlkjbkldsajfksdkfl2 값을 알아내야 합니다.

xref을 하여 따라가 보겠습니다.

sldkhjlhvfiuh 함수가 vlkjbkldsajfksdkfl2에 값을 채워 넣습니다.

sldkhjlhvfiuh 함수를 분석해 보겠습니다.
6줄 라인에 salkdhvkhlklhkjfdhkjd::segment 변수 값을 읽어서 a1에 복사해서 넣습니다.
그 뒤 a1을 리턴합니다.
여기까지의 흐름은
1. vlkjbkldsajfksdkfl2 값과 같으면 플래그를 출력한다.
2. vlkjbkldsajfksdkfl2 값은 sldkhjlhvfiuh 함수가 넣는다.
3. sldkhjlhvfiuh 함수는 salkdhvkhlklhkjfdhkjd::segment 변수 값을 리턴한다.
4. salkdhvkhlklhkjfdhkjd::segment 변수 값을 알아내야 한다.

62~63라인을 봤을 때 Getslifdhiuil3 함수의 반환값을 v8에 넣고 segment 값이 됩니다.

Getslifdhiuil3 함수를 분석해 보겠습니다.
24번 반복하면서 data[i] = data[i] ^ 87 - i 연산으로 암호화를 수행합니다.
암호화를 수행한 값을 역연산 하게 되면 최종적으로 우리가 알고 싶은 값을 얻어낼 수 있습니다.

data 배열의 값을 확인합니다.
byte_140003000 = bytearray([0x15, 0x35, 0x07, 0x11, 0x2B, 0x63, 0x05, 0x05, 0x2A, 0x71,
0x20, 0x0E, 0x76, 0x23, 0x73, 0x74, 0x14, 0x3E, 0x1A, 0x35,
0x33, 0x08, 0x16, 0x74, 0x00])
for i in range(0x18):
byte_140003000[i] = byte_140003000[i] ^ 87 - i
print(chr(byte_140003000[i]),end='')
XOR 암호화는 한번 더 연산을 수행하면 복호화되므로 파이썬으로 페이로드를 작성합니다.


'Reversing > Dreamhack' 카테고리의 다른 글
| [Dreamhack] legacyopt (0) | 2026.02.05 |
|---|---|
| [Dreamhack] please, please, please (0) | 2026.02.04 |
| [Dreamhack] rev-basic-5 (0) | 2026.01.27 |
| [Dreamhack] rev-basic-7 (0) | 2026.01.27 |
| [Dreamhack] flag printer (0) | 2026.01.26 |