728x90
1. 문제
Key 값이 5D88-53B4-52A87D27-1D0D-5B09 일때 Name은 무엇인가
힌트 : Name은 두자리인데.. 알파벳일수도 있고 숫자일수도 있고..
정답인증은 Name의 MD5 해쉬값(대문자)
이번엔 반대로 키젠되는 값을 주고 그에 해당하는 Name을 맞춰야한다
델파이로 만들어짐
2. 접근방법
basic 17번 문젠가 그거랑 비슷하다.
int __usercall TForm1_Button1Click@<eax>(int a1@<eax>, int a2@<ebx>)
{
int name_len; // eax
int v4; // eax
char v5; // zf
int v7; // [esp-14h] [ebp-2Ch]
unsigned int v8[2]; // [esp-10h] [ebp-28h] BYREF
int *v9; // [esp-8h] [ebp-20h]
int v10; // [esp-4h] [ebp-1Ch]
void *serial; // [esp+0h] [ebp-18h] BYREF
int v12; // [esp+4h] [ebp-14h] BYREF
int v13; // [esp+8h] [ebp-10h] BYREF
int v14; // [esp+Ch] [ebp-Ch]
int v15; // [esp+10h] [ebp-8h]
int v16; // [esp+14h] [ebp-4h] BYREF
int savedregs; // [esp+18h] [ebp+0h] BYREF
v14 = 0;
v13 = 0;
v12 = 0;
serial = 0;
v10 = a2;
v9 = &savedregs;
v8[1] = (unsigned int)&loc_45BC02;
v8[0] = (unsigned int)NtCurrentTeb()->NtTib.ExceptionList;
__writefsdword(0, (unsigned int)v8);
Controls::TControl::GetText(*(Controls::TControl **)(a1 + 872));
v15 = v16;
name_len = v16;
if ( v16 )
name_len = *(_DWORD *)(v16 - 4);
if ( name_len >= 3 ) // Name의 사이즈가 3이상이야지 들어옴. 문제에선 2바이트라했으니 패치해야함
{
Controls::TControl::GetText(*(Controls::TControl **)(a1 + 872));
v15 = v14;
v4 = v14;
if ( v14 )
v4 = *(_DWORD *)(v14 - 4);
if ( v4 <= 0x1E ) // Name size <= 0x1e
{
Controls::TControl::GetText(*(Controls::TControl **)(a1 + 884));
v7 = v13; // v13=serial
Controls::TControl::GetText(*(Controls::TControl **)(a1 + 872));
keygen(serial, (int)&v12); // keygen 함수
System::__linkproc__ LStrCmp(v7, v12);
if ( v5 )
Forms::TApplication::MessageBox(*(Forms::TApplication **)off_45E9C0[0], "Well done!", "Good Boy!!!", 0x40u);
else
Sleep_0(0x14Du);
}
else
{
Controls::TControl::SetText(*(Controls::TControl **)(a1 + 884), (const int)&str_Please_Enter_No[1]);
}
}
else
{
Controls::TControl::SetText(*(Controls::TControl **)(a1 + 884), (const int)&str_Please_Enter_Mo[1]);
}
__writefsdword(0, v8[0]);
v9 = (int *)&loc_45BC09;
System::__linkproc__ LStrClr(&serial);
System::__linkproc__ LStrClr(&v12);
System::__linkproc__ LStrArrayClr(&v13, 2);
return System::__linkproc__ LStrClr(&v16);
}
결국 keygen() 함수를 분석해야한다. 첫번째 인자로 serial을 갖고 들어간다
int __fastcall keygen(void *input, int a2)
{
....
v31 = a2;
v33 = input;
System::__linkproc__ LStrAddRef(input);
v21 = &savedregs;
v20[1] = (unsigned int)&loc_45BAAA;
v20[0] = (unsigned int)NtCurrentTeb()->NtTib.ExceptionList;
__writefsdword(0, (unsigned int)v20);
v2 = 0;
v3 = 0;
v30 = 0;
v4 = (char *)v33;
if ( name )
v4 = (char *)*((_DWORD *)name - 1);
if ( (int)v4 > 0 )
{
v5 = 1;
do
{
v6 = 0x772 * (v2 + (unsigned __int8)name[v5 - 1]);
v3 = 2280 * (v6 * v6 + v6);
v2 = v3;
++v5;
--v4;
}
while ( v4 );
}
v7 = (int)v33;
if ( v33 )
v7 = *((_DWORD *)v33 - 1);
if ( v7 >= 1 )
{
do
v30 += 605316 * ((unsigned __int8)*((char *)v33 + --v7) + 12);
while ( v7 );
}
System::__linkproc__ LStrCat3((int)&v28, v33, &str_w09__720_______[1]);
sub_45B54C(v28, &v32);
v8 = 0;
v9 = 0;
v10 = (int)v33;
if ( v33 )
v10 = *((_DWORD *)v33 - 1);
if ( v10 >= 1 )
{
do
{
v8 = 33682 * (v9 + (unsigned __int8)*((char *)v33 + v10 - 1) + v8 + 4240);
v9 = v8 + v8 * (v8 - 51);
--v10;
}
while ( v10 );
}
v11 = 0;
v12 = (char *)v33;
if ( v33 )
v12 = (char *)*((_DWORD *)v33 - 1);
if ( (int)v12 > 0 )
{
v29 = 1;
do
{
v13 = 2 * ((unsigned __int8)*((char *)v33 + v29 - 1) + v11);
v14 = (unsigned __int8)*((char *)v33 + v29 - 1) + 883 * ((v13 * v13 * v13) ^ 0x10 | 0x44) + 1091;
v11 = v14 * v14;
++v29;
--v12;
}
while ( v12 );
}
Sysutils::IntToHex(v3, 4);
System::__linkproc__ LStrCopy(&v27);
Sysutils::IntToHex(v30, 0);
System::__linkproc__ LStrCopy(&v26);
v19 = v26;
System::__linkproc__ LStrCopy(&v25);
v18 = v25;
Sysutils::IntToHex(v8, 0);
System::__linkproc__ LStrCopy(&v24);
v17 = v24;
Sysutils::IntToHex(v11, 0);
System::__linkproc__ LStrCopy(&v23);
System::__linkproc__ LStrCatN(v31, 9, v15, &str___13[1], v19, &str___13[1], v18, &str___13[1], v17, &str___13[1], v23);
__writefsdword(0, v20[0]);
v21 = (int *)&loc_45BAB1;
System::__linkproc__ LStrArrayClr(&v22, 10);
return System::__linkproc__ LStrArrayClr(&v32, 2);
}
basic 17번 문제와 동일한 로직이다. 다른점은 Name의 값이 2바이트라는 점이다.
5D88-53B4-52A87D27-1D0D-5B09 의 키가 생성되는데, 맨 처음 4바이트가 위 코드의 형광펜쳐진 부분에서 생성된다. 따라서 우리는 저번 17번 코드에서 포팅한 코드에서 2바이트 형식으로 조금만 손봐주면 된다. 로직 설명은 아예 동일해서 아래 글을 참고하면 된다
3. 풀이
import hashlib
v6 = 0
v2 = 0
flag = 0
for i in range(0x21, 0x7F):
for j in range(0x21, 0x7F):
# i = ord("A")
# j = ord("B")
v6 = (v2 + i) * 0x772
tmp = (v6 * v6) & 0xFFFFFFFF
tmp = ((tmp + v6) * 0x474) & 0xFFFFFFFF
tmp = (tmp + tmp) & 0xFFFFFFFF
v6 = (tmp + j) * 0x772
tmp = (v6 * v6) & 0xFFFFFFFF
tmp = ((tmp + v6) * 0x474) & 0xFFFFFFFF
tmp = (tmp + tmp) & 0xFFFFFFFF
if tmp >> (8 * 2) == 0x5D88:
flag = chr(i) + chr(j)
print("Name is " + flag)
enc = hashlib.md5()
enc.update(flag.encode("utf-8"))
encText = enc.hexdigest()
print("md5 hash is " + str(encText).upper())
flag = 1
break
> E:\JungJaeho\STUDY\Self\hacking\Wargame\CodeEngine\advance rev\08>C:/Users/wogh8732/AppData/Local/Programs/Python/Python37/python.exe "e:/JungJaeho/STUDY/Self/hacking/Wargame/CodeEngine/advance rev/08/ex3.py"
Name is C6
md5 hash is 7E8B9F5CAB4A8FE24FAD9FE4B7452702
참고로 원본 바이너리로는 위와같이 출력 안됌. 코드 패치해서 Name 사이즈 비교를 2로 수정해야함
4. 몰랐던 개념
728x90
'워게임 > CodeEngn' 카테고리의 다른 글
[CodeEngn] Advance RCE L10 (0) | 2021.02.05 |
---|---|
[CodeEngn] Advance RCE L09 (0) | 2021.02.04 |
[CodeEngn] Advance RCE L07 (0) | 2021.02.02 |
[CodeEngn] Advance RCE L06 (0) | 2021.01.30 |
[CodeEngn] Advance RCE L05 (0) | 2021.01.29 |
Uploaded by Notion2Tistory v1.1.0