.. | ||
ret2win | ||
stack-shellcode | ||
pointer-redirecting.md | ||
README.md | ||
ret2win.md | ||
stack-pivoting-ebp2ret-ebp-chaining.md | ||
stack-shellcode.md | ||
uninitialized-variables.md |
스택 오버플로우
htARTE (HackTricks AWS Red Team Expert)를 통해 **제로부터 영웅까지 AWS 해킹 배우기**!
HackTricks를 지원하는 다른 방법:
- 회사를 HackTricks에서 광고하거나 HackTricks를 PDF로 다운로드하고 싶다면 구독 요금제를 확인하세요!
- 공식 PEASS & HackTricks 스왜그를 구매하세요
- The PEASS Family를 발견하세요, 당사의 독점 NFTs 컬렉션
- 💬 Discord 그룹 또는 텔레그램 그룹에 가입하거나 트위터 🐦 @hacktricks_live를 팔로우하세요.
- 해킹 트릭을 공유하려면 HackTricks 및 HackTricks Cloud github 저장소에 PR을 제출하세요.
스택 오버플로우란
스택 오버플로우는 프로그램이 할당된 스택에 저장할 수 있는 데이터보다 더 많은 데이터를 쓸 때 발생하는 취약점입니다. 이러한 초과 데이터는 인접한 메모리 공간을 덮어쓰게 하여 유효한 데이터의 손상, 제어 흐름의 중단 및 악의적 코드의 실행으로 이어질 수 있습니다. 이 문제는 주로 입력에 대한 경계 확인을 수행하지 않는 안전하지 않은 함수의 사용으로 인해 발생합니다.
이 덮어쓰기의 주요 문제는 저장된 명령 포인터 (EIP/RIP) 및 **저장된 베이스 포인터 (EBP/RBP)**가 스택에 저장되어 이전 함수로 돌아가기 위해 사용된다는 점입니다. 따라서 공격자는 이를 덮어쓰고 프로그램의 실행 흐름을 제어할 수 있습니다.
이 취약점은 일반적으로 함수가 할당된 양보다 더 많은 바이트를 스택에 복사하기 때문에 발생합니다. 따라서 스택의 다른 부분을 덮어쓸 수 있습니다.
이에 취약한 일부 일반 함수는 strcpy
, strcat
, sprintf
, gets
등입니다. 또한 **길이 인수를 사용하는 fgets
, read
및 memcpy
**와 같은 함수는 지정된 길이가 할당된 양보다 큰 경우 취약하게 사용될 수 있습니다.
예를 들어, 다음 함수들이 취약할 수 있습니다:
void vulnerable() {
char buffer[128];
printf("Enter some text: ");
gets(buffer); // This is where the vulnerability lies
printf("You entered: %s\n", buffer);
}
스택 오버플로우 오프셋 찾기
스택 오버플로우를 찾는 가장 일반적인 방법은 매우 큰 A
입력을 제공하고 (python3 -c 'print("A"*1000)'
) 주소 0x41414141
에 액세스를 시도했다는 Segmentation Fault
가 발생하는지 확인하는 것입니다.
또한, 스택 오버플로우 취약점을 발견한 후에는 리턴 주소를 덮어쓸 수 있는 오프셋을 찾아야 합니다. 이를 위해 보통 De Bruijn sequence가 사용됩니다. 이는 크기가 _k_인 알파벳과 길이가 _n_인 부분 수열에 대해 모든 가능한 길이 _n**의 부분 수열이 한 번씩** 연속적인 부분 수열로 나타나는 순환 수열입니다.
이렇게 하면 EIP를 제어하기 위해 필요한 오프셋을 수동으로 찾아야 하는 대신, 이러한 시퀀스 중 하나를 패딩으로 사용하고 그것을 덮어쓴 바이트의 오프셋을 찾을 수 있습니다.
이를 위해 pwntools를 사용할 수 있습니다:
from pwn import *
# Generate a De Bruijn sequence of length 1000 with an alphabet size of 256 (byte values)
pattern = cyclic(1000)
# This is an example value that you'd have found in the EIP/IP register upon crash
eip_value = p32(0x6161616c)
offset = cyclic_find(eip_value) # Finds the offset of the sequence in the De Bruijn pattern
print(f"The offset is: {offset}")
또는 GEF:
#Patterns
pattern create 200 #Generate length 200 pattern
pattern search "avaaawaa" #Search for the offset of that substring
pattern search $rsp #Search the offset given the content of $rsp
스택 오버플로우 악용
오버플로우 발생 시 (오버플로우 크기가 충분히 크다고 가정), 스택 내부의 로컬 변수 값을 덮어쓸 수 있게 됩니다. 이때 저장된 **EBP/RBP 및 EIP/RIP (또는 그 이상)**에 도달할 때까지 덮어쓸 수 있습니다.
이 유형의 취약점을 악용하는 가장 일반적인 방법은 반환 주소를 수정하여 함수가 종료될 때 제어 흐름이 사용자가 지정한 위치로 리디렉션되도록 하는 것입니다.
그러나 다른 시나리오에서는 간단한 CTF 챌린지와 같이 스택 내의 일부 변수 값을 덮어쓰는 것만으로도 악용에 충분할 수 있습니다.
Ret2win
이 유형의 CTF 챌린지에서는 바이너리 내부에 있는 함수가 호출되지 않고 이를 호출해야 하는 상황이 있습니다. 이러한 챌린지에서는 반환 주소를 덮어쓸 오프셋을 찾고 호출할 함수의 주소를 찾아야 합니다 (ASLR가 비활성화된 경우가 일반적) 따라서 취약한 함수가 반환될 때 숨겨진 함수가 호출됩니다:
{% content-ref url="ret2win/" %} ret2win {% endcontent-ref %}
스택 쉘코드
이 시나리오에서 공격자는 스택에 쉘코드를 배치하고 제어 가능한 EIP/RIP를 남용하여 쉘코드로 이동하고 임의의 코드를 실행할 수 있습니다:
{% content-ref url="stack-shellcode/" %} stack-shellcode {% endcontent-ref %}
ROP 및 Ret2... 기술
이 기술은 이전 기술의 주요 보호 기능인 **실행 불가능한 스택 (NX)**를 우회하는 기본 프레임워크입니다. 이를 통해 바이너리 내의 기존 명령을 남용하여 임의 명령을 실행하는 여러 기술 (ret2lib, ret2syscall 등)을 수행할 수 있습니다:
{% content-ref url="../rop-return-oriented-programing/" %} rop-return-oriented-programing {% endcontent-ref %}
보호 유형
취약점 악용을 방지하려는 여러 보호 기능이 있습니다. 이를 확인하려면 다음을 참조하십시오:
{% content-ref url="../common-binary-protections-and-bypasses/" %} common-binary-protections-and-bypasses {% endcontent-ref %}