1. 문제
1) mitigation 확인
2) 문제 확인
- 환경변수 team_name=bi0s를 설정하고 파라미터를 주면 됨
3) 코드흐름 파악
3-1) main
__int64 __fastcall main(int a1, char **a2, char **a3)
{
const char *s1; // [rsp+20h] [rbp-10h]
s1 = getenv("team_name");
if ( s1 && !strncmp(s1, "bi0s", 4uLL) )
{
if ( a1 == 2 )
{
if ( (unsigned int)sub_87C(s1, a2[1]) == 1 )
sub_830(a2[1]);
else
printf("Better luck next time!");
}
else
{
printf("usage: chall <input>");
}
}
else
{
printf("Nope.");
}
return 0LL;
}
- 파라미터 한 개를 줬을 때 sub_87C()를 호출하고 조건문이 맞으면 sub_830()을 호출한다.
3-2) sub_87C()
__int64 __fastcall sub_87C(char *a1, const char *a2)
{
size_t v3; // rbx
char v4; // dl
size_t v5; // rax
char *v6; // [rsp+8h] [rbp-68h]
char v7[32]; // [rsp+10h] [rbp-60h]
__int64 v8; // [rsp+30h] [rbp-40h]
int v9; // [rsp+48h] [rbp-28h]
int v10; // [rsp+50h] [rbp-20h]
int v11; // [rsp+54h] [rbp-1Ch]
int v12; // [rsp+58h] [rbp-18h]
int i; // [rsp+5Ch] [rbp-14h]
v6 = a1;
v12 = 0;
v11 = 0;
strcpy((char *)&v8, "1617181926381617919194");
if ( strlen(a2) != 22 )
return 0LL;
for ( i = 0; ; ++i )
{
v3 = i;
if ( v3 >= strlen(v6) )
break;
v12 += v6[i];
}
v9 = 0;
v12 /= 30;
while ( v11 != 22 )
{
if ( v11 & 1 )
v4 = a2[v11] - 4;
else
v4 = a2[v11] + 4;
v7[v11] = v4;
v7[v11] ^= v12;
++v11;
}
v10 = 0;
for ( i = strlen(v7) - 1; i >= 0; --i )
{
v5 = strlen(v7);
if ( v7[v5 - i - 1] != *((_BYTE *)&v8 + i) )
return 0LL;
}
return 1LL;
}
- 먼저, 리턴 값이 참이 되기 위해 첫 번째 if문과 마지막 if문을 피해야 한다.
- 접근 방법에서 단계별로 참이 되기 위해 어떻게 구성해야되는지 살펴보자
3-3) sub_830()
int __fastcall sub_830(__int64 a1)
{
return printf("HackCTF{%s}", a1);
}
- a1을 받고 플래그 값을 출력한다.
- 여기서 a1은 바이너리를 실행할 때 인자 값으로 들어가는 것이다.
즉, sub_87C()에서 리턴 값이 1이 되도록 인자 값을 세팅하게 되면 그게 플래그 값이 된다.
2. 접근 방법
- copy_number변수에 "1617181926381617919194"를 복사
- 파라미터 길이가 22여야 한다.
- for문에서 환경변수의 각 자리 수를 더해 sum_env에 넣는다.
- v11과 1을 AND연산해서 참 또는 거짓일 경우 v4에 param[v11] ± 4를 넣는다.
- 그리고 v7[v11]에 v4를 넣고 sum_env와 xor한고 v11을 증가시킨다.
- 즉, v11이 0부터 21까지 돌면서
- v11 홀수 :
v7[v11] = (param[v11] - 4) xor sum_env
- v11 짝수 :
v7[v11] = (param[v11] - 4) xor sum_env
- v11 홀수 :
- v7의 길이만큼 for문이 돌면서 copy_number와 비교
- 이 때, v7의 인덱스는 0 ~ 21, copy_number는 거꾸로 1byte씩 비교한다.
그럼 이제 디버깅하면서 확인해보자
(참고로 파라미터는 "A"*22만큼 주고 실행하였다.)
- env값을 모두 합한 값은 0x16e가 된다.
- 그리고 최종적으로 sum_env에는 0xc가 저장됨
- 첫 번째 인덱스에 들어 있는 "A"(0x41)값에 4를 더하고 0xc와 xor한 값인 0x49가 v7[0]에 들어가게 된다.
- 그렇게 while문이 다 돌고 v7에 값이 세팅되면 다음 for문에서 copy_number와 v7와 값을 비교한다.
3. 문제 풀이
그럼 거꾸로 해보면 답이 나온다. xor한 값에 xor을 한 번더하면 그대로니깐
파이썬을 이용해서 구해보자
cp_num = "1617181926381617919194"[::-1]
new_list = []
idx = 0
for data in cp_num:
if 1 == idx % 2:
new_list.append(chr((ord(data) ^ 0xc) + 0x4))
else:
new_list.append(chr((ord(data) ^ 0xc) - 0x4))
idx += 1
print("".join(new_list))
Uploaded by Notion2Tistory v1.1.0