Skip to content

Commit 2cf9106

Browse files
committed
Add format string for no_dollars
And also reduce payload lengths to minimum. Closes Gallopsled#2130 Closes Gallopsled#2532
1 parent a76db16 commit 2cf9106

File tree

1 file changed

+31
-7
lines changed

1 file changed

+31
-7
lines changed

pwnlib/fmtstr.py

+31-7
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@ def send_payload(payload):
104104
from pwnlib.memleak import MemLeak
105105
from pwnlib.util.cyclic import *
106106
from pwnlib.util.fiddling import randoms
107+
from pwnlib.util.misc import align
107108
from pwnlib.util.packing import *
108109

109110
log = getLogger(__name__)
@@ -931,10 +932,11 @@ class FmtStr(object):
931932
932933
"""
933934

934-
def __init__(self, execute_fmt, offset=None, padlen=0, numbwritten=0, badbytes=frozenset()):
935+
def __init__(self, execute_fmt, offset=None, padlen=0, numbwritten=0, badbytes=frozenset(), no_dollars=False):
935936
self.execute_fmt = execute_fmt
936937
self.offset = offset
937938
self.padlen = padlen
939+
self.no_dollars = no_dollars
938940
self.numbwritten = numbwritten
939941
self.badbytes = badbytes
940942

@@ -946,23 +948,29 @@ def __init__(self, execute_fmt, offset=None, padlen=0, numbwritten=0, badbytes=f
946948
self.leaker = MemLeak(self._leaker)
947949

948950
def leak_stack(self, offset, prefix=b""):
949-
payload = b"START%%%d$pEND" % offset
951+
if self.no_dollars:
952+
payload = b'%c' * (offset - 1) + b'START%pEND'
953+
else:
954+
payload = b"START%%%d$pEND" % offset
955+
950956
leak = self.execute_fmt(prefix + payload)
951957
try:
952958
leak = re.findall(br"START(.*?)END", leak, re.MULTILINE | re.DOTALL)[0]
953959
leak = int(leak, 16)
954960
except ValueError:
955961
leak = 0
962+
except IndexError:
963+
log.error("Cannot leak anything: exec_fmt not returning formatted data")
956964
return leak
957965

958966
def find_offset(self):
959-
marker = cyclic(20)
967+
marker = cyclic(context.bytes + 3)
960968
for off in range(1,1000):
961969
leak = self.leak_stack(off, marker)
962970
leak = pack(leak)
963971

964972
pad = cyclic_find(leak[:4])
965-
if pad >= 0 and pad < 20:
973+
if 0 <= pad < context.bytes:
966974
return off, pad
967975
else:
968976
log.error("Could not find offset to format string on stack")
@@ -978,9 +986,25 @@ def _leaker(self, addr):
978986
if addr & 0xfff == 0 and self.leaker._leak(addr+1, 3, False) == b"ELF":
979987
return b"\x7f"
980988

989+
max_len = self.padlen + 8 + context.bytes
990+
for _ in range(33):
991+
offset = self.offset + max_len // context.bytes
992+
if self.no_dollars:
993+
payload = b'%c' * (offset - 1) + b'START%sEND'
994+
else:
995+
payload = b"START%%%d$sEND" % offset
996+
if len(payload) > max_len:
997+
max_len += align(len(payload) - max_len, context.bytes)
998+
else:
999+
break
1000+
else:
1001+
raise RuntimeError("this is a bug ... format string building did not converge")
1002+
9811003
fmtstr = fit({
982-
self.padlen: b"START%%%d$sEND" % (self.offset + 16//context.bytes),
983-
16 + self.padlen: addr
1004+
self.padlen: {
1005+
0: payload,
1006+
max_len: addr
1007+
}
9841008
})
9851009

9861010
leak = self.execute_fmt(fmtstr)
@@ -1000,7 +1024,7 @@ def execute_writes(self):
10001024
10011025
"""
10021026
fmtstr = randoms(self.padlen).encode()
1003-
fmtstr += fmtstr_payload(self.offset, self.writes, numbwritten=self.padlen + self.numbwritten, badbytes=self.badbytes, write_size='byte')
1027+
fmtstr += fmtstr_payload(self.offset, self.writes, numbwritten=self.padlen + self.numbwritten, badbytes=self.badbytes, no_dollars=self.no_dollars, write_size='byte')
10041028
self.execute_fmt(fmtstr)
10051029
self.writes = {}
10061030

0 commit comments

Comments
 (0)