리버싱 실전 | 워게임 풀이 - Ubuntu Linux

2021. 5. 31. 06:01Layer7/Reverse Engineering

728x90

- main 파일 분석 (반복문 전)

 

우선 main 파일 분석이 우선일 것 같아 메모장에 적어가며 분석했습니다.

 

:thinking:의 흔적들

s : 사용자가 입력한 문자열이 들어가는 string형 변수
    0x555555755080
dest : s가 복사될 변수
        0x5555557550c0
n : s의 길이가 담겨있는 변수
a : rbp-4
b : rbp-8
c : rip+0x2076c
d : rip+0x2007dd 


1. read

0, s, 0x31가 인자로 들어간 상태에서 입력을 받습니다.

+) read 함수는 자세하게 분석 하지 않아도 될 것 같아서 딱 여기까지만 하고 끝냈습니다


2. strlen

사용자가 입력한 s라는 문자열의 길이를 반환합니다.

+) 이것 역시 이정도 정의만 생각해놓고 생략


3. strcpy 

strcpy에 dest, s를 인자로 넣습니다.

s라는 문자열에는 사용자가 입력한 문자열이 들어있고, 이를 dest에 복사합니다.
그러므로 dest에는 s의 문자열의 복사본이 들어있는 상태로 함수가 종료됩니다.


4. strlen

s 문자열의 길이를 반환합니다.


5. memfrob

우선 이 함수에서 쓰일 rax를 0으로 초기화 해놓고 시작합니다.

memfrob에는 위에서 썼던 s라는 문자열, n이라는 변수가 인자로 들어갑니다.

+) rdi 주소에 있는 데이터들을 rsi에 있는 값의 길이만큼 42랑 xor
+) xor은 같으면 0, 다르면 1

위에 적혀있는 내용들은 메모장에 적어놨던 원본 내용입니다.

 

여기까지의 함수들보단 그 아래에 있는 코드들이 더 중요하니

설명은 저 메모장의 내용으로만 그치고 문제의 반복문 파트로 넘어가도록 하겠습니다.

 

 

- main 파일 분석 (반복문)

 

어셈블리 코드

여기서 자주 나온 것들은 변수명으로 묶어서 정리했습니다.

 

s : 사용자가 입력한 문자열이 들어가는 string형 변수
    0x555555755080
dest : s가 복사될 변수
        0x5555557550c0
n : s의 길이가 담겨있는 변수
a : rbp-4
b : rbp-8
c : rip+0x2076c
d : rip+0x2007dd 

 

원래 어셈블리 코드에서 이러한 부분들을 변수명으로 바꾸고 직관적으로 보겠습니다.

 

  • mov dword ptr a,0 : 초기식
  • jmp 0x5555555548c4 <0x5555555548c4> : 조건식으로 점프

  • mov eax, dword ptr a : rax=0 (현재 dword ptr a = 0)
  • movsxd rdx, eax : rdx = 0
  • lea rax, d : 0x555555601080(s의 주소값)을 rax가 가짐
  • movzx ecx, byte ptr [rdx + rax] : byte[rax[rdx]]
  • mov eax, dword ptr a : eax=a
  • movsxd rdx, eax : rdx <- eax
  • lea rax, c : c의 값 -> rax
  • movzx eax, byte ptr [rdx + rax] : byte[rax[rdx]]
  • xor eax, ecx : eax, ecx를 xor
  • movsx eax, al : eax <- al
  • add dword ptr b, eax : dword ptr b에 eax 대입 (eax=al)
  • add dword ptr a, 1 : i++
  • cmp dword ptr a, 0x13 : i>=0x13

 

 

- FLAG 찾기

 

" 대충 흐름 보는 분석은 다 했는데 이제 뭘 해야 FLAG를 찾을 수 있을까..... "

라는 이 고민을 저는 1시간을 했습니다.

 

자그마치 1시간이요

 

1시간...

 

아무리 해도 생각이 나질 않아서 뭐라도 해보자는 생각으로 그냥 노가다 전략에 들어갔습니다.

이때 당시 시간이 제출까지 5시간이 남은 상황이었고, 다른 과제들도 있었기에 마음이 급했습니다...

 

일단 read로 문자열을 읽어온 다음에

저 코드에 입력되어있던 문자열 값이랑 비교해서 True, Flase를 가리고

그에 맞게 슬픈 표정이든 다른 표정이든 출력을 해주는 것이 이 코드의 동작 방식입니다.

 

아까 위에서 코드가 동작하는 걸 보니 rax 레지스터에 문자열에 관한 정보들이 저장되고 있었습니다.

반복문 전까지는 볼 필요가 없을 것 같으니 반복문 시작부터 x/s 명령어로 하나하나 보기 시작했습니다.

 

만약 예상이 틀렸다면 다른 방법으로 또 노가다를 할 생각이였....

 

ni를 계속 누르면서 rax에 0x0이 아닌 다른 값들이 들어있을 때마

x/s [주소 값] 명령어로 문자열을 출력해봤더니 중간쯤 가서 뭔가 이상한 문자열이 보였습니다.

 

?

CTF나 워게임에서 misc 문제들을 풀 때를 생각해보면

이런 이상한 문자열, 사진, 그림 같은 것들을 복호화하면 항상 FLAG가 나왔던 것 같습니다.

 

지금까지 했던 연산을 떠올려보니 생각나는 게 XOR밖에 없어서

일단 그에 맞춰 복호화 코드를 만들었습니다.

(코드는 Dev C++, C언어로 짰습니다.)

 

#include<stdio.h>
#include<string.h>

int main(){
	char arr[]="F\031^\rYu]\036XGu\033^u_ZuHES";
	int l;
	l=strlen(arr);
	for(int i=0;i<l;i++){
		arr[i]=arr[i]^42;//XORXORXORXORXORXORXOR
		printf("%c",arr[i]);
	}
}

코드 실행 결과

예상외로 뭔가 잘 풀리고 있는 것 같습니다.

이제 나온 저 문자열을 main 파일을 실행시킨 후에 입력하면...

 

FLAG 획득 성공

이렇게 FLAG가 나오게 됩니다

 

FLAG : securinets{l3t's_w4rm_1t_up_boy}

728x90