본문 바로가기
소프트웨어(SW) 보안약점 진단원/구현단계 보안약점 제거 기준

구현단계 보안약점 기준 - 정수형 오버플로우

by 브루노W 2025. 5. 27.
유형 입력데이터 검증 및 표현
보안약점 정수형 오버플로우
개요
정수형 오버플로우는 정수값이 증가하면서 허용된 가장 큰 값보다 커져서 실제 저장되는 값이 의도치 않게 아주 작은 수이거나 음수가 되어 발생한다.

특히 반복문 제어, 메모리 할당, 메모리 복사 등을 위한 조건으로 사용자가 제공하는 입력값을 사용하고 그 과정에서 정수형 오버플로우가 발생하는 경우 보안상 문제를 유발할 수 있다.
보안대책
언어·플랫폼별 정수타입의 범위를 확인하여 사용한다.

정수형 변수를 연산에 사용하는 경우, 결과값의 범위를 체크하는 모듈을 사용한다.

외부 입력값을 동적 메모리 할당에 사용하는 경우, 변수값이 적절한 범위 내에 존재하는 값인지 확인한다.
진단방법
변수를 사용하여 배열의 크기를 동적으로 결정하고 있는 경우, 변수가 외부 입력값인지 확인하고, 해당 변수가 의도한 범위 내에 존재하는지 확인하는 절차가 있는지 확인한다.

외부 입력값에 대한 검증 절차가 없다면 취약하다.
연관된 설계단계 기준 보안기능 입력값 검증

 

코드예제

 

● 안전하지 않은 코드 예 (Java)

String msg_str = "";
String tmp = request.getParameter("slf_msg_param_num");
tmp = StringUtil.isNullTrim(tmp);
if (tmp.equals("0")) {
    msg_str = PropertyUtil.getValue(msg_id);
} else {
    // 외부 입력값을 정수형으로 사용할 때 입력값의 크기를 검증하지 않고 사용
    int param_ct = Integer.parseInt(tmp);
    String[] strArr = new String[param_ct];

 

● 안전한 코드 예 (Java)

String msg_str = "";
String tmp = request.getParameter("slf_msg_param_num");
tmp = StringUtil.isNullTrim(tmp);
if (tmp.equals("0")) {
    msg_str = PropertyUtil.getValue(msg_id);
} else {
    // 외부 입력값을 정수형으로 사용할 때 입력값의 크기를 검증하고 사용
    try {
        int param_ct = Integer.parseInt(tmp);
        if (param_ct < 0) {
            throw new Exception();
        }
    	String[] strArr = new String[param_ct];
    } catch(Exception e) {
    	msg_str = "잘못된 입력(접근) 입니다.";
    }

 

 

● 안전하지 않은 코드 예 (C#)

public static void Main(string[] args)
{
    // 외부 입력값을 사용할 때, 입력 값의 크기가 너무 클 경우 오버플로우 발생
    int usrNum = Int32.Parse(args[0]);
    string[] array = {"one", "two", "three", "four"};
    string num = array[usrNum];
}

 

● 안전한 코드 예 (C#)

public static void Main(string[] args)
{
    // checked 구문을 사용하여 오버플로우의 발생 여부 및 크기 확인
    try{
        int usrNum = checked(Int32.Parse(args[0]));
        string[] array = {"one", "two", "three", "four"};
        if(usrNum < 3)string num = array[usrNum];
    }
    catch (System.OverflowException e) { … }
}

 

 

● 안전하지 않은 코드 예 (C)

void main(int argc, char* argv[])
{
    // 외부 입력값을 사용할 때, 입력 값의 크기가 너무 클 경우 오버플로우 발생
    int usr_num = 0;
    char* num_array[] = {"one", "two", "three", "four"};
    char* num = NULL;
    usr_num = atoi(argv[1]);
    num = num_array[usr_num];
}

 

● 안전한 코드 예 (C)

void main(int argc, char* argv[])
{
    // 외부 입력값을 사용할 때, 입력 값의 크기가 너무 클 경우 오버플로우 발생
    int usr_num = 0;
    char* num_array[] = {"one", "two", "three", "four"};
    char* num = NULL;
    usr_num = atoi(argv[1]);
    if (usr_num >= 0 && usr_num < 4) {
    	num = num_array[usr_num];
    }
}

 

 

진단방법
 
변수를 사용하여 배열의 크기를 동적으로 결정하고 있는 경우(①), 변수가 외부 입력값인지 확인하고(②), 해당 변수가 의도한 범위내에 존재하는지 확인하는 절차가 있는지 확인한다. 외부 입력값에 대한 검증 절차가 없다면 취약하다.

 

 

● 일반적인 진단의 예

…
String cnt = request.getParameter("cnt"); ·····························②
if( cnt == null ) {
	cnt = "0";
}
int cntI = Integer.parseInt(cnt);
String[] arr = new String[cntI]; ···········································①
for( int i = 0 ; i <cntI ; i++ ) {
	arr[i] = request.getParameter("r"+i);
}
…

 


● 정탐코드

public static Vector parsFileBySize(String parFile, int[] parLen, int parLine) throws Exception {
    // 파싱결과 구조체
    Vector parResult = new Vector();
    // 파일 오픈
    String parFile1 = parFile.replace('\\', FILE_SEPARATOR).replace('/', FILE_SEPARATOR);
    File file = new File(parFile1);
    BufferedReader br = null;
    try {
        // 파일이며, 존재하면 파싱 시작
        if (file.exists() && file.isFile()) {
            // 1. 입력된 라인수만큼 파일 텍스트 내용을 읽어서 String[]에 쌓는다.
            br = new BufferedReader(new InputStreamReader(new FileInputStream(file)));
            String [] strArr = new String [parLine];
            String line = "";
            int readCnt = 0;
            while ((line = br.readLine()) != null && readCnt < parLine) {
                if (line.length() <= MAX_STR_LEN)
                	strArr[readCnt++] = line;
}

정수형 변수의 값이 증가하면서 정수형 한계값보다 더 커지는 경우 아주 작은 값이 되거나 음수가 될 수 있다. 이러한 상황에 대한 검사가 이루어지지 않고 진행하는 경우 취약하다.

 

 

● 정탐코드

String msg_str = "";
String tmp = request.getParameter("slf_msg_param_num");
tmp = StringUtil.isNullTrim(tmp);
if (tmp.equals("0")) {
    msg_str = PropertyUtil.getValue(msg_id);
} else {
    // 외부 입력값을 정수형으로 사용할 때 입력값의 크기를 검증하지 않고 사용
    int param_ct = Integer.parseInt(tmp);
    String[] strArr = new String[param_ct];
    ......
}

외부의 입력(slf_msg_param_num)으로 받은 값을 배열의 크기(size)를 결정하는데 사용하고 있다. 만일 외부에서 입력받은 값(param_ct)이 음수값인 경우, 배열의 크기가 음수가 되어 시스템에 문제가 발생할 수 있으므로 취약하다고 판단한다.

 

 

● 오탐코드

try {
    URL url = Util.class.getClassLoader().getResource(publicKeyFilepath);
    pubKey = url.openStream();
} catch (MalformedURLException e) {
    pubKey = new FileInputStream(publicKeyFilepath);
}
byte[] bytes = new byte[pubKey.available()];

pubKey.available() 함수는 int 값을 리턴 한다. 그러므로 정수값 한계를 벗어난 값은 발생하지 않는다.

 

 

● 오탐코드

String[] referer_split = Util.split(request.getHeader("Referer").toString(),"/");
String refererValue = referer_split[referer_split.length-1];

입력 값은 HTTP 헤더의 한계값이 있으므로 정수의 한계를 초과할 가능성이 없다.

 

 

● 오탐코드

public static void main(String[] args) {
    String[] jsargs = {"-j="+args[0]};
    String[] allArgs = new String[jsargs.length + args.length];

인자의 개수가 정수의 한계 이상으로 입력된다는 것은 실현 가능성이 희박하므로 취약하지 않은 것으로 판단한다.