권한 있는 파일 디스크립터 노출을 통한 로컬 권한 상승

🛡️ 강사 제공 인가된 실습 환경에서 수행

Unix 도메인 소켓을 통해 높은 권한의 프로세스가 가진 파일 디스크립터가 노출될 때 발생하는 권한 상승 원리를 정리한 학습 노트이다.

1. 핵심 원리

이번 권한 상승은 다음 구조 때문에 가능했다.

낮은 권한의 사용자가 접근할 수 있는 관리 소켓
                    +
민감한 파일을 열어둔 root 데몬
                    +
사용자가 발생시킬 수 있는 보안 트리거
                    +
민감한 FD를 함께 전달하는 개발 실수

          root 전용 파일 내용 유출

              root 권한 획득

단순히 root 소유의 소켓이 존재한다는 이유만으로 권한 상승이 가능한 것은 아니다. 접근 가능한 소켓, root 데몬, 조작 가능한 트리거, 민감한 FD 유출이 모두 연결되면서 공격이 가능해졌다.


2. 운영 중이던 구성요소

2.1 archivist 사용자

archivist는 이미 확보한 일반 사용자 계정이다.

이 사용자는 다음 두 가지 행동을 할 수 있었다.

1. 로컬 JetDirect 프린터 서비스에 명령 전송
2. /run/paperwork/mgmt.sock에 연결

두 기능 모두 단독으로는 root 권한 상승을 의미하지 않는다. 하지만 이후 root 데몬의 잘못된 동작과 연결되면서 공격에 사용됐다.

2.2 JetDirect 프린터 서비스

실행 프로그램: /home/archivist/printer/jetdirect.py
실행 사용자: archivist
통신 주소: 127.0.0.1:9100

JetDirect는 로컬에서 PJL 프린터 명령을 받는 서비스다. 받은 명령은 다음 로그에 기록했다.

/home/archivist/printer/logs/commands.log

따라서 archivist는 로그를 직접 편집하지 않더라도 JetDirect에 명령을 보내 로그 내용에 영향을 줄 수 있었다.

archivist

    │ PJL 명령 전송

JetDirect

    │ 받은 명령 기록

commands.log

2.3 paperwork-daemon

paperwork-daemon은 터미널과 관계없이 백그라운드에서 계속 실행되면서 관리 요청을 기다리는 데몬이다.

실행 프로그램: /usr/bin/paperwork-daemon
실행 사용자: root
역할: 관리 소켓 연결 처리 및 프린터 로그 검사

실행 중인 프로세스는 다음 명령으로 확인했다.

ps aux | grep '[p]aperwork'
root ... /usr/bin/python3 /usr/bin/paperwork-daemon

여기서 중요한 것은 /usr/bin/paperwork-daemon 파일이 root 소유라는 사실이 아니라, 현재 실행 중인 프로세스가 root 권한이라는 것이다.

root 권한으로 실행되기 때문에 이 데몬은 일반 사용자가 읽을 수 없는 관리자 설정 파일을 열 수 있었다.

2.4 관리용 Unix 소켓

내부에서 서비스 중인 Unix 도메인 소켓을 확인했다.

ss -lnpx
u_str LISTEN 0 5 /run/paperwork/mgmt.sock

소켓의 소유권과 접근 권한도 확인했다.

ls -la /run/paperwork/mgmt.sock
srw-rw---- 1 root archivist ... /run/paperwork/mgmt.sock

이 결과는 다음을 의미한다.

소켓 소유자: root
소켓 그룹: archivist
접근 가능 사용자: root와 archivist 그룹

따라서 archivist는 이 소켓을 통해 상대 프로세스에 연결할 수 있었다.


3. 소켓과 데몬의 관계

다음 두 사실은 처음에는 별개의 정보였다.

paperwork-daemon이 root로 실행 중이다.
/run/paperwork/mgmt.sock에 archivist가 접근할 수 있다.

이 정보만으로는 paperwork-daemon이 해당 소켓을 서비스한다고 확정할 수 없다.

그래서 데몬 파일의 Python 코드를 확인했다.

cat /usr/bin/paperwork-daemon

코드를 통해 paperwork-daemon이 직접 /run/paperwork/mgmt.sock을 만들고 연결을 기다린다는 것을 확인했다.

paperwork-daemon(root)

        ├─ mgmt.sock 생성
        ├─ 소켓 그룹을 archivist로 설정
        └─ 소켓을 통한 연결 대기

따라서 전체 관계가 다음과 같이 확정됐다.

archivist

    │ /run/paperwork/mgmt.sock에 연결

paperwork-daemon

    └─ root 권한으로 연결 처리

root 데몬과 통신할 수 있다는 사실은 중요한 공격 조건이지만, 이것만으로는 취약점이라고 할 수 없다. 실제 취약점은 연결 이후 데몬이 클라이언트에게 전달하는 정보에 있었다.


4. root 데몬이 열어둔 관리자 파일

paperwork-daemon은 동작에 필요한 관리자 설정 파일을 root 권한으로 열어둔 상태였다.

/etc/paperwork/admin_pins.conf

이 파일은 일반 archivist 사용자가 직접 읽을 수 없는 root 전용 파일이었다.

archivist

    │ admin_pins.conf 직접 열기

권한 검사

    └─ 접근 거부

하지만 paperwork-daemon은 root 권한이므로 해당 파일을 정상적으로 열 수 있었다.

paperwork-daemon(root)

    │ admin_pins.conf 열기

관리자 파일의 FD 보유

FD는 이미 열린 파일에 접근할 수 있는 손잡이라고 생각하면 된다.

root 데몬이 관리자 파일을 열어둔 것 자체는 취약점이 아니다. 데몬이 정상적인 기능을 수행하기 위해 민감한 파일을 사용하는 경우는 흔하다.

문제는 이 손잡이를 낮은 권한의 사용자에게 전달했다는 것이다.


5. 트리거의 역할

archivist가 관리 소켓에 연결한다고 항상 관리자 파일의 FD가 전달되는 것은 아니었다.

paperwork-daemon은 먼저 commands.log를 검사했다.

commands.log에 의심 명령어 없음

정상 상태 메시지만 전달

commands.log에 의심 명령어 존재

보안 기능 실행

분석용 증거 자료의 FD 전달

데몬이 의심스러운 명령으로 판단한 문자열은 다음과 같았다.

FSQUERY
FSUPLOAD
FSDOWNLOAD

이 문자열들은 보안 기능을 실행시키는 트리거 역할을 했다.

트리거란 특정 동작을 시작하게 만드는 조건이나 스위치를 의미한다.

FSQUERY가 로그에 존재

보안 문제가 발생했다고 판단

증거 자료 전달 기능 실행

따라서 먼저 JetDirect에 FSQUERY 명령을 보내 commands.log에 해당 문자열을 기록했다.

archivist

    │ FSQUERY 전송

JetDirect

    │ commands.log에 기록

paperwork-daemon이 트리거 발견

FSQUERY가 관리자 파일을 직접 읽어주는 것은 아니다. FSQUERY는 관리자 파일의 FD를 전달하는 보안 기능을 실행시키는 조건일 뿐이다.


6. 개발자의 의도와 실수

개발자의 의도는 의심스러운 프린터 명령을 발견하면 분석을 위해 commands.log를 증거 자료로 전달하는 것이었던 것으로 보인다.

의심스러운 프린터 명령 발견

보안 잠금 기능 실행

분석을 위해 commands.log 전달

하지만 실제로는 로그 파일의 FD뿐만 아니라 관리자 파일의 FD까지 함께 전달하고 있었다.

원래 필요했던 정보
└─ commands.log의 FD

실제로 전달한 정보
├─ commands.log의 FD
└─ admin_pins.conf의 FD

게다가 소켓에 연결한 사용자가 이 관리자 FD를 받아도 되는지 확인하는 인증 및 권한 검사가 없었다.

따라서 archivist가 트리거를 발생시킨 뒤 관리 소켓에 연결하면 두 FD를 모두 받을 수 있었다.

중요한 점은 다음과 같다.

관리자 파일을 열어둔 것 자체가 아니라, 그 파일의 열린 손잡이를 인증 없이 소켓 클라이언트에게 전달한 것이 실제 취약점이다.


7. FD를 전달받으면 파일을 읽을 수 있는 이유

일반적인 접근에서는 archivist가 관리자 파일을 직접 열어야 한다.

archivist

    │ 관리자 파일을 직접 열기

파일 권한 검사

    └─ 접근 거부

하지만 이번에는 root 데몬이 이미 파일을 열어둔 상태에서 그 손잡이를 archivist에게 넘겨줬다.

paperwork-daemon(root)

    │ 관리자 파일을 열어둠

관리자 파일의 손잡이 보유

    │ mgmt.sock을 통해 전달

archivist

    └─ 전달받은 손잡이로 파일 내용 확인

archivist가 파일을 새로 연 것이 아니기 때문에 파일 경로에 대한 권한 검사를 다시 받지 않는다. root가 이미 성공적으로 열어둔 파일에 접근할 수 있는 손잡이를 그대로 이용한 것이다.

이런 파일 손잡이를 Unix 소켓을 통해 전달할 때 사용된 기능이 SCM_RIGHTS다.

이 기능 자체는 정상적인 Linux 기능이다. 문제는 어떤 FD를 누구에게 전달하는지 제대로 검증하지 않은 사용 방식에 있다.


8. 전체 공격 흐름

8.1 실행 중인 root 데몬 발견

paperwork-daemon이 root 권한으로 실행 중임을 확인

8.2 접근 가능한 관리 소켓 발견

/run/paperwork/mgmt.sock 발견

소켓 그룹이 archivist임을 확인

archivist가 연결할 수 있음을 확인

8.3 데몬과 소켓의 관계 확인

paperwork-daemon의 Python 코드 확인

데몬이 mgmt.sock을 직접 서비스함을 확인

8.4 민감한 FD와 검증 누락 발견

root 데몬이 admin_pins.conf를 열어둠

보안 기능 실행 시 admin FD까지 전달

연결자에 대한 인증과 권한 검사 없음

8.5 트리거 생성

archivist가 JetDirect에 FSQUERY 전송

commands.log에 FSQUERY 기록

보안 기능 실행 조건 충족

8.6 관리자 파일의 FD 획득

archivist가 mgmt.sock에 연결

paperwork-daemon이 FSQUERY 트리거 확인

log FD와 admin FD 전달

archivist가 admin FD로 관리자 파일 확인

8.7 root 권한 획득

admin_pins.conf에서 관리자 비밀번호 획득

su로 root 사용자 전환

root 권한 획득

9. 공격 조건과 실제 취약점 구분

주변 조건

  • paperwork-daemon이 root로 실행 중이다.
  • mgmt.sock의 소유자가 root이다.
  • archivistmgmt.sock에 연결할 수 있다.
  • JetDirect가 프린터 명령을 로그에 기록한다.

이 조건들은 각각 단독으로는 취약점이 아니다.

공격 가능성을 만든 조건

  • 낮은 권한의 archivist가 root 데몬과 통신할 수 있다.
  • archivist가 보안 기능을 실행시키는 로그 트리거를 만들 수 있다.
  • root 데몬이 민감한 관리자 파일을 열어두고 있다.

실제 핵심 취약점

  • root 데몬이 연결한 사용자를 인증하지 않는다.
  • 전달 대상 FD에 대한 권한 검사가 없다.
  • 증거 자료에 민감한 관리자 파일의 FD까지 포함한다.
root 데몬 + 접근 가능한 소켓 + 조작 가능한 트리거

                    │ 공격 가능한 환경

인증 없이 민감한 관리자 FD 전달

                    │ 실제 취약점

root 전용 파일 내용 유출

10. 한 문장 요약

archivist가 프린터 로그에 의심 명령을 기록해 보안 기능을 실행시킨 뒤, root 데몬이 로그 FD와 함께 잘못 전달한 관리자 파일의 열린 손잡이를 받아 비밀번호를 확인한 로컬 권한 상승이다.

원본 · velog.io