@@ -104,6 +104,7 @@ def send_payload(payload):
104
104
from pwnlib .memleak import MemLeak
105
105
from pwnlib .util .cyclic import *
106
106
from pwnlib .util .fiddling import randoms
107
+ from pwnlib .util .misc import align
107
108
from pwnlib .util .packing import *
108
109
109
110
log = getLogger (__name__ )
@@ -931,10 +932,11 @@ class FmtStr(object):
931
932
932
933
"""
933
934
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 ):
935
936
self .execute_fmt = execute_fmt
936
937
self .offset = offset
937
938
self .padlen = padlen
939
+ self .no_dollars = no_dollars
938
940
self .numbwritten = numbwritten
939
941
self .badbytes = badbytes
940
942
@@ -946,23 +948,29 @@ def __init__(self, execute_fmt, offset=None, padlen=0, numbwritten=0, badbytes=f
946
948
self .leaker = MemLeak (self ._leaker )
947
949
948
950
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
+
950
956
leak = self .execute_fmt (prefix + payload )
951
957
try :
952
958
leak = re .findall (br"START(.*?)END" , leak , re .MULTILINE | re .DOTALL )[0 ]
953
959
leak = int (leak , 16 )
954
960
except ValueError :
955
961
leak = 0
962
+ except IndexError :
963
+ log .error ("Cannot leak anything: exec_fmt not returning formatted data" )
956
964
return leak
957
965
958
966
def find_offset (self ):
959
- marker = cyclic (20 )
967
+ marker = cyclic (context . bytes + 3 )
960
968
for off in range (1 ,1000 ):
961
969
leak = self .leak_stack (off , marker )
962
970
leak = pack (leak )
963
971
964
972
pad = cyclic_find (leak [:4 ])
965
- if pad >= 0 and pad < 20 :
973
+ if 0 <= pad < context . bytes :
966
974
return off , pad
967
975
else :
968
976
log .error ("Could not find offset to format string on stack" )
@@ -978,9 +986,25 @@ def _leaker(self, addr):
978
986
if addr & 0xfff == 0 and self .leaker ._leak (addr + 1 , 3 , False ) == b"ELF" :
979
987
return b"\x7f "
980
988
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
+
981
1003
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
+ }
984
1008
})
985
1009
986
1010
leak = self .execute_fmt (fmtstr )
@@ -1000,7 +1024,7 @@ def execute_writes(self):
1000
1024
1001
1025
"""
1002
1026
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' )
1004
1028
self .execute_fmt (fmtstr )
1005
1029
self .writes = {}
1006
1030
0 commit comments