Skip to content

Commit e5af2bc

Browse files
authored
Fix format string badbytes inconsistency (Gallopsled#1895)
* Fix format string badbytes inconsistency Fixes Gallopsled#1888 * fmtstr: Make sure initial atom is considered
1 parent 6fa13de commit e5af2bc

File tree

1 file changed

+14
-8
lines changed

1 file changed

+14
-8
lines changed

pwnlib/fmtstr.py

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -304,14 +304,15 @@ def make_atoms_simple(address, data, badbytes=frozenset()):
304304

305305
i = 0
306306
out = []
307+
end = address + len(data)
307308
while i < len(data):
308309
candidate = AtomWrite(address + i, 1, data[i])
309-
while i + candidate.size < len(data) and any(x in badbytes for x in pack(candidate.end)):
310+
while candidate.end < end and any(x in badbytes for x in pack(candidate.end)):
310311
candidate = candidate.union(AtomWrite(candidate.end, 1, data[i + candidate.size]))
311312

312313
sz = min([s for s in SPECIFIER if s >= candidate.size] + [float("inf")])
313-
if i + sz > len(data):
314-
raise RuntimeError("impossible to avoid badbytes starting after offset %d (address %x)" % (i, i + address))
314+
if candidate.start + sz > end:
315+
raise RuntimeError("impossible to avoid badbytes starting after offset %d (address %#x)" % (i, i + address))
315316
i += candidate.size
316317
candidate = candidate.union(AtomWrite(candidate.end, sz - candidate.size, 0, 0))
317318
out.append(candidate)
@@ -498,7 +499,7 @@ def merge_atoms_overlapping(atoms, sz, szmax, numbwritten, overflows):
498499
# the best write is the one which sets the largest number of target
499500
# bytes correctly
500501
candidate = AtomWrite(atom.start, 0, 0)
501-
best = (0, None)
502+
best = (atom.size, idx, atom)
502503
for nextidx, nextatom in enumerate(atoms[idx:], idx):
503504
# if there is no atom immediately following the current candidate
504505
# that we haven't written yet, stop
@@ -527,6 +528,8 @@ def merge_atoms_overlapping(atoms, sz, szmax, numbwritten, overflows):
527528

528529
_, nextidx, best_candidate = best
529530
numbwritten_here += best_candidate.compute_padding(numbwritten_here)
531+
if numbwritten_here > maxwritten:
532+
maxwritten = numbwritten_here
530533
offset = 0
531534

532535
# for all atoms that we merged, check if all bytes are written already to update `done``
@@ -799,7 +802,7 @@ def make_atoms(writes, sz, szmax, numbwritten, overflows, strategy, badbytes):
799802
all_atoms += atoms
800803
return all_atoms
801804

802-
def fmtstr_split(offset, writes, numbwritten=0, write_size='byte', write_size_max='long', overflows=16, strategy="small", badbytes=frozenset()):
805+
def fmtstr_split(offset, writes, numbwritten=0, write_size='byte', write_size_max='long', overflows=16, strategy="small", badbytes=frozenset(), no_dollars=False):
803806
"""
804807
Build a format string like fmtstr_payload but return the string and data separately.
805808
"""
@@ -813,7 +816,7 @@ def fmtstr_split(offset, writes, numbwritten=0, write_size='byte', write_size_ma
813816
szmax = WRITE_SIZE[write_size_max]
814817
atoms = make_atoms(writes, sz, szmax, numbwritten, overflows, strategy, badbytes)
815818

816-
return make_payload_dollar(offset, atoms, numbwritten)
819+
return make_payload_dollar(offset, atoms, numbwritten, no_dollars=no_dollars)
817820

818821
def fmtstr_payload(offset, writes, numbwritten=0, write_size='byte', write_size_max='long', overflows=16, strategy="small", badbytes=frozenset(), offset_bytes=0, no_dollars=False):
819822
r"""fmtstr_payload(offset, writes, numbwritten=0, write_size='byte') -> str
@@ -844,6 +847,8 @@ def fmtstr_payload(offset, writes, numbwritten=0, write_size='byte', write_size_
844847
b'%47806c%5$lln%22649c%6$hnaaaabaa\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00'
845848
>>> fmtstr_payload(1, {0x0: 0x1337babe}, write_size='byte')
846849
b'%190c%7$lln%85c%8$hhn%36c%9$hhn%131c%10$hhnaaaab\x00\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00'
850+
>>> fmtstr_payload(6, {0x8: 0x55d15d2004a0}, badbytes=b'\n')
851+
b'%1184c%14$lln%49c%15$hhn%6963c%16$hn%81c%17$hhn%8c%18$hhnaaaabaa\x08\x00\x00\x00\x00\x00\x00\x00\x0c\x00\x00\x00\x00\x00\x00\x00\t\x00\x00\x00\x00\x00\x00\x00\r\x00\x00\x00\x00\x00\x00\x00\x0b\x00\x00\x00\x00\x00\x00\x00'
847852
>>> context.clear(arch = 'i386')
848853
>>> fmtstr_payload(1, {0x0: 0x1337babe}, write_size='int')
849854
b'%322419390c%5$na\x00\x00\x00\x00'
@@ -900,11 +905,12 @@ class FmtStr(object):
900905
901906
"""
902907

903-
def __init__(self, execute_fmt, offset=None, padlen=0, numbwritten=0):
908+
def __init__(self, execute_fmt, offset=None, padlen=0, numbwritten=0, badbytes=frozenset()):
904909
self.execute_fmt = execute_fmt
905910
self.offset = offset
906911
self.padlen = padlen
907912
self.numbwritten = numbwritten
913+
self.badbytes = badbytes
908914

909915
if self.offset is None:
910916
self.offset, self.padlen = self.find_offset()
@@ -968,7 +974,7 @@ def execute_writes(self):
968974
969975
"""
970976
fmtstr = randoms(self.padlen).encode()
971-
fmtstr += fmtstr_payload(self.offset, self.writes, numbwritten=self.padlen + self.numbwritten, write_size='byte')
977+
fmtstr += fmtstr_payload(self.offset, self.writes, numbwritten=self.padlen + self.numbwritten, badbytes=self.badbytes, write_size='byte')
972978
self.execute_fmt(fmtstr)
973979
self.writes = {}
974980

0 commit comments

Comments
 (0)