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

Gallopsled / pwntools / 16781787372

06 Aug 2025 02:43PM UTC coverage: 73.829% (+0.1%) from 73.731%
16781787372

push

github

web-flow
Decode and pretty print `_IO_*` flags in FileStructure member (#2542)

* Decode `_IO_*` flags in FileStructure member

The `_flags` and `_flags2` bitmasks are decoded to a readable string when printing the struct.
Next to setting the flags as an integer like before, you can set individual bits now and check set bits.

```
fileStr = FileStructure(null=0xdeadbeeef)
fileStr.flags = 0xfbad1807
fileStr.flags = IO_flags._IO_MAGIC | IO_flags._IO_USER_BUF | IO_flags._IO_UNBUFFERED
fileStr.flags._IO_USER_BUF = 1
```

Printing the FileStructure shows the flags in human readable form too

```
{ flags: 0xfbad0401 (_IO_USER_BUF | _IO_UNBUFFERED | _IO_MAGIC)
_IO_read_ptr: 0x0
...
```

* Update CHANGELOG

3835 of 6472 branches covered (59.26%)

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

1 existing line in 1 file now uncovered.

13442 of 18207 relevant lines covered (73.83%)

0.74 hits per line

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

93.37
/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
1✔
26
from __future__ import division
1✔
27

28
import ctypes
1✔
29

30
from pwnlib.context import context
1✔
31
from pwnlib.log import getLogger
1✔
32
from pwnlib.util.packing import pack, unpack
1✔
33

34
log = getLogger(__name__)
1✔
35

36
length=0
1✔
37
size='size'
1✔
38
name='name'
1✔
39

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

74
del name, size, length
1✔
75

76

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

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

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

88
    Examples:
89

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

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

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

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

143
    def __int__(self):
1✔
144
        return int(self._flags)
1✔
145

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

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

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

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

181

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

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

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

203

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

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

212
    Examples:
213

214
        FILE structure with flags as 0xfbad1807 and _IO_buf_base and _IO_buf_end pointing to 0xcafebabe and 0xfacef00d
215

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

226
        Check the length of the FileStructure
227

228
        >>> len(fileStr)
229
        224
230

231
        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
232

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

270
    vars_=[]
1✔
271
    length={}
1✔
272

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

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

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

301
    def __len__(self):
1✔
302
        return len(bytes(self))
1✔
303

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

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

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

322
        Example:
323

324
            Payload for data uptil _IO_buf_end
325

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

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

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

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

387
        Example:
388

389
            Payload for writing 100 bytes to stdout from the address 0xcafebabe
390

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

405
    def read(self,addr=0,size=0):
1✔
406
        r"""
407
        Reading data into arbitrary memory location.
408

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

415
        Example:
416

417
            Payload for reading 100 bytes from stdin into the address 0xcafebabe
418

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

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

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

443
        Example:
444

445
            Example payload if address of _IO_list_all is 0xfacef00d and fake vtable is at 0xcafebabe -
446

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