【发布时间】:2025-02-26 19:10:02
【问题描述】:
我已经被这个问题困扰了几天,但仍然没有设法解决它。基本上,我想从攻击者程序到目标进行远程系统调用。但在展示代码之前,我认为展示我的思考过程是个好主意,因为此时问题可能是任何问题。 我正在通过以下步骤执行此远程系统调用:
- 解析 /proc/
/maps 文件以获取可执行区域。 - 将数据存储在可执行区域并编写一个自定义缓冲区,对其进行系统调用。
- 存储旧寄存器并设置新寄存器以进行系统调用
- 写入新寄存器并继续执行
- 在系统调用之后,目标程序将中断,这将允许我获取 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, injection_address, (mem_voidptr_t)injection_buf, sizeof(injection_buf));
//Attach to process and store current registers
ptrace(PTRACE_ATTACH, process.pid, NULL, NULL);
ptrace(PTRACE_GETREGS, process.pid, NULL, &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, process.pid, NULL, ®s);
ptrace(PTRACE_CONT, process.pid, NULL, NULL);
waitpid(process.pid, &status, WSTOPPED);
//Get the registers after syscall to store the return of mmap
ptrace(PTRACE_GETREGS, process.pid, NULL, ®s);
alloc_addr = (mem_voidptr_t)regs.rax; //store the return of mmap
//Restore the original buffer at 'injection_address'
mem_ex_write(process, injection_address, (mem_voidptr_t)old_data, sizeof(old_data));
//Continue the original execution
ptrace(PTRACE_SETREGS, process.pid, NULL, &old_regs);
ptrace(PTRACE_CONT, process.pid, NULL, 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, alloc_addr, &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) 编译的。有什么想法吗?
【问题讨论】:
标签: c linux memory system-calls ptrace