본문 바로가기
Study/Software Security

[소프트웨어보안] 소프트웨어의 정적 분석 방법

by 8희 2022. 10. 12.

소프트웨어의 정적 분석 방법 이론

1. 정적 분석 vs 동적 분석

 

1) 정적 분석
- 소프트웨어의 소스코드 있을 분석이 가능. 코드의 내용 속에서 취약성을 찾아낸다.
- 중요한 점: 구문 에러 논리적 에러를 찾지는 못한다.
2) 동적 분석
- 소프트웨어를 실행하여 가능한 모든 우를 실행하도록 하여 오류가 있는 지를 확인한다.
- 소스코드를 갖고 있지 않은 경우가 많다.
- 소프트웨어 개발자가 제시하지 않은 use case를 고려   있다.

 

2. 블랙 박스 테스트 vs 화이트 박스 테스트

1) 블랙 박스 Test
- 소프트웨어의 내부 구조를 전혀 알지 못한다. (소스코드를 포함)
- 소프트웨어를 다양한 각도로 실행하여 반응을 확인 하는 형태로  소프트웨어를 테스트한다.
- Test 시나리오 (입/출력 Set) 공격자의 경험 의존.

 

2) 화이트 박스 Test

- 소스 코드, 기능 구조에 대해서 이해를 바탕으로 Test를 진행.

- 소프트웨어의 소스코드 내부 구조에 대한 이해를 바탕으로 Test 시나리오(입/출력 Set) 작성.

 

-> 정적 분석은 화이트 박스 Test, 동적 분석은 둘 다 가능!

 


소프트웨어의 정적 분석 방법 실습

1) 정적 분석 실습

void foo(char *str)
{
	char* buf = new cahr[8]; //buf는 스택의 영역에 저장, 8바이트는 힙 영역에 저장
	strcpy(buf, str); //Possible buffer overrun 
    	//buf는 8바이트 공간, 근데 buf에 들어오는 값의 길이를 알 수 없어서 문제 발생 가능성

	FILE* file = fopen("out.txt","w");
	if(!file)
		return; //메모리 누수
        //파일이 안 열린다고 함수를 종료하면 buf의 주소 값이 날라가서 8바이트인 힙 영역에 접근 불가능

	for(char* c = buf; *c; ++c)
		fputc((int)*c, file);

	delete buf; //힙 공간을 지우려면 이게 아니라 delete[] buf여야 한다.
    	//파일을 열었으니 fclose(file)을 해 줘야 한다.
}

 

2) 정적 분석 실습

/* 취약한 코드 */
void f1(struct fred_t *p) //p는 외부에서 입력 받는 값
{
	// dereference p and then check if it's NULL  
    int x = p->x; //p가 NULL일 수도 있는데 그러면 p가 가리키는 x가 존재할 수 없다.
	if (p) 
		do_something(x); 
}

/* 수정 코드 */
void f1(struct fred_t *p) 
{
    int x;
	if (p)
    	x = p->x; //입력 받은 p가 NULL인지 아닌지 부터 확인
	do_something(x); 
}

 

3) 정적 분석 실습

/* 취약한 코드 */
void f2() {
	const char *p = NULL;
	for (int I = 0; str[i] != '\0'; i++) 
    	{  
        	if (str[i] == ' ') { 
			p = str + I;  
           		 break;
		}
        	//만약 str 포인터가 가리키고 있는 값에 아무것도 없다면 p는 그대로 NULL 값을 가진다.
	}
	return p[1]; //이때 P[1]을 출력하려고 하면 오류 발생! (어떤 것도 가리키고 있지 않음)
}

/* 수정 코드 */
void f2() {
	const char *p = NULL;
	for (int I = 0; str[i] != '\0'; i++) 
    	{  
        	if (str[i] == ' ') { 
			p = str + I;  
            		break;
		}
	}
    	if(p) //NULL이 아닐 때만 출력하도록 코드 수정
		return p[1]; 
}

 

4) 동적 분석 실습

int fd;
int *getval(void)
{  
    int *tmp;
    read(fd, &tmp, sizeof(tmp)); //정상적인 파일이라면 잘 진행되갰지만 실행 전까지 정상적인 파일인지 모름
    return tmp;
}

void foo(void)
{
    int *b = getval();
    *b = 0;
}