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
|
||||
# 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
|
||||
charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789{}_!?"
|
||||
|
||||
|
||||
# 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
|
||||
# include project files
|
||||
from BreakpointManager import BreakpointManager
|
||||
from Helper import *
|
||||
from Bruteforce import *
|
||||
|
||||
# main func
|
||||
def main():
|
||||
@ -231,13 +40,24 @@ def main():
|
||||
bm = BreakpointManager(args["positiveAddr"], args["negativeAddr"], args["winAddr"])
|
||||
|
||||
# start the bruteforcing madness ;)
|
||||
DisableLogging()
|
||||
# DisableLogging()
|
||||
Bruteforce(bm, args["knownPrefix"], args["knownSuffix"])
|
||||
|
||||
# g'night, gdb
|
||||
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
|
||||
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