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

Gallopsled / pwntools / 13291379916

12 Feb 2025 05:33PM UTC coverage: 71.132% (+0.1%) from 71.024%
13291379916

Pull #2542

github

web-flow
Merge a7274b5c5 into 3eb690bd3
Pull Request #2542: Decode `_IO_*` flags in FileStructure member

3636 of 6418 branches covered (56.65%)

75 of 79 new or added lines in 1 file covered. (94.94%)

1 existing line in 1 file now uncovered.

12919 of 18162 relevant lines covered (71.13%)

0.71 hits per line

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

93.44
/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

25
from __future__ import absolute_import
2✔
26
from __future__ import division
2✔
27

28
import ctypes
2✔
29

30
from pwnlib.context import context
2✔
31
from pwnlib.log import getLogger
2✔
32
from pwnlib.util.misc import python_2_bytes_compatible
2✔
33
from pwnlib.util.packing import pack, unpack
2✔
34

35
log = getLogger(__name__)
2✔
36

37
length=0
2✔
38
size='size'
2✔
39
name='name'
2✔
40

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

75
del name, size, length
2✔
76

77

78
def _update_var(l):
2✔
79
    r"""
80
    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.
81

82
    Arguments:
83
        l(int)
84
            l=8 for 'amd64' architecture and l=4 for 'i386' architecture
85

86
    Return Value:
87
        Returns a dictionary in which each field is mapped to its corresponding length according to the architecture set
88

89
    Examples:
90

91
        >>> _update_var(8)
92
        {'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, '_freeres_list': 8, '_freeres_buf': 8, '_pad5': 8, '_mode': 4, '_unused2': 20, 'vtable': 8}
93
    """
94
    var={}
2✔
95
    for i in variables:
2✔
96
        var[variables[i]['name']]=variables[i]['size']
2✔
97
    for i in var:
2✔
98
        if var[i]<=0:
2✔
99
            var[i]+=l
2✔
100
    if l==4:
2!
NEW
101
        var['_unused2']=40
×
102
    else:
103
        var['_unused2']=20
2✔
104
    return var
2✔
105

106
class IO_flags:
2✔
107
    _IO_MAGIC =         0xFBAD0000 # Magic number
2✔
108
    _IO_MAGIC_MASK =    0xFFFF0000
2✔
109
    _IO_USER_BUF =          0x0001 # Don't deallocate buffer on close.
2✔
110
    _IO_UNBUFFERED =        0x0002
2✔
111
    _IO_NO_READS =          0x0004 # Reading not allowed.
2✔
112
    _IO_NO_WRITES =         0x0008 # Writing not allowed.
2✔
113
    _IO_EOF_SEEN =          0x0010
2✔
114
    _IO_ERR_SEEN =          0x0020
2✔
115
    _IO_DELETE_DONT_CLOSE = 0x0040 # Don't call close(_fileno) on close.
2✔
116
    _IO_LINKED =            0x0080 # In the list of all open files.
2✔
117
    _IO_IN_BACKUP =         0x0100
2✔
118
    _IO_LINE_BUF =          0x0200
2✔
119
    _IO_TIED_PUT_GET =      0x0400 # Put and get pointer move in unison.
2✔
120
    _IO_CURRENTLY_PUTTING = 0x0800
2✔
121
    _IO_IS_APPENDING =      0x1000
2✔
122
    _IO_IS_FILEBUF =        0x2000
2✔
123
    _IO_USER_LOCK =         0x8000
2✔
124

125
class IO_flags2:
2✔
126
    _IO_FLAGS2_MMAP = 1
2✔
127
    _IO_FLAGS2_NOTCANCEL = 2
2✔
128
    _IO_FLAGS2_USER_WBUF = 8
2✔
129
    _IO_FLAGS2_NOCLOSE = 32
2✔
130
    _IO_FLAGS2_CLOEXEC = 64
2✔
131
    _IO_FLAGS2_NEED_LOCK = 128
2✔
132

133
class _FlagsUnionBase(ctypes.Union):
2✔
134
    def __getattr__(self, name):
2✔
NEW
135
        if any(name == field[0] for field in self._flags_bits._fields_):
×
NEW
136
            return getattr(self._flags_bits, name)
×
NEW
137
        return super().__getattr__(name)
×
138
    
139
    def __setattr__(self, name, value):
2✔
140
        if any(name == field[0] for field in self._flags_bits._fields_):
2✔
141
            setattr(self._flags_bits, name, value)
2✔
142
        return super().__setattr__(name, value)
2✔
143

144
    def __int__(self):
2✔
145
        return int(self._flags)
2✔
146

147
    def __str__(self):
2✔
148
        return "{:#x} ({})".format(self._flags, self._flags_bits)
2✔
149

150
# https://elixir.bootlin.com/glibc/glibc-2.41/source/libio/libio.h#L66
151
class _IOFileFlags_bits(ctypes.LittleEndianStructure):
2✔
152
    _pack_ = 1
2✔
153
    _fields_ = [
2✔
154
        ("_IO_USER_BUF", ctypes.c_uint8, 1), # Don't deallocate buffer on close.
155
        ("_IO_UNBUFFERED", ctypes.c_uint8, 1),
156
        ("_IO_NO_READS", ctypes.c_uint8, 1), # Reading not allowed.
157
        ("_IO_NO_WRITES", ctypes.c_uint8, 1), # Writing not allowed.
158
        ("_IO_EOF_SEEN", ctypes.c_uint8, 1),
159
        ("_IO_ERR_SEEN", ctypes.c_uint8, 1),
160
        ("_IO_DELETE_DONT_CLOSE", ctypes.c_uint8, 1), # Don't call close(_fileno) on close.
161
        ("_IO_LINKED", ctypes.c_uint8, 1), # In the list of all open files.
162
        ("_IO_IN_BACKUP", ctypes.c_uint8, 1),
163
        ("_IO_LINE_BUF", ctypes.c_uint8, 1),
164
        ("_IO_TIED_PUT_GET", ctypes.c_uint8, 1), # Put and get pointer move in unison.
165
        ("_IO_CURRENTLY_PUTTING", ctypes.c_uint8, 1),
166
        ("_IO_IS_APPENDING", ctypes.c_uint8, 1),
167
        ("_IO_IS_FILEBUF", ctypes.c_uint8, 1),
168
        ("_IO_BAD_SEEN__UNUSED", ctypes.c_uint8, 1), # No longer used, reserved for compat.
169
        ("_IO_USER_LOCK", ctypes.c_uint8, 1),
170
        ("_IO_MAGIC", ctypes.c_uint16, 16), # Magic number 0xFBAD0000.
171
    ]
172

173
    def __str__(self):
2✔
174
        return " | ".join(name for name, _, _ in self._fields_ if getattr(self, name))
2✔
175

176
class _IOFileFlags(_FlagsUnionBase):
2✔
177
    _fields_ = [
2✔
178
        ("_flags", ctypes.c_uint64),
179
        ("_flags_bits", _IOFileFlags_bits),
180
    ]
181

182

183
# https://elixir.bootlin.com/glibc/glibc-2.41/source/libio/libio.h#L85
184
class _IOFileFlags2_bits(ctypes.LittleEndianStructure):
2✔
185
    _pack_ = 1
2✔
186
    _fields_ = [
2✔
187
        ("_IO_FLAGS2_MMAP", ctypes.c_uint8, 1),
188
        ("_IO_FLAGS2_NOTCANCEL", ctypes.c_uint8, 1),
189
        ("_IO_FLAGS2_USER_WBUF", ctypes.c_uint8, 1),
190
        ("_IO_FLAGS2_NOCLOSE", ctypes.c_uint8, 1),
191
        ("_IO_FLAGS2_CLOEXEC", ctypes.c_uint8, 1),
192
        ("_IO_FLAGS2_NEED_LOCK", ctypes.c_uint8, 1),
193
    ]
194

195
    def __str__(self):
2✔
196
        return " | ".join(name for name, _, _ in self._fields_ if getattr(self, name))
2✔
197

198
class _IOFileFlags2(_FlagsUnionBase):
2✔
199
    _fields_ = [
2✔
200
        ("_flags", ctypes.c_uint64),
201
        ("_flags_bits", _IOFileFlags2_bits),
202
    ]
203

204

205
@python_2_bytes_compatible
2✔
206
class FileStructure(object):
2✔
207
    r"""
208
    Crafts a FILE structure, with default values for some fields, like _lock which should point to null ideally, set.
209

210
    Arguments:
211
        null(int)
212
            A pointer to NULL value in memory. This pointer can lie in any segment (stack, heap, bss, libc etc)
213

214
    Examples:
215

216
        FILE structure with flags as 0xfbad1807 and _IO_buf_base and _IO_buf_end pointing to 0xcafebabe and 0xfacef00d
217

218
        >>> context.clear(arch='amd64')
219
        >>> fileStr = FileStructure(null=0xdeadbeeef)
220
        >>> fileStr.flags = 0xfbad1807 # or use flags by name:
221
        >>> fileStr.flags = IO_flags._IO_MAGIC | IO_flags._IO_USER_BUF | IO_flags._IO_UNBUFFERED | IO_flags._IO_NO_READS | IO_flags._IO_CURRENTLY_PUTTING | IO_flags._IO_IS_APPENDING
222
        >>> fileStr._IO_buf_base = 0xcafebabe
223
        >>> fileStr._IO_buf_end = 0xfacef00d
224
        >>> payload = bytes(fileStr)
225
        >>> payload
226
        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'
227

228
        Check the length of the FileStructure
229

230
        >>> len(fileStr)
231
        224
232

233
        The definition 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
234

235
        >>> q=FileStructure(0xdeadbeef)
236
        >>> q.flags = IO_flags._IO_MAGIC | IO_flags._IO_USER_BUF
237
        >>> q.flags._IO_TIED_PUT_GET = 1
238
        >>> q
239
        { flags: 0xfbad0401 (_IO_USER_BUF | _IO_TIED_PUT_GET | _IO_MAGIC)
240
         _IO_read_ptr: 0x0
241
         _IO_read_end: 0x0
242
         _IO_read_base: 0x0
243
         _IO_write_base: 0x0
244
         _IO_write_ptr: 0x0
245
         _IO_write_end: 0x0
246
         _IO_buf_base: 0x0
247
         _IO_buf_end: 0x0
248
         _IO_save_base: 0x0
249
         _IO_backup_base: 0x0
250
         _IO_save_end: 0x0
251
         markers: 0x0
252
         chain: 0x0
253
         fileno: 0x0
254
         _flags2: 0x0 ()
255
         _old_offset: 0xffffffffffffffff
256
         _cur_column: 0x0
257
         _vtable_offset: 0x0
258
         _shortbuf: 0x0
259
         unknown1: 0x0
260
         _lock: 0xdeadbeef
261
         _offset: 0xffffffffffffffff
262
         _codecvt: 0x0
263
         _wide_data: 0xdeadbeef
264
         _freeres_list: 0x0
265
         _freeres_buf: 0x0
266
         _pad5: 0x0
267
         _mode: 0x0
268
         _unused2: 0x0
269
         vtable: 0x0}
270
    """
271

272
    vars_=[]
2✔
273
    length={}
2✔
274

275
    def __init__(self, null=0):
2✔
276
            self.vars_ = [variables[i]['name'] for i in sorted(variables.keys())]
2✔
277
            self.setdefault(null)
2✔
278
            self.length = _update_var(context.bytes)
2✔
279
            self._old_offset = (1 << context.bits) - 1
2✔
280

281
    def __setattr__(self,item,value):
2✔
282
        if item in FileStructure.__dict__ or item in self.vars_:
2!
283
            if hasattr(self, item) and isinstance(getattr(self, item), _FlagsUnionBase):
2✔
284
                if isinstance(value, (bytes, bytearray)):
2✔
285
                    getattr(self, item)._flags = unpack(value.ljust(context.bytes, b'\x00'))
2✔
286
                else:
287
                    getattr(self, item)._flags = value
2✔
288
            else:
289
                object.__setattr__(self,item,value)
2✔
290
        else:
291
            log.error("Unknown variable %r" % item)
×
292

293
    def __repr__(self):
2✔
294
        structure=[]
2✔
295
        for i in self.vars_:
2✔
296
            val = getattr(self, i)
2✔
297
            if isinstance(val, int):
2✔
298
                structure.append(" %s: %#x" % (i, val))
2✔
299
            else:
300
                structure.append(" %s: %s" % (i, val))
2✔
301
        return "{"+ "\n".join(structure)+"}"
2✔
302

303
    def __len__(self):
2✔
304
        return len(bytes(self))
2✔
305

306
    def __bytes__(self):
2✔
307
        structure = b''
2✔
308
        for val in self.vars_:
2✔
309
            if isinstance(getattr(self, val), bytes):
2!
UNCOV
310
                structure += getattr(self, val).ljust(context.bytes, b'\x00')
×
311
            else:
312
                if self.length[val] > 0:
2!
313
                    structure += pack(int(getattr(self, val)), self.length[val]*8)
2✔
314
        return structure
2✔
315

316
    def struntil(self,v):
2✔
317
        r"""
318
        Payload for stuff till 'v' where 'v' is a structure member. This payload includes 'v' as well.
319

320
        Arguments:
321
            v(string)
322
                The name of the field uptil which the payload should be created.
323

324
        Example:
325

326
            Payload for data uptil _IO_buf_end
327

328
            >>> context.clear(arch='amd64')
329
            >>> fileStr = FileStructure(0xdeadbeef)
330
            >>> payload = fileStr.struntil("_IO_buf_end")
331
            >>> payload
332
            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'
333
        """
334
        if v not in self.vars_:
2!
335
            return b''
×
336
        structure = b''
2✔
337
        for val in self.vars_:
2!
338
            if isinstance(getattr(self, val), bytes):
2!
339
                structure += getattr(self, val).ljust(context.bytes, b'\x00')
×
340
            else:
341
                structure += pack(int(getattr(self, val)), self.length[val]*8)
2✔
342
            if val == v:
2✔
343
                break
2✔
344
        return structure[:-1]
2✔
345

346
    def setdefault(self,null):
2✔
347
            self.flags=_IOFileFlags()
2✔
348
            self._IO_read_ptr=0
2✔
349
            self._IO_read_end=0
2✔
350
            self._IO_read_base=0
2✔
351
            self._IO_write_base=0
2✔
352
            self._IO_write_ptr=0
2✔
353
            self._IO_write_end=0
2✔
354
            self._IO_buf_base=0
2✔
355
            self._IO_buf_end=0
2✔
356
            self._IO_save_base=0
2✔
357
            self._IO_backup_base=0
2✔
358
            self._IO_save_end=0
2✔
359
            self.markers=0
2✔
360
            self.chain=0
2✔
361
            self.fileno=0
2✔
362
            self._flags2=_IOFileFlags2()
2✔
363
            self._old_offset=0
2✔
364
            self._cur_column=0
2✔
365
            self._vtable_offset=0
2✔
366
            self._shortbuf=0
2✔
367
            self.unknown1=0
2✔
368
            self._lock=null
2✔
369
            self._offset=0xffffffffffffffff
2✔
370
            self._codecvt=0
2✔
371
            self._wide_data=null
2✔
372
            self._freeres_list=0
2✔
373
            self._freeres_buf=0
2✔
374
            self._pad5=0
2✔
375
            self._mode=0
2✔
376
            self._unused2=0
2✔
377
            self.vtable=0
2✔
378

379
    def write(self,addr=0,size=0):
2✔
380
        r"""
381
        Writing data out from arbitrary memory address.
382

383
        Arguments:
384
            addr(int)
385
                The address from which data is to be printed to stdout
386
            size(int)
387
                The size, in bytes, of the data to be printed
388

389
        Example:
390

391
            Payload for writing 100 bytes to stdout from the address 0xcafebabe
392

393
            >>> context.clear(arch='amd64')
394
            >>> fileStr = FileStructure(0xdeadbeef)
395
            >>> payload = fileStr.write(addr=0xcafebabe, size=100)
396
            >>> payload
397
            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'
398
        """
399
        self.flags._IO_NO_WRITES = 0
2✔
400
        self.flags._IO_CURRENTLY_PUTTING = 1
2✔
401
        self._IO_write_base = addr
2✔
402
        self._IO_write_ptr = addr+size
2✔
403
        self._IO_read_end = addr
2✔
404
        self.fileno = 1
2✔
405
        return self.struntil('fileno')
2✔
406

407
    def read(self,addr=0,size=0):
2✔
408
        r"""
409
        Reading data into arbitrary memory location.
410

411
        Arguments:
412
            addr(int)
413
                The address into which data is to be written from stdin
414
            size(int)
415
                The size, in bytes, of the data to be written
416

417
        Example:
418

419
            Payload for reading 100 bytes from stdin into the address 0xcafebabe
420

421
            >>> context.clear(arch='amd64')
422
            >>> fileStr = FileStructure(0xdeadbeef)
423
            >>> payload = fileStr.read(addr=0xcafebabe, size=100)
424
            >>> payload
425
            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'
426
        """
427
        self.flags._IO_NO_READS = 0
2✔
428
        self._IO_read_base = 0
2✔
429
        self._IO_read_ptr = 0
2✔
430
        self._IO_buf_base = addr
2✔
431
        self._IO_buf_end = addr+size
2✔
432
        self.fileno = 0
2✔
433
        return self.struntil('fileno')
2✔
434

435
    def orange(self,io_list_all,vtable):
2✔
436
        r"""
437
        Perform a House of Orange (https://github.com/shellphish/how2heap/blob/master/glibc_2.23/house_of_orange.c), provided you have libc leaks.
438

439
        Arguments:
440
            io_list_all(int)
441
                Address of _IO_list_all in libc.
442
            vtable(int)
443
                Address of the fake vtable in memory
444

445
        Example:
446

447
            Example payload if address of _IO_list_all is 0xfacef00d and fake vtable is at 0xcafebabe -
448

449
            >>> context.clear(arch='amd64')
450
            >>> fileStr = FileStructure(0xdeadbeef)
451
            >>> payload = fileStr.orange(io_list_all=0xfacef00d, vtable=0xcafebabe)
452
            >>> payload
453
            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'
454
        """
455
        if context.bits == 64:
2!
456
            self.flags = b'/bin/sh\x00'
2✔
457
            self._IO_read_ptr = 0x61
2✔
458
            self._IO_read_base = io_list_all-0x10
2✔
459
        elif context.bits == 32:
×
460
            self.flags = b'sh\x00'
×
461
            self._IO_read_ptr = 0x121
×
462
            self._IO_read_base = io_list_all-0x8
×
463
        self._IO_write_base = 0
2✔
464
        self._IO_write_ptr = 1
2✔
465
        self.vtable = vtable
2✔
466
        return self.__bytes__()
2✔
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