4. flag - Pwnable.kr 해설

2020. 3. 11. 01:53문제연습/Pwnable.kr (PWN)

반응형

티스토리 블로그는 PC 환경에 최적화되어 있습니다.

모바일 유저분들은 아래 네이버 블로그를 이용해 주세요.

 

4. flag

네이버 블로그는 모바일 환경에 최적화되어 있습니다.PC 유저분들은 아래 티스토리 블로그를 이용해 주세...

blog.naver.com

 

안녕하세요, ICMP입니다.

오늘은 pwnable.kr의 4번째 문제인 flag를 풀어 보도록 하겠습니다.

 

문제 내용

Papa brought me a packed present! let's open it.

Download : http://pwnable.kr/bin/flag

 

This is reversing task. all you need is binary

 

 

들어가기 전

What is reversing and UPX packing?

 

1. Reversing

리버스 엔지니어링 또는역공학은 장치 또는 시스템의 기술적인 원리를 그 구조분석을 통해 발견하는 과정이다.

 

2. UPX packing

UPX(UltimatePacker for eXecutables)는 여러 운영체제에서 수많은 파일 포맷을 지원하는오픈 소스실행 파일 압축프로그램이다.

 

 

문제 해설

일단 http://pwnable.kr/bin/flag링크로 들어가서 바이너리 파일을 다운로드하도록 하겠습니다.

파일을 다운로드한 후 cd 명령어로 flag 파일이 있는 곳으로 이동하여 gdb로 분석을 시도하도록 하겠습니다.

 

gdb에 대한 내용은 아래 링크를 이용해 주세요.

 

3. 버퍼 오버플로 (bof)

네이버 블로그는 모바일 환경에 최적화되어 있습니다.PC 유저분들은 아래 티스토리 블로그를 이용해 주세...

blog.naver.com

 

어떤 언어로 flag라는 파일을 작성했는지는 모르겠지만 그냥 한번 ./flag로 실행해보니 malloc 함수와 strcpy 함수에 flag를 넣어놨다는 내용이 출력됩니다.

이 말이 사실이면 flag라는 파일은 c언어로 작성된 프로그램이라고 추측할 수 있습니다.

 

그런데 조금 이상합니다.

gdb로 disas를 이용하니 symbol을 읽을 수 없다며 어셈블리 코드를 출력하지 않습니다.

이런 경우에는 파일이 손상되었거나 암호화(또는 패킹)를 하여 읽지 못하는 경우입니다.

 

먼저 exeinfo를 이용해 패킹 여부를 검사하도록 하겠습니다.

exeinfo에 대한 설치, 사용법은 아래 링크를 이용해 주세요.

 

Exeinfo PE (PEiD) 프로그램 분석 툴 - 다운로드와 사용법

Exeinfo PE? Exeinfo PE 는 A.S.L 이 만든 소프트웨어이며, 프리웨어 버전 이라고 되있는걸 보아하니 유료 버전도 있는 것 같다. 본 소프트웨어는 PEiD 와 같은 분석 툴이며, 실행 후 드래그&드롭 으로 간편하게..

deidesheim.tistory.com

 

flag 파일을 넣고 검사해보니 아래에 UPX 패킹이 감지되었습니다.

압축 때문에 gdb가 정상적으로 어셈블리 코드를 읽어낼 수 없었던 것입니다.

패킹 종류를 보니 UPX 패킹이 되어 있었군요.

이제 우리가 할 일은 upx 패킹을 풀고 파일을 분석하는 것입니다.

 

UPX를 설치하는 방법과 명령어는 아래링크를 이용해 주세요.

 

How to install upx ubuntu package on Ubuntu 18.04/Ubuntu 19.04/Ubuntu 16.04

How To Install "upx" Package on Ubuntu Quick Install Instructions of upx on Ubuntu Server. It’s Super Easy! simply click on Copy button to copy the command and paste into your command line terminal using built-in APT package manager. See below for quick st

zoomadmin.com

 

그럼 터미널 창을 열어서 cd 명령어로 flag가 있는 경로로 이동한 다음 upx -d ./flag 명령어를 입력하여 UPX unpacking을 진행하도록 합니다.

언 패킹이 되었으니 다시 한번 gdb로 파일을 분석해 보도록 하겠습니다.

 

드디어 제대로 gdb 분석이 되는군요.

disas main으로 main 문을 분석하니 다음과 같은 어셈블리 코드를 출력하였습니다.

 

레지스터의 이름에 %가 붙어있는 걸로 보니 AT&T 문법으로 어셈블리 코딩을 했나 봅니다.

이를 미리 확인하는 이유는 Operand 순서가 달라지기 때문입니다.

정확한 내용은 아래 링크를 이용해 주세요.

 

Linux Assembly Code

Linux Assembly Code 글쓴이 : 이호 (i@flyduck.com) 최신 글이 있는 곳 : http://linux.flyduck.com/ v0.1.0 2000년 3월 28일 차례 이 문서는 리눅스에서 사용하는 어셈블리 문법에 대해서 (특히 x86에서) 간략히 요약한 글입니다. GAS와 AT&T 문법에서는 어셈블리 코드의 형식과 이것이 인텔에서 사용하는 문법과 어떤 차이가 있는지를 나타냅니다. 이 부분은 인텔에서 사용하는 어셈블리(Macro A

doc.kldp.org

이 어셈블리 코드를 해석해서 우리 입맛에 맞게 c 코드로 직접 변환해 보도록 하겠습니다.

어셈블리 코드를 해석해 보도록 하겠습니다.

 

현재 I will malloc() and strcpy the flag there. take it.라는 문자열을 출력 시키기 위해 puts 함수를 이용하였습니다.

그러면 puts 함수의 인자로 들어갈 문자열을 이미 어딘가에 저장했다는 건데, puts 함수를 출력하기 전에 edi 레지스터에 어떤 주소를 집어넣고 있습니다. gdb를 통해 0x496658 주소의 내용을 확인해보니 우리가 본 문자열이 들어가 있습니다.

 

어셈블리 코드에서 나타나는 레지스터에 대한 내용은 아래 링크를 참고해 주세요.

 

[개념 이해] CPU 레지스터

리버싱이나 악성코드 분석을 하기 위해서는 레지스터에 대해 알아아 합니다. OllyDBG.exe로 디버깅하면서 우측 상단에 EAX, EBX... 등으로 되어 있는 것을 한번쯤 보셨을 것입니다. 이것이 바로 OllyDBG.exe에서..

securityfactory.tistory.com

 

위에서 분석한 내용을 기반으로 c언어 코드로 변환해 보면 아마 puts("I will malloc() and strcpy the flag there. take it.");의 형태 코드가 되겠네요.

계속해서 어셈블리 코드를 해석해 보도록 하겠습니다.

 

puts 함수로 문자열을 출력 후 malloc 함수를 통해 동적 할당을 하고 있습니다.

malloc 함수를 호출하기 전에 먼저 함수에 들어갈 인자를 준비하는 과정이 필요합니다.

때마침 puts 함수 call 후 mov $0x64,%edi 코드가 있습니다. (GAS 문법과는 다르게 오퍼랜드 순서가 반대입니다!!!)

이후 malloc 함수가 call 되는데, 이를 통해 malloc(0x64)로 동적 할당을 했다고 볼 수 있습니다.

 

c언어 동적할당과 malloc 함수에 대한 내용은 아래 링크를 참고해 주세요.

 

C 언어 코딩 도장: 35.1 메모리 할당하기

메모리를 사용하려면 malloc 함수로 사용할 메모리 공간을 확보해야 합니다(memory allocation). 이때 필요한 메모리 크기는 바이트 단위로 지정합니다(메모리 할당, 해제 함수는 stdlib.h 헤더 파일에 선언되어 있습니다). 포인터 = malloc(크기); void *malloc(size_t _Size); 성공하면 메모리 주소를 반환, 실패하면 NULL을 반환 다음 내용을 소스 코드 편집 창에 입력한 뒤 실행해보세요. 만약 컴파일할 때 "

dojang.io

동적 할당을 통한 메모리 확보된 주소는 실행마다 달라집니다.

그렇기 때문에 내용의 변조가 없는 flag(문자열)을 참고하고 있는 주소를 통해 flag를 추출해야 합니다.

 

malloc 함수의 어셈블리 코드와 작동 원리는 아래 링크를 참고해 주세요.

 

What exactly does _malloc do in assembly?

public main main proc near push ebp mov ebp, esp and esp, 0FFFFFFF0h sub esp, 30h mov dword ptr [esp], 8 ; size call _malloc mov [esp+2Ch], eax mov dword ptr [esp+4], ...

stackoverflow.com

계속해서 읽어보도록 하겠습니다.

 

malloc 함수의 어셈블리 코드에서 다음과 같이 작동합니다.(위 링크를 참고해 주세요.)

It's a pretty straightforward function: pass the number of BYTES you want as the only parameter, in rdi.

You'll get back a pointer to the allocated bytes returned in rax.

 

요약하자면 malloc 함수는 rdi에게 동적할당할 바이트 수를 저장, malloc의 인자로 들어가고 동적할당된 메모리 공간에 대한 포인터를 rax 레지스터에 저장합니다.

(rdi나 edi나 32bit 64bit 차이일 뿐 다른 기능은 똑같습니다. 정확한 내용은 아래 링크를 이용해 주세요.)

 

what are the purpose of different types of assembly registers?

Assume this is in AT&T syntax. When there is a question such as: movl (%rdi), %ecx What is the purpose of %rdi or %ecx? I understand the concept of mov(q,l,w,b) or add(q,l,w,b) and so on. ...

stackoverflow.com

 

0x400320 위치에서 다시 어떤 함수를 call 하고 있습니다. 추측하기로는 아마 strcpy(문자열 복사) 함수가 아닐까 생각합니다.

 

지금까지 얻었던 모든 내용을 압축하여 c언어로 다시 의사 코드 작성해보면 다음과 같습니다.

아주 깔끔하죠???

1
2
3
4
5
6
7
8
int main() {
    puts(*0x496658);
    rdi = malloc(0x64);
    rsi = 0x6c2070;
    strcpy(rdi, rsi);
 
    return 0;
}
 

이제 얼마 안 남았습니다. 조금만 더 힘내봅시다.

 

0x0000000000401184 위치에서 갑자기 0x2c0ee5(%rip)가 나옵니다. rip 레지스터는 다음 명령어 주소를 보관하는 역할을 합니다.

즉 rip = 0x000000000040118b 값을 저장하고 있습니다.

디버거 동작 환경에 따라 다르게 표시되지만 0x2c0ee5(%rip)은 rip+0x2c0ee5를 가리키는 포인터입니다.

주솟값을 계산하자면 0x2c0ee5 + 0x000000000040118b = 0x6c2070입니다.

 

위에서 우리가 만든 c언어 의사 코드와 비교할 때 rsi = 0x6c2070;가 맞는 것입니다.

즉 flag는 0x6c2070 주소에 있다고 볼 수 있습니다.

 

0x6c2070로 가서 값을 확인해보니 0x496628 주소가 있었습니다.

이 주소로 이동하니 또 다른 값이 있어서 0x496628 주소에 저장된 값을 문자로 출력하니 우리가 원하던 flag가 출력되었습니다.

 

이번 문제는 여러모로 공부가 된 아주 좋은 리버싱 문제였습니다.

다음 시간에는 passcode 해설을 진행하도록 하겠습니다..

이상 ICMP였습니다!!

반응형