이전에 해봤던 오버플로우 공격은 버퍼의 주소와 크기를 알 고 있었기에 가능한 공격이었다.
실제 상황에서는 정확한 주소와 크기를 알기 힘들다.
브루트포스로 주소를 일일이 대입하기에는 너무 오래걸린다.

여기 '거리' 라고 표시되어 있는 부분을 모를때, RET가 앞인지 뒤인지 모를 때 의 해결법이다.
이를 해결하기 위해 다음을 배워보자!
RET 주소 스프레잉 기법
버퍼 크기에 의해 RET 주소 영역이 결정된다.
특정 위치의 RET 주소 마스킹 대신, 가능한 모든 위치에 RET 주소를 마스킹하는 방법이다.

버퍼 크기의 범위를 10~100바이트로 추정하자. 여기에 20+ $\alpha$바이트 만큼 마진을 추가하자.
버퍼 시작 주소로 부터 120 + $\alpha$바이트 만큼 4바이트 단위로 RET 주소로 마스킹 한다.
이렇게 하면 추정 영역에서 어디 하나는 RET 영역이 걸린다는 뜻이다.
버퍼의 시작 주소 범위만 알 때
이럴 땐 수학적으로 접근해야 한다.
H : 버퍼의 시작 주소 범위
S : 버퍼의 크기 범위
L : NOP 영역의 크기
일 때, H = 100, S = 120, L = 150이라 가정하자.

버퍼의 정확한 시작 주소를 X라고 하면
X + S까지 RT를 작성하면 된다.
하지만 우리는 정확한 시작 주소를 모르니 X를 모르는 어떤 수 A라고 가정해보자.
A <= x <= A + H가 되겠으며, 이 범위를 시각화 하면 아래와 같다.

A + H + S ~ A + L + S 의 범위에 존재하는 RET는 무조건 걸리게 되어있다.
이 범위를 RET로 마스킹하면 된다.
64비트 프로그램 버퍼 오버플로우 공격
지금까지 32비트 프로그램에서 동작하는 오버플로우 공격을 알아봤다.
64비트 프로그램의 경우 주소가 0x00...으로 시작한다.
그런데 strcpy 등을 이용하여 버퍼에 작성시 문제가 생긴다.
null pointer를 만나면 strcpy가 종료되어 메모리를 덮어쓸 수 없게 된다.

정상적인 주소의 경우 RET의 마지막 2비트에는 0000이 저장된다. RET 다음에 악성 코드의 주소를 삽입하려 하면 null pointer를 만났기 때문에 strcpy가 악성코드를 쓰지 않는다.
빅엔디안의 경우 낮은 주소, 스택의 바텀, 에서 높은 주소로 차례대로 0x00...이 작성 되고
리틀엔디안의 경우 높은 주소에서 낮은 주소로 0x00...이 작성된다.
리틀엔디안에 대한 버퍼 오버플로우 공격
악성 코드를 RET 영역 후방에 위치시키지 않고 전방에 위치 시킨다.

단 이 방법의 경우 악성 코드의 크기가 버퍼의 크기에 제약된다.
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
void foo(char *str){
char buf[100];
}
int main(int argc, char **argv)
{
char str[400];
FILE * badfile;
badfile = fopen("badfile","r");
fread(str, sizeof(char), 400, badfile);
foo(str)
printf("foo is returned");
return 0;
}
여기서 char buf의 크기가 10일 경우 위와 같은 방법으로는 악성 코드를 작성할 수 없게 된다.

이 경우에는 main()의 스택 프레임에 악성 코드를 작성한다.
foo()의 스택 프레임에 badfile에서 리턴 주소를 str의 시작 주소로 적어둔다.
'컴퓨터 과학 > 시스템보안' 카테고리의 다른 글
| 스택 버퍼 오버플로우 공격3 (0) | 2024.11.27 |
|---|---|
| 스택 버퍼 오버플로우 공격 (0) | 2024.11.22 |
| 스택 메모리의 호출 관계 (0) | 2024.11.22 |
| 리눅스 메모리 레이아웃 (0) | 2024.11.21 |
| 컴퓨터 구조 및 x86 아키텍처 (0) | 2024.11.20 |