계: Input Validation and Representation

입력 검증 및 표현 문제는 메타 문자, 대체 인코딩 및 숫자 표현 때문에 발생합니다. 보안 문제는 입력을 신뢰하기 때문에 발생합니다. 문제로는 "Buffer Overflows", "Cross-Site Scripting" 공격, "SQL Injection", 그 외 여러 가지가 있습니다.

Integer Overflow

Abstract
Integer overflow를 다루지 않으면 로직 오류 또는 buffer overflow가 발생할 수 있습니다.
Explanation
정수 오버플로 오류는 산술 연산의 결과값이 데이터 형식의 최대값보다 크거나 최소값보다 작을 수 있다는 것을 프로그램이 고려하지 못할 때 발생합니다. 이러한 오류는 종종 사용자 입력이 부호 있는 값과 부호 없는 값 사이의 암묵적 변환과 충돌하는 메모리 할당 함수에서 문제를 일으킵니다. 프로그램이 메모리를 과소 할당하거나 부호 있는 값을 메모리 연산에서 부호 없는 값으로 해석하도록 공격자가 만들 수 있는 경우, 해당 프로그램은 버퍼 오버플로에 취약할 수 있습니다.

예제 1: OpenSSH 3.3에서 발췌한 다음 코드는 integer overflow의 전형적인 경우를 보여 줍니다.


nresp = packet_get_int();
if (nresp > 0) {
response = xmalloc(nresp*sizeof(char*));
for (i = 0; i < nresp; i++)
response[i] = packet_get_string(NULL);
}
nresp의 값이 1073741824이고 sizeof(char*)의 값이 일반적으로 사용되는 4이면 nresp*sizeof(char*) 작업의 결과가 overflow되며, xmalloc()의 인수는 0이 됩니다. malloc() 구현은 대부분 0바이트 버퍼의 할당을 허용하여 이후 루프가 반복되어 heap buffer response가 overflow됩니다.

예제 2: 이 예제에서는 일련의 가변 길이 구조로 구성된 사용자 입력을 처리합니다. 입력의 첫 2바이트는 처리할 구조의 크기를 지정합니다.


char* processNext(char* strm) {
char buf[512];
short len = *(short*) strm;
strm += sizeof(len);
if (len <= 512) {
memcpy(buf, strm, len);
process(buf);
return strm + len;
} else {
return -1;
}
}


프로그래머가 구조 크기에 끼치는 상한을 설정했습니다. 구조 크기가 512보다 크면 입력이 처리되지 않습니다. 문제는 len이 부호 있는 정수여서 최대 구조 길이가 부호 있는 정수를 사용해 확인되지만 memcpy() 호출에서는 len이 부호 없는 정수로 변환된다는 점입니다. len이 음수이면 구조의 크기가 적절한 것으로 표시되지만(if 분기를 가져옴) memcpy()에서 복사하는 메모리 양이 상당히 많아 공격자가 strm의 데이터로 스택을 overflow할 수 있습니다.
References
[1] blexim Basic Integer Overflows Phrack
[2] D. Plakosh Coding Flaws That Lead to Security Failures 2nd Annual Hampton University Information Assurance Symposium
[3] Les Hatton Safer C: Developing Software for High-integrity and Safety-critical Systems McGraw-Hill Companies
desc.dataflow.cpp.integer_overflow
Abstract
정수 오버플로를 고려하지 않으면 논리 오류나 버퍼 오버플로를 일으킬 수 있습니다.
Explanation
정수 오버플로 오류는 산술 연산의 결과값이 데이터 형식의 최대값보다 크거나 최소값보다 작을 수 있다는 것을 프로그램이 고려하지 못할 때 발생합니다. 이러한 오류는 종종 사용자 입력이 부호 있는 값과 부호 없는 값 사이의 암묵적 변환과 충돌하는 메모리 할당 함수에서 문제를 일으킵니다. 프로그램이 메모리를 과소 할당하거나 부호 있는 값을 메모리 연산에서 부호 없는 값으로 해석하도록 공격자가 만들 수 있는 경우, 해당 프로그램은 버퍼 오버플로에 취약할 수 있습니다.

예제: 다음 코드 발췌는 정수 오버플로의 전형적인 경우를 보여줍니다.


77 accept-in PIC 9(10).
77 num PIC X(4) COMP-5. *> native 32-bit unsigned integer
77 mem-size PIC X(4) COMP-5.
...
ACCEPT accept-in
MOVE accept-in TO num
MULTIPLY 4 BY num GIVING mem-size

CALL "CBL_ALLOC_MEM" USING
mem-pointer
BY VALUE mem-size
BY VALUE 0
RETURNING status-code
END-CALL
num1073741824 값이 있으면 MULTIPLY 4 BY num 연산의 결과가 오버플로되며, malloc()에 대한 mem-size 인수는 0이 됩니다. 대부분의 malloc() 구현에서는 0바이트 버퍼를 할당하는 것이 허용되므로 힙 버퍼 mem-pointer가 후속 명령문에서 오버플로됩니다.
References
[1] blexim Basic Integer Overflows Phrack
[2] D. Plakosh Coding Flaws That Lead to Security Failures 2nd Annual Hampton University Information Assurance Symposium
[3] Les Hatton Safer C: Developing Software for High-integrity and Safety-critical Systems McGraw-Hill Companies
desc.dataflow.cobol.integer_overflow
Abstract
함수가 정수 계산을 잘못 처리하므로 오버플로/언더플로가 발생합니다.
Explanation
정수 오버플로/언더플로란 계산이나 산술 연산의 결과 값이 정수 유형의 최대값보다 크거나 최소값보다 작아서 결과 값의 하한/상한으로 루프백된 후 하한/상한 값에서 계산이 계속 반복되는 상황입니다. 산술 연산의 결과 값은 사실상 상한/하한 경계부터 시작되는 정수 범위의 계수입니다.

예를 들어 uint256 유형으로 저장되는 숫자는 0에서 2^256-1 범위의 256비트 부호 없는 숫자로 저장됩니니다. 산술 연산 결과가 상한보다 큰 숫자이면 오버플로가 발생하며 시작 값(0)에 나머지 값을 더합니다. 산술 연산 결과가 하한보다 작은 숫자이면 언더플로가 발생하며 최대값(2^256-1)에서 나머지 값을 뺍니다.

예제 1: 다음 공개 함수는 산술 연산을 사용하여 uint256 매핑을 업데이트합니다. 이 산술 연산으로 인해 정수 오버플로/언더플로가 발생할 수 있으며, 해당 현상은 맵에서 의도하지 않은 인덱스에 영향을 줄 수 있습니다.


contract overflow {
mapping(uint256 => uint256) map;

function init(uint256 k, uint256 v) public {
map[k] -= v;
}
}
References
[1] Enterprise Ethereum Alliance No Overflow/Underflow
desc.structural.solidity.swc101