기본 콘텐츠로 건너뛰기

memory-corruption-impact

memory-corruption-impact

메모리 오염 영향 평가

취약점의 심각도를 가장 정확하게 파악할 수 있는 방법은 POC 공격을 작성하는 것이지만, 이는 너무 많은 시간을 필요로 한다. 따라서 몇 가지 질문에 대한 답을 찾는 것으로 영향 평가를 수행할 수 있다.

메모리에서 버퍼의 위치

변수는 주로 스택, 힙, 지속 데이터(정적 변수, 전역 변수 포함) 이렇게 세 개의 메모리 영역에 저장되지만 종종 이 세 위치를 분할하거나 새로운 영역을 나누기도 한다. 때로는 초기화된 전역 변수와 초기화 되지 않은 전역 변수를 나누기도 하고, 특별할 위치에 TLS를 두기도 한다. 또한 공유 라이브러리는 라이브러리 코드 바로 다음에 위치하는 프로세스 메모리에 초기화되거나 비초기화된 상태에서 매핑된다. 어디서 메모리 오염이 일어나고 어떤 특별한 고려 사항이 적용되는지 파악할 필요성이 있으며, 운영체제 별 고유 메모리 배치에 대한 이해가 필요하다.

다른 데이터로 덮어쓰기 되는 것

메모리 오염은 공격자가 목표하는 변수에만 국한되지 않을 수 있으며, 다른 변수에 까지 값을 덮어 쓸 수 있다. 예제에서 보는 바와 같이 프로그램 카운터를 덮어쓰기전 지역 변수 값을 같이 덮어쓸 수 잇다.

지역 변수로의 오버플로우

int dostuff(char *login)
{
	char *ptr = (char *)malloc(1024);
	char buf[1024];
	...
	strcpy(buf, login);
	...
	free(ptr);

	return 0;
}

여기서 공격자는 프로그램 카운터를 덮어쓸 때 ptr 변수도 같이 덮어쓰게 되는데, ptr 변수는 프로그램이 리턴되기 바로 전에 해제되는 값이다. 이로 인해 유효하지 않은 주소 값으로 ptr 변수를 덮어 쓰게 되면 free() 함수 호출 시 프로그램 크래시가 발생할 수 있다. 이로 인해 단순히 프로그램 카운터를 덮어쓰는 것보다 훨씬 복잡해졌다. 이 처럼 버퍼 오버플로우 취약점 위험 평가 시에는 공격 시도를 완화할 수 있는 경로의 모든 변수에 관심을 기울여야 한다.

덮어쓰기가 가능한 바이트 수

정해진 크기로만 오버플로우를 일으키는 경우 공격을 좀더 어렵게 한다. 하지만 여전히 취약점 공격이 가능하다. 적은 수의 바이트만 변조된다면 취약점 공격 가능성은 어떤 데이터가 오염되는지에 따라 달려 있다. 메모리에서 다시 사용되지 않는 변수 값만 변경할 수 있다면 이 버그는 취약점을 공격하는 데 도움이 되지 않는다.

반대로 많은 양을 변조 시킬 수 있다면 이 버그는 메모리의 많은 부분을 오염시키고 프로세스를 파괴할 가능성이 높다. 가장 일반적인 예는 예외가 발생한 후 참조하는 함수 포인터 값을 갖고 있는 SEH 구조체를 닾어쓰는 윈도우상의 스택 기반 오버플로우다.

임의 장소에 다발적인 쓰기를 발생시키는 경우도 존재한다. 이와 같은 경우 공격자는 어떻게 공격할지에 대한 많은 선택권을 가지게 된다.

1, 2바이트의 덮어쓰기가 4바이트 덮어쓰기보다 공격이 더 쉬울 때가 있다. 예를 들어 포인터를 덮어쓴다고 할 때, 포인터가 객체를 가리키게 하는 대신 데이터 버퍼를 가리키게 포인터 값 중 최하위 바이트를 덮어씀으로써 안정적으로 취약점을 공격할 수 있다.

메모리를 오염시키는 데 사용될 수 있는 데이터

일부 취약점은 메모리를 덮어쓰는 데 사용된 데이터를 직접 제어할 수 없다. 이 데이터가 문자 제약이 있는지, 한 바이트 덮어쓰기인지, 공격자가 다루기 용이한 memset() 호출과 함깨 쓰이지는지에 따라 쓰임이 제한적일 수 있다.

간접적 메모리 오염

int process_string(char *string)
{
	char **tokens, *ptr;
	int tokencount;
	token = (char **)calloc(64, sizeof(char *));

	if(!tokens)
		return -1;

	for(ptr = string; *ptr;) 
	{
		int c;
		for(end = ptr; *end && !isspace(end); end++);
		c = *end;
		*end = '\0';
		
		tokens[tokencount++] = ptr;

		ptr = (c == 0 ? end : end + 1);	
	}
	...

메모리를 덮어쓰는 데 사용한 데이터는 공격자에 의해 직접 제어되지 않지만, 덮어쓰기 된 메모리는 공격자가 제어 가능한 데이터를 가리키는 포인터를 포함한다.

Off-by-One 덮어쓰기

Off-by-one 취약점은 공격자가 제어하지 않는 데이터에 덮어쓰기와 관련된 가장 일반적인 취약점 중 하나이다.

struct {
	int sequence;
	int mac[MAX_MAC];
	char *key;
};

int delete_session(struct session * session)
{
	memset(session->key, 0, KEY_SIZE);
	free(session->key);
	free(session);
}

int get_mac(int fd, struct session *session)
{
	unsigned int i, n;
	n = read_network_integer(fd);

	if(n > MAX_MAC)
		return -1;

	for(i = 0; i <= n; i++)
		session->mac[i] = read_network_integer(fd);
	...

공격자가 mac의 길이를 정확하게 MAX_MAC으로 지정했다면 get_mac()함수는 할당된 공간보다 한 엘리먼트를 더 읽게 된다. 이 경우 마지막에 읽어 들인 정수 값은 key 변수에 덮어 쓰이게 된다. delete_session() 함수가 호출되면 key 변수가 비워지기 전에 memset으로 값이 넘겨지는데, 이것으로 공격자는 메모리의 임의의 장소에 NULL 바이트 뿐만 아니라 그 밖의 값을 덮어쓸 수 있다. 이런 종류의 취약ㅈ머은 어떤 데이터를 덮어쓰기 할지 선택할 수 없으므로 복잡하다.

메모리 블록의 공유

메모리 관리자가 오동작으로 한 번 이상 같은 메모리 블록을 배포할 때 애플리케이션에서 발생한다. 이런 취약점은 다음 두가지 이유 중 하나로 발생한다.

  • 메모리 관리 코드의 버그
  • 올바르게 사용되지 않는 메모리 관리 API

정리

메모리 오염 취약점 공격 분야는 계속적으로 연구 중이고, 불가능했던 것으로 간주되던 부분을 이용해 공격하는 새로운 방법을 찾아내면서 계속적으로 진화하고 있다. 그러므로 검토자로서는 안전하다고 증명될 때까지는 모든 메모리 오염 이슈를 잠재적으로 심각한 취약점으로 취급할 필요가 있다.

이 블로그의 인기 게시물

X-Frame-Options-Test

X-Frame-Options 테스트하기 X-Frame-Options 페이지 구성 시 삽입된 프레임의 출처를 검증하여 허용하지 않는 페이지 URL일 경우 해당 프레임을 포함하지 않는 확장 응답 헤더이다. 보안 목적으로 사용되는 확장 헤더로 아직 적용되지 않은 사이트들이 많지만 앞으로 점차 적용될 것으로 보인다. X-Frame OptionsDENY, SAMEORIGIN, ALLOW-FROM 옵션을 이용하여 세부 정책을 설정한다. 옵션 설명 DENY Frame 비허용 SAMEORIGIN 동일한 ORIGIN에 해당하는 Frame만 허용 ALLOW-FROM 지정된 ORIGIN에 해당하는 Frame만 허용 크롬 4.1 , IE 8 , 오페라 10.5 , 사파리 4.0 , 파이어폭스 3.6.9 이상에서는 DENY , SAMEORIGIN 이 적용되며, ALLOW-FROM 은 각 브라우저 마다 지원 현황이 다르다. https://developer.mozilla.org/ko/docs/Web/HTTP/Headers/X-Frame-Options 해당 확장헤더는 브라우저에서 처리하는 응답 헤더이므로 미지원 브라우저 사용 시 설정과 무관하게 페이지 내 포함된 모든 Frame을 출력한다. (검증 테스트: Opera 5.0.0) 테스트 코드 DENY <!DOCTYPE html> < html lang = "en" > < head > < meta http-equiv = "X-Frame-Options" content = "deny" /> < title > Deny option Test </ title > </ head > < bod

C-lang-vulnerabilities

C 언어 공통 취약점 해당 글은 CERN Computer Security의 Common vulnerabilities guide for C programmers 글을 참고하여 작성하였습니다. C언어에서 발생하는 대부분의 취약점은 버퍼 오버플로우와 문자열 처리 미흡과 관련되어 있다. 이는 segmentation fault를 유발하고 입력 값을 조작할 경우 임의 코드 실행으로 이어질 수 있다. 이에 대부분의 에러와 조치 방안을 살펴보자고 한다. gets stdio gets() 함수는 버퍼 길이를 검증하지 않아 사용 시 항상 취약성을 야기한다. Vulnerable Code #include<stdio.h> int main() { char username[ 8 ]; int allow = 0 ; printf ( "Enter your username, please: " ); gets(username); //악의적인 값 삽입 if (grantAccess(username)) { allow = 1 ; } if (allow != 0 ) { //username을 오버플로우하여 덮어씀 privilegeAction(); } return 0 ; } Mitigation fgets() 함수 사용 및 동적 메모리 할당 #include <stdio.h> #include <stdlib.h> #define LENGTH 8 int main () { char * username, *nlptr; int allow = 0 ; username = malloc (LENGTH * sizeof (*username)); if (!username) return EXIT_FAILURE; printf ( "Enter your username, please:

HTML/CSS를 활용하여 카카오톡 클론 만들기

시간을 내어 HTML과 CSS를 공부한 것은 대학생 때가 마지막이었던 것으로 기억한다. 그 동안 사이드 프로젝트로 진행했던 여러 아이디어들을 결국 서비스하지 못했던 결정적인 이유는 프론트 엔드 기술 부족이었다고 생각하고 우선 HTML과 CSS 학습을 진행하였다. 프론트 엔드 기술은 많은 발전을 거듭하여 예전에 비해 큰 복잡성을 가지게 되었다. 빠른 시간 안에 숙지하지 못한 기법들에 대해서 알아보고 구현하고자 하는 아이디어에 활용할 수 있을 정도로 진행해보고자 한다. 또한 보안적 관점에서 발생할 수 있는 프론트 엔드 위협에 대해 파악할 수 있는 좋은 밑거름이 되길 기대해본다. 우선적으로 진행한 카카오 톡 디자인 클론은 노마드 아카데미의 강의를 수강하며 진행하였고 결과는 아래의 링크에서 확인할 수 있다. 소스코드 저장소 구현된 웹 페이지