pwnlib.memleak
— Helper class for leaking memory¶
-
class
pwnlib.memleak.
MemLeak
(f, search_range=20, reraise=True, relative=False)[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') >>> @pwnlib.memleak.MemLeak ... def leaker(addr): ... print "leaking 0x%x" % addr ... return binsh[addr:addr+4] >>> leaker.s(0)[:4] leaking 0x0 leaking 0x4 '\x7fELF' >>> leaker[:4] '\x7fELF' >>> hex(leaker.d(0)) '0x464c457f' >>> hex(leaker.clearb(1)) '0x45' >>> hex(leaker.d(0)) leaking 0x1 '0x464c457f' >>> @pwnlib.memleak.MemLeak ... def leaker_nonulls(addr): ... print "leaking 0x%x" % addr ... if addr & 0xff == 0: ... return None ... return binsh[addr:addr+4] >>> leaker_nonulls.d(0) == None leaking 0x0 True >>> leaker_nonulls[0x100:0x104] == binsh[0x100:0x104] leaking 0x100 leaking 0xff leaking 0x103 True
>>> memory = {-4+i: c for i,c in enumerate('wxyzABCDE')} >>> def relative_leak(index): ... return memory.get(index, None) >>> leak = pwnlib.memleak.MemLeak(relative_leak, relative = True) >>> leak[-1:2] 'zAB'
-
static
NoNewlines
(function)[source]¶ Wrapper for leak functions such that addresses which contain newline bytes are not leaked.
This is useful if the address which is used for the leak is provided by e.g.
fgets()
.
-
static
NoNulls
(function)[source]¶ Wrapper for leak functions such that addresses which contain NULL bytes are not leaked.
This is useful if the address which is used for the leak is read in via a string-reading function like
scanf("%s")
or smilar.
-
static
NoWhitespace
(function)[source]¶ Wrapper for leak functions such that addresses which contain whitespace bytes are not leaked.
This is useful if the address which is used for the leak is read in via e.g.
scanf()
.
-
static
String
(function)[source]¶ Wrapper for leak functions which leak strings, such that a NULL terminator is automaticall added.
This is useful if the data leaked is printed out as a NULL-terminated string, via e.g.
printf()
.
-
b
(addr, ndx = 0) → int[source]¶ Leak byte at
((uint8_t*) addr)[ndx]
Examples
>>> import string >>> data = string.ascii_lowercase >>> 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:'a'} >>> l.n(0,1) == 'a' True >>> l.clearb(0) == unpack('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:'a', 1: 'b', 2: 'c', 3: 'd'} >>> l.n(0, 4) == 'abcd' True >>> l.cleard(0) == unpack('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: '') >>> c.cache = {x:'x' for x in range(0x100, 0x108)} >>> c.clearq(0x100) == unpack('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:'a', 1: 'b'} >>> l.n(0, 2) == 'ab' True >>> l.clearw(0) == unpack('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 >>> l = MemLeak(lambda a: data[a:a+8], reraise=False) >>> l.d(0) == unpack('abcd', 32) True >>> l.d(22) == unpack('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
.
-
field_compare
(address, obj, expected)[source]¶ field_compare(address, field, expected) ==> bool
Leak a field from a structure, with an expected value. As soon as any mismatch is found, stop leaking the structure.
Parameters: - Return Value:
- The type of the return value will be dictated by
the type of
field
.
-
n
(addr, ndx = 0) → str[source]¶ Leak numb bytes at addr.
Returns: A string with the leaked bytes, will return None if any are missing Examples
>>> import string >>> data = string.ascii_lowercase >>> l = MemLeak(lambda a: data[a:a+4], reraise=False) >>> l.n(0,1) == 'a' True >>> l.n(0,26) == data True >>> len(l.n(0,26)) == 26 True >>> l.n(0,27) is None True
-
p16
(addr, val, ndx=0)[source]¶ Sets word at
((uint16_t*)addr)[ndx]
to val in the cache.Examples
>>> l = MemLeak(lambda x: '') >>> l.cache == {} True >>> l.setw(33, 0x41) >>> l.cache == {33: 'A', 34: '\x00'} True
-
p32
(addr, val, ndx=0)[source]¶ Sets dword at
((uint32_t*)addr)[ndx]
to val in the cache.Examples
See
setw()
.
-
p64
(addr, val, ndx=0)[source]¶ Sets qword at
((uint64_t*)addr)[ndx]
to val in the cache.Examples
See
setw()
.
-
p8
(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: 'A'} True
-
q
(addr, ndx = 0) → int[source]¶ Leak qword at
((uint64_t*) addr)[ndx]
Examples
>>> import string >>> data = string.ascii_lowercase >>> l = MemLeak(lambda a: data[a:a+16], reraise=False) >>> l.q(0) == unpack('abcdefgh', 64) True >>> l.q(18) == unpack('stuvwxyz', 64) True >>> l.q(19) is None True
-
s
(addr) → str[source]¶ Leak bytes at addr until failure or a nullbyte is found
Returns: A string, without a NULL terminator. The returned string will be empty if the first byte is a NULL terminator, or if the first byte could not be retrieved. Examples
>>> data = "Hello\x00World" >>> l = MemLeak(lambda a: data[a:a+4], reraise=False) >>> l.s(0) == "Hello" True >>> l.s(5) == "" True >>> l.s(6) == "World" True >>> l.s(999) == "" 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: '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, 'H\x00ello') >>> l.cache == {0: 'H', 1: '\x00', 2: 'e', 3: 'l', 4: 'l', 5: 'o', 6: '\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: '') >>> l.cache == {} True >>> l.setw(33, 0x41) >>> l.cache == {33: 'A', 34: '\x00'} True
-
struct
(address, struct)[source]¶ struct(address, struct) => structure object Leak an entire structure. :param address: Addess of structure in memory :type address: int :param struct: A ctypes structure to be instantiated with leaked data :type struct: class
- Return Value:
- An instance of the provided struct class, with the leaked data decoded
Examples
>>> @pwnlib.memleak.MemLeak ... def leaker(addr): ... return "A" >>> e = leaker.struct(0, pwnlib.elf.Elf32_Phdr) >>> hex(e.p_paddr) '0x41414141'
-
u16
(addr, ndx=0)[source]¶ w(addr, ndx = 0) -> int
Leak word at
((uint16_t*) addr)[ndx]
Examples
>>> import string >>> data = string.ascii_lowercase >>> l = MemLeak(lambda a: data[a:a+4], reraise=False) >>> l.w(0) == unpack('ab', 16) True >>> l.w(24) == unpack('yz', 16) True >>> l.w(25) is None True
-
u32
(addr, ndx=0)[source]¶ d(addr, ndx = 0) -> int
Leak dword at
((uint32_t*) addr)[ndx]
Examples
>>> import string >>> data = string.ascii_lowercase >>> l = MemLeak(lambda a: data[a:a+8], reraise=False) >>> l.d(0) == unpack('abcd', 32) True >>> l.d(22) == unpack('wxyz', 32) True >>> l.d(23) is None True
-
u64
(addr, ndx=0)[source]¶ q(addr, ndx = 0) -> int
Leak qword at
((uint64_t*) addr)[ndx]
Examples
>>> import string >>> data = string.ascii_lowercase >>> l = MemLeak(lambda a: data[a:a+16], reraise=False) >>> l.q(0) == unpack('abcdefgh', 64) True >>> l.q(18) == unpack('stuvwxyz', 64) True >>> l.q(19) is None True