1. Privileged Program의 필요성
Privileged program (특정 프로그램에 임시로 특권을 줌)
- ex. 일반 유저가 패스워드 바꿔야 할 때
2. Two-Tier Approach
특권이 요청되는 작업을 할 수 있는 방법 두가지
- OS에서 세분화된 액세스 제어를 구현
- Operation 종류에 따라 미세 컨트롤 ⇒ OS가 지나치게 복잡 해짐 ⇒ 버그 생길 가능성이 높아짐
- 확장 기능에 의존하여 세분화된 액세스 제어 수행
- 일반 프로그램 보다는 특권을 가진 Privileged Program을 만들어서 Program이 OS에게 요청
3. Privileged Program 종류
- Demons
- 백그라운드에서 실행
- root 또는 특권 가지고 실행
- Set-UID Programs
- UNIX 시스템에서 널리 사용
- 특수 비트로 표시된 프로그램
4. Superman Story
- Power Suit를 입으면 슈퍼맨과 같은 power가짐
- 문제: 나쁜 사람들이 입고 나쁜 짓
- Power Suit 2.0으로 발전
- 프로그래밍 한 대로만 움직일 수 있음 ⇒ 나쁜 짓 불가
- 이 컨셉과 비슷한 것이 Set-UID 매커니즘
- 일반 프로그램이 root 권한으로 실행
5. Set-UID 컨셉
- 사용자가 프로그램 소유자의 권한으로 프로그램을 실행할 수 있도록 허용
- 사용자가 일시적으로 상승된 권한으로 프로그램 실행 허용
- Linux OS에서 모든 프로세스는 두가지 ID를 가짐 (RUID, EUID)
- RUID: 프로세스의 실제 소유자를 식별
- EUID: 프로세스의 권한을 식별
- 액세스 제어는 EUID를 기반
- 일반 프로그램 실행: RUID = EUID (둘 다 프로그램을 실행하는 사용자의 ID와 동일)
- Set-UID 실행: RUID ≠ EUID (RUID는 여전히 사용자의 ID, EUID는 프로그램 소유자의 ID와 동일)
- 프로그램이 루트에 의해 소유되는 경우 프로그램은 루트 권한으로 실행
6. Set-UID 프로그램이 동작하는 방식
Set-UID 프로그램은 Set-UID 비트라고 불리는 특별한 마킹이 있다는 점을 제외하면 다른 프로그램과 같다.
(4로 설정해주면 s비트가 붙음)
$ sudo chmod 4655 myid
$ ./myid
uid=1000(seed) gid=1000(seed) euid=0(root)
7. Set-UID는 어떻게 보호되는가?
Set-UID는 일반 사용자가 권한을 상승시킬 수 있는 방법
- 이는 권한을 직접 부여하는 것과는 다름 (sudo 명령: sudo pw 알아야 실행 가능)
- 제한된 동작 – 슈퍼맨 설계 컴퓨터 칩과 유사
- 모든 프로그램을 Set-UID로 변환하는 것은 안전하지 않음 (ex. /bin/sh, vi)
8. 문제점은 없는가?
- 사용자가 코딩된 작업만 수행할 수 있다고 가정할 수 없음
- 개발자에 의한 코딩 결함
9. 어떤 공격이 존재하는가?
- User Inputs
- System Inputs
- Environment Variables (PATH 변조)
- 통신 취약점 이용
10. User Inputs를 통한 공격
- Set-UID 프로그램이 BOF나 FSB 가지고 있으면 공격자가 악의적인 input 넘겨서 공격가능
- BOF : 버퍼 오버플로하여 악성 코드 실행
- FSB : 사용자 입력을 형식 문자열로 사용하여 프로그램 동작 변경
- CHSH : 기본 셸 프로그램을 변경할 수 있는 기능이 있는 Set-UID 프로그램
- 셸 프로그램은 /etc/passwd 파일에 저장 (셸 변경을 위해서는 /etc/passwd 파일을 변경해야 함)
- user input 제대로 검증하지 않음 ⇒ ex. 셸이 다른 셸로 바꿈과 동시에 새로운 라인이 pw 파일에 들어감
- 공격자는 새 루트 계정을 만들 수 있음
10. System Inputs를 통한 공격
- user input이 바로 들어가는 것이 아니라 system input만을 활용하는 프로그램
- race condition 이용
- 권한이 없는 파일에서 권한 있는 파일에 대한 Symbolic link (like 바로가기)
- Symbolic link ⇒ root 소유의 중요한 파일을 가리킴 ⇒ 의도치 않게 업데이트 하도록
11. Environment Variables를 통한 공격
- 동작은 프로그램 내에서 보이지 않는 입력에 의해 영향을 받을 수 있음
- Enviornment variable (환경변수) : 프로그램을 실행하기 전에 사용자가 설정 가능
- PATH Enviornment Variable
- 셸 프로그램에서 사용자가 명령의 전체 경로(full path)를 제공하지 않는 경우 명령을 찾기 위해 사용
- system("ls")
- /bin/sh 를 먼저 호출
- /bin/sh는 PATH 환경 변수를 사용하여 "ls"(user로 부터 받은 명령어) 를 찾음
- 공격자는 PATH 변수를 조작하고 "ls" 명령이 발견되는 방법을 제어 가능 (malicious directory 경로로)
12. Capability Leaking
특정 권한으로 상승시켰는데 상승시킨 권한을 제대로 제거해주지 않고 누군가 상승된 권한을 악용하는 경우
- 경우에 따라 권한 있는 프로그램은 실행 중에 자동으로 다운그레이드
- ex) su program (현재 유저를 다른 유저로 바꿔줌)
- 이 프로그램은 권한 있는 Set-UID 프로그램
- 한 사용자가 다른 사용자(user1에서 user2로)로 전환할 수 있음
- 프로그램은 EUID: root, RUID: user1로 시작
- 암호 확인 후, 권한 다운그레이드를 통해 EUID와 RUID가 모두 user2가 됨
- 이러한 프로그램은 기능 누출을 초래
- 프로그램이 다운그레이드하기 전에 권한 있는 기능을 정리하지 못할 수 있음
12. Capability Leaking를 통한 공격
- fd = open ("/etc/zzz", O_RDWR | O_APPEND);
- 파일은 root만 쓸 수 있음
- file descriptor 생성 (프로그램은 root 소유 Set-UID 프로그램)
- setuid(getuid());
- 권한이 다운그레이드
- v[0] = "bin/sh"; v[1]=0 = 0;
- 프로그램에 대한 동작 제한이 해제되도록 셸 프로그램을 호출
- 프로그램이 파일을 닫는 것을 잊었으므로 file descriptor가 여전히 유효 ⇒ Capability Leaking
- 프로그램 어떻게 고치는가? 권한을 다운그레이드하기 전에 파일 설명자 삭제(파일 닫기)
12. Capability Leaking를 통한 공격 실제 예시
- OS X의 기능 누출
- OS X Yosemite는 2015년 7월에 기능 누수와 관련된 권한 상승 공격에 취약하다고 확인됨 (OS X 10.10)
- 동적 링커 dyld에 기능 추가 (DYLD_PRINT_TO_FILE 환경 변수, 여기에 버그)
- 동적 링커는 모든 파일을 열 수 있고, 만일 루트 소유 Set-UID 프로그램의 경우 루트 권한으로 실행
- 동적 링커 dyld는 파일을 닫지 않음 ⇒ 기능이 누출
- 시나리오 1(안전): Set-UID는 작업을 완료하고 프로세스는 종료 ⇒ 모든 것이 clean up ⇒ 안전
- 시나리오 2(안전하지 않음): "su" 프로그램과 유사하게, 특권 프로그램은 권한을 다운그레이드 (파일 닫지 않음)
13. Invoking Programs
- Set-UID가 걸린 프로그램에서 다른 외부 명령을 실행하는 상황에서의 문제점/위험성
- 프로그램 내부에서 외부 명령 호출
- 어떤 커맨드를 실행할지는 Set-UID 프로그램에 미리 정의 되어있고, user는 data만 줄 수있음 (커맨드를 제공하지 않아야 함)
- 공격
- 위와 같이 디자인하면 안전할 것이라 생각했으나, 여전히 위험한 상황 연출 가능
- 명령이 제대로 실행되지 않으면 사용자의 입력 data가 커맨드로 인식될 수 있는 상황이 있음
14. Invoking Programs 예시
- system() : 외부 명령을 호출하는 가장 쉬운 방법
- 이 프로그램은 /bin/cat 프로그램을 실행하도록 되어 있음 / 어떤 파일을 읽을지(cat)는 user input으로 받음
- root 소유 Set-UID 프로그램이기 때문에 프로그램은 모든 파일 read 가능하나, write 불가능
- data의 일부가 코드(명령 이름)가 됨
- catall "aa; /bin/sh"
- aa라는 파일을 읽고 쉘을 연다
- 프로그램에 Set-UID 걸려있었으므로, root 권한의 쉘 획득
14. Invoking Programs 예시
- Ubuntu 16.04에서 /bin/sh는 /bin/dash를 가리키며, 여기에는 공격에 대한 방어책이 있음
- Set-UID 프로세스 내에서 실행될 때 권한을 삭제
- dash 셸이 Set-UID 걸린 프로그램에 의해 호출되면 root 셸이 뜨는 것이 아니라 프로그램을 실행했던 RUID와 동일한 EUID를 가진 셸 실행
- 따라서, 실습에서는 취약한 셸(zsh)로 바꿔줌
15. Invoking Programs Safely : using execve( )
- System 함수는 취약
- 커맨드를 받을 때 검증 제대로 불가 (코드와 데이터가 섞여있고, 구분해서 검증 불가)
- 공격자가 (command1); (command2); 이런식으로 인자를 주면 커맨드 모두 실행 가능
- 동일하게, 커맨드를 실행하지만 코드와 데이터가 불리된 API 사용함으로써 문제 해결
- execve ( v[0], v, 0 )
- v[0] : 커맨드 이름
- v : 데이터
- 0 : 환경변수 주소
- 코드(명령 이름)와 데이터가 명확하게 분리되어 사용자 데이터가 코드가 될 수 없음
16. 추가적인 고려사항
- exec() family의 일부 함수는 exec()와 비슷하게 동작하지만 안전하지 않을 수 있음
- execlp(), execvp() 및 execvpe()는 셸의 동작을 복제, 이러한 함수는 PATH 환경 변수를 사용하여 공격 가능
17. 다른 언어에서의 Invoking External Commands
- 외부 명령을 호출하는 위험은 C 프로그램에 국한되지 않음
- system( ) 함수에 인해 발생하는 문제와 유사한 문제를 피해야 함
- 예시
- Perl: open() 함수는 명령을 실행할 수 있지만 셸을 통해 실행 가능
- PHP: system() 함수
18. Principle of Isolation
- code와 data를 섞어서 input으로 받지 말아야 함
- 위반했을 때 여러 공격 발생 가능
- system() code execution
- Cross Site Scripting
- SQL injection
- Buffer Overflow attacks
19. Principle of Least Privilege
- 최소한의 권한만을 부여
- 권한 있는 프로그램에는 해당 작업을 수행하는 데 필요한 권한이 부여되어야 함
- 권한 있는 프로그램에 권한이 필요하지 않은 경우 권한을 일시적으로 또는 영구적으로 비활성화
- Linux에서는 seteuid()와 setuid()를 사용하여 권한을 비활성화/폐기 가능
- OS마다 다른 방법 존재