6회차 목표 : 정보보안 공부
6회차 내용 : Race condition 공격
Race Condition Vulnerability
페이지 2 레이스 컨디션이 무엇인지 살펴보고, 어떤 문제점이 있고, 어떤 취약점이 있는
지 어떤 식으로 exploit해서 공격할 수 있는지, 해결책은 무엇인지로 알아보겠다.
페이지 3 공유되는 자원에 여러 프로세스 스레드가 접근 시 접근 순서의 제어를 해주지
않으면 이상한 결과가 나온다. 권한을 가진 애가 레이스 컨디션을 갖고 있고, 공격자가
이를 이용한다면 위험할 수 있다.
페이지 4 코드를 보며 레이스 컨디션을 보자. php 함수가 있다. 은행에서 인출하는 코드
이다. 인출 전 잔액을 확인한다. 인출하는 양과 잔액을 비교해서 인출한 양만큼 빼서 업
데이트 해준다. 여기서 레이스 컨디션이 발생할 수 있다. 스레드 1이 balance = 까지 실
행됐고, 스레드 2가 진입을 하게 되는데, 스레드 1이 인출한 양만큼 뺀 값을 인출할 수
있는 게 아니라, DB에 업데이트가 안 된 상태에서의 잔액을 비교하고 인출할 수 있다.
데이터 베이스 업데이트 전에 잔액을 모두 1000원으로 보고, 900원을 인출하는 경우에
1800원이나 인출하게 된다.
페이지 5 타임오브체크 타임오브유스. 보안 검증을 하고, 그 바탕으로 파일을 사용하려는
데 그걸 바꿔치기해서 우회해서 공격하는 기술이다. 스마트 tv에 새로운 어플리케이션을
다운 받으려고 한다. 먼저 usb에서 설치 파일의 해시를 계산. 그 후 정당한 프로그램으
로 사인 된 해시를 계산. 그 둘을 비교해서 정당한 프로그램을 판단해서 설치를 하거나
거부하거나 한다. 이런 식으로 설치가 되는데, 공격되는 대상을 보자.
TV가 usb 읽고 설치파일 가져오고 해시를 계산. 그리고 사이닝 된 해시를 가져온다. 시
그니처 사이닝 된 해시와 비교한다. 여기서 다시 한 번 usb를 읽고 설치한다. 해시 검증
이 끝난 다음에 usb를 바꿔서 검증되지 않은 프로그램을 설치하도록 한다. 삼성 이전 버
전에서 있었다.
페이지 6 레이스 컨디션이 어떤식으로 악용되는지 보자. 루트 소유의 set UID 프로그램
이다. UID는 루트이고, 실제 이용자 ID는 seed이다. access라는 함수를 이용해서 현재 유
저가 write 권한이 있는지 확인하고 파일을 연다. 여기서 effective UID를 확인하니 파일
을 쓸 수 있다. 엑세스 권한이 없으면 퍼미션 디나이.
페이지 7 앞에서 본 코드를 악용해서 악의적 행위를 하려한다. /etc/passwd 를 써서 비
밀번호를 바꾸려고 한다. 어떤식으로 공격하나. 바로 Symbolic link를 이용한다. tmp 디렉토리 밑에 있는 파일을 심볼릭 링크를 이용해서 /etc/passwd로 연결시키는 것이다. 심볼
릭 링크는 일종의 바로가기라고 보면 된다. 다른 파일을 가리키는 스페셜 파일이다. 리눅
스에서 화살표를 볼 수 있다. 이 파일은 다른 파일을 가리키는 파일이다.
페이지 8 공격에서 사용되는 프로세스는 이렇다. 프로그램에서 액세스라는 함수를 이용
해서 열려고 하는 프로그램이 실제 프로그램 실행하는 사람의 소유인가? 이 여는 파일의
write권한이 있는가? /tmp 밑에 x라는 파일을 만든다. 이 파일은 본인이 만들었기 때문에
write 권한이 있다. 이 부분에서 access 함수 체크를 넘어가게 된다. open을 하려고 할
텐데, 체크를 하고 오픈을 하기 직전에 심볼릭 링크를 만들어주는 것이다. tmp 밑에 x
파일을 passwd로 연결해준다. 그리고, 이 부분에서 오픈을 하게 된다. tmp x 가 passwd
이고, set UID가 루트이기 때문에 열리게 되어 write할 수 있다. 하지만 공격자 입장에서
어려운 점은 시간 체크이다. 체크를 실행할 때와 파일을 오픈할 때의 시간이 굉장히 짧
기에 메뉴얼로 심볼릭링크 만들고 연결 시키는 건 힘들다. 너무 일찍 만들면 access함수
에서 검증을 넘어가지 못 하고, 늦게 되면 그냥 프로그램은 tmp/x를 열지 심볼릭 링크를
열지는 않을 것이다. 이런 고난이 있다.
페이지 9 공격자 입장에서는 앞서 말한 challenge를 해결해야한다. 적절한 타이밍에 만
들기가 어렵다는 challenge. 이를 해결하는 게 두 개의 프로그램을 이용하는 것이다. 취
약한 프로그램을 루프 안에 돌리고, attacker program도 실행해서 운 좋게 그 시간에 들
어갈 수 있게 한다. 액세스 함수를 실행해서 체크를 한다. 이때 context switch가 운 좋게
발생해서 어태커 프로그램이 실행되고 시작. 스케쥴링에 따라 다시 open()이 된다. root
권한으로 열 수 있나 확인. set UID이므로 열 수 있게 된다.
페이지 10 공격이 어떻게 되는 지 좀 더 자세히 보자. 공격자의 프로그램이 하는 일이
있고, 취약한 프로그램이 하는 일이 있다. x 파일을 자기가 소유한 파일로 링크를 해둔다.
액세스 함수의 체크를 넘어가기 위함이다. 그 후 체크가 넘어가면 해당 파일을
etc/passwd로 링크를 바꾼다. 리얼 id의 권한을 체크하고 그 체크를 통과하면 그 파일을
열게 된다. 이 프로그램들이 동시에 계속 실행되는데, 운 좋게 A1, V1, A2 , V2 순으로 하
면 공격 가능
페이지 11 이 코드가 하는 일은 tmp/x 파일이 존재하는지 확인, 없으면 새 파일 만들어
서 editing한다. open() API에 옵션으로 O_CREAT는 파일 없으면 새 파일 만들기. 여기서
도 레이스 컨디션 문제가 있다. 체크가 끝나고 오픈이 발생하기 이전에 tmp/x를 passwd
로 링크를 시켜준다고 하면 결국에는 공격자는 passwd 파일을 루트 권한으로 열게되어write할 수 있게 된다. set-UID가 걸려있어 루트 권한으로 실행이 될 것이다.
페이지 12 앞에서 정보를 바탕으로 레이스 공격을 해보자. 이 코드는 tmp/XYZ 파일을
append 모드로 오픈하게 된다.
"a+"는 해당 파일에 새 내용을 추가하겠다는 옵션이다.
해당 파일에 개행 문자를 하나 넣고 버퍼에 내용을 버퍼 크기만큼 write하게 된다.
access를 이용해서 현재 real user가 write 권한 있는지 확인하고 그렇다면 아래 문장들을
실행하게 된다. set-UID도 걸려 있다.
권한 체크 하고 심볼릭 링크를 이용해서 공격 대상 파일에 연결하여 해당 파일이 연결되
어 파일을 write 할 수 있다.
페이지 13 실험을 위해서 특정 보안 기능을 끈다. tmp 폴더는 모든 유저가 자기 소유의
파일들을 맘껏 read write하도록 하는데, 심볼릭 링크에 대한 보호에 대해서 이러한 기능
이 있다. 실험을 위해서 이 기능을 끈다.
페이지 14 공격은 이런 순서로 되고, 공격 대상 파일을 선택. 특정 파일은 공격자의 원
래 권한으로 못 열기에 set-UID 걸려 있고, 루트 소유이고 race -condition이 있는 예제
코드를 이용해서 열어서 수정을 한다. passwd 파일을 수정하는 것을 보일 것이다. 레이
스 컨디션을 악용해서 원래 열리는 파일을 심볼릭 링크로 해준다. 이걸 만들어주는 걸
매뉴얼로 하면 공격 성능이 매우 떨어진다. 공격 프로세스와 취약 프로세스를 루프 돌려
서 계속 실행시킨다. 특정 조건이 만족되는지 확인한다.
페이지 15 공격대상 파일을 정하는데 etc/passwd이다. 새로운 유저를 루트 권한으로 추
가하는게 목적이다. 해시 같은 건 패스워드가 없을 때 계산된 해시이다. 패스워드 없이
루트권한으로 만들 것이라는 뜻.
페이지 16 취약 프로그램을 계속 실행하게 한다. 간단한 쉘스크립트를 짜서 무한히 돌아
가도록 한다. passwd_input은 앞에서의 만들고자 하는 유저의 정보가 들어가 있다. 이게
버퍼에 내용이 들어가 있고 파일로 전달이 될 것이다. fwrite로 쓰여질 거다.
페이지 17 공격자는 이런 공격 프로그램을 작성한다. 이것도 간단한데 무한루프를 돌면서 안의 내용을 실행한다. tmp/XYZ 이건 취약한 프로그램에서 열리는 파일이다. 이 파일
에 먼저 언링크를 한다.
-뒤의 심링크가 따라오기 때문에 먼저 해제해준다. 그 다음에
tmp/XYZ를 연결한다. 이렇게 연결 시켰을 때는 취약한 프로그램에서의 access api가 실
행되는 순간이다. 이게 먼저 실행되고 access가 실행되면 공격자의 id로 파일을 write하
는 걸 체크하는데 xyz가 공격자가 만든 파일에 링크됐으니 당연히 쓸 수 있으니 체크가
넘어가게 될 것이다. 그 아래 부분이 실행이 되어 언링크하고 passwd 파일로 링크를 한
다. 이 부분이 실행되고 난 다음에 fopen이 실행되면 파일을 조작할 수 있게 된다.
usleep 같은 경우 마이크로 세컨드 단위로 프로그램을 잠시 멈추는 것이다. 그 이유는
경험적으로 잠깐 슬립을 넣는 것이 공격 성공률을 높이는데 도움이 됐기 때문이다. 중간
중간 슬립 넣기. 이걸 실습을 한다면 이 안에 있는 숫자를 바꿔가며 실험해보면 공격이
잘 되는 수치가 있을 것이다. 이런 것들은 자유롭게 변경이 가능하다.
페이지 18 취약한 프로그램을 무한히 실행한다. 공격에 성공했는지 모니터링 하면서 쉘
스크립트를 멈추기 위해서 이런 식으로 했다. ls -l passwd 로 디렉토리 내에서의 정보가
타임스탬프의 값과 함께 출력된다. 이 파일은 언제 수정됐는지 알 수 있다. 실행된 결과
를 old와 new 변수에 넣고 old와 new가 같은지 계속 확인한다. 그 아래는 동일하다. 그
런데 new에 체크 파일을 다시 넣는다. 레이스 컨디션을 만족해서 공격을 성공하면
passwd 파일이 변경될 거고 타임스탬프가 달라질 것이다. 그러면 루프를 마치고, 공격이
성공했다는 메세지를 출력하고 쉘 스크립트가 종료될 것이다.
페이지 19 공격자는 앞에서 준비한 파일들을 실행해서 공격을 한다. 어택 프로세스를 백
그라운드로 실행하고, 계속 실행되는 도중에 취약 프로그램을 수행한다. 쉘 스크립트를
실행하게 되며 무한히 취약 프로그램이 수행된다. 타임스탬프 체크하다 공격 성공하면
저런 메세지가 뜨고 끝난다. passwd 파일 확인하면 추가한 테스트 유저의 passwd 인포
메이션을 확인할 수 있다.
페이지 20 이 레이스 컨디션 공격의 방어 기법을 보자. atomic operation 원자적 실행.
체크를 하고, 사용하는 로직이 있을 때, 공격자가 중간에 끼어들어 우회할 수 있는 걸 막
도록 타임 윈도우를 제거하며 방어하는 기법이 있다.
리피팅 쳌 앤 유스는 체크를 하고 사용하는데, 여러 개 페어를 두어서 공격자가 체크 로
직을 피하기 위해서 여러 번 상태를 바꿔주도록 수행하게 만든다. 타이밍이 중요하기에
체크하는 로직이 여러 번 수행되게 하면 공격자가 레이스 컨디션에서 이길 여지가 적어
지게 된다.스티키 심링크 프로텍션은 앞에서 살펴본 공격 예제에 특화된 방어기법이다. tmp 디렉
토리의 파일을 중요한 파일로 링크를 못 걸어두게 막는다.
프린시플 오브 리스트 프리빌리지는 어떤 실행파일이 있을 때, 그 실행파일이 가질 수
있는 권한을 최소화 해라. 그 오퍼레이션의 수행을 위한 권한만 줘야지 더 많이 줘선 안
된다. 레이스 컨디션에서 공격자가 악용하게 되더라도 공격자가 갖게 되는 권한이 부족
하게 되어 악성행위의 제한을 할 수 있다.
페이지 21 아토믹 오퍼레이션부터 보자. 앞에서 본 open api를 보자. 파일이 존재하지
않을 때만, 파일 만들기. verify 로직을 통과하고 링크를 만들든지 해서 open이 존재하는
파일을 열게 만든다. 뒤 로직에 의해서 수정이 된다. 그래서 O_CREAT | O_EXCL 두 옵션
을 주게 되면 파일이 이미 존재한다면 그 파일을 열지 않게 된다. 체크하고 사용하는데
에는 원자적 실행을 강제할 수 있다. 이렇게 O_REAL_USER
_
ID라는 옵션은 api에 존재하
진 않지만 이런 걸 구현해볼 수도 있다는 얘기이다. open은 effective user id만 확인했고,
real user id는 체크하지 않았다. 리얼 유저 아이디는 실제 실행파일을 실행한 유저이고,
이펙티브 유저 아이디는 해당 파일에 set UID가 걸려있을 때 해당 파일의 소유주의 id가
된다. 루트 권한일 경우 루트 권한으로 실행이 될 수 있다. open api는 effective만 체크
하니 레이스 컨디션 악용하면 루트 소유의 파일들이 열리고 수정할 수 있으니 이런 옵션
을 줘서 이펙티브가 아닌 실행파일을 실행한 리얼 유저 아이디를 보는 것이다. 이렇게
아토믹 오퍼레이션을 강제.
페이지 22 체크와 유즈를 여러번 반복하는 방식. 이미 살펴봤던 예제인데 파일에 대한
접근 권한 확인하고 오픈을 해준다. 이러한 pair를 여러 번 반복하고 있다. 마지막에서
inode 정보를 가져오고 서로 비교를 한다. 공격자가 중간에 레이스 컨디션으로 액세스를
통과한 이후에 파일을 바꿨다면 체크 로직에서 탐지가 될 것이다. 그러한 악성행위가 없
었다면 파일에 대한 수정이 이뤄지게 되는 것이다. 코드에서의 레이스 컨디션을 하려면
다섯 번의 레이스 윈도우를 통과해야한다. 검증을 통과한 이후에 정상적인 파일로 다시
바꾸고, 액세스 통과하고 다시 악성 파일로 바꾸고 오픈하고, 다음 검증 통과하기 위해서
정상 파일로 바꾸고... 이런 5번의 레이스 컨디션을 통과해야한다. 이거 타이밍 맞추기가
굉장히 어렵다. 검증 로직이 많으면 정말 어려워진다.
페이지 23 스티키 심링크 프로텍션. 스티키 비트가 무엇인지. ls 명령어로 /tmp를 치면
others 쪽에 t나 T가 있을 것이다. tmp 디렉토리는 모든 사람이 자신의 파일을 write 하
거나 실행할 수 있다. 이러한 권한이 있는데 user1이 생성하고, user 2가 또 다른 파일을
생성했을 때, 모든 사람이 쓸 수 있고, 실행할 수 있는 곳에서는 다른 유저가 다른 유저가 만든 파일을 쓰거나 사용하거나 삭제할 수 있다. 여기에 스티키 비트를 붙이면 그 디
렉토리에 소유자, 파일 소유자, 루트 유저 제외하고는 자신이 소유한 파일에만 접근할 수
있도록 한다. 다른 사람이 실행하거나 쓸 수 없도록 강제하기 위한 스티키 비트가 나온
것이다. 스티키 비트가 없으면 그런 폴더에서는 모든 사람이 마음대로 지우거나 수정할
수 있다. 보통 리눅스 같은 시스템에서는 스티키 비트가 붙은 폴더가 있다. 모든 사람이
접근할 수 있는 폴더가 있는데, 이런 폴더를 줄 수 있음으로 자유롭게 쓸 수 있다가 다
른 사람이 접근 못 하게 하는 것이다. Set UID는 실행파일의 소유자 권한으로 실행할 때
의미가 있다. 디렉토리에는 붙어 있어도 별 의미가 없다. Set GID는 UID보다는 의미가 있
다. 디렉토리가 A라는 디렉토리가 있는데 set GID가 걸려있다. 이 디렉토리의 그룹 아이
디가 AA였다. bob이라는 사람이 자신의 파일을 만들어서 A 디렉토리에 파일을 넣었다.
bob의 그룹 아이디가 BB이다. 디렉토리 카피 되는 순간 AA가 된다. 그룹 ID AA 갖는 사
람들이 접근할 수 있게 된다. 원래는 BB 그룹 아이디 사람들만 가능했는데 GID가 붙은
디렉토리에서 공동작업을 할 수 있게 한다. 해당 파일에 대한 접근이 용이하게 된다. 앞
에서 살펴본 공격에서는 스티키 비트가 붙어있는 범용 디렉토리에서 심볼릭 링크를 걸어
서 공격을 했었다.
페이지24 이런 스티키비트가 붙은 폴더에서 심볼릭 링크를 사용하지 못 하게 하는 방어
기법이다. 우분투 16.04 12.04 에서 활성화 할 수 있고 비활성화 할 수 있다. 실습은 비
활성화 하고 진행.
페이지 25 스트키 심링크 프로텍션이 걸려있을 때. 어떤 식으로 동작하는지 예제코드 이
용. tmp/XYZ을 여는 행위를 하는 간단한 예제 코드. 실행은 일반유저와 루트 유저. 결과
를 뒤에서 보면.
페이지 26 심볼릭 링크를 만들었는데 심링크 오너와 만든 사람의 아이디가 디렉토리 오
너나 effective UID와 일치를 해야한다. 실행 파일이 갖는 euid와 symbolic link 만든 사람
의 id가 동일하던지 아니면 이 사람이 directory owner 여야 한다. 심링크와 둘 중 어느
것이라도 하나 같아야 가능하다.
페이지 27 중요한 개념. 프린시플 오브 리스트 프리빌리지. 실행파일에 필요한 권한만
있어야 한다. 최소한의 권한만 갖도록 프로그래밍. 파일 오픈해서 수정하는 건데 루트 권
한으로 하는 권한을 너무 많이 가진 것으로 exploit으로 공격자가 악성행위의 범위가 많
다. 주의할 것은 레이스 컨디션 버그에서는 api를 이용하는게 이펙티브하나 버퍼 오버플
로우 같은 경우에는 효과적이지 않다.페이지 28 프린시플 오브 리스트 프리빌리지 강조하는 코드. 오픈은 euid를 기반으로 체
크한다. seteuid를 리얼 유아이디로 세팅. 이 프로그램이 루트 권한으로 이유아디를 가지
면서 실행된다고 했을 때, seteuid에서 리얼 유저 아이디로 변경된다. 그래서 체크를 할
수 있게 된다. 그리고 필요하다면 나중에 eff
uid로 변경해준다. 루트권한으로 실행되어야
_
하는 부분과 필요 없는 권한이 있다면 권한을 내려주고, 올려주는 그런 개념이다.
페이지 29 앞에서 잠깐 언급한 내용이 있다. 레이스 컨디션 공격을 막기 위해 setuid
euid를 이용해서 권한을 조정했다. 이런 걸 메모리 변조하는 버퍼오버플로우 공격에서도
사용할 수 있는가? 그건 안 된다.
버퍼 오버플로우는 메모리 변조로 리턴 어드레스 변조해서 api가 실행되는 곳으로 변조
하면 set uid가 실행이 될 것이다. 그러면 공격자가 원하는 파라미터도 조작할 수 있다.
그렇기에 이런 메모리 코럽션 공격에는 활용될 수 없다.
페이지 30 정리하면 레이스 컨디션이 무엇인지 살펴보았다. 운영체제에서 배운 사람들도
있을 것이다. 레이스 컨디션을 악용해서 공격자가 무엇을 할 수 있나 봤다. 타임오브체크
타임오브 유즈. 보안 체크와 사용 시점의 타임 갭인 윈도우를 악용해서 공격자가 원하는
악성행위를 함. 여러가지 방법으로 막았다. 레이스 컨디션 이런 거 많으니 프로그램을 잘
걸어둬야 한다. 크리티컬 리소스에 접근할 때, 락을 잘 이용해서 레이스 컨디션이 발생하
지 않게 잘 하면 된다. 공격이 발생하지 않더라도 이상한 결과를 내뱉을 수 있다. 레이스
컨디션은 항상 주의해서 프로그램을 개발해야한다는 게 주요 내용이다.
'[활동 정리] - 비밀번호 : helloㅁㅁㅁ > [2024]동계 모각코 개인' 카테고리의 다른 글
[모각코] 최종 회고 (0) | 2025.02.13 |
---|---|
[모각코] 동계 모각코 5회차 개인목표 및 결과 (0) | 2025.01.21 |
[모각코] 동계 모각코 4회차 개인목표 및 결과 (0) | 2025.01.21 |
[모각코] 동계 모각코 3회차 개인목표 및 결과 (0) | 2025.01.21 |
[모각코] 동계 모각코 2회차 개인목표 및 결과 (0) | 2025.01.10 |