问题描述
我已经被这个问题困扰了好几天了,但是仍然没有设法解决它。基本上,我想从攻击者程序到目标进行远程系统调用。但是在显示代码之前,我认为介绍我的思维过程是一个好主意,因为此时问题可能出在任何地方。 我正在通过以下步骤进行此远程syscall:
- 解析/ proc /
/ maps文件以获取可执行区域。 - 将数据存储在可执行区域中,并写入一个自定义缓冲区以对其进行系统调用。
- 存储旧寄存器并设置新寄存器以进行系统调用
- 写入新寄存器并继续执行
- 在syscall之后,目标程序将中断,这将使我获得mmap的输出,回退旧的寄存器,从而恢复旧的执行流程。
我正在使用我的内存库来解析mmap文件,获取进程ID和进程信息等。就我而言,它可以正常工作。无论如何,这是来源:https://github.com/rdbo/libmem
还有我用来拨打电话的代码:
mem_voidptr_t allocate_ex(mem_process_t process,mem_size_t size,mem_alloc_t allocation)
{
mem_voidptr_t alloc_addr = (mem_voidptr_t)MEM_BAD_RETURN;
if(!mem_process_is_valid(&process)) return alloc_addr;
int status;
int mmap_syscall = __NR_mmap;
struct user_regs_struct old_regs,regs;
mem_byte_t injection_buf[] =
{
0x0f,0x05,//syscall
0xcc //int3
};
//Parse /proc/<process.pid>/maps to get executable region
char path_buffer[64];
snprintf(path_buffer,sizeof(path_buffer),"/proc/%i/maps",process.pid);
int fd = open(path_buffer,O_RDONLY);
if(fd == -1) return alloc_addr;
int read_check = 0;
mem_size_t file_size = 0;
mem_string_t file_buffer = mem_string_init();
for(char c; (read_check = read(fd,&c,1)) != -1 && read_check != 0; file_size++)
{
mem_string_resize(&file_buffer,file_size);
mem_string_c_set(&file_buffer,file_size,c);
}
mem_size_t injection_address_pos,injection_address_end;
mem_string_t injection_address_str = mem_string_init();
mem_voidptr_t injection_address = (mem_voidptr_t)MEM_BAD_RETURN;
injection_address_pos = mem_string_find(&file_buffer,"r-xp",0);
injection_address_pos = mem_string_rfind(&file_buffer,"\n",injection_address_pos);
if(injection_address_pos == file_buffer.npos) return alloc_addr;
injection_address_end = mem_string_find(&file_buffer,"-",injection_address_pos);
injection_address_str = mem_string_substr(&file_buffer,injection_address_pos,injection_address_end);
injection_address = (mem_voidptr_t)strtoull(mem_string_c_str(&injection_address_str),NULL,16);
if(injection_address == (mem_voidptr_t)MEM_BAD_RETURN || injection_address == (mem_voidptr_t)0)
return alloc_addr;
printf("Injection address: %p\n",injection_address);
//Store the old data at 'injection_address' and write the injection buffer to it
mem_byte_t old_data[sizeof(injection_buf)];
mem_ex_read(process,injection_address,(mem_voidptr_t)old_data,sizeof(old_data));
mem_ex_write(process,(mem_voidptr_t)injection_buf,sizeof(injection_buf));
//Attach to process and store current registers
ptrace(PTRACE_ATTACH,process.pid,NULL);
ptrace(PTRACE_GETREGS,&old_regs);
memcpy(®s,&old_regs,sizeof(regs));
//Setup syscall registers
regs.rax = mmap_syscall; //syscall number
regs.rdi = 0; //address (arg0)
regs.rsi = size; //length (arg1)
regs.rdx = allocation.protection; //protection (arg2)
regs.r10 = allocation.type; //flags (arg3)
regs.r8 = -1; //fd (arg4)
regs.r9 = 0; //offset (arg5)
regs.rip = (unsigned long long)injection_address; //next instruction to execute
//Call mmap on external process
ptrace(PTRACE_SETREGS,®s);
ptrace(PTRACE_CONT,NULL);
waitpid(process.pid,&status,WSTOPPED);
//Get the registers after syscall to store the return of mmap
ptrace(PTRACE_GETREGS,®s);
alloc_addr = (mem_voidptr_t)regs.rax; //store the return of mmap
//Restore the original buffer at 'injection_address'
mem_ex_write(process,sizeof(old_data));
//Continue the original execution
ptrace(PTRACE_SETREGS,&old_regs);
ptrace(PTRACE_CONT,NULL);
//Return allocation address,if valid
if((mem_uintptr_t)alloc_addr >= (mem_uintptr_t)-2048)
alloc_addr = (mem_voidptr_t)MEM_BAD_RETURN;
return alloc_addr;
}
以及攻击者程序的主要功能:
int main()
{
mem_pid_t pid = mem_ex_get_pid(mem_string_new("target"));
mem_process_t process = mem_ex_get_process(pid);
int buffer = 10;
mem_alloc_t allocation = mem_alloc_init();
allocation.protection = PROT_READ | PROT_WRITE;
allocation.type = MAP_ANON | MAP_PRIVATE;
mem_voidptr_t alloc_addr = allocate_ex(process,sizeof(buffer),allocation);
printf("Allocation Address: %p\n",alloc_addr);
if(alloc_addr == (mem_voidptr_t)MEM_BAD_RETURN)
{
printf("Invalid allocation\n");
return -1;
}
//Check if worked by reading/writing to that buffer
int read_buffer = 0;
mem_ex_write(process,alloc_addr,&buffer,sizeof(buffer));
mem_ex_read(process,&read_buffer,sizeof(read_buffer));
printf("Read buffer: %i\n",read_buffer);
if(read_buffer == buffer)
printf("Success!\n");
return 0;
}
目标程序:
int main()
{
printf("Waiting for injection\n");
while(1);
}
攻击者程序的输出为:
Injection address: 0x55f6e104a000
Allocation Address: (nil)
Read buffer: 0
,并且在目标程序上引发了分段错误。可执行区域有效(我手动检查过),该过程也有效。 另外,我在调试目标程序时遇到了一些麻烦,显然GDB不允许ptrace从攻击者程序中执行其工作。运行Arch Linux。这两个程序都是用clang(x64)编译的。有什么想法吗?
解决方法
原来的问题是我正在使用process_vm_read和process_vm_write读取/写入内存。我通过将读取/写入方法更改为ptrace PEEK / POKE数据来使其工作。固定代码(包含在我的内存库中):
mem_voidptr_t injection_address;
struct user_regs_struct old_regs,regs;
int status;
const mem_byte_t injection_buffer[] =
{
0x0f,0x05,//syscall
0xcc //int3 (SIGTRAP)
};
mem_byte_t old_data[sizeof(injection_buffer)];
//Find injection address
char path_buffer[64];
snprintf(path_buffer,sizeof(path_buffer),"/proc/%i/maps",process.pid);
int fd = open(path_buffer,O_RDONLY);
if(fd == -1) return alloc_addr;
int read_check = 0;
mem_size_t file_size = 0;
mem_string_t file_buffer = mem_string_init();
for(char c; (read_check = read(fd,&c,1)) != -1 && read_check != 0; file_size++)
{
mem_string_resize(&file_buffer,file_size);
mem_string_c_set(&file_buffer,file_size,c);
}
mem_size_t injection_address_pos,injection_address_end;
mem_string_t injection_address_str = mem_string_init();
injection_address = (mem_voidptr_t)MEM_BAD_RETURN;
injection_address_pos = mem_string_find(&file_buffer,"r-xp",0);
injection_address_pos = mem_string_rfind(&file_buffer,"\n",injection_address_pos);
if(injection_address_pos == file_buffer.npos) return alloc_addr;
injection_address_end = mem_string_find(&file_buffer,"-",injection_address_pos);
injection_address_str = mem_string_substr(&file_buffer,injection_address_pos,injection_address_end);
injection_address = (mem_voidptr_t)strtoull(mem_string_c_str(&injection_address_str),NULL,16);
if(injection_address == (mem_voidptr_t)MEM_BAD_RETURN || injection_address == (mem_voidptr_t)0) return alloc_addr;
//Inject
ptrace(PTRACE_ATTACH,process.pid,NULL);
//Store data at injection_address
for(mem_size_t i = 0; i < sizeof(injection_buffer); i++)
((mem_byte_t*)old_data)[i] = (mem_byte_t)ptrace(PTRACE_PEEKDATA,injection_address + i,NULL);
//Write injection buffer to injection address
for(mem_size_t i = 0; i < sizeof(injection_buffer); i++)
ptrace(PTRACE_POKEDATA,((mem_byte_t*)injection_buffer)[i]);
ptrace(PTRACE_GETREGS,&old_regs);
regs = old_regs;
regs.rax = __NR_mmap; //syscall number
regs.rdi = (mem_uintptr_t)0; //arg0 (void* address)
regs.rsi = (mem_uintptr_t)size; //arg1 (size_t size)
regs.rdx = (mem_uintptr_t)protection; //arg2 (int protection)
regs.r10 = MAP_PRIVATE | MAP_ANON; //arg3 (int flags)
regs.r8 = -1; //arg4 (int fd)
regs.r9 = 0; //arg5 (off_t offset)
regs.rip = (mem_uintptr_t)injection_address; //next instruction
ptrace(PTRACE_SETREGS,®s);
ptrace(PTRACE_CONT,NULL);
waitpid(process.pid,&status,WSTOPPED);
ptrace(PTRACE_GETREGS,®s);
alloc_addr = (mem_voidptr_t)regs.rax;
//Restore old execution
ptrace(PTRACE_SETREGS,&old_regs);
for(mem_size_t i = 0; i < sizeof(injection_buffer); i++)
ptrace(PTRACE_POKEDATA,((mem_byte_t*)old_data)[i]);
//ptrace(PTRACE_CONT,NULL);
ptrace(PTRACE_DETACH,NULL);
if(alloc_addr == (mem_voidptr_t)__NR_mmap)
alloc_addr = (mem_voidptr_t)MEM_BAD_RETURN;
return alloc_addr;