
Nim을 무기화하는 실험 (https://nim-lang.org/)
Nim을 이용한 임플란트 개발 및 일반적인 공격적 작전에서의 무기화 실험을 진행하고 있습니다.
mingw 툴체인을 설치하고 nim 컴파일러에 단일 플래그를 전달하기만 하면 됩니다.| 파일 | 설명 |
|---|---|
| amsi_patch_2_bin.nim | 다른 방법을 사용하여 현재 프로세스에서 AMSI 패치 (WIP, 도움 요청) |
| excel_4_com_bin.nim | Excel COM 개체와 Excel 4 매크로를 사용하여 셸코드 주입 (WIP) |
이 저장소는 바이너리를 제공하지 않습니다. 직접 컴파일해야 합니다. 이 저장소는 예제 Nim 소스 파일을 Linux 또는 MacOS에서 Windows로 크로스 컴파일하도록 설정되었습니다.
VSCode Devcontainers를 사용하여 자동으로 개발 환경을 설정하세요 (개발 환경 설정 섹션 참조). 완료되면 간단히 make를 실행하세요.
시스템 패키지 관리자를 사용하여 Nim 설치 (Windows의 경우 공식 웹사이트의 설치 프로그램 사용)
brew install nimapt install nimchoco install nim(Nim은 또한 Dockerhub에 Docker 이미지를 제공합니다.)
이제 nim 및 nimble 명령을 사용할 수 있습니다. 전자는 Nim 컴파일러이고 후자는 Nim의 패키지 관리자입니다.
Windows로의 크로스 컴파일에 필요한 Mingw 툴체인 설치 (Windows에서 컴파일하는 경우 필요 없음):
apt-get install mingw-w64brew install mingw-w64마지막으로, 훌륭한 Winim 라이브러리와 함께 zippy 및 nimcrypto를 설치하세요.
nimble install winim zippy nimcrypto그런 다음 이 저장소의 루트로 cd하여 make를 실행하세요.
bin/ 디렉토리에서 바이너리와 DLL을 찾을 수 있습니다.
자세한 내용은 Nim 컴파일러 사용 가이드의 크로스 컴파일 섹션을 참조하세요.
MacOS/*nix에서 Windows로 크로스 컴파일하려면 mingw 툴체인이 필요하며, 일반적으로 brew install mingw-w64 또는 apt install mingw-w64를 실행하면 됩니다.
그런 다음 nim 컴파일러에 -d=mingw 플래그만 전달하면 됩니다.
예: nim c -d=mingw --app=console --cpu=amd64 source.nim
Nim 매뉴얼의 엄청난 FFI 섹션을 참조하세요.
C#의 P/Invoke에 익숙하다면 기본적으로 동일한 개념이지만 약간 더 지저분해 보입니다:
MessageBox 호출 예제```nim
type
HANDLE* = int
HWND* = HANDLE
UINT* = int32
LPCSTR* = cstring
proc MessageBox*(hWnd: HWND, lpText: LPCSTR, lpCaption: LPCSTR, uType: UINT): int32 {.discardable, stdcall, dynlib: "user32", importc: "MessageBoxA".}
MessageBox(0, "Hello, world !", "Nim is Powerful", 0)
복잡한 Windows API 호출이 필요하다면 [Winim 라이브러리](https://github.com/khchen/winim)를 사용하세요. 엄청난 시간을 절약해주며, 가져오는 방식에 따라 실행 파일 크기에 크게 영향을 주지 않습니다(아래 참조).
COM 지원도 있습니다!!!
## `DllMain`이 내보내진 Windows DLL 생성
Nim 포럼에 [이 글](https://forum.nim-lang.org/t/1973)을 올려주신 분께 큰 감사를 드립니다.
Nim 컴파일러는 Windows DLL을 생성하도록 지시할 때 컴파일 시점에 자동으로 `DllMain` 함수를 만들려고 시도하지만, 어떤 이유로 실제로 내보내지는 않습니다. 내보내진 `DllMain`을 가지려면 `--nomain`을 전달하고 적절한 pragma(`stdcall, exportc, dynlib`)를 사용하여 직접 `DllMain` 함수를 정의해야 합니다.
Nim의 가비지 컬렉터를 초기화하려면 `DllMain` 내에서 `NimMain`도 호출해야 합니다. (매우 중요합니다, 그렇지 않으면 컴퓨터가 말 그대로 폭발할 것입니다).
예시:```nim
import winim/lean
proc NimMain() {.cdecl, importc.}
proc DllMain(hinstDLL: HINSTANCE, fdwReason: DWORD, lpvReserved: LPVOID) : BOOL {.stdcall, exportc, dynlib.} =
NimMain()
if fdwReason == DLL_PROCESS_ATTACH:
MessageBox(0, "Hello, world !", "Nim is Powerful", 0)
return true
컴파일하려면:``` nim c -d=mingw --app=lib --nomain --cpu=amd64 mynim.dll
### XLL 생성하기
XLL(Excel DLL, 상상해 보세요)을 auto open 함수와 함께 만들어 페이로드 전달에 사용할 수 있습니다. 다음 코드는 auto open 함수와 링크 라이브러리로 컴파일하는 데 필요한 모든 보일러플레이트 코드를 포함하는 간단한 XLL을 생성합니다. POC는 DLL로 컴파일되며, 그런 다음 확장자를 .xll로 변경하면 더블 클릭 시 Excel에서 열리고 페이로드가 실행됩니다:```nim
#[
Compile:
nim c -d=mingw --app=lib --nomain --cpu=amd64 nim_xll.nim
Will compile as a DLL, you can then just change the extension to .xll
]#
import winim/lean
proc xlAutoOpen() {.stdcall, exportc, dynlib.} =
MessageBox(0, "Hello, world !", "Nim is Powerful", 0)
proc NimMain() {.cdecl, importc.}
proc DllMain(hinstDLL: HINSTANCE, fdwReason: DWORD, lpvReserved: LPVOID) : BOOL {.stdcall, exportc, dynlib.} =
NimMain()
return true
XLL로 할 수 있는 다른 은밀한 작업들이 많이 있습니다. XLL 트레이드크래프트의 더 많은 예시는 여기를 참조하세요.
Nim FAQ 페이지에서 가져왔습니다.
가장 큰 크기 감소를 위해 다음 플래그를 사용하세요: -d:danger -d:strip --opt:size
추가로, 컴파일러에 --passc=-flto --passl=-flto를 전달하면 몇 바이트를 더 줄일 수 있다는 것을 알게 되었습니다. 또한 이 저장소의 Makefile을 참조하세요.
이 플래그들은 크기를 극적으로 줄입니다: MacOSX에서 크로스 컴파일할 때 셸코드 인젝션 예제가 484.3 KB에서 46.5 KB로 줄어듭니다!
이것을 알아낸 @Shitsecure에게 큰 감사를 드립니다!
기본적으로 Nim은 EXE를 반사적으로 로드하는 대부분의 도구에 필요한 재배치 테이블이 있는 PE를 생성하지 않습니다.
재배치 섹션이 있는 Nim 실행 파일을 생성하려면 링커에 몇 가지 추가 플래그를 전달해야 합니다.
구체적으로:
--passL:-Wl,--dynamicbase
전체 예제 명령어:
nim c --passL:-Wl,--dynamicbase my_awesome_malwarez.nim
```
## Winim 라이브러리 사용 시와 미사용 시 실행 파일 크기 차이
놀랍게도 크기 차이는 매우 미미합니다. 특히 위에서 언급한 크기 최적화를 적용하면 더욱 그렇습니다.
이 목적을 위해 두 예제 `pop_bin.nim`과 `pop_winim_bin.nim`이 만들어졌습니다.
전자는 `MessageBox` WinAPI 호출을 수동으로 정의하고, 후자는 Winim 라이브러리(특히 `winim/lean`으로, 코어 SDK만 포함합니다. 자세한 내용은 [여기](https://github.com/khchen/winim#usage) 참조)를 사용합니다. 결과:```
byt3bl33d3r@ecl1ps3 OffensiveNim % ls -lah bin
-rwxr-xr-x 1 byt3bl33d3r 25K Nov 20 18:32 pop_bin_32.exe
-rwxr-xr-x 1 byt3bl33d3r 32K Nov 20 18:32 pop_bin_64.exe
-rwxr-xr-x 1 byt3bl33d3r 26K Nov 20 18:33 pop_winim_bin_32.exe
-rwxr-xr-x 1 byt3bl33d3r 34K Nov 20 18:32 pop_winim_bin_64.exe
```
Winim 라이브러리 전체를 `import winim/com`으로 가져오면 약 ~20KB 정도만 추가되며, 이는 추상화하는 기능의 양을 고려할 때 그 추가 크기가 100% 가치가 있습니다:```
byt3bl33d3r@ecl1ps3 OffensiveNim % ls -lah bin
-rwxr-xr-x 1 byt3bl33d3r 42K Nov 20 19:20 pop_winim_bin_32.exe
-rwxr-xr-x 1 byt3bl33d3r 53K Nov 20 19:20 pop_winim_bin_64.exe
```
## Opsec 고려사항
Nim은 FFI를 통해 `LoadLibrary`를 사용하여 DLL을 동적으로 해석하기 때문에, 외부에서 가져온 함수들은 실행 파일의 정적 임포트에 나타나지 않습니다 (자세한 내용은 [이 블로그 게시물](https://web.archive.org/web/20210117002945/https://secbytes.net/implant-roulette-part-1:-nimplant/)을 참조):

Nim 소스를 DLL로 컴파일하면, 자체 `DllMain`을 지정하든 안 하든 항상 `NimMain`이 내보내지는 것 같습니다(??). 이는 잠재적으로 시그니처로 사용될 수 있으며, 실제로 개발 스택에서 Nim을 사용하는 곳이 얼마나 되는지 모르겠습니다. 확실히 눈에 띕니다.

## Nim 런타임 없이 Nim 작성하기
Nim은 안티바이러스 솔루션에서 크게 탐지되므로, 이를 우회하는 한 가지 방법은 Nim 런타임 없이 Nim 프로그램을 작성하는 것입니다. [Writing Nim-less Nim](https://www.youtube.com/watch?v=EXX3HmCG3pw)은 Nim 및 C 런타임 없이 Nim 코드를 작성하는 방법을 설명하는 강연이며, 해당 강연의 소스 코드는 [여기](https://github.com/m4ul3r/writing_nimless)에서 확인할 수 있습니다. 이 강연은 [zimawhit3](https://github.com/zimawhit3)의 [Bitmancer](https://github.com/zimawhit3/Bitmancer/tree/main) 작업을 기반으로 확장합니다.
기본 개념은 `winim`의 타입 정의에 의존하고 Nim 런타임이 사용되지 않는 코드 작성을 활용하는 것입니다.
## C 코드를 Nim으로 변환
https://github.com/nim-lang/c2nim
작은 C 스니펫 몇 개를 번역하는 데 사용했으며, 큰 프로젝트는 시도하지 않았습니다.
## 언어 브리지
- Python 통합: https://github.com/yglukhov/nimpy
* 이것은 정말 흥미롭습니다. [특히 이 부분](https://github.com/yglukhov/nimpy/blob/master/nimpy/py_lib.nim#L330)이 그렇습니다. 약간 수정하면 메모리에서 PythonxXX.dll을 로드할 수 있을까요?
- Java VM 통합: https://github.com/yglukhov/jnim
## 디버깅
`repr()` 함수를 `echo`와 함께 사용하면 거의 모든(??) 데이터 타입(심지어 구조체도!)을 지원합니다!
자세한 내용은 [이 블로그 게시물](https://nim-lang.org/blog/2017/10/02/documenting-profiling-and-debugging-nim-code.html)을 참조하세요.
## 개발 환경 설정
이 저장소는 [VSCode Devcontainers](https://code.visualstudio.com/docs/remote/create-dev-container)를 지원하여 Docker 컨테이너 내에서 개발할 수 있도록 합니다. 이는 개발 환경 설정을 자동화합니다.
1. VSCode와 Docker Desktop을 설치하세요.
2. 이 저장소를 클론하고 VSCode에서 여세요.
3. `Visual Studio Code Remote - Containers` 확장을 설치하세요.
4. 명령 팔레트를 열고 `Remote-Containers: Reopen in Container` 명령을 선택하세요.
VSCode는 Docker 이미지를 빌드하고(시간이 좀 걸립니다) 미리 구축된 Nim 개발 환경으로 바로 이동시켜 줍니다!
## 제가 빠진 함정들
- Winim으로 winapi를 호출할 때 null 값을 전달하려면, Nim의 내장 `nil` 값 대신 Winim 라이브러리에 정의된 `NULL` 값을 사용해야 합니다. (으악)
- Windows에서 `open()`을 호출한 후 생성된 파일의 OS 핸들을 얻으려면 `f.getFileHandle()`이 아닌 `f.getOsFileHandle()`을 호출해야 합니다. 이유가 있어서 그렇습니다.
- Nim 컴파일러는 사용법을 보면 `-a:value` 또는 `--arg:value` 형식으로만 인수를 전달하는 것처럼 보이지만, 실제로는 `-a=value` 또는 `--arg=value` 형식도 허용합니다. (Makefile에 중요)
- 바이트 배열을 정의할 때는 최소한 첫 번째 값에 바이트 배열임을 명시해야 합니다. 약간 이상하지만 괜찮습니다 (https://forum.nim-lang.org/t/4322)
C#에서의 바이트 배열:```csharp
byte[] buf = new byte[5] {0xfc,0x48,0x81,0xe4,0xf0,0xff}
```
Nim에서의 바이트 배열:```nim
var buf: array[5, byte] = [byte 0xfc,0x48,0x81,0xe4,0xf0,0xff]
```
## 흥미로운 Nim 라이브러리
- https://github.com/dom96/jester
- https://github.com/pragmagic/karax
- https://github.com/Niminem/Neel
- https://github.com/status-im/nim-libp2p
- https://github.com/PMunch/libkeepass
- https://github.com/def-/nim-syscall
- https://github.com/tulayang/asyncdocker
- https://github.com/treeform/ws
- https://github.com/guzba/zippy
- https://github.com/rockcavera/nim-iputils
- https://github.com/FedericoCeratto/nim-socks5
- https://github.com/CORDEA/backoff
- https://github.com/treeform/steganography
- https://github.com/miere43/nim-registry
- https://github.com/status-im/nim-daemon
## 임플란트 개발을 위한 Nim 링크
- https://web.archive.org/web/20210117002945/https://secbytes.net/implant-roulette-part-1:-nimplant/
- https://securelist.com/zebrocys-multilanguage-malware-salad/90680/
- https://github.com/MythicAgents/Nimplant
- https://github.com/elddy/Nim-SMBExec
- https://github.com/elddy/NimScan
## 기여자
기여해주신 모든 분들께 가상의 포옹을 ❤️
<a href="https://github.com/byt3bl33d3r/OffensiveNim/graphs/contributors">
<img src="https://contrib.rocks/image?repo=byt3bl33d3r/OffensiveNim" />
</a>
| 파일 | 설명 |
|---|
| pop_bin.nim | Winim 라이브러리를 사용하지 않고 MessageBox WinApi 호출 |
| pop_winim_bin.nim | Winim 라이브러리를 사용하여 MessageBox 호출 |
| pop_winim_lib.nim | 내보낸 DllMain을 가진 Windows DLL 생성 예제 |
| execute_assembly_bin.nim | CLR을 호스팅하고 메모리에서 .NET 어셈블리를 반사적으로 실행 |
| clr_host_cpp_embed_bin.nim | C++ 코드를 직접 임베딩하여 CLR 호스팅, 디스크에서 .NET 어셈블리 실행 |
| scshell_c_embed_bin.nim | Nim 내에 SCShell (C)을 직접 임베딩하여 기존 C 코드를 빠르게 무기화하는 방법을 보여줌 |
| fltmc_bin.nim | 모든 미니필터 드라이버 열거 |
| blockdlls_acg_ppid_spoof_bin.nim | PPID를 explorer.exe로 스푸핑하는 일시 중단된 프로세스를 생성하며, BlockDLLs 및 ACG를 활성화함 |
| named_pipe_client_bin.nim | 명명된 파이프 클라이언트 |
| named_pipe_server_bin.nim | 명명된 파이프 서버 |
| embed_rsrc_bin.nim | 컴파일 시 리소스(zip 파일)를 임베딩하고 런타임에 내용을 추출 |
| self_delete_bin.nim | 잠겨 있거나 현재 실행 중인 실행 파일을 디스크에서 삭제하는 방법. @jonasLyk가 발견한 방법 |
| encrypt_decrypt_bin.nim | Nimcrypto 라이브러리를 사용한 AES256(CTR 모드) 암호화/복호화 |
| amsi_patch_bin.nim | 현재 프로세스에서 AMSI 패치 |
| amsi_providerpatch_bin.nim | AMSI를 우회하기 위해 AMSI Provider DLL(이 경우 MpOav.dll)을 패치. 여기에 발표됨 |
| etw_patch_bin.nim | 현재 프로세스에서 ETW 패치 (기여자: ) |
| wmiquery_bin.nim | WMI를 사용하여 실행 중인 프로세스 및 설치된 AV 조회 |
| out_compressed_dll_bin.nim | 메모리에서 관리되는 DLL을 로드하기 위해 PowerShell 코드를 압축, Base-64 인코딩 및 출력합니다. 원래 PowerSploit 스크립트를 Nim으로 포팅한 것입니다. |
| dynamic_shellcode_local_inject_bin.nim | 배열에 하드코딩하는 대신 동적으로 복구된 셸코드를 로컬에 주입하는 POC. |
| shellcode_callback_bin.nim | 콜백 함수를 사용하여 셸코드 실행 |
| shellcode_bin.nim | 일시 중단된 프로세스를 생성하고 VirtualAllocEx/CreateRemoteThread로 셸코드를 주입합니다. 또한 컴파일 타임 정의를 사용하여 아키텍처, OS 등을 감지하는 방법을 보여줍니다. |
| shellcode_fiber.nim | 파이버를 통한 셸코드 실행 |
| shellcode_inline_asm_bin.nim | 인라인 어셈블리를 사용하여 셸코드 실행 |
| ssdt_dump.nim | 예외 디렉터리의 런타임 함수 테이블을 사용한 간단한 SSDT 검색. MDSEC 기사에서 영감을 받은 기술 |
| syscalls_bin.nim | 직접 시스템 호출을 만드는 방법을 보여줌 |
| execute_powershell_bin.nim | CLR 호스팅 및 비관리형 runspace를 통해 PowerShell 실행 |
| passfilter_lib.nim | 암호 복잡성 필터를 (남용)하여 암호 변경 사항을 파일에 기록 |
| minidump_bin.nim | MiniDumpWriteDump를 사용하여 lsass의 메모리 덤프 생성 |
| http_request_bin.nim | HTTP 요청을 만드는 몇 가지 방법을 보여줌 |
| execute_sct_bin.nim | GetObject()를 통한 .sct 파일 실행 |
| scriptcontrol_bin.nim | MSScriptControl COM 개체를 사용하여 VBScript 및 JScript 동적 실행 |
| excel_com_bin.nim | Excel COM 개체와 매크로를 사용하여 셸코드 주입 |
| keylogger_bin.nim | SetWindowsHookEx를 사용하는 키로거 |
| memfd_python_interpreter_bin.nim | memfd_create 시스템 호출을 사용하여 바이너리를 익명 파일에 로드하고 execve 시스템 호출로 실행. |
| uuid_exec_bin.nim | UUID 배열의 셸코드를 힙 공간에 심고 EnumSystemLocalesA 콜백을 사용하여 셸코드를 실행. |
| unhookc.nim | EDR/AV 후크를 회피하기 위해 ntdll.dll 언후킹 (ired.team의 C 코드 템플릿 임베딩) |
| unhook.nim | EDR/AV 후크를 회피하기 위해 ntdll.dll 언후킹 (순수 Nim 구현) |
| taskbar_ewmi_bin.nim | 셸코드를 실행하기 위해 작업 표시줄의 실행 중인 응용 프로그램 속성을 통한 추가 창 메모리 주입 사용. |
| fork_dump_bin.nim | Windows의 fork() 구현을 (남용)하고 PROCESS_CREATE_PROCESS 액세스 권한을 사용하여 원격 프로세스에 대한 핸들을 획득합니다. 그런 다음 MiniDumpWriteDump()를 사용하여 포크된 프로세스의 메모리를 덤프하려고 시도합니다. |
| ldap_query_bin.nim | ADO의 ADSI 공급자를 사용하여 COM을 통해 LDAP 쿼리 수행 |
| sandbox_process_bin.nim | 프로세스의 무결성 수준을 Untrusted로 설정하고 중요한 토큰을 제거하여 샌드박싱합니다. 이는 PPL 프로세스(예: AV/EDR)를 "조용히 비활성화"하는 데 사용될 수 있습니다. |
| list_remote_shares.nim | NetShareEnum을 사용하여 현재 사용자가 액세스할 수 있는 공유 목록 표시 |
| chrome_dump_bin.nim | Chrome의 sqlite 데이터베이스에서 쿠키 읽기 및 복호화 |
| suspended_thread_injection.nim | 일시 중단된 스레드 주입을 통한 셸코드 실행 |
| dns_exfiltrate.nim | TXT 레코드 쿼리를 통한 간단한 DNS 유출 |
| rsrc_section_shellcode.nim | 바이너리의 .rsrc 섹션에 임베드된 셸코드 실행 |
| token_steal_cmd.nim | 토큰 도용/가장 후 명령 실행 |
| anti_analysis_isdebuggerpresent.nim | 디버거 확인을 통한 간단한 안티 분석 |
| sandbox_domain_check.nim | 컴퓨터가 도메인에 연결되어 있는지 확인하는 간단한 샌드박스 회피 기술 |
| Hook.nim | MessageBoxA를 위한 공격적 후킹 예제 |
| anti_debug.nim | 두 가지 안티 디버깅 기술 시연 |
| anti_debug_via_tls.nim | TLS를 통한 안티 디버깅 |
| local_pe_execution.nim | 메모리에서 exe 및 dll 파일 실행 |
| stack_string_allocation.nim | 배열을 사용하여 스택에 C 및 와이드 문자열 할당 |
| hardware_breakpoints.nim | 하드웨어 중단점을 사용한 함수 후킹 |