2. 포맷 스트링

O C언어로 만드는 프로그램 중 변수의 값을 출력하거나 입력 받을 때 입력 값을 처리하는 부분에서 메모리공간에 접근할 수 있는 문제를 이용하는 취약점


O 근거 자료 

주요정보통신기반시설 기술적 취약점 분석 평가 상세 가이드 (p.655)


O 판단 기준

양호임의의 문자열 입력에 대한 검증이 이루어지는 경우
취약임의의 문자열 입력에 대한 검증이 이루어지지 않는 경우
- 정상적인 입력에서는 미 발생한 500에러나 에러 메시지가 발생할 경우 
- 내부의 일반 코드에서 에러가 발생했다는 메시지가 표시될 경우 
- 서버에서 완전하지 않거나 이상한 응답을 할 경우 
- 응답을 받지 못하고 갑자기 연결이 끊어질 경우
- 전체 웹 사이트가 반응이 없을 경우  


O 점검 방법

- 변수 값에 다음과 같은 패턴(문자열 입력 포맷)을 삽입한다.

: %n%n%n%n%n%n%n%n%n%n

: %s%s%s%s%s%s%s%s%s%s

: %1!n!%2!n!%3!n!%4!n!%5!n!%6!n!%7!n!%8!n!%9!n!!n!

: %1!s!%2!s!%3!s!%4!s!%5!s!%6!s!%7!s!%8!s!%9!s!!s!


O 조치 방법 

- 컴파일러에서는 문자열 입력 포맷에 대한 자체적인 검사를 내장하고 있으므로 문자열 입력 포맷 검증 후 소스 코드에 적용

- 웹 서버 및 웹 서버 응용프로그램(WAS)의 제공사에서 안전성이 검증된 최신 보안 패치가 반영 및 적용되도록 유지

- 웹사이트 인수 값 처리 중 발생할 경우 사용자가 입력하는 인수 값의 유효성에 대한 검증 로직 구현

- 아래의 취약한 포맷 스트링 함수 사용 지양

: Fprintf, printf, sprint, snprintf, vfprintf, vprintf, vsprintf, syslog

- 포맷 스트링을 함수의 입력 파라미터로 직접 사용 금지


O 시큐어 코딩(Secure Coding) 예시

# JAVA ▶ 
// 외부 입력값이 포맷 문자열 출력에 사용되지 않도록 수정
import java.util.Calendar;

public class Main {    
    public static void main(String[] args) {
        Calendar validDate = Calendar.getInstance();
        validDate.set(2014, Calendar.OCTOBER, 14);
        System.out.printf("%s did not match! HINT: It was issued on %2$terd of some month", args[0], validate);
    }
}


# C ▶ 
void incorrect_password(const char *user) {
    static const char msg_format[] = "%s cannot be authenticated.₩n";
    size_t len = strlen(user) + sizeof(msg_format);
    char *msg = (char *)malloc(len);
    
    if (msg == NULL) {
        /* 오류 처리 */
    }
    
    int ret = snprintf(msg, len, msg_format, user);

    if (ret < 0 || ret >= len) {
        /* 오류 처리 */
    }
    
    if (fputs(msg, stderr) == EOF) {
        /* 오류 처리 */
    }
    
    free(msg);
    msg = NULL;
}