각각의 프로그램들은 서로 다른 권한을 가지고 실행된다.
예를 들어 /etc/shadow file은 user의 pw를 저장하는 파일이다.
이 파일에는 모든 유저의 정보가 hash로 들어가 있기에 매우 중요한 파일이다. 그래서 root권한을 부여한다.
만약 Alice라는 user가 자신의 pw를 바꾸고 싶다면, 이 유저는 write 권한이 없는데 어떡하지? 라는 생각에서 시작된다.
이런 사용자들은 '특권'을 요청할 수 있어야 한다.
만약 OS가 직접 접근 권한을 미세하게 조정할 수 있도록 하려면 매우 복잡하게 된다. 따라서 user가 권한을 요청하도록 한다.
하지만 user가 kernel(OS)에 직접적인 요청을 하는 것이 불가하기에 extension을 중간 과정으로 거치는데,
그 extension 중 하나가 fine-grained privileged program인 것이다.
Privileged Programs 종류
Daemons
- 항상 background에서 돌고 있다.
- root 권한 혹은 특권을 가진다.
- 보통 android application
Set-UID Programs
- 보통 Linux
- rwx/... 여기에 special token(특수 권한 비트(Special Permission Bit))을 부여한다.
Set-UID
A 프로그램이 있을 때, A의 소유자가 있고 실행자가 있다. 그러면 실행될 때는 실행자의 권한으로 실행되게 된다.
그렇지만 만약 A에 set-uid가 세팅된다면, 실행자의 권한이 아닌 소유자의 권한으로 실행되게 된다.

예를 들어 이 passwd 파일은 shadow 파일을 업데이트하는 파일인데, -rws를 보면 s로 setuid가 설정된 것을 알 수 있다.
만약 setuid가 설정되어 있으면, 일반 사용자가 passwd 명령어를 실행하는 순간, 이 프로세스는 파일의 소유자인 root의 권한(EUID=root)을 일시적으로 얻게 된다. 그 덕분에 일반 사용자는 자신의 비밀번호를 변경하기 위해 root 소유의 /etc/shadow 파일을 안전하게 수정할 수 있다.
하지만 setuid가 없다면 root 권한으로 소유된 shadow파일은 update 불가하다.
즉, 프로그램에 setuid가 설정되면 실행자가 소유자의 권한을 갖게 되는 것이다. 그럼 그 소유자의 또다른 프로그램들도 업데이트를 할 수 있게 된다.
보통 process는 두 id를 가지고 있다.
RUID(Real UID) - 나의 ID
EUID(Effective UID) - process의 접근 권한을 나타낸다
보통은 RUID와 EUID가 같은데, 만약 setuid가 적용됐다면 RUID(user)와 EUID(owner)가 다를 수 있다.
Set-UID 적용
[1]

/bin/cat의 내용을 mycat에 복사한다. 만약 내가 Alice라면, mycat은 Alice 소유 프로그램이 된다.
chown으로 mycat의 권한을 root로 변경한다. (내가 root pw를 알고 있다는 가정 하에..)
mycat의 정보를 확인해보면 소유자가 root로 변경된 것을 볼 수 있다.

mycat으로 /etc/shadow의 내용을 확인하려고 하면 Permission denied가 뜬다.
mycat은 root 소유라고 하더라도, 이용자는 Alice이기 때문에 root 소유의 파일(shadow)을 못 읽는 것이다.

그래서 위처럼 chmod 4755(4:set uid 설정 비트, 755:원래 권한)로 mycat의 권한을 바꿔준다.
이후 mycat으로 root 소유인 /etc/shadow의 내용을 확인할 수 있게 된다.
[2]

id를 확인하는 /bin/id를 myid에 copy하고 이를 root 권한으로 변경해준다.
이후 myid를 확인해보면 uid, gid, groups 모두 seed 권한임을 알 수 있다.
즉, myid의 소유는 root지만 실행은 seed라는 것이다.

그런데 만약 chmod 4755로 myid를 바꿔주고 실행시키면, euid가 root로 뜨는 것을 볼 수 있다.
나(uid)는 seed, 즉 seed 권한으로 myid를 실행시켰지만, 프로그램이 실행되는 동안은 root 권한을 가진다는 말이다.
[3]

chmod 4755로 setuid를 설정하니 shadow의 내용을 볼 수 있다.

root 소유의 mycat을 seed 소유로 바꾸고 chmod 4755로 setuid를 설정해도 Permission denied가 뜬다.
그 이유는, setuid는 '프로그램의 소유자 권한으로 변경'하는 것인데,
현재 mycat은 chown으로 seed 소유로 바꾼 프로그램이기에 root 권한을 필요로 하는 shadow를 읽을 수 없는 것이다.
Set-UID의 안전성
- sudo 명령어처럼 직접적으로 권한을 주는 형태가 아니다. sudo는 실행마다 비밀번호를 요구한다.
- 제한된 행동만 실행할 수 있다.
- /bin/sh, 즉 쉘은 계속 실행되고, 명령어를 입력할 수 있는 프로그램이기에 위험하다.
- vi(텍스트 편집기)도 수정이 가능하기에 위험하다.
- user input을 통해 / system input을 통해 / 환경변수를 통해 / non-privileged process를 통해 공격 가능하다.
User Input을 통한 공격
1. Buffer Overflow
정상적인 input이 아닌 매우 긴 input을 넣어서 프로그램 내부의 메모리 레이아웃을 깨버리는 것.
return address를 overwrite하여 공격자가 원하는 부분으로 실행 부분을 바꾸거나 스택 메모리에 악성코드를 심어 그 위치로 jmp하도록 할 수 있다.
2. Format String Vulnerability
%d, %f, %n 등의 format을 이용할 때 user의 input을 제대로 검증하지 않아 발생하는 문제
3. Change Shell (CHSH)
터미널의 프롬프트에 명령어를 쓸 때 여러 종류의 sh이 있다. 이 쉘을 바꾸기 위해서는 /etc/passwd 파일을 바꿔야 한다.
만약 CHSH의 입력으로 [쉘 이름];rootX:__:__:0:0 를 넣는다고 해보자. 이 rootX:__:__:0:0은 passwd 파일 내부의 format이다. id는 root 권한을 주기 위해 0으로 입력될 것이다.
원래는 CHSH [쉘이름] 이렇게만 넣어줘야 하는데, 위처럼 넣었다면 input을 검증하지 않고 passwd 파일에 넣게 된다.
따라서 passwd 파일에는 rootX라는 사용자가 id=0(root) 권한을 가졌다고 입력이 될 것이다.
System Input을 통한 공격
Race Condition
어떤 파일에 접근할 때 누군가가 w하고 있으면 r만 할 수 있거나, 동시에 두 명이 w할 수 없다거나... 이런 조건을 어겼을 때 race condition이 발생해서 예상과는 다른 결과가 나오게 된다. 이를 race condition 공격이라고 한다.
예시)
어떤 setuid 프로그램이 /tmp/log 파일을 생성하여 내용을 기록한다고 가정해 보자. 공격자는 이 프로그램이 log 파일을 열기 직전에, 심볼릭 링크를 이용해 /tmp/log가 /etc/passwd와 같은 중요한 파일을 가리키도록 빠르게 바꿔치기할 수 있다. 그러면 setuid 프로그램은 root 권한으로 /tmp/log 파일에 내용을 쓰려고 했지만, 실제로는 /etc/passwd 파일에 의도치 않은 데이터를 덮어쓰게 되어 시스템을 손상시킬 수 있다.
환경변수를 통한 공격
예시)
Set-UID 프로그램 내부에서 system("ls")와 같이 상대 경로로 명령어를 호출하는 코드가 있다고 가정하자. 보통은 /bin/ls가 실행되겠지만, 공격자가 PATH 환경 변수의 맨 앞에 악의적인 ls가 있는 디렉토리(예: /tmp/fake_bin)를 추가하면, setuid 프로그램은 root 권한으로 공격자가 만든 가짜 ls를 실행하게 되어 심각한 보안 문제로 이어질 수 있다.
Capability Leaking
su
만약 Alice 로 로그인했다가 Bob으로 바꾸고 싶으면 su Bob으로 바꿀 수 있다.
프로그램을 시작할 때는 EUID=root, RUID=Alice였겠지만, su 명령 후 passwd 검증이 통과되면,
EUID, RUID 모두 Bob이 된다.
Set-UID 프로그램은 작업을 수행하는 데 필요한 최소한의 시간 동안만 root 권한(EUID=root)을 유지하고, 작업이 끝나면 setuid(getuid())와 같은 함수를 호출하여 원래 사용자의 권한(EUID=RUID)으로 돌아오는 것이 안전하다. 이를 '권한 낮추기(Privilege Drop)'라고 한다.
하지만 Capability Leaking(권한 누수)은 권한을 낮추기 전에 root 권한으로 열어둔 파일 디스크립터(File Descriptor)를 닫지 않았을 때 발생한다. 프로세스의 EUID는 일반 사용자로 돌아왔더라도, 이미 열려있는 파일 디스크립터는 여전히 root 권한을 유지하고 있다. 공격자는 이 닫히지 않은 디스크립터를 통해 root만 접근 가능한 파일에 계속해서 읽거나 쓸 수 있게 된다.
Invoking Programs
setuid가 걸린 프로그램에서 외부 command를 호출해서 사용할 때, 만약 user가 자신이 원하는 command를 선택하여 실행시킬 수 있다면 매우 위험하기 때문에, 어떤 command를 실행할지는 setuid가 걸린 프로그램에 이미 하드코딩 되어있다.
따라서 user는 어떤 data를 넣을지만 고를 수 있는데, 만약 이 input을 넣을 때 악의적으로 command를 변경할 수 있는 input을 작성한다면 문제가 될 수 있다.

위처럼 chat *command에 command를 받아 이를 실행시키는데,

만약 catall이라는 setuid가 적용된 프로그램에서 입력으로 "aa;/bin/sh"를 받는다면,
[aa를 보여주고 /bin/sh을 띄워라] 라는 명령어로 인식하게 된다.
그러면 root 권한을 가진 sh이 뜨게 되는 것이다.
/bin/dash
dash 쉘은 이미 보안이 좀 돼있다. 만약 이거로 쉘을 띄운다면, root권한의 sh이 아니라 사용자의 ruid 권한의 sh이 실행된다.
execve()
system 함수는 input을 받을 때 검증을 제대로 하지 못하는 단점이 있다. input을 ___;__;___ 이런 식으로 받을 수 있는 것이다.
따라서 코드와 데이터가 분리된 api를 사용하면 위의 문제를 해결할 수 있다. 그것이 execve()이다.
execve는 인자로 [command name, input data, 환경변수 주소]를 받는다. 이때 만약 입력으로 "aa;/bin/sh"를 받는다면?
aa를 넣고 /bin/sh를 실행하는 것이 아닌, 그저 data를 "aa;/bin/sh"로 받는 것이 된다. 그러면 no such file or dir 에러가 뜬다.
하지만 이 exec_ api들은 여전히 PATH 공격에는 취약하다는 문제가 있다.
'정보보안 > 소프트웨어및시스템보안' 카테고리의 다른 글
| Code Reuse Attack (1) | 2025.10.21 |
|---|---|
| Control Flow Hijacking - Shellcode (0) | 2025.10.20 |
| Control Flow Hijacking (0) | 2025.10.14 |