Я застрял с этой проблемой в течение нескольких дней, и до сих пор не удалось ее исправить. По сути, я хочу сделать удаленный системный вызов от программы злоумышленника к цели. Но прежде чем показывать код, я думаю, было бы неплохо представить ход моих мыслей, так как проблема на данном этапе может заключаться в чем угодно. Я делаю этот удаленный системный вызов с помощью следующих шагов:
- Разберите файл /proc/‹process_id›/maps, чтобы получить исполняемый регион.
- Сохраните данные в исполняемой области и напишите собственный буфер, который выполняет системный вызов.
- Сохраните старые регистры и настройте новые, чтобы сделать системный вызов
- Запишите новые регистры и продолжите выполнение
- После системного вызова целевая программа прервется, что позволит мне получить вывод mmap, восстановить старые регистры и, следовательно, восстановить старый поток выполнения.
Я использую свою библиотеку памяти для анализа файлов mmap, получения идентификатора процесса и информации о процессе и т. Д. Насколько я понимаю, он работает правильно. В любом случае, вот источник: 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). Любые идеи?