기본 콘텐츠로 건너뛰기

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

정리

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

이 블로그의 인기 게시물

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

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

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