pwnlib.memleak
— Helper class for leaking memory¶
-
class
pwnlib.memleak.
MemLeak
(f, search_range=20, reraise=True)[source]¶ MemLeak is a caching and heuristic tool for exploiting memory leaks.
It can be used as a decorator, around functions of the form:
- def some_leaker(addr):
- ... return data_as_string_or_None
It will cache leaked memory (which requires either non-randomized static data or a continouous session). If required, dynamic or known data can be set with the set-functions, but this is usually not required. If a byte cannot be recovered, it will try to leak nearby bytes in the hope that the byte is recovered as a side-effect.
Parameters: Example
>>> import pwnlib >>> binsh = pwnlib.util.misc.read('/bin/sh', mode='rb') >>> @pwnlib.memleak.MemLeak ... def leaker(addr): ... print("leaking 0x%x" % addr) ... return binsh[addr:addr+4] >>> leaker.s(0)[:4] leaking 0x0 leaking 0x4 b'\x7fELF' >>> leaker[:4] b'\x7fELF' >>> hex(leaker.d(0)) '0x464c457f' >>> hex(leaker.clearb(1)) '0x45' >>> hex(leaker.d(0)) leaking 0x1 '0x464c457f' >>> @pwnlib.memleak.MemLeak ... def leaker(addr): ... if addr & 0xff == 0: ... print("leaker failed 0x%x" % addr) ... return ... print("leaking 0x%x" % addr) ... return binsh[addr:addr+4] >>> leaker.d(0) leaker failed 0x0 >>> leaker.d(0x100) == pwnlib.util.packing.u32(binsh[0x100:0x104]) leaker failed 0x100 leaking 0xff leaking 0x103 True >>> leaker[0xf0:0x110] == binsh[0xf0:0x110] == leaker.n(0xf0, 0x20) leaking 0xf0 leaking 0xf4 leaking 0xf8 leaking 0xfc leaking 0x107 leaking 0x10b leaking 0x10f True >>> import ctypes >>> class MyStruct(ctypes.Structure): ... _pack_ = True ... _fields_ = [("a", ctypes.c_char), ... ("b", ctypes.c_uint32),] >>> leaker.field(0x101, MyStruct.b) == leaker.d(0x102) True
-
b
(addr, ndx=0) → int[source]¶ Leak byte at
((uint8_t*) addr)[ndx]
Examples
>>> import string >>> data = string.ascii_lowercase.encode('utf8') >>> l = MemLeak(lambda a: data[a:a+2], reraise=False) >>> l.b(0) == ord('a') True >>> l.b(25) == ord('z') True >>> l.b(26) is None True
-
clearb
(addr, ndx=0) → int[source]¶ Clears byte at
((uint8_t*)addr)[ndx]
from the cache and returns the removed value or None if the address was not completely set.Examples
>>> l = MemLeak(lambda a: None) >>> l.cache = {0: b'a'} >>> l.n(0, 1) == b'a' True >>> l.clearb(0) == unpack(b'a', 8) True >>> l.cache {} >>> l.clearb(0) is None True
-
cleard
(addr, ndx=0) → int[source]¶ Clears dword at
((uint32_t*)addr)[ndx]
from the cache and returns the removed value or None if the address was not completely set.Examples
>>> l = MemLeak(lambda a: None) >>> l.cache = {0: b'a', 1: b'b', 2: b'c', 3: b'd'} >>> l.n(0, 4) == b'abcd' True >>> l.cleard(0) == unpack(b'abcd', 32) True >>> l.cache {}
-
clearq
(addr, ndx=0) → int[source]¶ Clears qword at
((uint64_t*)addr)[ndx]
from the cache and returns the removed value or None if the address was not completely set.Examples
>>> c = MemLeak(lambda addr: b'') >>> c.cache = {x: b'x' for x in range(0x100, 0x108)} >>> c.clearq(0x100) == unpack(b'xxxxxxxx', 64) True >>> c.cache == {} True
-
clearw
(addr, ndx=0) → int[source]¶ Clears word at
((uint16_t*)addr)[ndx]
from the cache and returns the removed value or None if the address was not completely set.Examples
>>> l = MemLeak(lambda a: None) >>> l.cache = {0: b'a', 1: b'b'} >>> l.n(0, 2) == b'ab' True >>> l.clearw(0) == unpack(b'ab', 16) True >>> l.cache {}
-
d
(addr, ndx=0) → int[source]¶ Leak dword at
((uint32_t*) addr)[ndx]
Examples
>>> import string >>> data = string.ascii_lowercase.encode('utf8') >>> l = MemLeak(lambda a: data[a:a+8], reraise=False) >>> l.d(0) == unpack(b'abcd', 32) True >>> l.d(22) == unpack(b'wxyz', 32) True >>> l.d(23) is None True
-
field
(address, obj)[source]¶ field(address, field) => a structure field.
Leak a field from a structure.
Parameters: - address (int) – Base address to calculate offsets from
- field (obj) – Instance of a ctypes field
- Return Value:
- The type of the return value will be dictated by
the type of
field
.
-
n
(addr, ndx = 0) → bytes[source]¶ Leak numb bytes at addr.
Returns: A string with the leaked bytes, or None if any are missing Examples
>>> import string >>> data = string.ascii_lowercase.encode('ascii') >>> l = MemLeak(lambda a: data[a:a+4], reraise=False) >>> l.n(0, 1) == b'a' True >>> l.n(0, 26) == data True >>> len(l.n(0, 26)) == 26 True >>> l.n(0, 27) is None True
-
q
(addr, ndx=0) → int[source]¶ Leak qword at
((uint64_t*) addr)[ndx]
Examples
>>> import string >>> data = string.ascii_lowercase.encode('utf8') >>> l = MemLeak(lambda a: data[a:a+16], reraise=False) >>> l.q(0) == unpack(b'abcdefgh', 64) True >>> l.q(18) == unpack(b'stuvwxyz', 64) True >>> l.q(19) is None True
-
raw
(addr, numb) → list[source]¶ Return a list of numb leaked bytes at addr. Bytes that could not be leaked are replaced by None.
-
rawb
(addr)[source]¶ raw(addr) -> bytes or None
Returns the byte at addr or None if it could not be leaked.
-
s
(addr) → bytes[source]¶ Leak bytes at addr until failure or a nullbyte is found
Returns: A bytes, without a NULL terminator. The returned bytes will be empty if the first byte is a NULL terminator, or if the first byte could not be retrieved. Examples
>>> data = b"Hello\x00World" >>> l = MemLeak(lambda a: data[a:a+4], reraise=False) >>> l.s(0) == b"Hello" True >>> l.s(5) == b"" True >>> l.s(6) == b"World" True >>> l.s(999) == b"" True
-
setb
(addr, val, ndx=0)[source]¶ Sets byte at
((uint8_t*)addr)[ndx]
to val in the cache.Examples
>>> l = MemLeak(lambda x: '') >>> l.cache == {} True >>> l.setb(33, 0x41) >>> l.cache == {33: b'A'} True
-
setd
(addr, val, ndx=0)[source]¶ Sets dword at
((uint32_t*)addr)[ndx]
to val in the cache.Examples
See
setw()
.
-
setq
(addr, val, ndx=0)[source]¶ Sets qword at
((uint64_t*)addr)[ndx]
to val in the cache.Examples
See
setw()
.
-
sets
(addr, val, null_terminate=True)[source]¶ Set known string at addr, which will be optionally be null-terminated
Note that this method is a bit dumb about how it handles the data. It will null-terminate the data, but it will not stop at the first null.
Examples
>>> l = MemLeak(lambda x: '') >>> l.cache == {} True >>> l.sets(0, b'H\x00ello') >>> l.cache == {0: b'H', 1: b'\x00', 2: b'e', 3: b'l', 4: b'l', 5: b'o', 6: b'\x00'} True
-
setw
(addr, val, ndx=0)[source]¶ Sets word at
((uint16_t*)addr)[ndx]
to val in the cache.Examples
>>> l = MemLeak(lambda x: b'') >>> l.cache == {} True >>> l.setw(33, 0x41) >>> l.cache == {33: b'A', 34: b'\x00'} True
-
struct
(address, struct)[source]¶ struct(address, struct) => structure object
Leak an entire structure.
Parameters: - address (int) – Address of structure in memory
- struct (class) – A ctypes structure to be instantiated with leaked data
- Return Value:
- An instance of the provided struct class, with the leaked data decoded