pwning in c++ (basic)

71
Pwning in C++ -basic- Angelboy [email protected]

Upload: angel-boy

Post on 14-Apr-2017

7.121 views

Category:

Technology


16 download

TRANSCRIPT

Pwning in C++-basic-

Angelboy [email protected]

Outline• Virtual function table

• Vtable Hijacking

• Vector & String

• New & delete

• Copy constructor & assignment operator

Virtual function table• Virtual function is a key mechanism to support

polymorphism in C++

• For each class with virtual functions, depending on the class inheritance hierarchy, the compiler will create one or more associated virtual function table ( table )

Virtual function tablewritable section

(heap)

typeinfo

Person::speak() Person::phd()

typeinfo

Stu::speak() Person::phd()

Stu::pwn()

read-only section

vtable for Person

vtable for Stu

compiler generates the table for all class

Virtual function tablewritable section

(heap)ddaa

meh

vfptr a

vfptr a

b

typeinfo

Person::speak() Person::phd()

typeinfo

Stu::speak() Person::phd()

Stu::pwn()

read-only section

vtable for Person

vtable for Stu

new a Person and a Stu object

Virtual function tablewritable section

(heap)ddaa

meh

vfptr a

vfptr a

b

typeinfo

Person::speak() Person::phd()

typeinfo

Stu::speak() Person::phd()

Stu::pwn()

read-only section

vtable for Person

vtable for Stu

ddaa->speak()

Virtual function tablewritable section

(heap)ddaa

meh

vfptr a

vfptr a

b

typeinfo

Person::speak() Person::phd()

typeinfo

Stu::speak() Person::phd()

Stu::pwn()

read-only section

vtable for Person

vtable for Stu

vfptr == *ddaa 取 vfptr

Virtual function tablewritable section

(heap)ddaa

meh

vfptr a

vfptr a

b

typeinfo

Person::speak() Person::phd()

typeinfo

Stu::speak() Person::phd()

Stu::pwn()

read-only section

vtable for Person

vtable for Stu

call *vfptr (Person::speak(ddaa))

Virtual function tablewritable section

(heap)ddaa

meh

vfptr a

vfptr a

b

typeinfo

Person::speak() Person::phd()

typeinfo

Stu::speak() Person::phd()

Stu::pwn()

read-only section

vtable for Person

vtable for Stu

meh->speak()

Virtual function tablewritable section

(heap)ddaa

meh

vfptr a

vfptr a

b

typeinfo

Person::speak() Person::phd()

typeinfo

Stu::speak() Person::phd()

Stu::pwn()

read-only section

vtable for Person

vtable for Stu

vfptr == *meh 取 vfptr

Virtual function tablewritable section

(heap)ddaa

meh

vfptr a

vfptr a

b

typeinfo

Person::speak() Person::phd()

typeinfo

Stu::speak() Person::phd()

Stu::pwn()

read-only section

vtable for Person

vtable for Stu

call *vfptr (Stu::speak(meh))

Virtual function tablewritable section

(heap)ddaa

meh

vfptr a

vfptr a

b

typeinfo

Person::speak() Person::phd()

typeinfo

Stu::speak() Person::phd()

Stu::pwn()

read-only section

vtable for Person

vtable for Stu

meh->pwn()

Virtual function tablewritable section

(heap)ddaa

meh

vfptr a

vfptr a

b

typeinfo

Person::speak() Person::phd()

typeinfo

Stu::speak() Person::phd()

Stu::pwn()

read-only section

vtable for Person

vtable for Stu

vfptr == *meh 取 vfptr

Virtual function tablewritable section

(heap)ddaa

meh

vfptr a

vfptr a

b

typeinfo

Person::speak() Person::phd()

typeinfo

Stu::speak() Person::phd()

Stu::pwn()

read-only section

vtable for Person

vtable for Stu

call *(vfptr+0x10) (Stu::pwn(meh))

Vtable Hijacking• Need some another vulnerability

• Use-after-free, Heap overflow ….

• Force the table and Hijack the vfptr

• Because the vfptr is writable

Virtual function tablewritable section

(heap)ddaa

meh

vfptr a

vfptr a

b

typeinfo

Person::speak() Person::phd()

typeinfo

Stu::speak() Person::phd()

Stu::pwn()

read-only section

vtable for Person

vtable for Stu

Virtual function tablewritable section

(heap)

meh

&shellcode 0xddaa

ddaa

0xdead 0xbeef

typeinfo

Person::speak() Person::phd()

typeinfo

Stu::speak() Person::phd()

Stu::pwn()

read-only section

vtable for Person

vtable for Stu

heap overflow force a vtabe in ddaa

and hijack the vfptr of meh

ddaa

Virtual function tablewritable section

(heap)

meh

&shellcode 0xddaa

ddaa

0xdead 0xbeef

typeinfo

Person::speak() Person::phd()

typeinfo

Stu::speak() Person::phd()

Stu::pwn()

read-only section

vtable for Person

vtable for Stu

meh->speak()

ddaa

Virtual function tablewritable section

(heap)

meh

&shellcode 0xddaa

ddaa

0xdead 0xbeef

typeinfo

Person::speak() Person::phd()

typeinfo

Stu::speak() Person::phd()

Stu::pwn()

read-only section

vtable for Person

vtable for Stu

vfptr = *meh 取 vfptr

ddaa

Virtual function tablewritable section

(heap)

meh

&shellcode 0xddaa

ddaa

0xdead 0xbeef

typeinfo

Person::speak() Person::phd()

typeinfo

Stu::speak() Person::phd()

Stu::pwn()

read-only section

vtable for Person

vtable for Stu

ddaa

call *(vfptr) (call shellcode(meh))

Virtual function tablewritable section

(heap)

meh

&shellcode 0xddaa

ddaa

0xdead 0xbeef

typeinfo

Person::speak() Person::phd()

typeinfo

Stu::speak() Person::phd()

Stu::pwn()

read-only section

vtable for Person

vtable for Stu

ddaa

call *(vfptr) (call shellcode(meh))

PWN !! 但通常會有 DEP/NX 保護,可能要跳 libc 中的 one-gadget

或是其他可利⽤用的地⽅方

Vector & String• Vector

• A dynamic array

• 分配在 heap 段

• ⽐比⼀一般 c 中的陣列更有彈性,當空間不夠⼤大時會重新兩倍⼤大的的⼩小來放置新的 vector ,再把原本的空間還給系統

Vector & String• Vector

• member

• _M_start : vector 起始位置

• vector::begin()

• _M_finish : vector 結尾位置

• vector::end()

• _M_end_of_storage :容器最後位置

• if _M_finish == _M_end_of_storage in push_back

• It will alloca a new space for the vector

• 以這個來判斷空間是否⾜足夠放元素

Vector & String• Vector

• member function

• push_back : 在 vector 最後加⼊入新元素

• pop_back : 移除 vector 最後⼀一個元素

• insert :插⼊入元素到 vector 第 n 個位置

• erase :移除 vector 中第 n 個元素

• ……

Vector & String• Vector layoutvector <string> vec

_M_start

_M_finish

_M_end_of_storage

Vector & String• Vector layout

vec.push_back(“meh”)_M_start

_M_finish

_M_end_of_storage

address of meh string

Vector & String• Vector layout

vec.push_back(“meheap”)_M_start

_M_finish

_M_end_of_storage

address of meh string

因為 _M_finish == _ M_end_of_storage 所以會先將藍⾊色那塊 delete 掉 再從新 new ⼀一塊新的 vector 並把舊的值複製過去

Vector & String• Vector layout

vec.push_back(“meheap”)_M_start

_M_finish

_M_end_of_storage

address of meh string

address of meh string address of meheap string

Vector & String• Vector layout

vec.push_back(“meh.py”)_M_start

_M_finish

_M_end_of_storage

address of meh string

address of meh string address of meheap string

address of meh string

address of meheap string address of meh.py string

Vector & String• Vector layout

vec.push_back(“pwn”)_M_start

_M_finish

_M_end_of_storage

address of meh string

address of meh string address of meheap string

address of meh string

address of meheap string address of meh.py string

address of pwn string

Vector & String• Vector layout

vec.pop_back()_M_start

_M_finish

_M_end_of_storage

address of meh string

address of meh string address of meheap string

address of meh string

address of meheap string address of meh.py string

address of pwn stringcall destructor of pwn string

Vector & String• Vector layout

vec.pop_back()_M_start

_M_finish

_M_end_of_storage

address of meh string

address of meh string address of meheap string

address of meh string

address of meheap string address of meh.py string

address of pwn string

Vector & String• String

• a dynamic char array

• ⽐比起以往的字串陣列更加安全,全部動態配置記憶體空間,減少⼀一般 buffer overflow 的發⽣生

• 在給定 input 時,會不斷重新分配空間給 user 直到結束後,就會回傳適當的⼤大⼩小給 user

• 有許多種實作⽅方式,這邊介紹最常⾒見的⼀一種

• g++

Vector & String• String

• member

• size :字串的⻑⾧長度

• Capacity : 該 string 空間的容量

• reference count : 引⽤用計數

• 只要有其他元素引⽤用該字串就會增加

• 如果其他元素不引⽤用了,也會減少

• 當 reference == 0 時就會,將空間 delete 掉

• value : 存放字串內容

Vector & String• String

• member function

• length() : string ⼤大⼩小

• capacity() : ⺫⽬目前 string 空間容量

• c_str() : Get C string equivalent

• ……

Vector & String• String layout

str

string str cin >> str

Vector & String• String layout

str

string str cin >> strinput : aa

size = 2 capacity = 2

refcnt = 0 aa

Vector & String• String layout

str

string str cin >> strinput : aaa

size = 2 capacity = 2 refcnt = -1

aasize = 3

capacity = 4 refcnt = 0

aaa

Vector & String• String layout

str

string str cin >> str

input : aaaaa

size = 2 capacity = 2 refcnt = -1

aasize = 4

capacity = 4 refcnt = -1

aaaasize = 5

capacity = 8 refcnt = 0

aaaaa

Vector & String• String layout

str

string str cin >> str

input : a*125

size = 2 capacity = 2 refcnt = -1

aasize = 4

capacity = 4 refcnt = -1

aaaasize = 8

capacity = 8 refcnt = -1 aaaaaaaa

size = 125 capacity = 128

refcnt = 0 a*125

依此類推 capacity 會 不斷以⼆二的指數倍增⻑⾧長 直到 input 結束 ...

Vector & String• String layout

str

vector<string> vec vec.push_back(str)

size = 2 capacity = 2 refcnt = -1

aasize = 4

capacity = 4 refcnt = -1

aaaasize = 8

capacity = 8 refcnt = -1 aaaaaaaa

size = 125 capacity = 128

refcnt = 1 a*125

_M_start _M_finish

_M_end_of_storage

str

...

Vector & String• String layout

str

size = 2 capacity = 2 refcnt = -1

aasize = 4

capacity = 4 refcnt = -1

aaaasize = 8

capacity = 8 refcnt = -1 aaaaaaaa

size = 125 capacity = 128

refcnt = 2 a*125

_M_start _M_finish

_M_end_of_storage

str

str

str

vector<string> vec vec.push_back(str) vec.push_back(str)

...

Vector & String• String layout

str

size = 2 capacity = 2 refcnt = -1

aasize = 4

capacity = 4 refcnt = -1

aaaasize = 8

capacity = 8 refcnt = -1 aaaaaaaa

size = 125 capacity = 128

refcnt = 1 a*125

_M_start _M_finish

_M_end_of_storage

str

str

str

vec.pop_back()這邊會 call str destuctor 但不會 delete 空間

...

Vector & String• String layout

str

size = 2 capacity = 2 refcnt = -1

aasize = 4

capacity = 4 refcnt = -1

aaaasize = 8

capacity = 8 refcnt = -1 aaaaaaaa

size = 125 capacity = 128

refcnt = 0 a*125

_M_start _M_finish

_M_end_of_storage

str

str

str

vec.pop_back()這邊會 call str destuctor 但不會 delete 空間

...

Vector & String• String layout size = 2

capacity = 2 refcnt = -1

aasize = 4

capacity = 4 refcnt = -1

aaaasize = 8

capacity = 8 refcnt = -1 aaaaaaaa

size = 125 capacity = 128

refcnt = -1 a*125

_M_start _M_finish

_M_end_of_storage

str

str

str

end of scope這邊會 call str destuctor

因 refcnt < 0 會做 delete

...

New & Delete• 在 c++ 預設的情況下 ,new/delete 的最底層實作依舊是靠

malloc/free 去處理記憶體管理

• 在 c++ 中,記憶體配置池稱為 free store ,但預設情況下 free store 位置是在 heap

• 不過事實上 new/delete 是可以 overloading 的,也就是⾃自⾏行去做記憶體管理,另外最⼤大差別就是new/delete 實際上會去 call constructor/destructor ⽽而 malloc/free 只做單純的記憶體配置

• 因此盡量不要讓 malloc/free 與 new/delete 混⽤用,不然可能會出現⼀一些不可預期的狀況

New & Delete• new ⼤大致上流程

• operator new

• 與 malloc 類似,單純配置記憶體空間,但配置失敗會進⼊入 exception ⽽而 malloc 則是返回 null ,有點像在 malloc 上⼀一層 wrapper

• constructor

• delete ⼤大致上流程

• destructor

• operator delete

• 與 free 類似,釋放⼀一塊記憶體空間,有點像是在 free 上⼀一層 wrapper

New & Delete• 因此 new/delete 及 operator new / operator

delete 也應該成對配對

• 記憶體函式配對

配置函式 解除函式new delete

new [] delete []operator new operator delete

operator new[] operator delete[]malloc free

What’s wrong in this code

What’s wrong in this code

What’s wrong in this code

Copy constructor & assignment operator

• shadow copy

• 只做單純 pointer (value) 的複製,複製完後內容與原本的相同

• deep copy

• 會在配置更多記憶體空間,包含 pointer 所指向的內容也都⼀一併複製

Copy constructor & assignment operator

• shadow copy

nameorange

StuA

Copy constructor & assignment operator

• shadow copy

nameorange

name

StuA

StuB

Copy constructor & assignment operator

• deep copy

nameorange

StuA

Copy constructor & assignment operator

• deep copy

nameorange

name

StuA

StuB orange

Copy constructor & assignment operator

• Copy constructor

• c++ 在進⾏行複製 object 會使⽤用 copy constructor

• 通常 class 的 member 有指標時,就需要⾃自⾏行去實作

• 若未特別定義則會使⽤用 default copy constructor

• 只做 shadow copy

Copy constructor & assignment operator

• Assignment operator

• c++ 在進⾏行 “=“ 這個 operator 時 object 會使⽤用 assignment operator 這個 function 去 assign object 得直

• 通常 class 的 member 有指標時,就需要⾃自⾏行去實作

• 若未特別定義則會使⽤用 default assignment operator

• 只做 shadow copy

Copy constructor & assignment operator

• 何時會使⽤用 copy constructor

• func(Stu stu)

• return stu

• vector 等 STL 容器

• ….

Copy constructor & assignment operator

• 何時會使⽤用 assignment operator

• stuA = stuB

• vector 等 STL 容器

• ex : vector.erase()

• …

Copy constructor & assignment operator

call constructor

id

name

vector

Copy constructor & assignment operator

new char [str.length() + 1]id = 1337

name orange

vector

Copy constructor & assignment operator

push_back(student)id = 1337

name orange

vector

id = 1337

name copy the value to vector

using shadow copy

Copy constructor & assignment operator

~Stu()id = 1337

name orange

vector

id = 1337

name 因 student 的 life time 結束 所以

call destructor

Copy constructor & assignment operator

delete [] nameid = 1337

name orange

vector

id = 1337

name

Copy constructor & assignment operator

~vector()id = 1337

name orange

vector

id = 1337

name 因 stulist 的 life time 結束 所以

call destructor

Copy constructor & assignment operator

~Stu()id = 1337

name orange

vector

id = 1337

name vector 會去 依次去呼叫 內容的

destructor

Copy constructor & assignment operator

delete [] nameid = 1337

name orange

vector

id = 1337

name

Copy constructor & assignment operator

delete [] nameid = 1337

name orange

vector

id = 1337

name

double free

Copy constructor & assignment operator

• 總結

• 基本上 c++ 在只要做任何複製的動作時通常都會去使⽤用 copy constructor 或者是 assignment operator

• 所以基本上物件只要有 pointer 都盡量養成習慣去定義 copy constructor 跟 assignment opeator

Practice• HITCON 2015 final ghostparty

• https://github.com/scwuaptx/CTF-Practice