일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 | 31 |
- 리버싱
- CS/자료구조/Circular_Queue
- Tree/AVL
- Tree/Binary_Search_Tree
- CS/자료구조/Stack
- Tree/AVL/Deletion
- Tree/RBTree/Insertion
- 코드엔진
- tree
- Tree/RBTree/Deletion
- Tree/Binary_Tree
- Tree/BST
- CS/자료구조/Doubly_Linked_List
- UTCTF
- Tree/AVL/Insertion
- CS/자료구조/Linked_List
- codeengn
- CS/자료구조/Priority_Queue
- CS/자료구조/Circular_Linked_List
- CS/자료구조/Singly_Linked_List
- Tree/Traversal
- ctf
- forensic
- CS/자료구조/Queue
- Tree/RBTree
- reversing
- Today
- Total
SuperVingo
CodeEngn.com Basic RCE L07 WriteUp 본문
1. 실행화면
아무거나 입력했더니
2. ExeInfoPE 분석
TASM / MASM / FASM 으로 제작되었으니 다른 언어가 아닌 어셈블리어로 제작된 프로그램이라고 유추할 수 있고, 패킹이 되어있지 않으므로 분석을 진행한다
3-1. 올리디버거 분석
전체적으로 2개의 함수가 보이고, 첫번째 함수는 main함수, 두번째 함수에서 strcat, strcmp등이 보이므로 시리얼 생성 및 비교 후, MessageBox를 출력하는 함수로 보이므로 두번째 함수를 집중적으로 보자.
이 함수 내 진행 흐름을 대충 보자면
처음 GetDlgItemTextA를 통해서 우리가 입력한 Text를 가져온 후, GetVolumeInformationA 실행 후, lstrcat + Some operation 후, strcmp를 통해 분기한다. 우리는 GetVolumeInformationA에 대해 알아야 할 필요가 있어보인다.
파일 시스템과 볼륨에 대한 정보를 얻어온다.
lpRootPathName을 통해 루트를 전해주면 여러 정보를 내뱉는다.
우리는 문제에서 C드라이브의 이름이 CodeEngn일때 이므로 lpVolumeNameBuffer에 집중하면 된다.
lpRootPathName(올리디버거에서는 Root라 적혀있다.)을 NULL값으로 주었으므로
현재 실행되는 파일의 루트 디렉토리를 사용한다고 되어있다. 그리고 volumeName은 0x0040225C에 저장된다.
그 후, lstrcmp를 진행한다. lstrcmp는 Dest 이후에 Src를 붙여넣는 함수이다. 그러면 0x0040225C, 즉 volumeName뒤에 "4562-ABEX"를 붙인다. 그 후,
반복문을 통해서 0x0040225C, 0x0040225D, 0x0040225E, 0x0040225F에 1씩 더하는 행동을 2번. 즉,
0x0040225C, 0x0040225D, 0x0040225E, 0x0040225F에 2씩 더하는 연산을 진행한다.
0x0040225C에 volumeName + "4562-ABEX"이 저장되어 있고, 이에 첫번째, 두번째, 세번째, 네번째 글자에 +2 연산을 진행한다.
그 후, 0x00402000에 "L2C-5781"을 붙인 후, 뒤에 volumeName + "4562-ABEX" 를 붙여 우리가 입력한 시리얼과 비교한다.
그럼, volumeName에 CodeEngn을 대입하면 정답을 구할 수 있다.
3-2. Ghidra 분석
Ghidra에서 실행하니 Entry 함수가 보인다. 근데 Entry에서 왠만한 함수는 전부 ExitProcess, return으로 종료된다. 하지만 FUN_00401056()에 들어가니
이런 코드가 보인다. 디컴파일 된 코드에서 변수(volumeName과 InputString)을 설정해주고 보면
BOOL FUN_00401056(void)
{
int iVar1;
BOOL BVar2;
char cVar3;
int unaff_EBP;
if (*(int *)(unaff_EBP + 0x10) != 0x65) {
if (*(int *)(unaff_EBP + 0x10) != 2) {
return 0;
}
BVar2 = EndDialog(*(HWND *)(unaff_EBP + 8),0);
return BVar2;
}
GetDlgItemTextA(*(HWND *)(unaff_EBP + 8),0x68,&InputString,0x25);
GetVolumeInformationA
((LPCSTR)0x0,&volumeName,0x32,(LPDWORD)&DAT_00402194,(LPDWORD)&DAT_00402190,
(LPDWORD)&DAT_004020c8,(LPSTR)0x0,0);
lstrcatA(&volumeName,"4562-ABEX");
cVar3 = '\x02';
do {
iVar1 = CONCAT13(DAT_0040225f,CONCAT12(DAT_0040225e,CONCAT11(DAT_0040225d,volumeName))) + 1;
volumeName = (undefined)iVar1;
iVar1 = CONCAT13(uRam00402260,(int3)((uint)iVar1 >> 8)) + 1;
DAT_0040225d = (undefined)iVar1;
iVar1 = CONCAT13(uRam00402261,(int3)((uint)iVar1 >> 8)) + 1;
DAT_0040225e = (undefined)iVar1;
iVar1 = CONCAT13(uRam00402262,(int3)((uint)iVar1 >> 8)) + 1;
DAT_0040225f = (undefined)iVar1;
uRam00402260 = (undefined)((uint)iVar1 >> 8);
uRam00402261 = (undefined)((uint)iVar1 >> 0x10);
uRam00402262 = (undefined)((uint)iVar1 >> 0x18);
cVar3 = cVar3 + -1;
} while (cVar3 != '\0');
lstrcatA(&DAT_00402000,"L2C-5781");
lstrcatA(&DAT_00402000,&volumeName);
iVar1 = lstrcmpiA(&DAT_00402000,&InputString);
if (iVar1 != 0) {
MessageBoxA(*(HWND *)(unaff_EBP + 8),s_The_serial_you_entered_is_not_co_0040243b,
s_Error!_00402434,0);
BVar2 = FUN_0040112d();
return BVar2;
}
MessageBoxA(*(HWND *)(unaff_EBP + 8),s_Yep,_you_entered_a_correct_seria_00402411,
s_Well_Done!_00402406,0);
BVar2 = FUN_0040112d();
return BVar2;
}
GetDlgItemTextA(*(HWND *)(unaff_EBP + 8),0x68,&InputString,0x25);
GetVolumeInformationA
((LPCSTR)0x0,&volumeName,0x32,(LPDWORD)&DAT_00402194,(LPDWORD)&DAT_00402190,
(LPDWORD)&DAT_004020c8,(LPSTR)0x0,0);
lstrcatA(&volumeName,"4562-ABEX");
GetDlgItemTextA에서 InputString을 받아오고, GetVolumeInformationA에서 volumeName을 얻어온다.
그 후, volumeName 뒤에 "4562-ABEX"를 붙인다.
do {
iVar1 = CONCAT13(DAT_0040225f,CONCAT12(DAT_0040225e,CONCAT11(DAT_0040225d,volumeName))) + 1;
volumeName = (undefined)iVar1;
iVar1 = CONCAT13(uRam00402260,(int3)((uint)iVar1 >> 8)) + 1;
DAT_0040225d = (undefined)iVar1;
iVar1 = CONCAT13(uRam00402261,(int3)((uint)iVar1 >> 8)) + 1;
DAT_0040225e = (undefined)iVar1;
iVar1 = CONCAT13(uRam00402262,(int3)((uint)iVar1 >> 8)) + 1;
DAT_0040225f = (undefined)iVar1;
uRam00402260 = (undefined)((uint)iVar1 >> 8);
uRam00402261 = (undefined)((uint)iVar1 >> 0x10);
uRam00402262 = (undefined)((uint)iVar1 >> 0x18);
cVar3 = cVar3 + -1;
} while (cVar3 != '\0');
이거 한숨밖에 안나오고 있었는데...
004010ad b2 02 MOV DL,0x2
004010af 83 05 5c ADD dword ptr [volumeName],0x1
22 40 00 01
004010b6 83 05 5d ADD dword ptr [DAT_0040225d],0x1
22 40 00 01
004010bd 83 05 5e ADD dword ptr [DAT_0040225e],0x1
22 40 00 01
004010c4 83 05 5f ADD dword ptr [DAT_0040225f],0x1
22 40 00 01
004010cb fe ca DEC DL
004010cd 75 e0 JNZ LAB_004010af
어셈블리어가 더 쉽다... volumeName에 앞 네자리에 +1 연산을 2번씩, 총 +2를 하게된다.
lstrcatA(&DAT_00402000,"L2C-5781");
lstrcatA(&DAT_00402000,&volumeName);
iVar1 = lstrcmpiA(&DAT_00402000,&InputString);
if (iVar1 != 0) {
MessageBoxA(*(HWND *)(unaff_EBP + 8),s_The_serial_you_entered_is_not_co_0040243b,
s_Error!_00402434,0);
BVar2 = FUN_0040112d();
return BVar2;
}
MessageBoxA(*(HWND *)(unaff_EBP + 8),s_Yep,_you_entered_a_correct_seria_00402411,
s_Well_Done!_00402406,0);
BVar2 = FUN_0040112d();
return BVar2;
이후, DAT_00402000에 "L2C-5781"과 volumeName을 붙여 InputString과 비교하여 분기된다.
즉, 시리얼은 "L2C-5781" + (volumeName앞 4자리 + 2 계산) + "4562-ABEX"이다.
A. 문제는 CodeEngn을 입력하면 어떻게 바뀌는가이다. 시리얼이 아니라.... 이거때문에 고생 많이했다.....
'Wargame[워게임] > CodeEngn' 카테고리의 다른 글
CodeEngn.com Basic RCE L09 WriteUp (0) | 2020.07.29 |
---|---|
CodeEngn.com Basic RCE L08 WriteUp (0) | 2020.07.29 |
CodeEngn.com Basic RCE L06 WriteUp (0) | 2020.07.27 |
CodeEngn.com Basic RCE L05 WriteUp (0) | 2020.07.27 |
CodeEngn.com Basic RCE L04 WriteUp (0) | 2020.07.27 |