baseball 풀이

2022. 10. 6. 19:31Dreamhack Wargame

728x90

문제 제목
문제 정보
문제 파일과 함께 주어진 .txt 파일

[text_in.txt]
Pepero is a cookie stick, dipped in compound chocolate, manufactured by ????? Confectionery in South Korea
Pepero Day is held annually on November 11

[text_out.txt]
7/OkZQIau/jou/R1by9acyjjutd0cUdlWshecQhkZUn1cUH1by9g4/9qNAn1byGaby9pbQSjWshgbUmqZAF+JtOBZUn1b8e1YoMPYoM1ny95ZAO+J/jaNAOB2vhrNLhVNDO0cshWNDIjbnrnZQhj4AM1S/Fmu/jou/GjN/n1bUm5JUFpNte1NyH1VA9yZUqLZQu13VR=

[flag_out.txt]
S/jeutjaJvhlNA9Du/GaJBhLbQdjd+n1Jy9BcD3=

 

바이너리 분석 문제입니다.

문제 파일과 함께 txt 파일이 3개 딸려왔네요.

파일 내용이 text_in.txt 빼고는 전부 암호화되어있습니다.

 

어떠한 임의의 문자열을 넣었을 때 나오는 파일이 text_out 파일인 것 같습니다.

= flag_out 파일의 원본을 찾는 문제

 

__int64 __fastcall main(int a1, char **a2, char **a3)
{
  __int64 v3; // rdx
  __int64 v5; // [rsp-38h] [rbp-38h]
  __int64 v6; // [rsp-30h] [rbp-30h]
  __int64 v7; // [rsp-28h] [rbp-28h]
  __int64 v8; // [rsp-20h] [rbp-20h]
  __int64 v9; // [rsp-18h] [rbp-18h]
  __int64 v10; // [rsp-10h] [rbp-10h]

  __asm { endbr64 }
  if ( a1 != 3 )
  {
    sub_1190("Usage : ./baseball <table filename> <input filename>\n", 1LL, 53LL, stderr);
    sub_1180(0xFFFFFFFFLL);
  }
  v5 = sub_1170(a2[1], "rb", a3);
  if ( !v5 )
  {
    sub_1190("File not found\n", 1LL, 15LL, stderr);
    sub_1180(0xFFFFFFFFLL);
  }
  sub_1160(v5, 0LL, 2LL);
  v6 = sub_1140(v5);
  sub_1160(v5, 0LL, 0LL);
  if ( v6 != 64 )
  {
    sub_1190("Invalid table\n", 1LL, 14LL, stderr);
    sub_1180(0xFFFFFFFFLL);
  }
  sub_1100(&unk_4040, 65LL, 1LL, v5);
  sub_1110(v5);
  v7 = sub_1170(a2[2], "rb", v3);
  if ( !v7 )
  {
    sub_1190("File not found\n", 1LL, 15LL, stderr);
    sub_1180(0xFFFFFFFFLL);
  }
  sub_1160(v7, 0LL, 2LL);
  v8 = sub_1140(v7);
  if ( !v8 )
  {
    sub_1190("Invalid input\n", 1LL, 14LL, stderr);
    sub_1180(0xFFFFFFFFLL);
  }
  sub_1160(v7, 0LL, 0LL);
  v9 = sub_1150(v8 + 1);
  if ( !v9 )
  {
    sub_1190("Allocation failed\n", 1LL, 18LL, stderr);
    sub_1180(0xFFFFFFFFLL);
  }
  sub_1130(v9, 0LL, v8 + 1);
  sub_1100(v9, v8, 1LL, v7);
  sub_1110(v7);
  v10 = sub_1289(v9, (unsigned int)v8);
  sub_1120("%s", v10);
  sub_10F0(v9);
  sub_10F0(v10);
  return 0LL;
}

IDA로 문제 파일을 열어서 main() 함수만 가져와봤습니다.

블로그 상에서 보기에는 코드가 좀 길어 보이니 중요 부분별로 나눠서 분석해보겠습니다.

 

  v5 = sub_1170(a2[1], "rb", a3);
  if ( !v5 )
  {
    sub_1190("File not found\n", 1LL, 15LL, stderr);
    sub_1180(0xFFFFFFFFLL);
  }
  sub_1160(v5, 0LL, 2LL);
  v6 = sub_1140(v5);
  sub_1160(v5, 0LL, 0LL);
  if ( v6 != 64 )
  {
    sub_1190("Invalid table\n", 1LL, 14LL, stderr);
    sub_1180(0xFFFFFFFFLL);
  }
  sub_1100(&unk_4040, 65LL, 1LL, v5);
  sub_1110(v5);

첫 번째 입력 부분.

a2라는 파일에서 테이블을 읽어옵니다.

만약 파일이 비어있거나, 테이블의 길이가 64byte가 아니라면 각 상황에 맞는 문자열을 출력해주고 프로그램을 종료합니다.

 

  v6 = sub_1170();
  if ( !v6 )
  {
    sub_1190("File not found\n", 1LL, 15LL, stderr);
    sub_1180(0xFFFFFFFFLL);
  }
  sub_1160(v6, 0LL, 2LL);
  v7 = sub_1140(v6);
  if ( !v7 )
  {
    sub_1190("Invalid input\n", 1LL, 14LL, stderr);
    sub_1180(0xFFFFFFFFLL);
  }
  sub_1160(v6, 0LL, 0LL);
  v8 = sub_1150(v7 + 1);
  if ( !v8 )
  {
    sub_1190("Allocation failed\n", 1LL, 18LL, stderr);
    sub_1180(0xFFFFFFFFLL);
  }
  sub_1130(v8, 0LL, v7 + 1);
  sub_1100(v8, v7, 1LL, v6);
  sub_1110(v6);

두 번째 입력 부분.

이번에는 v6에 어떠한 입력값을 담습니다.

아마 Input을 읽어오는 것 같습니다.

첫 번째 입력 부분과 같이 입력값이 형식에 맞지 않으면 문자열을 출력해주고 실행을 종료합니다.

 

  v9 = sub_1289(v8, (unsigned int)v7);
  sub_1120("%s", v9);
  sub_10F0(v8);
  sub_10F0(v9);
  return 0LL;

이번에는 sub_1289() 함수에 Input을 넣어서 return 값을 출력하고 실행을 종료합니다.

sub_1289() 함수를 보겠습니다.

 

__int64 __fastcall sub_1289(_BYTE *a1, int a2)
{
  _BYTE *v3; // rax
  _BYTE *v4; // rax
  _BYTE *v5; // rax
  _BYTE *v6; // rax
  _BYTE *v7; // rax
  _BYTE *v8; // [rsp-30h] [rbp-30h]
  _BYTE *v9; // [rsp-30h] [rbp-30h]
  __int64 v10; // [rsp-30h] [rbp-30h]
  _BYTE *v11; // [rsp-28h] [rbp-28h]
  unsigned __int64 v12; // [rsp-20h] [rbp-20h]
  __int64 v13; // [rsp-18h] [rbp-18h]
  _BYTE *v14; // [rsp-10h] [rbp-10h]

  __asm { endbr64 }
  v12 = (4 * a2 / 32 + 4) / 0x48uLL + 4 * a2 / 32 + 4 + 1;
  if ( v12 < a2 )
    return 0LL;
  v13 = sub_1150(v12);
  if ( !v13 )
    return 0LL;
  v14 = &a1[a2];
  v11 = a1;
  v8 = (_BYTE *)v13;
  while ( v14 - v11 > 2 )
  {
    *v8 = byte_4040[*v11 >> 2];
    v8[1] = byte_4040[(v11[1] >> 4) | (16 * *v11) & 0x30];
    v8[2] = byte_4040[(v11[2] >> 6) | (4 * v11[1]) & 0x3C];
    v3 = v8 + 3;
    v8 += 4;
    *v3 = byte_4040[v11[2] & 0x3F];
    v11 += 3;
  }
  if ( v14 != v11 )
  {
    v4 = v8;
    v9 = v8 + 1;
    *v4 = byte_4040[*v11 >> 2];
    if ( v14 - v11 == 1 )
    {
      *v9 = byte_4040[(16 * *v11) & 0x30];
      v5 = v9 + 1;
      v10 = (__int64)(v9 + 2);
      *v5 = 61;
    }
    else
    {
      *v9 = byte_4040[(v11[1] >> 4) | (16 * *v11) & 0x30];
      v6 = v9 + 1;
      v10 = (__int64)(v9 + 2);
      *v6 = byte_4040[(4 * v11[1]) & 0x3C];
    }
    v7 = (_BYTE *)v10;
    v8 = (_BYTE *)(v10 + 1);
    *v7 = 61;
  }
  *v8 = 0;
  return v13;
}

원래는 이 함수를 하나하나 분석해서 곧이곧대로 테이블을 구하고, 역연산을 하는 식으로 문제를 풀어보려고 했는데, 너무 시간이 오래 걸릴 것 같아서 문제 댓글을 조금 참고해보기로 했습니다.

 

문제 댓글을 보니 Base64 얘기가 굉장히 많이 나왔습니다.

문제 파일 외에 주어졌던 세 개의 텍스트 파일 중 text_in.txt만 Base64가 아닌 게 수상해서 Cyber Chef 툴에 Base64 옵션을 넣어서 돌려봤습니다.

 

Base64 Encoding

혹시나 하고 text_out.txt랑 비교해봤는데, 문자열 길이가 같았습니다.

아무래도 일대일 치환인 것 같네요.

 

#include<bits/stdc++.h>
using namespace std;

int main(){
	ios_base::sync_with_stdio(false);
	cin.tie(NULL);
	cout.tie(NULL);
	string text_out="7/OkZQIau/jou/R1by9acyjjutd0cUdlWshecQhkZUn1cUH1by9g4/9qNAn1byGaby9pbQSjWshgbUmqZAF+JtOBZUn1b8e1YoMPYoM1ny95ZAO+J/jaNAOB2vhrNLhVNDO0cshWNDIjbnrnZQhj4AM1S/Fmu/jou/GjN/n1bUm5JUFpNte1NyH1VA9yZUqLZQu13VR=";
	string text_in="UGVwZXJvIGlzIGEgY29va2llIHN0aWNrLCBkaXBwZWQgaW4gY29tcG91bmQgY2hvY29sYXRlLCBtYW51ZmFjdHVyZWQgYnkgPz8/Pz8gQ29uZmVjdGlvbmVyeSBpbiBTb3V0aCBLb3JlYQpQZXBlcm8gRGF5IGlzIGhlbGQgYW5udWFsbHkgb24gTm92ZW1iZXIgMTE=";
	string flag_out="S/jeutjaJvhlNA9Du/GaJBhLbQdjd+n1Jy9BcD3=";
	string flag_in="AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA";
	for(int i=0;i<=40;i++){
		for(int j=0;j<=200;j++){
			if (text_out[j]==flag_out[i]) {
				flag_in[i]=text_in[j];
			}
		}
	}
	cout<<flag_in;
}

위와 같은 코드를 짜서 실행시켰습니다.

 

Result

결괏값이 나왔습니다.

형태가 Base64이니 옵션을 Base64로 넣어서 Decoding 해보겠습니다.

 

FLAG 획득 완료
문제 풀이 성공

왜 문제 이름이 baseball인지 이제야 알겠네요 ㅋㅋㅋ

728x90

'Dreamhack Wargame' 카테고리의 다른 글

crawling 풀이  (0) 2023.04.23
Long Sleep 풀이  (0) 2023.04.21
Basic_Forensics_1 풀이  (0) 2022.07.23
sint 풀이  (0) 2022.05.31
patch 풀이  (0) 2022.05.30