mirror of
https://github.com/maride/barf.git
synced 2024-12-22 06:27:29 +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"])
|
||||
|
||||
# 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 ;)
|
||||
Bruteforce(bm, tm, args["knownPrefix"], args["knownSuffix"], args["chunksize"])
|
||||
|
@ -14,14 +14,10 @@ def BruteforceChar(bm, tm, knownPrefix, knownSuffix, chunksize):
|
||||
|
||||
found = False
|
||||
|
||||
## detect best score
|
||||
# we want to get the score for "everything correct except last character".
|
||||
# we do this by combining knownPrefix + keyFragment with an "impossible" character.
|
||||
# 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.
|
||||
# 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()
|
||||
# detect best score
|
||||
refScore = Calibrate(bm, tm, knownPrefix + keyFragment, knownSuffix, chunksize)
|
||||
if refScore is False:
|
||||
return False
|
||||
|
||||
# iterate over every character in the charset
|
||||
for c in generateCharset(chunksize):
|
||||
@ -29,9 +25,7 @@ def BruteforceChar(bm, tm, knownPrefix, knownSuffix, chunksize):
|
||||
inp = knownPrefix + keyFragment + c + knownSuffix
|
||||
|
||||
# and try it
|
||||
bm.ResetBreakpoints()
|
||||
tm.Run(inp)
|
||||
score = bm.PopScore()
|
||||
score = RunAndScore(bm, tm, inp)
|
||||
|
||||
# yay, that's a hit
|
||||
if score > refScore or bm.HitWin():
|
||||
@ -79,6 +73,38 @@ def Bruteforce(bm, tm, knownPrefix, knownSuffix, chunksize):
|
||||
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.
|
||||
# the chunksize is the amount of characters to stuff into an entry
|
||||
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.
|
||||
# That means it is designed to have a unified interface, independent of e.g. persistent mode.
|
||||
class TargetManager:
|
||||
breakpointManager = None
|
||||
usePersistent = False
|
||||
|
||||
# vars used for persistent mode
|
||||
@ -22,11 +23,13 @@ class TargetManager:
|
||||
checkpointIndex = 1
|
||||
isRunning = False
|
||||
|
||||
# bm is the BreakpointManager in use
|
||||
# usePersistent is a boolean, determing if the experimental persistent mode should be used
|
||||
# startAddr is the address to start the persistent run
|
||||
# endAddr is the address to jump back to startAddr
|
||||
# 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
|
||||
|
||||
if usePersistent:
|
||||
@ -68,6 +71,9 @@ class TargetManager:
|
||||
# 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
|
||||
# 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
|
||||
# means we just need to feed input into the binary, then continue running it
|
||||
|
Loading…
Reference in New Issue
Block a user