Skip to content
KitploitKITPLOIT
도구익스플로잇블로그
Log in
제출
도구익스플로잇블로그
제출

해킹, 침투 테스트 및 사이버 보안 도구를 당신의 보안 무기고에!

Kitploit은 해킹, 사이버 보안 및 침투 테스트 도구 디렉토리입니다. 최신 프로젝트 업데이트를 발견하여 취약점을 찾고, 시스템을 분석하고, 테스트를 자동화하고, 보안을 강화하세요.

피드문의개인정보© 2026 Kitploit

도구 디렉토리

카테고리

모든 카테고리 보기
Loading categories
ShellcodeFluctuation — RW/NoAccess와 RX 사이에서 셸코드의 메모리 보호를 전환한 다음 그 내용을 암호화/복호화하는 고급 인메모리 회피 기법 | Kitploit
도구/GitHubGitHub/mgeeky/shellcodefluctuation
Payload GenerationShellcodePost-ExploitationRed TeamingShellcode GenerationPayload DevelopmentAdversarial AttackPayload Development #16위Payload Generation #16위Shellcode #14위
1.1k163474년 전Kitploit 검토 완료

인기

모두 보기 →

커뮤니티에서 가장 많이 사용되는 도구를 찾아보세요.

모든 도구 탐색

도구 컬렉션을 둘러보세요

모든 도구 보기 →
공유
Shellcode Generation #16위
GitHubmgeeky/shellcodefluctuation

ShellcodeFluctuation

RW/NoAccess와 RX 사이에서 셸코드의 메모리 보호를 전환한 다음 그 내용을 암호화/복호화하는 고급 인메모리 회피 기법

저장소 보기

Shellcode Fluctuation PoC

셸코드의 내용을 주기적으로 암호화하고 복호화하여 RW(또는 NoAccess)와 RX 메모리 보호 상태 사이를 오가도록 만드는 또 다른 인메모리 회피 기법의 PoC 구현체입니다. 셸코드가 RW 또는 NoAccess 메모리 페이지에 상주하면 Moneta나 pe-sieve 같은 스캐너가 이를 추적하거나 덤프하여 분석할 수 없게 됩니다.

Intro

ThreadStackSpoofer를 릴리스한 후 README의 다음 항목에 대한 질문을 몇 가지 받았습니다.

슬립 전에 Beacon의 메모리 페이지 보호를 (RX/RWX에서) RW로 변경하고 내용을 암호화하세요. (Moneta나 pe-sieve 같은 스캐너를 회피할 수 있습니다)

그 전까지 저는 커뮤니티에서 이미 페이로드를 암호화/복호화하고 메모리 보호를 전환하여 비정상적인 실행 영역을 찾는 메모리 스캐너를 회피하는 방법을 알고 있다고 확신했습니다. 하지만 질문이 그렇지 않다는 것을 증명했기에, 저는 또 다른 회피 전략을 문서화하고 커뮤니티가 활용할 수 있는 샘플 구현을 제공하기 위해 이 무기화되지 않은 PoC를 공개하기로 결정했습니다.

이 PoC는 공격 커뮤니티에 이미 알려진 비교적 단순한 기법을 시연한 것입니다. (그래서 제가 정말 새로운 것을 가져온 것은 아닙니다.) 앞서 언급한 두 메모리 스캐너를 대상으로 회피 능력을 보여주는 일부 상용 프레임워크가 보여주는 마법 뒤에 숨은 비밀을 공개하고자 하는 바람에서입니다.

RW로 전환할 때의 비교는 다음과 같습니다. (또 다른 옵션은 PAGE_NOACCESS로 전환하는 것입니다. 아래에 설명되어 있습니다.)

  1. 암호화되지 않은 Beacon
  2. 암호화된 Beacon (변동)

comparison

이 구현은 제 ThreadStackSpoofer와 함께 상용 C2 제품이 제공하는 기능을 따라잡을 수 있는 샘플 구현을 Offensive Security 커뮤니티에 제공하며, 우리 Red Team 도구에서도 그에 못지않은 성능을 낼 수 있도록 합니다. 💪


어떻게 동작하나요?

이 프로그램은 셸코드 자가 주입을 수행합니다. (대략적인 과정은 고전적인 VirtualAlloc + memcpy + CreateThread 방식입니다.) 셸코드가 실행되면 (이 구현은 특히 Cobalt Strike Beacon 임플란트를 대상으로 합니다) Beacon이 잠들 때 kernel32!Sleep을 가로채는 Windows 함수가 후킹됩니다. 후킹된 MySleep 함수가 호출될 때마다 해당 메모리 할당의 경계를 찾아 보호를 RW로 전환한 다음 모든 바이트를 xor32로 암호화합니다. 예정된 시간만큼 대기한 후, 셸코드가 다시 우리의 MySleep 핸들러로 돌아오면 셸코드 데이터를 복호화하고 보호 상태를 RX로 되돌립니다.

PAGE_READWRITE로의 변동 방식

  1. 파일에서 셸코드 내용을 읽습니다.
  2. kernel32!Sleep을 우리 콜백을 가리키도록 후킹합니다.
  3. VirtualAlloc + memcpy + CreateThread를 통해 셸코드를 주입하고 실행합니다. ThreadStackSpoofer에서와 달리 여기서는 셸코드를 실행하기 위해 ntdll의 어떤 것도 후킹하지 않고 우리 자신의 함수에서 점프합니다. 이는 변조된 ntdll 메모리를 가리키는 단순한 IOC를 메모리에 남기지 않으려는 시도입니다.
  4. Beacon이 슬립을 시도하는 즉시 우리의 MySleep 콜백이 호출됩니다.
  5. Beacon의 메모리 할당이 암호화되고 보호 상태가 RW로 전환됩니다.
  6. 그런 다음 원래 kernel32!Sleep을 언후킹하여 Sleep이 트램폴린(in-line hooked)되었다는 단순한 IOC가 메모리에 남지 않도록 합니다.
  7. 이후 추가 통신을 기다리는 동안 Beacon이 슬립하도록 원래 ::Sleep을 호출합니다.
  8. 슬립이 끝나면 셸코드 데이터를 복호화하고 메모리 보호를 RX로 되돌린 다음 kernel32!Sleep을 다시 후킹하여 이후의 슬립도 가로챌 수 있도록 합니다.

PAGE_NOACCESS로의 변동 방식

  1. 파일에서 셸코드 내용을 읽습니다.
  2. kernel32!Sleep을 우리 콜백을 가리키도록 후킹합니다.
  3. VirtualAlloc + memcpy + CreateThread를 통해 셸코드를 주입하고 실행합니다 ...
  4. Vectored Exception Handler(VEH)를 초기화하여 Access Violation 예외를 잡을 우리만의 핸들러를 설정합니다.
  5. Beacon이 슬립을 시도하는 즉시 우리의 MySleep 콜백이 호출됩니다.
  6. Beacon의 메모리 할당이 암호화되고 보호 상태가 PAGE_NOACCESS로 전환됩니다.
  7. 그런 다음 원래 kernel32!Sleep을 언후킹하여 Sleep이 트램폴린(in-line hooked)되었다는 단순한 IOC가 메모리에 남지 않도록 합니다.
  8. 이후 추가 통신을 기다리는 동안 Beacon이 슬립하도록 원래 ::Sleep을 호출합니다.
  9. 슬립이 끝나면 kernel32!Sleep을 다시 후킹하여 이후의 슬립도 가로챌 수 있도록 합니다.
  10. 셸코드는 실행을 재개하려 시도하며, 페이지가 NoAccess로 표시되어 있으므로 Access Violation이 발생합니다.
  11. 우리의 VEH 핸들러가 예외를 잡아 복호화하고 메모리 보호를 RX로 되돌린 뒤 셸코드 실행이 재개됩니다.

새로운 기법은 아닙니다

이 기법은 완전히 새로운 것도 아니고, 제가 직접 고안한 것도 아닙니다. 단지 이 개념과 실제 활용법을 보여주는 구현일 뿐이며, 우리 Offensive Security 커뮤니티가 상용 C2 프레임워크가 제공하는 기능을 따라잡을 수 있도록 한 것입니다.

사실 저는 몇 년 전 Josh Lospinoso 님이 만든 놀라운 Gargoyle 작업을 통해 셸코드 메모리 보호를 전환하는 아이디어를 접하게 되었습니다.

관련 배경 자료는 다음과 같습니다.

  • gargoyle, a memory scanning evasion technique
  • Bypassing Memory Scanners with Cobalt Strike and Gargoyle

Gargoyle은 VirtualProtect을 호출하는 ROP 시퀀스를 활용하여 자기 인식 및 자기 변동 셸코드라는 개념을 한 단계 더 발전시킵니다. 하지만 이 기법은 인상적이지만, Cobalt Strike의 Beacon과 함께 사용하려면 스레드를 종료하고 메모리에서 Beacon을 계속 다시 초기화해야 하기 때문에 적용하기가 그만큼 어렵습니다.

이 방식은 완벽하지는 않지만, 우리는 이미 자체 주입 로더 프로세스의 기반 위에서 작동하고 있으므로 셸코드가 작동하는 환경으로 원하는 모든 것을 할 수 있고 원하는 대로 숨길 수 있습니다. 이 기법(그리고 이전의 ThreadStackSpoofer)은 이러한 방식으로 셸코드를 실행함으로써 얻을 수 있는 이점을 보여줍니다.

PAGE_NOACCESS로 변동하는 구현은 ORCA666 님이 자신의 https://github.com/ORCA666/0x41 인젝터에서 선보인 작업에서 영감을 받았습니다. 그는 다음을 보여주었습니다.

  1. vectored exception handler(VEH)를 초기화할 수 있고,
  2. 셸코드 페이지를 no-access로 전환한 다음,
  3. 셸코드가 실행을 재개하려는 즉시 발생하는 Access Violation 예외를 잡아 메모리 페이지를 복호화하고 Read+Execute로 되돌릴 수 있습니다.

이 구현에는 해당 아이디어가 포함되어 있으며, <fluctuate>에서 옵션 2로 사용할 수 있습니다. 그의 다른 프로젝트도 꼭 확인해 보시기 바랍니다.


Demo

ShellcodeFluctuation 도구는 세 개의 매개변수를 받습니다. 첫 번째는 셸코드 경로이고 두 번째는 기능 수정자입니다.``` Usage: ShellcodeFluctuation.exe : -1 - Read shellcode but dont inject it. Run in an infinite loop. 0 - Inject the shellcode but don't hook kernel32!Sleep and don't encrypt anything 1 - Inject shellcode and start fluctuating its memory with standard PAGE_READWRITE. 2 - Inject shellcode and start fluctuating its memory with ORCA666's PAGE_NOACCESS.

### Moneta (겉보기에는) 오탐```
C:\> ShellcodeFluctuation.exe beacon64.bin -1

먼저 Moneta64 스캐너가 별다른 의심스러운 동작 없이 그저 무한 루프를 실행하는 프로세스에 대해 어떻게 판단하는지 살펴보겠습니다:

moneta false positive

보시다시피 일부 **오탐(false positive)**이 있습니다(적어도 제가 보기에는 그렇습니다). Mismatching PEB module / Phantom image를 감지한 것으로 보입니다. 메모리 경계는 ShellcodeFluctuate.exe 모듈 자체를 가리키며, 이 모듈이 MEM_IMAGE 유형임에도 불구하고 프로세스의 PEB에 연결되어 있지 않음을 나타낼 수 있습니다. 이는 일반적이지 않으며 상당히 이상하게 들립니다. 이 IOC의 원인은 저도 알지 못하며, 더 잘 이해하려 시도하지도 않았습니다. 하지만 실제로 크게 걱정할 만한 사항은 아닙니다.

이 탐지의 원인을 아시는 분이 있다면 정말 궁금합니다! 꼭 연락 주세요.

암호화되지 않은 비콘```

C:> ShellcodeFluctuation.exe beacon64.bin 0

두 번째 사용 사례는 우리 프로세스 내에서 작동하는 Beacon의 메모리 IOC를 제시합니다. 이는 맞춤형 `Artifact Kits`나 `User-Defined Reflective Loaders`(예: 제 [`ElusiveMice`](https://github.com/mgeeky/ElusiveMice))를 전혀 사용하지 않으며, 결과를 망칠 수 있는 초기 작업도 수행하지 않습니다.

![moneta 암호화되지 않음](https://assets.kitploit.com/production/public/readmes/50718/6a4e3a230a362c25da6f4aa6955b822d2a83215848c1bc09566a27ea9db653c9/dd2e0560a688886c0fe06debe92f153e129daa6654cb17c2976edee8661e3bd3-display-v1.webp)

`Moneta64`가 우리 shellcode가 있는 위치를 가리키는 `Abnormal private executable memory`를 올바르게 인식하는 것을 볼 수 있습니다.
이는 자동화 스캐너가 우리 shellcode를 덤프하고 분석할 수 있도록 노출하는 매우 강력한 메모리 IOC입니다. 좋지 않네요.

### RW 보호 기능이 있는 암호화된 Beacon```
C:\> ShellcodeFluctuation.exe beacon64.bin 1

이제 이 구현의 관점에서 가장 흥미로운 세 번째 사용 사례는 변동하는 Beacon입니다.

moneta encrypted

다소 오탐 으로 간주되는 첫 번째 IOC를 제외하면, kernel32.dll 메모리가 수정되었음을 가리키는 새로운 IOC가 보입니다.
하지만 이번에는 Abnormal private executable memory IOC가 없습니다. 우리의 변동(반복적인 암호화/복호화 및 메모리 보호 전환)이 활성화되어 있는 상태입니다.

그리고 참고로, pe-sieve는 /data 3 옵션을 사용하면 주입된 PE도 탐지합니다(이 옵션이 지정되지 않으면 탐지되지 않습니다):

pe-sieve

현재 제 추측은 PE-Sieve가 Moneta와 동일한 특성을 포착하고 있다는 것입니다(아래의 kernel32.dll의 수정된 코드 에서 설명됨) - PE 매핑 모듈의 작업 세트(Working set)가 비어 있지 않다는 사실은 일종의 코드 인젝션이 있었다는 명백한 증거입니다. 그 특성은 Implanted PE / Implanted 로 표시됩니다. 만약 그렇다면, 결론은 Moneta의 관찰과 유사합니다. 탐지 측면에서 그 IOC에 대해 그다지 신경 쓸 필요는 없다고 생각합니다.

현재로서는 셸코드 실행을 중간에 가로챌 더 나은 방법을 생각해내지 못했습니다(Cobalt Strike를 기준으로 말하면), kernel32!Sleep을 후킹하는 것 외에는요. 따라서 우리는 이런 종류의 IOC를 남겨둘 수밖에 없습니다.

도구 다운로드