계: Time and State

분산 컴퓨팅에서 중요한 것은 시간과 상태입니다. 즉, 둘 이상의 구성 요소가 통신하려면 상태를 공유해야 하며 시간이 걸립니다.

대부분의 프로그래머들은 자신들의 작업을 의인화합니다. 하나의 컨트롤 스레드로 마치 자신이 직접 작업한 것처럼 전체 프로그램을 수행할 수 있을 것으로 생각합니다. 하지만 최신 컴퓨터는 작업 간에 매우 빠르게 전환되므로 멀티코어, 멀티 CPU 또는 분산 시스템에서 두 이벤트가 정확히 동시에 발생할 수 있습니다. 프로그래머가 만든 프로그램 실행 모델과 실제 현실 간에 빠르게 결함이 생기기 마련입니다. 이러한 결함은 스레드, 프로세스, 시간 및 정보 간의 예기치 않은 상호작용과 관련이 있습니다. 이러한 상호 작용은 공유 상태를 통해 발생합니다. 세마포, 변수, 파일 시스템 그리고 정보를 저장할 수 있는 모든 것이 여기에 포함됩니다.

Insecure Temporary File

Abstract
안전하지 않은 임시 파일을 만들어 사용하면 응용 프로그램과 시스템 데이터가 공격에 취약해질 수 있습니다.
Explanation
응용 프로그램이 임시 파일을 너무 자주 필요로 하기 때문에 C 라이브러리와 Windows(R) API에 이를 생성하기 위한 다양한 메커니즘이 많이 있습니다. 이 함수 대부분이 다양한 형태의 공격에 취약합니다.
예제: 다음 코드는 네트워크에서 수집한 중간 데이터를 처리하기 전에 저장하기 위해 임시 파일을 사용합니다.


...
if (tmpnam_r(filename)){
FILE* tmp = fopen(filename,"wb+");
while((recv(sock,recvbuf,DATA_SIZE, 0) > 0)&&(amt!=0))
amt = fwrite(recvbuf,1,DATA_SIZE,tmp);
}
...


안전하지 않은 방법으로 임시 파일을 만든다는 점 외에는 별다른 특징이 없는 이 코드는 바로 그 점 때문에 수많은 다양한 공격에 취약합니다. 다음 섹션에서 이런 함수들 때문에 생긴 취약점에 대해 설명합니다. 임시 파일 생성과 관련한 가장 심각한 보안 문제는 Unix 기반 운영 체제에서 발생하지만, Windows 응용 프로그램도 같은 위험을 안고 있습니다. 이 섹션에서는 Unix 및 Windows 시스템의 임시 파일 생성에 대해 모두 다룹니다.

방법과 동작은 시스템마다 다를 수 있지만 각각이 야기하는 근본적인 위험은 대체로 일정합니다. 안전한 코어 언어 함수에 대한 정보 및 안전한 임시 파일 생성 방법에 관한 조언은 권고 사항 섹션을 참조하십시오.

임시 파일 생성을 지원하도록 설계된 함수는 단순히 파일 이름만 제공하는지 또는 실제로 새 파일을 여는지에 따라 두 그룹으로 나눌 수 있습니다.

그룹 1 - "고유한" 파일 이름:

임시 파일 생성 프로세스를 지원하도록 설계된 첫 번째 그룹의 C 라이브러리 및 WinAPI 함수는 프로그램이 열 새 임시 파일에 고유한 파일 이름을 만들어 프로세스를 지원합니다. 이 그룹에는 Windows API의 GetTempFileName() 함수뿐 아니라 tmpnam(), tempnam(), mktemp() 및 이에 상응하는, 앞에 _(밑줄)이 붙은 C++ 함수 등의 C 라이브러리가 있습니다 이 그룹의 함수는 속성 상 선택한 파일 이름에 대한 경쟁 조건(race condition)이 발생합니다. 함수가 파일 이름 선택 시점에 이름이 고유하다는 것은 보장하지만 이름을 선택한 후 응용 프로그램이 파일을 열기 전에 다른 프로세서나 공격자가 같은 이름의 파일을 생성하는 것을 방지하는 메커니즘이 없습니다. 같은 함수의 다른 호출로 인해 발생하는 자연스러운 충돌의 위험 외에도 이들 함수가 생성한 파일 이름이 추측하기 어려울 만큼 무작위성이 보장되지 않기 때문에 공격자가 악의적으로 충돌을 일으킬 수 있습니다.

선택한 이름의 파일이 만들어지면 파일을 여는 방법에 따라 파일의 기존 내용 또는 접근 권한이 그대로 유지될 수 있습니다. 임시 파일의 기존 내용이 악성인 경우, 공격자는 응용 프로그램이 임시 파일에서 데이터를 읽을 때 위험한 데이터를 응용 프로그램에 삽입하게 됩니다. 공격자가 완화된 접근 권한의 임시 파일을 미리 만들게 되면 응용 프로그램이 임시 파일에 저장한 데이터에 접근, 수정 및 손상시킬 수 있습니다. Unix 기반 시스템에서는 공격자가 임시 파일을 다른 중요한 파일의 링크로 미리 만드는 경우 훨씬 심각한 공격이 될 수 있습니다. 이때 응용 프로그램이 임시 파일을 자르거나 임시 파일에 데이터를 쓰는 경우, 모르는 사이에 공격자 대신 시스템을 손상시키는 작업을 수행할 수 있습니다. 이는 프로그램을 높은 권한으로 실행할 때 특히 위험해집니다.

마지막으로 최선의 방법은 O_CREATO_EXCL 플래그를 사용한 open() 호출 또는 CREATE_NEW 속성을 사용한 CreateFile() 호출로 파일을 여는 것입니다. 이 방법은 파일이 이미 있을 때는 파일을 열지 않기 때문에 앞서 설명한 종류의 공격을 예방할 수 있습니다. 하지만 공격자가 임시 파일 이름의 순서를 정확하게 예측할 수 있는 경우 응용 프로그램이 필요한 임시 저장소를 여는 것을 막아 Denial Of Service(DoS) 공격을 일으킬 수 있습니다. 이런 종류의 공격은 이들 함수가 생성하는 파일의 이름 선택에 사용된 무작위성의 수준이 낮은 것을 감안하면 어렵지 않게 실행할 수 있습니다.

그룹 2 - "고유한" 파일:

두 번째 그룹의 C 라이브러리 함수는 고유한 파일 이름을 생성할 뿐 아니라 파일을 여는 방식으로 일부 임시 파일 관련 보안 문제를 해결하려 합니다. 이 그룹에는 tmpfile() 및 이에 상응하는, 앞에 _(밑줄)이 붙은 C++ 함수뿐 아니라 동작 기능이 좀 더 우수한 C 라이브러리 함수 mkstemp() 등의 C 라이브러리 함수가 있습니다.

tmpfile() 형식의 함수는 "wb+" 플래그가 전달되면(즉, 읽기/쓰기 모드의 이진 파일로 전달되면) 고유한 파일 이름을 생성하고 fopen()과 같은 방식으로 파일을 엽니다. 파일이 이미 있으면, 앞에서 언급한 고유한 파일 이름 선택과 이후의 선택한 파일 열기 사이에 존재하는 경쟁 조건(race condition) 관련 보안 문제를 해결하기 위해 tmpfile()은 크기 0으로 파일을 자릅니다. 하지만 이 동작으로 함수의 보안 문제를 해결하지는 못합니다. 첫째, 공격자는 대체로 tmpfile()이 연 파일이 보유하고 있을 완화된 접근 권한으로 파일을 미리 만들 수 있습니다. 뿐만 아니라, Unix 기반 시스템에서 공격자가 파일을 다른 중요한 파일의 링크로 미리 만드는 경우, 응용 프로그램은 높은 권한을 사용하여 해당 파일을 잘라 공격자 대신 시스템을 손상시킬 수 있습니다. 마지막으로 tmpfile()이 새 파일을 만들게 되면 해당 파일에 적용되는 접근 권한이 운영 체제 별로 다르기 때문에 공격자가 사용할 파일 이름을 미리 예측할 수 없는 경우에도 응용 프로그램 데이터가 취약해질 수 있습니다.

결국 임시 파일을 만드는 안전한 방법은 mkstemp()입니다. 이 함수는 사용자가 제공한 파일 이름 템플릿과 무작위로 생성된 일련의 문자를 기반으로 고유한 파일을 만들고 엽니다. 그런 파일을 만들 수 없는 경우 작업은 실패하고 -1을 반환합니다. 요즘의 시스템에서는 0600 모드를 사용하여 파일을 엽니다. 즉, 파일은 사용자가 접근 권한을 명시적으로 변경하는 경우를 제외하고 외부에서 조작할 수 없습니다. 하지만 mkstemp()도 예측 가능한 파일 이름 사용에서 자유롭지 못하며 공격자가 사용할 파일 이름을 예측하고 미리 만들어 mkstemp()가 실패하게 만들면 응용 프로그램이 denial of service 공격에 취약해질 수 있습니다.
References
[1] B. Schneier Yarrow: A secure pseudorandom number generator
[2] CryptLib
[3] Crypto++
[4] BeeCrypt
[5] OpenSSL
[6] CryptoAPI: CryptGenRandom() Microsoft
[7] RtlGenRandom() Microsoft
[8] .NET System.Security.Cryptography: Random Number Generation Microsoft
desc.semantic.cpp.insecure_temporary_file
Abstract
안전하지 않은 임시 파일을 만들어 사용하면 응용 프로그램과 시스템 데이터가 공격에 취약해질 수 있습니다.
Explanation
응용 프로그램이 임시 파일을 너무 자주 필요로 하기 때문에 이를 생성하기 위한 여러 메커니즘이 존재합니다. 이 함수 대부분이 다양한 형태의 공격에 취약합니다.
예제: 다음 코드는 네트워크에서 수집한 중간 데이터를 처리하기 전에 저장하기 위해 임시 파일을 사용합니다.


...
try:
tmp_filename = os.tempnam()
tmp_file = open(tmp_filename, 'w')
data = s.recv(4096)
while True:
more = s.recv(4096)
tmp_file.write(more)
if not more:
break
except socket.timeout:
errMsg = "Connection timed-out while connecting"
self.logger.exception(errMsg)
raise Exception
...


안전하지 않은 방법으로 임시 파일을 만든다는 점 외에는 별다른 특징이 없는 이 코드는 바로 그 점 때문에 수많은 다양한 공격에 취약합니다. 다음 섹션에서 이런 함수들 때문에 생긴 취약점에 대해 설명합니다. 임시 파일 생성과 관련한 가장 심각한 보안 문제는 Unix 기반 운영 체제에서 발생하지만, Windows 응용 프로그램도 같은 위험을 안고 있습니다.

방법과 동작은 시스템마다 다를 수 있지만 각각이 야기하는 근본적인 위험은 대체로 일정합니다. 안전한 코어 언어 함수에 대한 정보 및 안전한 임시 파일 생성 방법에 관한 조언은 권고 사항 섹션을 참조하십시오.

임시 파일 생성을 지원하도록 설계된 함수는 단순히 파일 이름만 제공하는지 또는 실제로 새 파일을 여는지에 따라 두 그룹으로 나눌 수 있습니다.

그룹 1 - "고유한" 파일 이름:

임시 파일 생성 프로세스를 지원하도록 설계된 첫 번째 그룹의 함수는 프로그램이 열 새 임시 파일에 고유한 파일 이름을 만들어 프로세스를 지원합니다. 이 그룹의 함수는 속성 상 선택한 파일 이름에 대한 경쟁 조건(race condition)이 발생합니다. 함수가 파일 이름 선택 시점에 이름이 고유하다는 것은 보장하지만 이름을 선택한 후 응용 프로그램이 파일을 열기 전에 다른 프로세서나 공격자가 같은 이름의 파일을 생성하는 것을 방지하는 메커니즘이 없습니다. 같은 함수의 다른 호출로 인해 발생하는 자연스러운 충돌의 위험 외에도 이들 함수가 생성한 파일 이름이 추측하기 어려울 만큼 무작위성이 보장되지 않기 때문에 공격자가 악의적으로 충돌을 일으킬 수 있습니다.

선택한 이름의 파일이 만들어지면 파일을 여는 방법에 따라 파일의 기존 내용 또는 접근 권한이 그대로 유지될 수 있습니다. 임시 파일의 기존 내용이 악성인 경우, 공격자는 응용 프로그램이 임시 파일에서 데이터를 읽을 때 위험한 데이터를 응용 프로그램에 삽입하게 됩니다. 공격자가 완화된 접근 권한의 임시 파일을 미리 만들게 되면 응용 프로그램이 임시 파일에 저장한 데이터에 접근, 수정 및 손상시킬 수 있습니다. Unix 기반 시스템에서는 공격자가 임시 파일을 다른 중요한 파일의 링크로 미리 만드는 경우 훨씬 심각한 공격이 될 수 있습니다. 이때 응용 프로그램이 임시 파일을 자르거나 임시 파일에 데이터를 쓰는 경우, 모르는 사이에 공격자 대신 시스템을 손상시키는 작업을 수행할 수 있습니다. 이는 프로그램을 높은 권한으로 실행할 때 특히 위험해집니다.

마지막으로 최선의 방법은 os.O_CREATos.O_EXCL 플래그를 사용한 open() 호출을 사용하여 파일을 여는 것입니다. 이 방법은 파일이 이미 있을 때는 파일을 열지 않기 때문에 앞서 설명한 종류의 공격을 예방할 수 있습니다. 하지만 공격자가 임시 파일 이름의 순서를 정확하게 예측할 수 있는 경우 응용 프로그램이 필요한 임시 저장소를 여는 것을 막아 Denial Of Service(DoS) 공격을 일으킬 수 있습니다. 이런 종류의 공격은 이들 함수가 생성하는 파일의 이름 선택에 사용된 무작위성의 수준이 낮은 것을 감안하면 어렵지 않게 실행할 수 있습니다.

그룹 2 - "고유한" 파일:

두 번째 그룹의 함수는 고유한 파일 이름을 생성할 뿐 아니라 파일을 여는 방식으로 일부 임시 파일 관련 보안 문제를 해결하려 합니다. 이 그룹에는 tmpfile()과 같은 함수가 포함됩니다.

tmpfile() 형식의 함수는 "wb+" 플래그가 전달되면(즉, 읽기/쓰기 모드의 이진 파일로 전달되면) 고유한 파일 이름을 생성하고 open()과 같은 방식으로 파일을 엽니다. 파일이 이미 있으면, 앞에서 언급한 고유한 파일 이름 선택과 이후의 선택한 파일 열기 사이에 존재하는 경쟁 조건(race condition) 관련 보안 문제를 해결하기 위해 tmpfile()은 크기 0으로 파일을 자릅니다. 하지만 이 동작으로 함수의 보안 문제를 해결하지는 못합니다. 첫째, 공격자는 대체로 tmpfile()이 연 파일이 보유하고 있을 완화된 접근 권한으로 파일을 미리 만들 수 있습니다. 뿐만 아니라, Unix 기반 시스템에서 공격자가 파일을 다른 중요한 파일의 링크로 미리 만드는 경우, 응용 프로그램은 높은 권한을 사용하여 해당 파일을 잘라 공격자 대신 시스템을 손상시킬 수 있습니다. 마지막으로 tmpfile()이 새 파일을 만들게 되면 해당 파일에 적용되는 접근 권한이 운영 체제 별로 다르기 때문에 공격자가 사용할 파일 이름을 미리 예측할 수 없는 경우에도 응용 프로그램 데이터가 취약해질 수 있습니다.
References
[1] B. Schneier Yarrow: A secure pseudorandom number generator
[2] Python Library Reference: os Python
[3] Python Library Reference: tempfile Python
[4] Symlink race WikiPedia
[5] Time of check to time of use WikiPedia
desc.semantic.python.insecure_temporary_file