mirror of
https://github.com/maride/barf.git
synced 2024-12-22 14:37:29 +00:00
Split code into modules
This commit is contained in:
parent
bf068a2780
commit
a4396df9ce
216
barf.py
216
barf.py
@ -20,204 +20,13 @@
|
|||||||
# In doubt, see https://github.com/maride/barf
|
# In doubt, see https://github.com/maride/barf
|
||||||
# Have fun with the script! :)
|
# Have fun with the script! :)
|
||||||
|
|
||||||
|
# include project path as include path
|
||||||
|
sys.path.insert(1, "/home/maride/barf/src")
|
||||||
|
|
||||||
# The charset to try, sorted by the likelihood of a character class
|
# include project files
|
||||||
charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789{}_!?"
|
from BreakpointManager import BreakpointManager
|
||||||
|
from Helper import *
|
||||||
|
from Bruteforce import *
|
||||||
# Breakpoint wrapper class
|
|
||||||
# A breakpoint class with patented, award-winning score functionality.
|
|
||||||
class CounterBreakpoint(gdb.Breakpoint):
|
|
||||||
# addr is the address of the breakpoint
|
|
||||||
# isGood is a boolean, determing if the breakpoint is good-to-hit or bad-to-hit
|
|
||||||
# (means a negative breakpoint has isGood = false, and vice versa)
|
|
||||||
def __init__(self, addr, isGood):
|
|
||||||
self.isGood = isGood
|
|
||||||
self.currentScore = 0
|
|
||||||
|
|
||||||
# gdb requires address literals to start with a star
|
|
||||||
if addr[0] != "*":
|
|
||||||
addr = "*" + addr
|
|
||||||
|
|
||||||
super().__init__(addr)
|
|
||||||
|
|
||||||
# returns the score of this breakpoint
|
|
||||||
def GetScore(self):
|
|
||||||
return self.currentScore
|
|
||||||
|
|
||||||
# resets the score to 0
|
|
||||||
def ResetScore(self):
|
|
||||||
self.currentScore = 0
|
|
||||||
|
|
||||||
# returns the score and resets it to 0 afterwards
|
|
||||||
def PopScore(self):
|
|
||||||
i = self.GetScore()
|
|
||||||
self.ResetScore()
|
|
||||||
return i
|
|
||||||
|
|
||||||
# the function called by GDB if the breakpoint is hit
|
|
||||||
def stop(self):
|
|
||||||
if self.isGood:
|
|
||||||
self.currentScore += 1
|
|
||||||
else:
|
|
||||||
self.currentScore -= 1
|
|
||||||
|
|
||||||
# don't break into gdb GUI
|
|
||||||
return False
|
|
||||||
|
|
||||||
|
|
||||||
# Abstracts the breakpoints into a single class:
|
|
||||||
# - returns the score of the positive and negative breakpoint
|
|
||||||
# - checks if the win function was hit
|
|
||||||
# - takes care of resetting all breakpoints with a single call
|
|
||||||
class BreakpointManager:
|
|
||||||
posB = None
|
|
||||||
negB = None
|
|
||||||
winB = None
|
|
||||||
|
|
||||||
def __init__(self, pAddr, nAddr, wAddr):
|
|
||||||
if pAddr:
|
|
||||||
self.posB = CounterBreakpoint(pAddr, True)
|
|
||||||
if nAddr:
|
|
||||||
self.negB = CounterBreakpoint(nAddr, False)
|
|
||||||
if wAddr:
|
|
||||||
self.winB = CounterBreakpoint(wAddr, True)
|
|
||||||
|
|
||||||
def GetScore(self):
|
|
||||||
score = 0
|
|
||||||
if self.posB:
|
|
||||||
score += self.posB.GetScore()
|
|
||||||
if self.negB:
|
|
||||||
score += self.negB.GetScore()
|
|
||||||
return score
|
|
||||||
|
|
||||||
def ResetBreakpoints(self):
|
|
||||||
if self.posB:
|
|
||||||
self.posB.ResetScore()
|
|
||||||
if self.negB:
|
|
||||||
self.negB.ResetScore()
|
|
||||||
if self.winB:
|
|
||||||
self.winB.ResetScore()
|
|
||||||
|
|
||||||
def PopScore(self):
|
|
||||||
score = 0
|
|
||||||
if self.posB:
|
|
||||||
score += self.posB.PopScore()
|
|
||||||
if self.negB:
|
|
||||||
score += self.negB.PopScore()
|
|
||||||
return score
|
|
||||||
|
|
||||||
def HitWin(self):
|
|
||||||
return self.winB.GetScore() != 0
|
|
||||||
|
|
||||||
|
|
||||||
# Enables the typical GDB spam
|
|
||||||
def EnableLogging():
|
|
||||||
gdb.execute("set logging off")
|
|
||||||
|
|
||||||
|
|
||||||
# Disables the typical GDB spam
|
|
||||||
def DisableLogging():
|
|
||||||
gdb.execute("set logging file /dev/null")
|
|
||||||
gdb.execute("set logging redirect on")
|
|
||||||
gdb.execute("set logging on")
|
|
||||||
|
|
||||||
|
|
||||||
# Runs a given input through GDB
|
|
||||||
def TryInput(inp):
|
|
||||||
gdb.execute(f"run 2>/dev/null 1>&2 <<< $(echo '{inp}')")
|
|
||||||
|
|
||||||
|
|
||||||
# Prints a small MOTD, hence the name of the function
|
|
||||||
def MOTD():
|
|
||||||
print("+--------------------------------------------+")
|
|
||||||
print("| 🥩 BARF - Breakpoint-Assisted Rough Fuzzer |")
|
|
||||||
print("| (c) 2021 Martin 'maride' Dessauer |")
|
|
||||||
print("| github.com/maride/barf |")
|
|
||||||
print("+--------------------------------------------+")
|
|
||||||
|
|
||||||
|
|
||||||
# bruteforces a single character, sandwiched between the known parts.
|
|
||||||
# Returns the most promising string.
|
|
||||||
def BruteforceChar(bm, knownPrefix, knownSuffix):
|
|
||||||
# keyFragment is the variable were we store our found-to-be-correct chars
|
|
||||||
keyFragment = ""
|
|
||||||
|
|
||||||
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()
|
|
||||||
TryInput(knownPrefix + keyFragment + "^" + knownSuffix)
|
|
||||||
refScore = bm.PopScore()
|
|
||||||
|
|
||||||
# iterate over every character in the charset
|
|
||||||
for c in charset:
|
|
||||||
# generate full input string
|
|
||||||
inp = knownPrefix + keyFragment + c + knownSuffix
|
|
||||||
|
|
||||||
# and try it
|
|
||||||
bm.ResetBreakpoints()
|
|
||||||
TryInput(inp)
|
|
||||||
score = bm.PopScore()
|
|
||||||
|
|
||||||
# yay, that's a hit
|
|
||||||
if score > refScore:
|
|
||||||
keyFragment += c
|
|
||||||
found = True
|
|
||||||
break
|
|
||||||
|
|
||||||
# check if we found something this round
|
|
||||||
return keyFragment if found else False
|
|
||||||
|
|
||||||
|
|
||||||
# Bruteforce calls BruteforceChar until:
|
|
||||||
# - BruteforceChar was unable to increase the score using any character in the charset, OR
|
|
||||||
# - the "win" breakpoint is hit :)
|
|
||||||
def Bruteforce(bm, knownPrefix, knownSuffix):
|
|
||||||
while True:
|
|
||||||
res = BruteforceChar(bm, knownPrefix, knownSuffix)
|
|
||||||
if res is False:
|
|
||||||
# no character from the given charset matched. :(
|
|
||||||
EnableLogging()
|
|
||||||
print("BARF is done with the charset and was unable to increase the score further. Issues may be:")
|
|
||||||
print(" - Your charset is too small")
|
|
||||||
print(" - Your chunk size is too small")
|
|
||||||
print(" - Your breakpoints are off")
|
|
||||||
print(" - The specified binary doesn't operate round-wise, so it's impossible to calculate a proper score")
|
|
||||||
if len(knownPrefix) > 0:
|
|
||||||
print(f"Anyway, I stopped with the key '{knownPrefix}[...mystery!...]{knownSuffix}'")
|
|
||||||
print("Maybe that helps you. Have a good night!")
|
|
||||||
DisableLogging()
|
|
||||||
return knownPrefix + knownSuffix
|
|
||||||
else:
|
|
||||||
# good input, we stepped further
|
|
||||||
knownPrefix += res
|
|
||||||
EnableLogging()
|
|
||||||
print(f"Found new scorer, we're now at '{knownPrefix}[...]{knownSuffix}'")
|
|
||||||
DisableLogging()
|
|
||||||
|
|
||||||
# let's examine it further - check if we hit the win breakpoint :)
|
|
||||||
if bm.HitWin():
|
|
||||||
EnableLogging()
|
|
||||||
print("BARF found the flag - or at least managed to hit the 'win' breakpoint!")
|
|
||||||
print(f"Winning guess for the flag is '{knownPrefix + knownSuffix}'")
|
|
||||||
DisableLogging()
|
|
||||||
return knownPrefix + knownSuffix
|
|
||||||
|
|
||||||
|
|
||||||
# getArguments grabs the arguments from pre-defined variables and returns it as a dict
|
|
||||||
def getArguments():
|
|
||||||
a = dict()
|
|
||||||
a["positiveAddr"] = barf_positive_addr
|
|
||||||
a["negativeAddr"] = barf_negative_addr
|
|
||||||
a["winAddr"] = barf_win_addr
|
|
||||||
a["knownPrefix"] = barf_known_prefix
|
|
||||||
a["knownSuffix"] = barf_known_suffix
|
|
||||||
return a
|
|
||||||
|
|
||||||
# main func
|
# main func
|
||||||
def main():
|
def main():
|
||||||
@ -231,13 +40,24 @@ def main():
|
|||||||
bm = BreakpointManager(args["positiveAddr"], args["negativeAddr"], args["winAddr"])
|
bm = BreakpointManager(args["positiveAddr"], args["negativeAddr"], args["winAddr"])
|
||||||
|
|
||||||
# start the bruteforcing madness ;)
|
# start the bruteforcing madness ;)
|
||||||
DisableLogging()
|
# DisableLogging()
|
||||||
Bruteforce(bm, args["knownPrefix"], args["knownSuffix"])
|
Bruteforce(bm, args["knownPrefix"], args["knownSuffix"])
|
||||||
|
|
||||||
# g'night, gdb
|
# g'night, gdb
|
||||||
gdb.execute("quit")
|
gdb.execute("quit")
|
||||||
|
|
||||||
|
|
||||||
|
# getArguments grabs the arguments from pre-defined variables and returns it as a dict
|
||||||
|
def getArguments():
|
||||||
|
a = dict()
|
||||||
|
a["positiveAddr"] = barf_positive_addr
|
||||||
|
a["negativeAddr"] = barf_negative_addr
|
||||||
|
a["winAddr"] = barf_win_addr
|
||||||
|
a["knownPrefix"] = barf_known_prefix
|
||||||
|
a["knownSuffix"] = barf_known_suffix
|
||||||
|
return a
|
||||||
|
|
||||||
|
|
||||||
# actually execute main function
|
# actually execute main function
|
||||||
main()
|
main()
|
||||||
|
|
||||||
|
49
src/BreakpointManager.py
Normal file
49
src/BreakpointManager.py
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
from CounterBreakpoint import CounterBreakpoint
|
||||||
|
import gdb
|
||||||
|
|
||||||
|
# Abstracts the breakpoints into a single class:
|
||||||
|
# - returns the score of the positive and negative breakpoint
|
||||||
|
# - checks if the win function was hit
|
||||||
|
# - takes care of resetting all breakpoints with a single call
|
||||||
|
class BreakpointManager:
|
||||||
|
posB = None
|
||||||
|
negB = None
|
||||||
|
winB = None
|
||||||
|
|
||||||
|
def __init__(self, pAddr, nAddr, wAddr):
|
||||||
|
if pAddr:
|
||||||
|
self.posB = CounterBreakpoint(pAddr, True)
|
||||||
|
if nAddr:
|
||||||
|
self.negB = CounterBreakpoint(nAddr, False)
|
||||||
|
if wAddr:
|
||||||
|
self.winB = CounterBreakpoint(wAddr, True)
|
||||||
|
|
||||||
|
def GetScore(self):
|
||||||
|
score = 0
|
||||||
|
if self.posB:
|
||||||
|
score += self.posB.GetScore()
|
||||||
|
if self.negB:
|
||||||
|
score += self.negB.GetScore()
|
||||||
|
return score
|
||||||
|
|
||||||
|
def ResetBreakpoints(self):
|
||||||
|
if self.posB:
|
||||||
|
self.posB.ResetScore()
|
||||||
|
if self.negB:
|
||||||
|
self.negB.ResetScore()
|
||||||
|
if self.winB:
|
||||||
|
self.winB.ResetScore()
|
||||||
|
|
||||||
|
def PopScore(self):
|
||||||
|
score = 0
|
||||||
|
if self.posB:
|
||||||
|
score += self.posB.PopScore()
|
||||||
|
if self.negB:
|
||||||
|
score += self.negB.PopScore()
|
||||||
|
return score
|
||||||
|
|
||||||
|
def HitWin(self):
|
||||||
|
return self.winB.GetScore() != 0
|
||||||
|
|
79
src/Bruteforce.py
Normal file
79
src/Bruteforce.py
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
from Helper import *
|
||||||
|
|
||||||
|
# The charset to try, sorted by the likelihood of a character class
|
||||||
|
charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789{}_!?"
|
||||||
|
|
||||||
|
# bruteforces a single character, sandwiched between the known parts.
|
||||||
|
# Returns the most promising string.
|
||||||
|
def BruteforceChar(bm, knownPrefix, knownSuffix):
|
||||||
|
# keyFragment is the variable were we store our found-to-be-correct chars
|
||||||
|
keyFragment = ""
|
||||||
|
|
||||||
|
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()
|
||||||
|
TryInput(knownPrefix + keyFragment + "^" + knownSuffix)
|
||||||
|
refScore = bm.PopScore()
|
||||||
|
|
||||||
|
# iterate over every character in the charset
|
||||||
|
for c in charset:
|
||||||
|
# generate full input string
|
||||||
|
inp = knownPrefix + keyFragment + c + knownSuffix
|
||||||
|
|
||||||
|
# and try it
|
||||||
|
bm.ResetBreakpoints()
|
||||||
|
TryInput(inp)
|
||||||
|
score = bm.PopScore()
|
||||||
|
|
||||||
|
# yay, that's a hit
|
||||||
|
if score > refScore:
|
||||||
|
keyFragment += c
|
||||||
|
found = True
|
||||||
|
break
|
||||||
|
|
||||||
|
# check if we found something this round
|
||||||
|
return keyFragment if found else False
|
||||||
|
|
||||||
|
|
||||||
|
# Bruteforce calls BruteforceChar until:
|
||||||
|
# - BruteforceChar was unable to increase the score using any character in the charset, OR
|
||||||
|
# - the "win" breakpoint is hit :)
|
||||||
|
def Bruteforce(bm, knownPrefix, knownSuffix):
|
||||||
|
while True:
|
||||||
|
res = BruteforceChar(bm, knownPrefix, knownSuffix)
|
||||||
|
if res is False:
|
||||||
|
# no character from the given charset matched. :(
|
||||||
|
EnableLogging()
|
||||||
|
print("BARF is done with the charset and was unable to increase the score further. Issues may be:")
|
||||||
|
print(" - Your charset is too small")
|
||||||
|
print(" - Your chunk size is too small")
|
||||||
|
print(" - Your breakpoints are off")
|
||||||
|
print(" - The specified binary doesn't operate round-wise, so it's impossible to calculate a proper score")
|
||||||
|
if len(knownPrefix) > 0:
|
||||||
|
print(f"Anyway, I stopped with the key '{knownPrefix}[...mystery!...]{knownSuffix}'")
|
||||||
|
print("Maybe that helps you. Have a good night!")
|
||||||
|
DisableLogging()
|
||||||
|
return knownPrefix + knownSuffix
|
||||||
|
else:
|
||||||
|
# good input, we stepped further
|
||||||
|
knownPrefix += res
|
||||||
|
EnableLogging()
|
||||||
|
print(f"Found new scorer, we're now at '{knownPrefix}[...]{knownSuffix}'")
|
||||||
|
DisableLogging()
|
||||||
|
|
||||||
|
# let's examine it further - check if we hit the win breakpoint :)
|
||||||
|
if bm.HitWin():
|
||||||
|
EnableLogging()
|
||||||
|
print("BARF found the flag - or at least managed to hit the 'win' breakpoint!")
|
||||||
|
print(f"Winning guess for the flag is '{knownPrefix + knownSuffix}'")
|
||||||
|
DisableLogging()
|
||||||
|
return knownPrefix + knownSuffix
|
||||||
|
|
||||||
|
|
44
src/CounterBreakpoint.py
Normal file
44
src/CounterBreakpoint.py
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
import gdb
|
||||||
|
|
||||||
|
# Breakpoint wrapper class
|
||||||
|
# A breakpoint class with patented, award-winning score functionality.
|
||||||
|
class CounterBreakpoint(gdb.Breakpoint):
|
||||||
|
# addr is the address of the breakpoint
|
||||||
|
# isGood is a boolean, determing if the breakpoint is good-to-hit or bad-to-hit
|
||||||
|
# (means a negative breakpoint has isGood = false, and vice versa)
|
||||||
|
def __init__(self, addr, isGood):
|
||||||
|
self.isGood = isGood
|
||||||
|
self.currentScore = 0
|
||||||
|
|
||||||
|
# gdb requires address literals to start with a star
|
||||||
|
if addr[0] != "*":
|
||||||
|
addr = "*" + addr
|
||||||
|
|
||||||
|
super().__init__(addr)
|
||||||
|
|
||||||
|
# returns the score of this breakpoint
|
||||||
|
def GetScore(self):
|
||||||
|
return self.currentScore
|
||||||
|
|
||||||
|
# resets the score to 0
|
||||||
|
def ResetScore(self):
|
||||||
|
self.currentScore = 0
|
||||||
|
|
||||||
|
# returns the score and resets it to 0 afterwards
|
||||||
|
def PopScore(self):
|
||||||
|
i = self.GetScore()
|
||||||
|
self.ResetScore()
|
||||||
|
return i
|
||||||
|
|
||||||
|
# the function called by GDB if the breakpoint is hit
|
||||||
|
def stop(self):
|
||||||
|
if self.isGood:
|
||||||
|
self.currentScore += 1
|
||||||
|
else:
|
||||||
|
self.currentScore -= 1
|
||||||
|
|
||||||
|
# don't break into gdb GUI
|
||||||
|
return False
|
||||||
|
|
29
src/Helper.py
Normal file
29
src/Helper.py
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
import gdb
|
||||||
|
|
||||||
|
# Enables the typical GDB spam
|
||||||
|
def EnableLogging():
|
||||||
|
gdb.execute("set logging off")
|
||||||
|
|
||||||
|
|
||||||
|
# Disables the typical GDB spam
|
||||||
|
def DisableLogging():
|
||||||
|
gdb.execute("set logging file /dev/null")
|
||||||
|
gdb.execute("set logging redirect on")
|
||||||
|
gdb.execute("set logging on")
|
||||||
|
|
||||||
|
|
||||||
|
# Runs a given input through GDB
|
||||||
|
def TryInput(inp):
|
||||||
|
gdb.execute(f"run 2>/dev/null 1>&2 <<< $(echo '{inp}')")
|
||||||
|
|
||||||
|
|
||||||
|
# Prints a small MOTD, hence the name of the function
|
||||||
|
def MOTD():
|
||||||
|
print("+--------------------------------------------+")
|
||||||
|
print("| 🥩 BARF - Breakpoint-Assisted Rough Fuzzer |")
|
||||||
|
print("| (c) 2021 Martin 'maride' Dessauer |")
|
||||||
|
print("| github.com/maride/barf |")
|
||||||
|
print("+--------------------------------------------+")
|
||||||
|
|
Loading…
Reference in New Issue
Block a user