mirror of
				https://github.com/maride/barf.git
				synced 2025-10-10 19:06:51 +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…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user