This repository was archived by the owner on Jul 7, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 7
Expand file tree
/
Copy pathcontext.py
More file actions
127 lines (114 loc) · 5.36 KB
/
context.py
File metadata and controls
127 lines (114 loc) · 5.36 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
'''A redefinition of pwntools' `context` to add on
some additional context attributes.'''
from os import path
from pwnlib import context
from pwnlib.log import getLogger
from pwnlib.elf.elf import ELF
# IMPORTANT: pwnscripts must not be a relative import to prevent circular importing
import pwnscripts
log = getLogger('pwnlib.exploit')
__all__ = ['context', '_pwntools_context']
_pwntools_context = context.context
_pwnscripts_LOCALS = ['libc_database', 'libc', 'binary', 'clear', 'is_local', '_local']
class ContextType(context.ContextType):
'''This is the extended class that inherits from
pwnlib.context.ContextType. You can use it to spawn a
_new_ context, but a new `ContextType()` will not* affect
pwnlib's original internal `pwnlib.context.context`,
and consequently will not provide expected behaviour.
Basically, don't init this object unless you know what you're doing.
*Unfortunately, assigning to .binary *will* currently affect pwntools' context.
This is planned to be fixed.
'''
# Waiting for python3.9's dict unions here...
defaults = {**context.ContextType.defaults,
**{'libc_database': None, 'libc': None, 'binary': None, '_local': None}}
@context._validator
def _local(self, state: bool) -> bool: # simple wrapper to fit into `context`'s framework
if isinstance(state, bool): return state
@property
def is_local(self) -> bool:
'''Check if the most recently opened tube was a local process().
Returns: bool.
True if pwnscripts observed a local binary process(),
False if pwnscripts observed a remote() connection,
RuntimeError if neither has been detected.
''' # NOTE: this attribute should be updated by other parts of pwnscripts.
if isinstance(self._local, bool): return self._local
raise RuntimeError('pwnscripts.context: no running tubes have been detected thus far.')
def clear(self, *a, **kw):
'''overwritten pwnscripts method: clear pwnscripts context as well
'''
self._tls._current.clear()
super().clear(*a, **kw)
@context._validator
def binary(self, binary):
'''overwritten pwnscripts method: spawn context.binary with pwnscript's ELF()
'''
# Some parts of pwnlib make use of context.binary, so we need to write to _pwntools_context
# This breaks the original design of ContextType, but no better solution has been concieved
_pwntools_context.binary = binary
if not isinstance(binary, ELF): # This is pwnlib's ELF
binary = pwnscripts.elf.ELF(binary)
return binary
@context._validator
def libc_database(self, db_dir: str):
'''
>>> context.libc_database = 'libc-database'
>>> context.libc_database
<pwnscripts.libcdb_query.libc_database object at 0x7fffffffffff>
'''
return pwnscripts.libc_database(db_dir)
@context._validator
def libc(self, assigned: str):
'''
>>> context.libc_database = 'libc-database'
>>> context.libc = 'examples/libc.so.6'
[*] '/path/to/pwnscripts/libc-database/db/libc6_2.27-3ubuntu1_amd64.so'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: PIE enabled
>>> context.libc
libc('/path/to/pwnscripts/libc-database/db/libc6_2.27-3ubuntu1_amd64.so')
or
>>> context.libc = 'libc6_2.27-3ubuntu1_amd64'
[*] libc=`'libc6_2.27-3ubuntu1_amd64'' is not a file; assuming a libc-database id was given!
>>> context.libc
libc('/path/to/pwnscripts/libc-database/db/libc6_2.27-3ubuntu1_amd64.so')
'''
if not isinstance(assigned, str): # assume a libc() object was given
return assigned
if path.isfile(assigned): # assume binary
return pwnscripts.libc(binary=assigned)
# assume id
log.info("libc=`%r' is not a file; assuming a libc-database id was given!" % assigned)
return pwnscripts.libc(id=assigned)
_pwnscripts_context = ContextType()
class ContextWrapper(ContextType):
'''Wrapper over pwnlib.context.context so that modifications to
pwnscripts.context.context will propagate correctly to the rest of pwnlib
This wrapper is highly prone to unexpected behaviour. If you're reading this
and you have a better programmatic suggestion, please raise an Issue/PullRequest!
An example of unexpected behaviour:
>>> with context.local(log_level='info'): context.arch = 'arm'
>>> context.arch == 'arm'
False
>>> with context.local(log_level='info'): context.binary = 'mybinary'
>>> context.binary is None
False
In the first instance, context.arch is not preserved (*expected behaviour*)
because it's assignment should be contained to the with-statement.
In the second instance, context.binary *is preserved* because it is one of the
overwritten methods in pwnscripts.
'''
def __setattr__(self, attr, value):
if attr not in _pwnscripts_LOCALS:
return setattr(_pwntools_context, attr, value)
return setattr(_pwnscripts_context, attr, value)
def __getattribute__(self, attr):
if attr not in _pwnscripts_LOCALS:
return getattr(_pwntools_context, attr)
return getattr(_pwnscripts_context, attr)
context = ContextWrapper()