오래 못 할 짓 하지 않기
[ 컴퓨터 보안 ] 4. Capability Leaking / Environment Variable 본문
[ 컴퓨터 보안 ] 4. Capability Leaking / Environment Variable
쫑알bot 2024. 9. 10. 20:05(참고) https://juyeong-lee.tistory.com/26
우리는 프로그램을 EUID로 실행시킨다.
- EUID : 특정 프로세스를 실행할 때 해당 프로세스에게 받는 권한
- RUID : 특정 프로세스를 실행할 때 프로세스가 인식하는 내 권한
ex) 프로그램 A 를 실행할 땐 root 권한으로 실행하게 되어있다.
Alice가 이 프로그램을 시켰을 때 EUID , RUID는?
➡️ EUID = root , RUID = Alice
EUID : 프로그램이 실행될 때 적용되는 권한
RUID : 실행한 사용자의 권한 및 ID
Capability Leaking
특정 프로그램을 실행할 때 권한을 얻게 되는 게 Set-UID의 기능이다.
그럼 프로그램 실행이 끝났을 땐 어떻게 되는가?
권한이 제대로 반환되어야 한다.
하지만, 그 권한이 제대로 반환되지 않았을 때, 즉 아이언맨 슈트를 입고 임무를 완수한 뒤에도
계속 슈트를 입고 활동하는 것과 같아진다.
악의적으로 사용하면 관리자의 권한으로 모든 것을 할 수 있다.
아래 예시를 보자
fd = open("/etc/zzz", O_RDWR | O_APPEND);
if (fd == -1) {
printf("Cannot open /etc/zzz\n");
exit(0);
}
// Print out the file descriptor value
printf("fd is %d\n", fd);
// Permanently disable the privilege by making the
// effective uid the same as the real uid
setuid(getuid());
// Execute /bin/sh
v[0] = "/bin/sh"; v[1] = 0;
execve(v[0], v, 0);
이 프로그램에 대해 다음과 같은 Shell command를 사용한다고 하자.
파일에 echo(aaaaaa) 는 되지 않지만
File Descriptor에 쓰는 것(ccccc)는 되는 상황
우선 이 프로그램을 실행시키는 것에 대해서는 우리가 root 권한을 가질 수 있다.
하지만 write 하는 경우에는 root 권한이 없다.
1) 이를 적용해보면 fd를 여는 건 root 권한이므로 문제없다.
fd에게 문자열을 보내는 것 또한 문제가 없다.
2) 하지만 파일에 직접 쓰는 것은 우리에게 권한이 없다.
따라서 Permission denied 메시지가 나온다.
int main(int argc, char *argv[]){
char *v[3];
char *command;
if(argc < 2) {
printf("Please type a file name.\n");
return 1;
}
v[0] = "/bin/cat"; v[1] = argv[1]; v[2] = NULL;
command = malloc(strlen(v[0]) + strlen(v[1]) + 2);
sprintf(command, "%s %s", v[0], v[1]);
system(command);
return 0 ;
}
해당 프로그램을 실행시킬 때 넣은 인자값들로
System command를 실행시키는 프로그램이다.
input을 code로 만드는 방법이다.
input 안에 ; 을 넣어서 그 앞을 명령어인 것처럼 넣어서
입력을 명령어로 바꿀 수 있는 것이다.
이와 같은 걸로는 XSS , SQL Injection 이 있다.
안전하게 하려면 Command 말고 execve로 하는 게 낫다.
그래야 중간에 명령어인 걸로 착각해서 자르지 않고
그 문자열 채로 읽어내기 때문에
가장 중요한 건
Data와 Code가 절대 섞이지 않게 해라
➡️ Data가 들어갈 자리에는 Data로 / Code가 들어갈 자리에는 Code로 인식하게 해라
Environment Variable
: 프로세스가 동작하는 데에 영향을 미치는 동적인 변수
위와 같이 사용할 수 있다.
프로세스가 환경변수를 가지게 되는 방법은 2가지가 있다.
- 부모 프로세스로부터 fork()
- execve() system call
여기에서 인자로 envp를 받을 수 있다.
extern char ** environ;
void main(int argc, char* argv[], char* envp[])
{
int i = 0; char* v[2]; char* newenv[3];
if (argc < 2) return;
// Construct the argument array
v[0] = "/usr/bin/env"; v[1] = NULL;
// Construct the environment variable array
newenv[0] = "AAA=aaa"; newenv[1] = "BBB=bbb"; newenv[2] = NULL;
switch(argv[1][0]) {
case '1': // Passing no environment variable.
execve(v[0], v, NULL);
case '2': // Passing a new set of environment variables.
execve(v[0], v, newenv);
case '3': // Passing all the environment variables.
execve(v[0], v, environ);
default:
execve(v[0], v, NULL);
}
}
3번째 명령어에서 ' LOGNAME =bob ' 가
5번째 명령어에서 반영이 안 된 이유 : 쉘 변수라서 환경 변수로 안 들어감
➡️ 반영 시키기 위해서는 ' export {변수 명} = { 변수 값 } ' 를 써야한다.
➡️ 쉘 변수를 해제하려면 ' unset { 쉘 변수명 } '
(출처)
한동대학교 고윤민교수님 - 컴퓨터보안
'3학년 2학기 > 컴퓨터 보안(Computer Security)' 카테고리의 다른 글
[ 컴퓨터 보안 ] 6. Race Condition (0) | 2024.10.06 |
---|---|
[ 컴퓨터 보안 ] 5. Buffer Overflow (0) | 2024.10.05 |
[ 컴퓨터 보안 ] 3. Authentication (인증) + Set-UID 특수권한 (0) | 2024.09.06 |
[ 컴퓨터 보안 ] 2. Linux 권한 관련 (0) | 2024.09.03 |
[ 컴퓨터 보안 ] 1. Security의 개념 (0) | 2024.08.30 |