
쉘코드, PE 및 COFF 파일을 난독화된 위치 독립적 페이로드로 변환하는 다형성 암호기로, RC4 및 무작위 블록 암호 암호화와 AsmJit 라이브러리를 사용한 쓰레기 명령어 생성을 포함합니다.
발표된 곳
Shoggoth는 C++와 asmjit 라이브러리를 기반으로 한 오픈소스 프로젝트로, 주어진 셸코드, PE 및 COFF 파일을 다형적으로 암호화하는 데 사용됩니다.
Shoggoth는 페이로드와 해당 로더를 난독화된 형태로 저장하는 출력 파일을 생성합니다. 출력 내용은 위치 독립적이므로 셸코드로 직접 실행할 수 있습니다. 페이로드가 실행되는 동안 런타임에 자체 복호화됩니다. 암호화 루틴 외에도 Shoggoth는 루틴 사이에 아무것도 변경하지 않는 가비지 명령어를 추가합니다.
저는 다양한 동적 명령어 생성 접근 방식, 어셈블리 관행 및 시그니처 탐지를 연구하기 위해 이 프로젝트를 개발하기 시작했습니다. 새로운 학습 내용을 바탕으로 정기적으로 저장소를 업데이트할 계획입니다.
현재 기능은 아래와 같습니다.
입력 파일에 대한 Shoggoth의 일반적인 실행 흐름은 아래 이미지에서 확인할 수 있습니다. 기본 설정으로 이 흐름을 관찰할 수 있습니다.
기본적으로 Shoggoth는 선택한 모드(COFF 또는 PE 파일)에 따라 사전 컴파일된 로더 셸코드와 입력 파일을 먼저 병합합니다. 그런 다음 생성된 여러 가비지 명령어를 이 병합된 페이로드에 추가합니다. 로더, 가비지 명령어 및 페이로드를 포함하는 스텁은 먼저 RC4 암호화로 암호화된 후, 해당 복호화기를 결합하여 무작위로 생성된 블록 암호로 암호화됩니다. 마지막으로 결과 블록에 가비지 명령어를 추가합니다.
Shoggoth는 가비지 스텁이나 암호화 루틴을 위해 명령어를 무작위로 생성할 때 AsmJit 라이브러리를 사용합니다.
AsmJit는 C++ 언어로 작성된 머신 코드 생성을 위한 경량 라이브러리입니다. X86, X86_64 및 AArch64 아키텍처용 머신 코드를 생성할 수 있으며 기본 명령어와 모든 최신 확장을 지원합니다. AsmJit를 사용하면 연산 코드, 레지스터, 즉시 피연산자, 호출 레이블을 지정하고 코드 내 임의의 오프셋에 임의의 값을 포함시킬 수 있습니다. AsmJit를 사용하여 일부 어셈블리 명령어를 생성할 때는 어셈블러 클래스에서 필요한 어셈블리 연산에 해당하는 API 함수를 어셈블리 피연산자 값과 함께 호출하기만 하면 됩니다. 각 API 호출에 대해 AsmJit는 내부 CodeHolder 구조에 코드 및 재배치 정보를 저장합니다. 생성할 모든 어셈블리 명령어의 API 함수를 호출한 후, JitRuntime 클래스를 사용하여 CodeHolder에서 실행 권한이 있는 메모리로 코드를 복사하고 재배치할 수 있습니다.
코드 생성 라이브러리를 찾던 중 AsmJit를 접하게 되었고, 많은 인기 프로젝트에서 널리 사용된다는 것을 알게 되었습니다. 그래서 제 요구에 맞게 사용하기로 결정했습니다. Shoggoth가 레드 팀 컨텍스트에서 이를 사용하는 첫 번째 프로젝트인지는 모르겠지만, 향후 구현에 참고가 될 수 있을 것이라고 믿습니다.
Shoggoth는 주어진 PE 및 COFF 파일을 암호화하는 데 사용될 수 있어, 사전 컴파일된 위치 독립적 로더 덕분에 둘 다 셸코드로 실행될 수 있습니다. 저는 단순히 C to Shellcode 방법을 사용하여 이전 프로젝트를 위해 수정한 잘 알려진 PE 및 COFF 로더의 PIC 버전을 얻었습니다. 컴파일을 위해 PIC 형태의 LSASS 덤퍼인 HandleKatz 프로젝트의 Makefile을 사용했습니다.
기본적으로 C to Shellcode 기술로 셸코드를 얻기 위해 로더 소스 코드에서 모든 전역 변수를 제거하고 모든 문자열을 스택에 저장했으며, 런타임에 필요한 DLL을 로드하고 파싱하여 Windows API 함수 주소를 확인했습니다. 그 후 링커 스크립트로 진입점을 결정하고 MinGW를 사용하여 다양한 컴파일 플래그로 코드를 컴파일했습니다. 생성된 실행 파일의 .text 섹션을 추출하여 로더 셸코드를 얻었습니다. 위와 같이 코드를 편집한 후 얻은 실행 파일에는 .text 섹션 외에 다른 섹션이 없으므로 이 섹션의 코드를 위치 독립적으로 사용할 수 있습니다.
이들의 소스 코드는 COFFLoader 및 PELoader 디렉토리에서 확인하고 편집할 수 있습니다. 또한 이러한 소스 코드의 컴파일된 버전은 stub 디렉토리에서 찾을 수 있습니다. 현재로서는 이러한 로더를 편집하거나 변경하려면 시그니처를 준수하고 stub 디렉토리에서 사전 컴파일된 바이너리를 교체해야 합니다.
BOF에 인수를 전달하려면 '--coff-arg' 옵션을 사용하십시오. Shoggoth는 TrustedSec의 beacon_generate.py 스크립트를 사용하여 생성할 수 있는 패킹된 인수를 포함하는 미리 형식화된 16진수 문자열을 기대합니다. 이 스크립트의 복사본이 COFFArgGenerator/beacon_generate.py로 포함되어 있습니다. (@Octoberfest7님께 감사드립니다)
Shoggoth는 먼저 스트림 암호 중 하나인 RC4 알고리즘을 사용하여 얻은 페이로드를 암호화합니다. 여기서 사용되는 키를 무작위로 생성한 후, 해당 키로 페이로드를 암호화합니다. 런타임에 페이로드를 복호화하는 복호화기 스텁은 AsmJit를 사용하여 동적으로 생성되고 어셈블됩니다. 스텁에 사용되는 레지스터는 각 샘플마다 무작위로 선택됩니다.
Shoggoth에 사용된 RC4 알고리즘 구현을 위해 Nayuki의 코드를 참조했습니다.
첫 번째 암호화가 수행된 후, Shoggoth는 두 번째 암호화인 무작위로 생성된 블록 암호를 사용합니다. 두 번째 암호화를 통해 RC4 복호화기와 선택적으로 페이로드, 가비지 명령어 및 RC4로 암호화된 로더를 포함하는 스텁을 암호화합니다. 암호화할 청크를 8바이트 블록으로 나누고 각 블록에 대해 무작위로 생성된 명령어를 사용합니다. 이러한 명령어에는 ADD, SUB, XOR, NOT, NEG, INC, DEC, ROL 및 ROR이 포함됩니다. 이러한 명령어의 피연산자도 무작위로 선택됩니다.
생성된 가비지 명령어 로직은 Ege Balci의 놀라운 SGN 프로젝트에서 크게 영감을 받았습니다. Shoggoth는 무작위 바이트를 점프하는 명령어, 부작용이 없는 명령어, 가짜 함수 호출, 부작용이 있지만 초기 값을 유지하는 명령어를 기반으로 가비지 명령어를 선택할 수 있습니다. 이러한 모든 명령어는 무작위로 선택되며, AsmJit 라이브러리의 해당 API 함수를 호출하여 생성됩니다. 또한 크기와 다양한 조합을 늘리기 위해 이러한 생성 함수는 재귀적으로 호출됩니다.
Shoggoth의 첫 번째 버전에는 가비지 명령어를 넣을 수 있는 많은 위치가 있습니다. 예를 들어 블록 암호 명령어 사이 또는 RC4 암호 명령어 사이에 가비지 명령어를 넣을 수 있습니다. 그러나 데모 목적으로 생성된 페이로드의 추가 복잡성을 피하기 위해 다음 버전으로 남겨두었습니다.
주 프로젝트를 컴파일하지 않았습니다. 따라서 직접 컴파일해야 합니다. 선택적으로 PE 로더 또는 COFF 로더의 소스 코드를 편집하려면 제공된 Makefile을 사용하여 컴파일할 수 있도록 컴퓨터에 MinGW가 있어야 합니다.
______ _ _
/ _____) | _ | |
( (____ | |__ ___ ____ ____ ___ _| |_| |__
\____ \| _ \ / _ \ / _ |/ _ |/ _ (_ _) _ \
_____) ) | | | |_| ( (_| ( (_| | |_| || |_| | | |
(______/|_| |_|\___/ \___ |\___ |\___/ \__)_| |_|
(_____(_____|
by @R0h1rr1m
"Tekeli-li! Tekeli-li!"
Usage of Shoggoth.exe:
-h | --help Show the help message.
-v | --verbose Enable more verbose output.
-i | --input <Input Path> Input path of payload to be encrypted. (Mandatory)
-o | --output <Output Path> Output path for encrypted input. (Mandatory)
-s | --seed <Value> Set seed value for randomization.
-m | --mode <Mode Value> Set payload encryption mode. Available mods are: (Mandatory)
[*] raw - Shoggoth doesn't append a loader stub. (Default mode)
[*] pe - Shoggoth appends a PE loader stub. The input should be valid x64 PE.
[*] coff - Shoggoth appends a COFF loader stub. The input should be valid x64 COFF.
--coff-arg <Argument> Set argument for COFF loader. Generate this string using COFFArgGenerator/beacon_generate.py.
example: --coff-arg 0a0000000600000068656c6c6f00
Only used in COFF loader mode. (Thanks to @Octoberfest7)
-k | --key <Encryption Key> Set first encryption key instead of random key.
--dont-do-first-encryption Don't do the first (stream cipher) encryption.
--dont-do-second-encryption Don't do the second (block cipher) encryption.
--encrypt-only-decryptor Encrypt only decryptor stub in the second encryption.
"그것은 어떤 지하철보다도 거대한, 형용할 수 없는 끔찍한 것이었다—형체 없는 원형질 거품의 덩어리, 희미하게 자체 발광하며, 우리를 향해 내려오는 터널을 가득 채운 전방 전체에 녹색 빛의 농포처럼 수많은 임시 눈이 형성되고 사라지고, 미친 펭귄들을 짓누르고 온갖 쓰레기를 악랄하게 쓸어버린 반짝이는 바닥 위를 미끄러져 내려오고 있었다." ~ H. P. 러브크래프트, 《광기의 산맥에서》
쇼고스(Shoggoth)는 크툴루 신화에 등장하는 가상의 괴물입니다. 이 존재들은 H. P. 러브크래프트의 소네트 연작 《유고스에서 온 균류》(1929–30)에서 잠깐 언급되었고, 이후 그의 소설 《광기의 산맥에서》(1931)에서 자세히 설명되었습니다. 이들은 당면한 작업에 필요한 어떤 기관이나 부속물이든 형성할 수 있지만, 평소 상태는 눈, 입, 꿈틀거리는 촉수로 뒤덮인 꿈틀거리는 덩어리입니다.
이 생물들이 스스로 형태를 바꾸는 젤라틴 같은 살덩어리이며 러브크래프트의 묘사에서 고정된 형태가 없기 때문에, 저는 다형성 암호화 도구에 이 이름을 붙이고 싶었습니다. 🙂
승인된 보안 테스트에만 사용하십시오. 명시적 허가 없이 시스템에 이 도구를 오용하는 것은 불법입니다.