mirror of
https://github.com/maride/barf.git
synced 2024-12-22 22:47:30 +00:00
Properly implement calibration
This commit is contained in:
parent
50aa2e7277
commit
6619f7b966
2
barf.py
2
barf.py
@ -41,7 +41,7 @@ def main():
|
|||||||
bm = BreakpointManager(args["positiveAddr"], args["negativeAddr"], args["winAddr"])
|
bm = BreakpointManager(args["positiveAddr"], args["negativeAddr"], args["winAddr"])
|
||||||
|
|
||||||
# Manage the target with the TargetManager
|
# Manage the target with the TargetManager
|
||||||
tm = TargetManager(args["persistent"], args["startAddr"], args["endAddr"], args["buffAddr"])
|
tm = TargetManager(bm, args["persistent"], args["startAddr"], args["endAddr"], args["buffAddr"])
|
||||||
|
|
||||||
# start the bruteforcing madness ;)
|
# start the bruteforcing madness ;)
|
||||||
Bruteforce(bm, tm, args["knownPrefix"], args["knownSuffix"], args["chunksize"])
|
Bruteforce(bm, tm, args["knownPrefix"], args["knownSuffix"], args["chunksize"])
|
||||||
|
@ -14,14 +14,10 @@ def BruteforceChar(bm, tm, knownPrefix, knownSuffix, chunksize):
|
|||||||
|
|
||||||
found = False
|
found = False
|
||||||
|
|
||||||
## detect best score
|
# detect best score
|
||||||
# we want to get the score for "everything correct except last character".
|
refScore = Calibrate(bm, tm, knownPrefix + keyFragment, knownSuffix, chunksize)
|
||||||
# we do this by combining knownPrefix + keyFragment with an "impossible" character.
|
if refScore is False:
|
||||||
# the resulting score is the base for the next round of guessing, hopefully with a single solution better than the score of knownPrefix + keyFragment + impossibleChar.
|
return False
|
||||||
# please also note that this will massively fail if the "impossible" character is part of the flag, at the very position it was tested on ... have fun detecting that
|
|
||||||
bm.ResetBreakpoints()
|
|
||||||
tm.Run(knownPrefix + keyFragment + "^" * chunksize + knownSuffix)
|
|
||||||
refScore = bm.PopScore()
|
|
||||||
|
|
||||||
# iterate over every character in the charset
|
# iterate over every character in the charset
|
||||||
for c in generateCharset(chunksize):
|
for c in generateCharset(chunksize):
|
||||||
@ -29,9 +25,7 @@ def BruteforceChar(bm, tm, knownPrefix, knownSuffix, chunksize):
|
|||||||
inp = knownPrefix + keyFragment + c + knownSuffix
|
inp = knownPrefix + keyFragment + c + knownSuffix
|
||||||
|
|
||||||
# and try it
|
# and try it
|
||||||
bm.ResetBreakpoints()
|
score = RunAndScore(bm, tm, inp)
|
||||||
tm.Run(inp)
|
|
||||||
score = bm.PopScore()
|
|
||||||
|
|
||||||
# yay, that's a hit
|
# yay, that's a hit
|
||||||
if score > refScore or bm.HitWin():
|
if score > refScore or bm.HitWin():
|
||||||
@ -79,6 +73,38 @@ def Bruteforce(bm, tm, knownPrefix, knownSuffix, chunksize):
|
|||||||
return knownPrefix + knownSuffix
|
return knownPrefix + knownSuffix
|
||||||
|
|
||||||
|
|
||||||
|
# Finds out the base score when filling the binary with partly correct chars (e.g. the already found-to-be-correct prefix)
|
||||||
|
# It does this by combining knownPrefix + keyFragment and knownSuffix with an "impossible" character.
|
||||||
|
# We're only able to proceed if every character (except one) returns the same score - the "except one" score is the winner ;)
|
||||||
|
# Note that this function will massively fail if the "impossible" character is part of the flag, at the very position it was tested on ... have fun detecting that
|
||||||
|
def Calibrate(bm, tm, prefix, suffix, chunksize):
|
||||||
|
score1 = RunAndScore(bm, tm, prefix + '^' * chunksize + suffix)
|
||||||
|
score2 = RunAndScore(bm, tm, prefix + '`' * chunksize + suffix)
|
||||||
|
|
||||||
|
if score1 == score2:
|
||||||
|
# we found a stable score, return it
|
||||||
|
return score1
|
||||||
|
else:
|
||||||
|
# There is some kind of inconsistency in the executable, stop here.
|
||||||
|
EnableLogging()
|
||||||
|
print(score1)
|
||||||
|
print(score2)
|
||||||
|
print("BARF was unable to calibrate.")
|
||||||
|
print("While this may have multiple reasons, the most realistic are:")
|
||||||
|
print(" - The specified binary is not solvable on a round-based approach")
|
||||||
|
print(" -> reverse the binary further - is there some shuffeling mechanism in place?")
|
||||||
|
print(" - The 'no way that character is part of the flag' charset is actually part of the flag")
|
||||||
|
DisableLogging()
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
# Runs the given input and returns its breakpoint score
|
||||||
|
def RunAndScore(bm, tm, inp):
|
||||||
|
bm.ResetBreakpoints()
|
||||||
|
tm.Run(inp)
|
||||||
|
return bm.PopScore()
|
||||||
|
|
||||||
|
|
||||||
# generateCharset returns an iteratable object (string or set) to be used by the bruteforce function.
|
# generateCharset returns an iteratable object (string or set) to be used by the bruteforce function.
|
||||||
# the chunksize is the amount of characters to stuff into an entry
|
# the chunksize is the amount of characters to stuff into an entry
|
||||||
def generateCharset(chunksize):
|
def generateCharset(chunksize):
|
||||||
|
@ -13,6 +13,7 @@ from PersistenceBreakpoint import PersistenceBreakpoint
|
|||||||
# The TargetManager aims to be the one-size-fits-all solution for execution handling.
|
# The TargetManager aims to be the one-size-fits-all solution for execution handling.
|
||||||
# That means it is designed to have a unified interface, independent of e.g. persistent mode.
|
# That means it is designed to have a unified interface, independent of e.g. persistent mode.
|
||||||
class TargetManager:
|
class TargetManager:
|
||||||
|
breakpointManager = None
|
||||||
usePersistent = False
|
usePersistent = False
|
||||||
|
|
||||||
# vars used for persistent mode
|
# vars used for persistent mode
|
||||||
@ -22,11 +23,13 @@ class TargetManager:
|
|||||||
checkpointIndex = 1
|
checkpointIndex = 1
|
||||||
isRunning = False
|
isRunning = False
|
||||||
|
|
||||||
|
# bm is the BreakpointManager in use
|
||||||
# usePersistent is a boolean, determing if the experimental persistent mode should be used
|
# usePersistent is a boolean, determing if the experimental persistent mode should be used
|
||||||
# startAddr is the address to start the persistent run
|
# startAddr is the address to start the persistent run
|
||||||
# endAddr is the address to jump back to startAddr
|
# endAddr is the address to jump back to startAddr
|
||||||
# buffAddr is the address of the target buffer to be written in persistent mode
|
# buffAddr is the address of the target buffer to be written in persistent mode
|
||||||
def __init__(self, usePersistent, startAddr, endAddr, buffAddr):
|
def __init__(self, bm, usePersistent, startAddr, endAddr, buffAddr):
|
||||||
|
self.breakpointManager = bm
|
||||||
self.usePersistent = usePersistent
|
self.usePersistent = usePersistent
|
||||||
|
|
||||||
if usePersistent:
|
if usePersistent:
|
||||||
@ -68,6 +71,9 @@ class TargetManager:
|
|||||||
# Please note, as this may cast some confusion, that at this point the binary
|
# Please note, as this may cast some confusion, that at this point the binary
|
||||||
# had a full run-thru, is equipped with checkpoints and breakpoints and is
|
# had a full run-thru, is equipped with checkpoints and breakpoints and is
|
||||||
# currently in break mode (not running, so to speak), and is at startAddr.
|
# currently in break mode (not running, so to speak), and is at startAddr.
|
||||||
|
# But, because we likely already hit some breakpoints (depends on the executable),
|
||||||
|
# we need to reset the scores.
|
||||||
|
self.breakpointManager.ResetBreakpoints()
|
||||||
|
|
||||||
# the executable is already running and reset
|
# the executable is already running and reset
|
||||||
# means we just need to feed input into the binary, then continue running it
|
# means we just need to feed input into the binary, then continue running it
|
||||||
|
Loading…
Reference in New Issue
Block a user