tsune Help

Libc-got-overwrite

楽してshellを取りたい.

glibc-2.35でgot-overwriteをしてrdi,rsiが制御できそうな関数をまとめる.

また,後日one-gadgetが刺さりそうな関数についてもまとめたい.

strtok

char buf[] = "/bin/sh"; strtok(buf, "/");

rdiがwritableでなければならない.

[*] testcase 9: strspn [+] Overwrite [0x7db47321a058] 0x7db473198800 -> 0x56452dc3e31e [*] callBack Executed. RDI: 0x7fffa38e6b96 HEX: 3168732f6e69622f STR: "/bin/sh1" RSI: 0x56452dc3f0bb HEX: 4f475b5b5b5b002f STR: "/" [*] testcase 31: strcspn [+] Overwrite [0x7db47321a108] 0x7db4731985a0 -> 0x56452dc3e31e [*] callBack Executed. RDI: 0x7fffa38e6ad7 HEX: 3168732f6e6962 STR: "bin/sh1" RSI: 0x56452dc3f0bb HEX: 4f475b5b5b5b002f STR: "/"

.got

register

strspn

rdi, rsi

strcspn

rdi, rsi

puts

puts("/bin/sh");

memmoveは直前のstdoutの内容がrdiに入る. また, printf("/bin/sh") ,及びprintf("%s","/bin/sh");"でも同じ

[*] testcase 6: __mempcpy [+] Overwrite [0x7360e081a040] 0x7360e07a0710 -> 0x5c53777902de [*] callBack Executed. RDI: 0x5c53b2dbf2a0 HEX: 357830203a494452 STR: "RDI: 0x5c53b2dbf2a0 HEX: 357830203a494452 STR: " 0x5c53777902de " RSI: 0x5c53777910bb HEX: 68732f6e69622f STR: "/bin/sh" [*] testcase 17: strlen [+] Overwrite [0x7360e081a098] 0x7360e079d7e0 -> 0x5c53777902de [*] callBack Executed. RDI: 0x5c53777910bb HEX: 68732f6e69622f STR: "/bin/sh"

.got

register

memmove

rsi (rdi)

strlen

rdi

getenv

getenv("/bin/sh");

rdiに素直に入る.

[*] testcase 17: strlen [+] Overwrite [0x71762261a098] 0x71762259d7e0 -> 0x63a855bb631e [*] callBack Executed. RDI: 0x63a855bb70bb HEX: 68732f6e69622f STR: "/bin/sh"

.got

register

strlen

rdi

calloc

calloc(0x50, 1);

0x50以上をアロケートするとmemmoveが呼ばれる. rdiにはbinsのnextが入るのでrdiを完全に操作するにはnextフィールドに対してUAFが必要.

ログではsafe-linkingされたnextの値が入った.

[*] testcase 47: memset [+] Overwrite [0x7a0ac501a188] 0x7a0ac4fa0f00 -> 0x64ee89cd131e [*] callBack Executed. RDI: 0x64ee8d169a90 HEX: 64ee8d169 STR: "i��N"

Fuzz code

#include <assert.h> #include <setjmp.h> #include <signal.h> #include <stdio.h> #include <string.h> #include <stdlib.h> char got_list[54][25] = { "strnlen ", "__rawmemchr ", "__libc_realloc ", "strncasecmp ", "_dl_exception_create ", "__mempcpy ", "wmemset ", "__libc_calloc ", "strspn ", "memchr ", "memmove ", "wmemchr ", "__stpcpy ", "wmemcmp ", "_dl_find_dso_for_object ", "strncpy ", "strlen ", "__strcasecmp_l ", "strcpy ", "wcschr ", "strchrnul ", "memrchr ", "_dl_deallocate_tls ", "__tls_get_addr ", "wmemset ", "bcmp ", "__strncasecmp_l ", "_dl_fatal_printf ", "strcat ", "wcscpy ", "strcspn ", "__strcasecmp ", "strncmp ", "wmemchr ", "__stpncpy ", "wcscmp ", "_dl_audit_symbind_alt ", "memmove ", "rindex ", "index ", "wcschr ", "memcpy ", "_dl_rtld_di_serinfo ", "_dl_allocate_tls ", "__tunable_get_val ", "wcslen ", "memset ", "wcsnlen ", "strcmp ", "_dl_allocate_tls_init ", "__nptl_change_stack_perm", "strpbrk ", "_dl_audit_preinit ", "strnlen ", }; unsigned long *got_plt_start; unsigned long *got_plt_end; unsigned long globalPtr; int globalIdx; static jmp_buf context; void fuzzer(int arg); void sigsegvHandler(int sig) { puts("[-]SIGSEGV ***INVALID ADDRESS***"); longjmp(context, 1); } void restore(int idx,unsigned long ptr) { got_plt_start[idx] = ptr; } void tryAccess(void *ptr) { if (setjmp(context) == 0) { fflush(stdout); printf("HEX: %lx ",*(unsigned long *)ptr); printf("STR: \"%s\" ",(char *)ptr); puts(""); } else { signal(SIGSEGV, sigsegvHandler); fuzzer(globalIdx+1); } } void callBack(void *rdi, void *rsi, void *rdx, void *rcx) { restore(globalIdx, globalPtr); puts("[*] callBack Executed."); printf("RDI: %p ",rdi); tryAccess(rdi); printf("RSI: %p ",rsi); tryAccess(rsi); printf("RDX: %p ", rdx); tryAccess(rdx); printf("RCX: %p ", rcx); tryAccess(rcx); } unsigned long overWrite(int idx) { unsigned long res = got_plt_start[idx]; printf("[+] Overwrite [0x%lx] 0x%lx -> 0x%lx\n",(unsigned long)&got_plt_start[idx],res,(unsigned long)callBack); got_plt_start[idx] = (unsigned long)callBack; return res; } void fuzzer(int arg) { for (int i= arg;i < 54;i++) { printf("[*] testcase %d: %s\n",i+1,got_list[i]); globalPtr = overWrite(i); globalIdx = i; puts("/bin/sh"); restore(i, globalPtr); } } int main(void) { signal(SIGSEGV, sigsegvHandler); puts("[[[[GOT-FUZZER]]]]"); got_plt_start = (unsigned long *)((0x7ffff7c00000+0x00000000021a018)-0x7ffff7c80e50+puts); got_plt_end = (unsigned long *)((0x7ffff7c00000+0x00000000021a1c0)-0x7ffff7c80e50+puts); fuzzer(0); }

検証した関数

strlen strcpy strcat strcmp strchr strstr strtok atoi printf puts fopen memchr memcmp memcpy memmove memset getenv
Last modified: 14 April 2025