기본 콘텐츠로 건너뛰기

Buffer-Overflows_2

Buffer-Overflows_2

Off-by-one buffer overflow는 단일 바이트 값이 오버플로우된 경우로 보통 Null 종료 버그libc 함수 사용 시 계산 실수로 인해 발생된다. Adjacent memory overflowsNull 종료 버그를 이용하여 두 문자열을 연결하는 경우로 메모리 상에서 두 버퍼가 나란히 붙어있어 이러한 명칭을 가진다. 예를 들어 Null 종료 버그로 인해 종료가 제대로 되지 않으면 strlen()함수와 같이 Null 종료에 의존적인 함수들이 인접한 메모리를 계속 읽게 된다.

Off-by-one buffer overflow

다음은 Off-by-one buffer overflow의 예시로 메모리 색인 시 Off-by-one buffer overflow가 발생한다.

static int 
b64_decode( const char* str, unsigned char* space, int size ) 
    { 
    const char* cp; 
    int space_idx, phase; 
    int d, prev_d = 0; 
    unsigned char c; 
    space_idx = 0; 
    phase = 0; 
    for ( cp = str; *cp != '\0'; ++cp ) 
        { 
        d = b64_decode_table[(int) *cp]; 
        if ( d != -1 ) 
            { 
            switch ( phase ) 
                { 
                case 0: 
                ++phase; 
                break; 
                case 1:
                c = ( ( prev_d << 2 ) | ( ( d & 0x30 ) >> 4 ) ); 
                if ( space_idx < size ) 
                    space[space_idx++] = c; 
                ++phase; 
                break; 
                case 2: 
                c = ( (( prev_d & 0xf )<< 4 ) | ( ( d & 0x3c ) >> 2 )); 
                if ( space_idx < size ) 
                    space[space_idx++] = c; 
                ++phase; 
                break; 
                case 3: 
                c = ( ( ( prev_d & 0x03 ) << 6 ) | d ); 
                if ( space_idx < size ) 
                    space[space_idx++] = c; 
                phase = 0; 
                break; 
                } 
            prev_d = d; 
            } 
        } 
    return space_idx; 
    } 

이 코드를 보고 Off-by-one buffer overflow취약점을 알아차리기는 어렵다. 테이블 내에서 문자를 디코딩할 수 있는지 확인하는 코드로 가능한 경우 switch-case문을 수행한다. switch-case문 내부의 if문은 space_idx 변수를 size 인자 값과 비교하여 space_idx 변수가 size 변수보다 작으면 space_idx 변수 값을 1씩 증가시킨다.

이때, space_idx는 255이고 size는 256이라면 space_idxsize보다 작기 때문에 space [space_idx ++] = c; 명령을 수행하게 되는 데, 이로 인해 Off-by-one buffer overflow 취약점이 발생하게 된다. 배열은 0부터 시작하여 인덱싱한다. 색인 생성이 0에서 시작하기 때문에 이와 같이 선언 된 배열 (예 : ‘char array [256];’)은 마지막 유효 색인이 255가 된다. 따라서 데이터가 저장되는 버퍼의 총 크기가 하나씩 버퍼 오버플로우가 발생한다.

Adjacent memory overflow

다음은 로깅 데몬 syslogd에서 발생한 Adjacent memory overflow이다.

/*
* Validate that the remote peer has permission to log to us.
*/
int
validate(sin, hname)
struct sockaddr_in *sin;
    const char *hname;
{
    int i;
    size_t l1, l2;
    char *cp, name[MAXHOSTNAMELEN];
    struct allowedpeer *ap;
    if (NumAllowed == 0)
        /* traditional behaviour, allow everything */
        return 1;
    strncpy(name, hname, sizeof(name));
    if (strchr(name, '.') == NULL) {
        strncat(name, ".", sizeof(name) - strlen(name) - 1);
        strncat(name, LocalDomain, sizeof name -strlen(name)-1);
    }
    ...
}

strncat()
길이를 지정하여 두 개의 문자열 합침
참고 : falinux - strncat()

strlen 과 sizeof 차이
문자열을 취급 할 때에는 strlen을 사용하고, 버퍼의 크기나 변수의 크기를 다룰때에는 sizeof를 사용한다.
참고 : falinux - strlen 과 sizeof 의 차이

이 예에서 hname변수는 MAXHOSTNAMELEN 바이트 이상이고 마침표를 포함하지 않는다고 가정한다.

strncat함수는 name 변수의 크기에서 name 변수에 저장된 바이트 수와 1을 뺀 값이 적용되며 name 변수의 바이트 수가 name 변수에 저장된 바이트 크기와 같은 경우 음수 값을 갖습니다.
('sizeof(name) – strlen(name) – 1')

만약 음수 값을 갖게 된다면 부호가 없는 정수가 나타낼 수 있는 최대 값 4GB의 데이터를 복사하려고 하게 된다. 이로 인해 버퍼 오버플로가 발생한다.

버퍼 오버플로우 취약점을 일으키는 원인을 이해하는 것이 중요하다. 그리고 버퍼 오버 플로우 가 어떻게 악용될 수 있는지 이해하는 것 또한 중요하다. Smashing The Stack For Fun And Profit논문은 이를 학습하기 좋은 문서 중 하나이다.

이 블로그의 인기 게시물

데일 카네기 인간관계론 정리

Remove-Server-Header

응답 메시지 내 서버 버전 정보 제거 1. Apache 1) 조치 방법 “/etc/htpd/conf/httpd.conf” 파일 안에서 1. ServerTokens OS → ServerTokens Prod 2. ServerSignature On → ServerSignature Off 로 변경한 후 아파치를 재시작하면 헤더 값의 아파치 버전 정보 및 OS 정보를 제거할 수 있다. 2) 참고 URL http://zetawiki.com/wiki/CentOS_ 아파치_보안권장설정_ServerTokens_Prod,_ServerSignature_Off 2. IIS 1) 조치 방법 IIS 6.0 urlscan_setup 실행. 설치. \windows\system32\inetsrv\urlscan\urlscan.ini 파일을 열어 다음 수정(RemoveServerHeader=0 을 RemoveServerHeader=1 로 변경) 서비스에서 IIS Admin Service 재시작. IIS 7.0 IIS 관리자를 열고 관리하려는 수준으로 이동합니다. 기능 보기에서 HTTP 응답 헤더를 두 번 클릭합니다. HTTP 응답 헤더 페이지에서 제거할 헤더를 선택합니다. 작업 창에서 제거를 클릭하고 예를 클릭합니다. 2) 참고 URL IIS 6.0 : http://gonnie.tistory.com/entry/iis6- 응답헤더-감추기 IIS 7.0 : https://technet.microsoft.com/ko-kr/library/cc733102(v=ws.10).aspx 3. jetty 1) 조치 방법 “jetty.xml” 파일에서 jetty.send.server.version=false 설정 2) 참고 URL http://attenuated-perspicacity.blogspot.kr/2009/09/jetty-61x-hardening.html 4. Nginx ...

American Fuzzy Lop And Address Sanitizer

American Fuzzy Lop And Address Sanitizer Address Sanitizer(ASAN) 단지 gcc/clang에 -fsanitize=address 옵션을 추가하는 것으로 간단히 사용할 수 있지만 그 효과는 충분하다. Example Out Of Bounds Read #include <stdio.h> int main() { int a[ 2 ] = { 3 , 1 }; int i = 2 ; printf ( "%i\n" , a[i]); } 예제 파일을 OutOfBoundsRead.c 로 생성하고 ASAN 옵션을 지정하여 clang 으로 컴파일하자. clang -g -fsanitize = address -fno -omit -frame -pointer OutOfBoundsRead . c -o OutOfBoundsRead 생성된 OutBoundsRead 파일을 실행하면 다음과 같은 결과를 볼 수 있다. ================================================================= ==3678==ERROR: AddressSanitizer: stack-buffer-overflow on address 0x7ffc0ba87428 at pc 0x47b7db bp 0x7ffc0ba87390 sp 0x7ffc0ba87388 READ of size 4 at 0x7ffc0ba87428 thread T0 ==3678==WARNING: Trying to symbolize code, but external symbolizer is not initialized! #0 0x47b7da (/root/ASAN/OutOfBoundsRead+0x47b7da) #1 0x7faba0260f44 (/lib/x86_64-linux-gnu/libc.so.6+0x21f44) #2 0x...