setuid 바이너리용 LD_PRELOAD

setuid 바이너리용 LD_PRELOAD

setuid/setgid 권한이 필요한 프로그램의 malloc/free 기능을 재정의하려고 합니다. 이를 위해 LD_PRELOAD 변수를 사용합니다. ~에 따르면ld문서, 내 라이브러리를 표준 검색 디렉토리 중 하나(저는 /usr/lib 선택)에 넣고 setuid/setgid 권한을 부여해야 합니다. 나는 이미 이것을 했습니다. 그러나 여전히 .so 파일에 연결할 수 없으며 오류가 발생합니다.

object 'liballoc.so' from LD_PRELOAD cannot be preloaded: ignored

가능한 이유는 무엇입니까? setuid/setgid 권한 없이 프로그램에서 이 .so 파일을 테스트했는데 모든 것이 잘 작동했습니다. 운영 체제: 레드햇 7.0

답변1

ld 문서에 따르면 내 라이브러리를 표준 검색 디렉토리 중 하나에 넣어야 합니다(내 선택 /usr/lib).

그게 실수입니다. 이를 넣어야 합니다 /usr/lib64(머신이 x86_64라고 가정).

방금 Centos 7 VM(RHEL 7과 동일해야 함)의 맨페이지에서 레시피를 시도했는데 작동했습니다.

루트 사용자로서:

cynt# cc -shared -fPIC -xc - <<<'char *setlocale(int c, const char *l){ errx(1, "not today"); }' -o /usr/lib64/liblo.so
cynt# chmod 4755 /usr/lib64/liblo.so

setuid 프로그램을 사용하는 일반 사용자로서:

cynt$ LD_PRELOAD=liblo.so su -
su: not today

이 기능을 사용하는 것이 좋은 생각인지 여부는 완전히 다른 것입니다(IMHO, 그렇지 않습니다).

답변2

man ld.so

안전 실행 모드
보안상의 이유로 동적 링커가 바이너리를 안전 실행 모드에서 실행해야 한다고 결정하면 특정 환경 변수의 영향이 무효화되거나 수정됩니다.
[...]
다음 조건이 충족되면 바이너리가 안전 실행 모드에서 실행됩니다. 모드 구현:

  • 프로세스의 실제 유효 사용자 ID가 다릅니다.

[...]
LD_예압
안전 실행 모드에서는 슬래시가 포함된 사전 로드 경로 이름이 무시됩니다. 또한 공유 개체는 표준 검색 디렉터리에서만 미리 로드되며, 사용자 ID 설정 모드 비트가 활성화된 경우에만(일반적이지 않음).

SUID 바이너리를 실행하면 이런 일이 발생합니다. 실제 UID와 유효 UID가 다릅니다. 그러나 이 바이너리가 다른(SUID가 아닌) 바이너리를 실행하는 경우 부모의 EUID는 자식의 RUID 및 EUID가 됩니다.

sudo sleep 1000 &

ps -o pid,ruid,euid,args --pid $! --ppid $!
  PID  RUID  EUID COMMAND
 7286  1000     0 sudo sleep 1000
 7287     0     0 sleep 1000

따라서 LD_PRELOAD 제한을 피하려면 sudo를 통해 바이너리를 호출하거나 래퍼 SUID 바이너리를 생성하여 실제 바이너리를 호출할 수 있습니다.

답변3

그 이유는 악성코드가 상승하는 것을 방지하기 위함입니다. AC 프로그램은아니요main()에서 실행을 시작합니다. 대신 C 런타임 라이브러리가 먼저 호출되어 환경(STDIO 스트림 포함), 컴파일 타임 상수가 아닌 전역 변수를 설정한 다음 main()을 호출합니다.

악의적인 행위자는 LD_PRELOAD=를 사용하여 libc.o 라이브러리를 사용자 정의 라이브러리로 덮어쓰고 시작 기능(예: LD_PRELOAD를 복원한 다음 /bin/sh를 호출)을 수정할 수 있습니다. SUID 프로세스가 LD_PRELOAD=를 무시하지 않으면 사용자는 /bin/passwd를 실행할 수 있으며 이제 루트 쉘을 갖게 됩니다. 이제 루트킷 등을 설치할 수 있습니다.

관련 정보