pwning in c++ (basic)
Post on 14-Apr-2017
7.121 Views
Preview:
TRANSCRIPT
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 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 >> 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
Copy constructor & assignment operator
• shadow copy
• 只做單純 pointer (value) 的複製,複製完後內容與原本的相同
• deep copy
• 會在配置更多記憶體空間,包含 pointer 所指向的內容也都⼀一併複製
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
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
~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
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
top related