문제분석 & 풀이
페이지에 접속하면 idx 값을 알려주고 "access denied"라고 한다.
코드 분석
1. 세션 idx 값을 화면에 출력해 알려준다.(5번줄)
2. PHPSESSID 쿠키의 값이 숫자가 아닌경우 "Access Denind"를 출력하고 프로그램 종료(6번줄)
3. 1초 뒤 mode 파라미터 값이 auth 이면 ./readme/{$_SESSION['idx']}.txt 경로 파일을 읽고 $reuslt에 저장한다. (8~10번줄)
4. $result에 idx 값이 들어있으면 문제가 클리어된다. (11~15번줄)
5. ./readme/{$_SESSION['idx']}.txt 경로 파일을 열어서 파일에 idx 값을 쓴다. (18~20번줄)6. 클라이언트 ip 주소가 "127.0.0.1"이 아니면 1초뒤에 ./readme/{$_SESSION['idx']}.txt 경로 파일을 삭제한다. (21~23번줄)
솔브를 위해서는 2가지를 해결해야한다.
1번째는 PHPSESSID 쿠키 값이 모두 숫자여야 한다는 것이다. 따라서 개발자도구(F12)를 이용해서 숫자로 값을 바꿨다.
2번째인데, 문제를 해결하기 위해서는 "./readme/{$_SESSION['idx']}.txt" 경로 파일에 idx값이 써있어야 한다. 따라서 값을 쓰기위한 시나리오를 생각하면 다음과 같다.
1) mode 파라미터 없이 전송해서 ./readme/{$_SESSION['idx']}.txt 경로 파일에 idx값을 쓴다.
2) mode=auth 를 전송해서 문제를 클리어한다.
그러나 문제는 "./readme/{$_SESSION['idx']}.txt" 경로 파일에 idx값을 쓰고 난 후 클라이언트 ip가 "127.0.0.1"이 아니면 파일이 삭제되어 생각한 시나리오로 문제를 해결할 수 없다.
클라이언트 ip값이 "127.0.0.1"이어야 한다는 의미인데 그것은 불가능하다. 그렇다면 어떻게 문제를 해결할 수 있을까? 이번 문제는 race condition attack을 이용하면 문제가 해결 될 것 같다!
○ race condition
레이스 컨디션이란 공유자원에 대해 여러 개의 프로세스가 동시에 접근하기 위해 경쟁하는 상태를 말한다.
race condition을 본격적으로 설명하기 전에, 시나리오대로 실행했을때 실행되는 코드의 순서를 생각해보자.
1) 파일에 idx값 쓰기 → 2) ip가 "127.0.0.1"이 아니면 1초 뒤 파일 삭제 → 3) 파일을 읽고 문제 클리어 결론적으로 문제 해결을 위해서는 1,3번 과정만 실행하면된다.
즉, 2번이 실행되기 전에 3번을 실행하면 문제가 해결된다는 의미다. 이때, race condition attack을 이용하여 2번이 실행되기 전에 3번을 실행하면 된다!
2번 과정의 경우 sleep() 함수에 의해 1초 지연시간 후에 파일을 삭제한다. 그렇다면 1번 과정을 실행하고 1초가 지나기 전에 3번 과정을 실행하면 문제가 해결 될 것이다!
race conditon을 쉽게 이해하기 위해 위에서 설명한 race condition 정의에 문제의 상황을 대입하면 다음과 같이 표현가능하다.
공유자원( ./readme/{$_SESSION['idx']}.txt 경로 파일)에 대해 여러 개의 프로세스(1번과정을 실행하는 프로세스, 3번과정을 실행하는 프로세스)가 동시에 접근하기 위해 경쟁하는 상태를 말한다.
위 설명을 종합적으로 정리해 공격시나리오를 다시 만들어보자.
○ 공격시나리오
1. 파일에 idx값 쓰는 동작을 실행한다. (mode 파라미터 없는 상태로 전송)
2. 파일이 삭제되기 전에 1초의 지연시간이 존재함으로 이를 이용해서 1초가 지나기 전에 파일을 읽고 문제를 클리어하는 동작(mode=auth를 전송)을 실행한다. (이때, 1번 동작이 끝나기 전에 새로운 동작을 먼저 실행했음으로 레이스 컨디션 상태가 된다.)
3. 결론적으로 파일에 idx 쓰기 → 파일 읽고 클리어 → 파일 삭제 순서로 프로그램이 실행된다.
공격시나리오를 완성했으니 이대로 실행해보자.
간단하게 race condition attack을 시도하기 위해 브라우저를 두 개 띄웠다.
(브라우저 각각을 하나의 프로세스라고 생각하면 이해하기 편할 것이다.)
* 참고 : 왼쪽, 오른쪽 브라우저의 PHPSESSID 값이 달라야 한다.
(같으면 race condition 상태가 안된다.)
왼쪽 브라우저는 파일에 idx를 쓰는 과정, 오른쪽 브라우저는 파일을 읽고 문제가 클리어되는 과정을 각각 실행할 것이다.
왼쪽 → 오른쪽 순서로 빠르게 새로고침을 했다.