第1页
Pwning in C++
-basicAngelboy scwuaptx@gmail.com
第2页
Outline
• Virtual function table • Vtable Hijacking
• Vector & String • New & delete • Copy constructor & assignment operator
第3页
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 )
第4页
Virtual function table
writable section (heap)
compiler generates the table for all class
read-only section
vtable for Person
typeinfo Person::speak() Person::phd()
vtable for Stu
typeinfo Stu::speak() Person::phd() Stu::pwn()
第5页
Virtual function table
writable section ddaa (heap)
vfptr
a
meh
new a Person and a Stu object
vfptr a b
read-only section
vtable for Person
typeinfo Person::speak() Person::phd()
vtable for Stu
typeinfo Stu::speak() Person::phd() Stu::pwn()
第6页
Virtual function table
ddaa->speak()
writable section ddaa (heap)
vfptr
a
meh
vfptr a b
read-only section
vtable for Person
typeinfo Person::speak() Person::phd()
vtable for Stu
typeinfo Stu::speak() Person::phd() Stu::pwn()
第7页
Virtual function table
vfptr == *ddaa 取 vfptr
writable section ddaa (heap)
vfptr
a
meh
vfptr a b
read-only section
vtable for Person
typeinfo Person::speak() Person::phd()
vtable for Stu
typeinfo Stu::speak() Person::phd() Stu::pwn()
第8页
Virtual function table
writable section ddaa (heap)
vfptr
a
meh
call *vfptr (Person::speak(ddaa))
vfptr a b
read-only section
vtable for Person
typeinfo Person::speak() Person::phd()
vtable for Stu
typeinfo Stu::speak() Person::phd() Stu::pwn()
第9页
Virtual function table
meh->speak()
writable section ddaa (heap)
vfptr
a
meh
vfptr a b
read-only section
vtable for Person
typeinfo Person::speak() Person::phd()
vtable for Stu
typeinfo Stu::speak() Person::phd() Stu::pwn()
第10页
Virtual function table
vfptr == *meh 取 vfptr
writable section ddaa (heap)
vfptr
a
meh
vfptr a b
read-only section
vtable for Person
typeinfo Person::speak() Person::phd()
vtable for Stu
typeinfo Stu::speak() Person::phd() Stu::pwn()
第11页
Virtual function table
call *vfptr (Stu::speak(meh))
writable section ddaa (heap)
vfptr
a
meh
vfptr a b
read-only section
vtable for Person
typeinfo Person::speak() Person::phd()
vtable for Stu
typeinfo Stu::speak() Person::phd() Stu::pwn()
第12页
Virtual function table
meh->pwn()
writable section ddaa (heap)
vfptr
a
meh
vfptr a b
read-only section
vtable for Person
typeinfo Person::speak() Person::phd()
vtable for Stu
typeinfo Stu::speak() Person::phd() Stu::pwn()
第13页
Virtual function table
vfptr == *meh 取 vfptr
writable section ddaa (heap)
vfptr
a
meh
vfptr a b
read-only section
vtable for Person
typeinfo Person::speak() Person::phd()
vtable for Stu
typeinfo Stu::speak() Person::phd() Stu::pwn()
第14页
Virtual function table
call *(vfptr+0x10) (Stu::pwn(meh))
writable section ddaa (heap)
vfptr
a
meh
vfptr a b
read-only section
vtable for Person
typeinfo Person::speak() Person::phd()
vtable for Stu
typeinfo Stu::speak() Person::phd() Stu::pwn()
第15页
Vtable Hijacking
• Need some another vulnerability • Use-after-free, Heap overflow ….
• Force the table and Hijack the vfptr • Because the vfptr is writable
第16页
Virtual function table
writable section ddaa (heap)
vfptr
a
meh
vfptr a b
read-only section
vtable for Person
typeinfo Person::speak() Person::phd()
vtable for Stu
typeinfo Stu::speak() Person::phd() Stu::pwn()
第17页
Virtual function table
heap overflow force a vtabe in ddaa and hijack the vfptr of meh
writable section ddaa (heap)
&shellcode
meh
0xddaa ddaa
0xdead
0xbeef
read-only section
vtable for Person
typeinfo Person::speak() Person::phd()
vtable for Stu
typeinfo Stu::speak() Person::phd() Stu::pwn()
第18页
Virtual function table
meh->speak()
writable section ddaa (heap)
&shellcode
meh
0xddaa ddaa
0xdead
0xbeef
read-only section
vtable for Person
typeinfo Person::speak() Person::phd()
vtable for Stu
typeinfo Stu::speak() Person::phd() Stu::pwn()
第19页
Virtual function table
vfptr = *meh 取 vfptr
writable section ddaa (heap)
&shellcode
meh
0xddaa ddaa
0xdead
0xbeef
read-only section
vtable for Person
typeinfo Person::speak() Person::phd()
vtable for Stu
typeinfo Stu::speak() Person::phd() Stu::pwn()
第20页
Virtual function table
call *(vfptr) (call shellcode(meh))
writable section ddaa (heap)
&shellcode
meh
0xddaa ddaa
0xdead
0xbeef
read-only section
vtable for Person
typeinfo Person::speak() Person::phd()
vtable for Stu
typeinfo Stu::speak() Person::phd() Stu::pwn()
第21页
Virtual function table
writable section ddaa (heap)
&shellcode
read-only section
vtable for Person
PWN !!meh
0xddaa ddaa
typeinfo Person::speak()
但通常會有 DEP/NX 保護,可0能x要de跳adlibc 中的 oneP-egrasdogne::tphd()
或是其他可利0x⽤b用的ee地f ⽅方
vtable for Stu
typeinfo
Stu::speak()
call *(vfptr) (call shellcode(meh))
Person::phd() Stu::pwn()
第22页
Vector & String
• Vector
• A dynamic array
• 分配在 heap 段
• ⽐比⼀一般 c 中的陣列更有彈性,當空間不夠⼤大時 會重新兩倍⼤大的的⼩小來放置新的 vector ,再把 原本的空間還給系統
第23页
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 • 以這個來判斷空間是否⾜足夠放元素
第24页
Vector & String
• Vector • member function • push_back : 在 vector 最後加⼊入新元素 • pop_back : 移除 vector 最後⼀一個元素 • insert :插⼊入元素到 vector 第 n 個位置 • erase :移除 vector 中第 n 個元素 • ……
第25页
Vector & String
• Vector layout
vector <string> vec
_M_start _M_finish _M_end_of_storage
第26页
Vector & String
• Vector layout
vec.push_back(“meh”)
_M_start _M_finish _M_end_of_storage
address of meh string
第27页
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 並把舊的值複製過去
第28页
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
第29页
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
第30页
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
第31页
Vector & String
• Vector layout
vec.pop_back()
_M_start _M_finish _M_end_of_storage
call destructor of pwn string
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
第32页
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
第33页
Vector & String
• String
• a dynamic char array • ⽐比起以往的字串陣列更加安全,全部動態配置記憶體空
間,減少⼀一般 buffer overflow 的發⽣生
• 在給定 input 時,會不斷重新分配空間給 user 直到結束 後,就會回傳適當的⼤大⼩小給 user
• 有許多種實作⽅方式,這邊介紹最常⾒見的⼀一種
• g++
第34页
Vector & String
• String • member • size :字串的⻑⾧長度 • Capacity : 該 string 空間的容量 • reference count : 引⽤用計數 • 只要有其他元素引⽤用該字串就會增加 • 如果其他元素不引⽤用了,也會減少 • 當 reference == 0 時就會,將空間 delete 掉 • value : 存放字串內容
第35页
Vector & String
• String • member function • length() : string ⼤大⼩小 • capacity() : ⺫⽬目前 string 空間容量 • c_str() : Get C string equivalent • ……
第36页
Vector & String
• String layout
string str cin >> str
str
第37页
Vector & String
• String layout
string str cin >> str input : aa
str
size = 2 capacity = 2
refcnt = 0 aa
第38页
Vector & String
• String layout
string str cin >> str input : aaa
str
size = 2 capacity = 2 refcnt = -1
aa
size = 3 capacity = 4
refcnt = 0 aaa
第39页
Vector & String
• String layout
string str cin >> str input : aaaaa
str
size = 2 capacity = 2 refcnt = -1
aa
size = 4 capacity = 4 refcnt = -1
aaaa
size = 5 capacity = 8
refcnt = 0 aaaaa
第40页
Vector & String
• String layout
string str cin >> str input : a*125
str
size = 125 capacity = 128
refcnt = 0 a*125
依此類推 capacity 會 不斷以⼆二的指數倍增⻑⾧長
直到 input 結束
size = 2 capacity = 2 refcnt = -1
aa
size = 4 capacity = 4 refcnt = -1
aaaa
size = 8 capacity = 8 refcnt = -1
aaaaaaaa
...
第41页
Vector & String
• String layout
vector<string> vec vec.push_back(str)
str
_M_start _M_finish _M_end_of_storage
size = 125 capacity = 128
refcnt = 1 a*125
str
size = 2 capacity = 2 refcnt = -1
aa
size = 4 capacity = 4 refcnt = -1
aaaa
size = 8 capacity = 8 refcnt = -1
aaaaaaaa
...
第42页
Vector & String
• String layout
vector<string> vec vec.push_back(str) vec.push_back(str)
str
_M_start _M_finish _M_end_of_storage
size = 125 capacity = 128
refcnt = 2 a*125
str
str str
size = 2 capacity = 2 refcnt = -1
aa
size = 4 capacity = 4 refcnt = -1
aaaa
size = 8 capacity = 8 refcnt = -1
aaaaaaaa
...
第43页
Vector & String
• String layout
vec.pop_back()
這邊會 call str destuctor 但不會 delete 空間
str
_M_start _M_finish _M_end_of_storage
size = 125 capacity = 128
refcnt = 1 a*125
str
str str
size = 2 capacity = 2 refcnt = -1
aa
size = 4 capacity = 4 refcnt = -1
aaaa
size = 8 capacity = 8 refcnt = -1
aaaaaaaa
...
第44页
Vector & String
• String layout
vec.pop_back()
這邊會 call str destuctor 但不會 delete 空間
str
_M_start _M_finish _M_end_of_storage
size = 125 capacity = 128
refcnt = 0 a*125
str
str str
size = 2 capacity = 2 refcnt = -1
aa
size = 4 capacity = 4 refcnt = -1
aaaa
size = 8 capacity = 8 refcnt = -1
aaaaaaaa
...
第45页
Vector & String
• String layout
end of scope
這邊會 call str destuctor 因 refcnt < 0 會做 delete
_M_start _M_finish _M_end_of_storage
size = 125 capacity = 128
refcnt = -1 a*125
str
str str
size = 2 capacity = 2 refcnt = -1
aa
size = 4 capacity = 4 refcnt = -1
aaaa
size = 8 capacity = 8 refcnt = -1
aaaaaaaa
...
第46页
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 混⽤用,不然可 能會出現⼀一些不可預期的狀況
第47页
New & Delete
• new ⼤大致上流程 • operator new • 與 malloc 類似,單純配置記憶體空間,但配置失敗會進⼊入 exception ⽽而 malloc 則是返回 null ,有點像在 malloc 上⼀一層 wrapper • constructor
• delete ⼤大致上流程 • destructor • operator delete • 與 free 類似,釋放⼀一塊記憶體空間,有點像是在 free 上⼀一層 wrapper
第48页
New & Delete
• 因此 new/delete 及 operator new / operator delete 也應該成對配對
• 記憶體函式配對
配置函式
new new [] operator new operator new[] malloc
解除函式
delete delete [] operator delete operator delete[]
free
第49页
What’s wrong in this code
第50页
What’s wrong in this code
第51页
What’s wrong in this code
第52页
Copy constructor & assignment operator
• shadow copy
• 只做單純 pointer (value) 的複製,複製完後內 容與原本的相同
• deep copy
• 會在配置更多記憶體空間,包含 pointer 所指向 的內容也都⼀一併複製
第53页
Copy constructor & assignment operator
• shadow copy
StuA
name
orange
第54页
Copy constructor & assignment operator
• shadow copy
StuA
name
orange
StuB
name
第55页
Copy constructor & assignment operator
• deep copy
StuA
name
orange
第56页
Copy constructor & assignment operator
• deep copy
StuA
name
orange
StuB
name
orange
第57页
Copy constructor & assignment operator
• Copy constructor
• c++ 在進⾏行複製 object 會使⽤用 copy constructor
• 通常 class 的 member 有指標時,就需要⾃自⾏行 去實作
• 若未特別定義則會使⽤用 default copy constructor
• 只做 shadow copy
第58页
Copy constructor & assignment operator
• Assignment operator
• c++ 在進⾏行 “=“ 這個 operator 時 object 會使⽤用 assignment operator 這個 function 去 assign object 得直
• 通常 class 的 member 有指標時,就需要⾃自⾏行去實 作
• 若未特別定義則會使⽤用 default assignment operator
• 只做 shadow copy
第59页
Copy constructor & assignment operator
• 何時會使⽤用 copy constructor
• func(Stu stu)
• return stu • vector 等 STL 容器
• ….
第60页
Copy constructor & assignment operator
• 何時會使⽤用 assignment operator
• stuA = stuB • vector 等 STL 容器
• ex : vector.erase()
•…
第61页
Copy constructor & assignment operator
call constructor
id name
vector
第62页
Copy constructor & assignment operator
new char [str.length() + 1]
id = 1337 name
orange
vector
第63页
Copy constructor & assignment operator
push_back(student)
id = 1337 name
orange
id = 1337 name
vector
copy the value to vector using
shadow copy
第64页
Copy constructor & assignment operator
~Stu()
id = 1337 name
orange
id = 1337 name
vector
因 student 的 life time 結束
所以
call destructor
第65页
Copy constructor & assignment operator
delete [] name
id = 1337 name
orange
id = 1337 name
vector
第66页
Copy constructor & assignment operator
~vector()
id = 1337 name
orange
id = 1337 name
vector
因 stulist 的 life time 結束
所以
call destructor
第67页
Copy constructor & assignment operator
~Stu()
id = 1337 name
orange
id = 1337 name
vector
vector 會去 依次去呼叫
內容的
destructor
第68页
Copy constructor & assignment operator
delete [] name
id = 1337 name
orange
id = 1337 name
vector
第69页
Copy constructor & assignment operator
delete [] name
id = 1337 name
orange
double free id = 1337
name
vector
第70页
Copy constructor & assignment operator
• 總結
• 基本上 c++ 在只要做任何複製的動作時通常都 會去使⽤用 copy constructor 或者是 assignment operator
• 所以基本上物件只要有 pointer 都盡量養成習慣 去定義 copy constructor 跟 assignment opeator
第71页
Practice
• HITCON 2015 final ghostparty • https://github.com/scwuaptx/CTF-Practice