보안 공부/소스코드 보안약점 진단

소스코드 보안약점 진단 - 경쟁조건: 검사 시점과 사용 시점(TOCTOU)

H.J.World 2022. 1. 24. 10:10
728x90
반응형

소스코드 보안약점 진단 // 소프트웨어 보안약점 진단 // SW 보안약점 진단과 같이 다양한 이름으로 불리는 진단 과업 중 하나이다.

SW개발보안은 해킹 등 사이버공격의 원인인 보안약점을 SW개발단계에서 사전에 제거하고 SW 개발 생명주기의 각 단계별로 수행하는 일련의 보안활동을 통하여 안전한 SW를 개발·운영하기 위한 목적으로 적용하는 개발체계이다.

해당 내용은 KISA에서 발간하는 취약점 진단 가이드 항목을 기준으로 작성한다.

 

제 3절 시간 및 상태

동시 또는 거의 동시 수행을 지원하는 병렬 시스템이나 하나 이상의 프로세스가 동작되는 환경에서 시간 및 상태를 부적절하게 관리하여 발생할 수 있는 보안약점이다.


1. 경쟁조건: 검사 시점과 사용 시점(TOCTOU)

가. 개요

병렬시스템(멀티프로세스로 구현한 응용프로그램)에서는 자원(파일, 소켓 등)을 사용하기에 앞서 자원의 상태를 검사한다. 하지만, 자원을 사용하는 시점과 검사하는 시점이 다르기 때문에, 검사하는 시점(Time Of Check)에 존재하던 자원이 사용하던 시점(Time Of Use)에 사라지는 등 자원의 상태 가 변하는 경우가 발생한다.

예를 들어, 프로세스 A와 B가 존재하는 병렬시스템 환경에서 프로세스 A는 자원사용(파일 읽기)에 앞서 해당 자원(파일)의 존재 여부를 검사(TOC) 한다. 이때는 프로세스 B가 해당 자원(파일)을 아직 사용(삭제)하지 않았기 때문에, 프로세스 A는 해당 자원(파일)이 존재한다고 판단한다. 그러나 프로 세스 A가 자원 사용(파일읽기)을 시도하는 시점(TOU)에 해당 자원(파일)은 사용불가능 상태이기 때문에 오류 등이 발생할 수 있다.

이와 같이 하나의 자원에 대하여 동시에 검사시점과 사용시점이 달라 생기는 보안약점으로 인해 동기 화 오류뿐만 아니라 교착상태 등과 같은 문제점이 발생할 수 있다.

나. 보안대책

공유자원(예: 파일)을 여러 프로세스가 접근하여 사용할 경우, 동기화 구문을 사용하여 한 번에 하나의 프로세스만 접근 가능하도록(synchronized, mutex 등) 하는 한편, 성능에 미치는 영향을 최소화 하기 위해 임계코드 주변만 동기화 구문을 사용한다.

다. 코드예제

다음의 예제는 파일을 대한 읽기와 삭제가 두 개의 스레드에 동작하게 되므로 이미 삭제된 파일을 읽으려고 하는 레이스컨디션1)이 발생할 수 있다.

- 안전하지 않은 코드의 예 JAVA -

1: class FileMgmtThread extends Thread {
2: private String manageType = "";
3: public FileMgmtThread (String type) {
4: manageType = type;
5: }
//멀티쓰레드 환경에서 공유자원에 여러프로세스가 사용하여 동시에 접근할 가능성이 있어
안전하지 않다.
6: public void run() {
7: try {
8: if (manageType.equals("READ")) {
9: File f = new File("Test_367.txt");
10: if (f.exists()) {
11: BufferedReader br = new BufferedReader(new FileReader(f));
12: br.close();
13: }
14: } else if (manageType.equals("DELETE")) {
15: File f = new File("Test_367.txt");
16: if (f.exists()) {
17: f.delete();
18: } else { … }
19: }
20: } catch (IOException e) { … }
21: }
22: }
23: public class CWE367 {
24: public static void main (String[] args) {
25: FileMgmtThread fileAccessThread = new FileMgmtThread("READ");
26: FileMgmtThread fileDeleteThread = new FileMgmtThread("DELETE");
//파일의 읽기와 삭제가 동시에 수행되어 안전하지 않다.
27: fileAccessThread.start();
28: fileDeleteThread.start();
29: }
30: }

 

- 안전한 코드의 예 JAVA -

따라서 다음 예제와 같이 동기화 구문인 synchronized를 사용하여 공유자원 (Test_367.txt)에 대한 안전한 읽기/쓰기를 수행할 수 있도록 한다.

1: class FileMgmtThread extends Thread {
2: private static final String SYNC = "SYNC";
3: private String manageType = "";
4: public FileMgmtThread (String type) {
5: manageType = type;
6: }
7: public void run() {
//멀티쓰레드 환경에서 synchronized를 사용하여 동시에 접근할 수 없도록 사용해야한다.
8: synchronized(SYNC) {
9: try {
10: if (manageType.equals("READ")) {
11: File f = new File("Test_367.txt");
12: if (f.exists()) {
13: BufferedReader br
14: = new BufferedReader(new FileReader(f));
15: br.close();
16: }
17: } else if (manageType.equals("DELETE")) {
18: File f = new File("Test_367.txt");
19: if (f.exists()) {
20: f.delete();
21: } else { … }
22: }
23: } catch (IOException e) { … }
24: }
25: }
26: }
27: public class CWE367 {
28: public static void main (String[] args) {
29: FileMgmtThread fileAccessThread = new FileMgmtThread("READ");
30: FileMgmtThread fileDeleteThread = new FileMgmtThread("DELETE");
// 아래 두줄
31: fileAccessThread.start();
32: fileDeleteThread.start();
33: }
34: }

 

라. 진단방법

소스코드 상에 다음과 같이 공유자원(파일/폴더, 소켓, 드라이버 등)을 여러 프로세스가 사용하는지 확인한다(①). 이 때, 하나의 공유자원을 동시에 접근할 가능성이 존재한다면 취약하다고 판단하며, 동기화 구문 등을 사용할 경우 안전하다고 판단한다. 그 외 공유자원 억세스를 관리하는 pool 형태의 자체 모듈을 제작할 경우에도 안전하다고 판단한다.

1: import java.io.*;
2:
3: class FileAccessThread extends Thread {
4: public void run() {
5: try {
6: File f = new File(“Test_367.txt”);-------------------------①
7: if(f.exists()) {
8: // 만약 파일이 존재하면 파일 내용을 읽음
9: BufferedReader br = new BufferedReader(new FileReader(f));
10: br.close();
11: }
12: } catch(IOException e) {
13: System.err.println(“IOException occured”);}
14: }
15: }
16:
17: class FileDeleteThread extends Thread {
18: public void run() {
19: File f = new File(“Test_367.txt”);-------------------------①
20: if (f.exists()) {
21: // 만약 파일이 존재하면 파일을 삭제함
22: f.delete();
23: }
24: }
25: }
26:
27: public class U367 {
28: public static void main(String[] args) {
29: // 파일의 읽기와 파일을 삭제하는 것을 동시에 수행한다.
30: FileAccessThread fileAccessThread = new FileAccessThread(); ②
31: FileDeleteThread fileDeleteThread = new FileDeleteThread();
32: fileAccessThread.start();
33: fileDeleteThread.start();
34: }
35: }

 

- 정탐코드의 예 -

TOCTOU는 C 프로그래밍을 할 때 다음과 같은 경우에 발생한다.

1: if (!access(file,W_OK))
2: {
3: f = fopen(file,”w+”);
4: operate(f);
5: …
6: }
7: else
8: {
9: fprintf(stderr,”Unable to open file %s.\n”,file);
10: }

 

- 정탐코드의 예 -

실제로 경쟁 조건이 이루어지지 않는 경우 취약하지 않다.

1: file = new File(filename);
2: File[] fList = file.listFiles();
3: for (int i = 0; i < fList.length; i++) {
4: currentList.add(fList[i].getAbsolutePath()
5: + “$” + getLastModifiedTime(fList[i]) + “$
6: + ((fList[i].length() / 1024) > 0 ? (fList[i].length() / 1024) : 1)
7: + “KB”);
8: }

 

728x90
반응형