From 31ab515a013c02f6e58b3ce35043031134bf08a7 Mon Sep 17 00:00:00 2001 From: maride Date: Mon, 31 May 2021 15:15:42 +0200 Subject: [PATCH] Add chunk support --- barf.py | 3 ++- barf.sh | 8 +++++- examples/double-trouble | Bin 0 -> 16760 bytes examples/double-trouble.c | 53 ++++++++++++++++++++++++++++++++++++++ src/Bruteforce.py | 20 +++++++++----- 5 files changed, 76 insertions(+), 8 deletions(-) create mode 100755 examples/double-trouble create mode 100644 examples/double-trouble.c diff --git a/barf.py b/barf.py index a877c6b..cb5c9c9 100644 --- a/barf.py +++ b/barf.py @@ -41,7 +41,7 @@ def main(): # start the bruteforcing madness ;) # DisableLogging() - Bruteforce(bm, args["knownPrefix"], args["knownSuffix"]) + Bruteforce(bm, args["knownPrefix"], args["knownSuffix"], args["chunksize"]) # g'night, gdb gdb.execute("quit") @@ -55,6 +55,7 @@ def getArguments(): a["winAddr"] = barf_win_addr a["knownPrefix"] = barf_known_prefix a["knownSuffix"] = barf_known_suffix + a["chunksize"] = barf_chunksize return a diff --git a/barf.sh b/barf.sh index 5a8794c..3d18e4c 100755 --- a/barf.sh +++ b/barf.sh @@ -12,6 +12,7 @@ WINADDR="" KNOWNPREFIX="" KNOWNSUFFIX="" BARFPATH="$(dirname $(realpath $0))/src" +CHUNKSIZE=1 # getopt is kind-of unstable across distributions and versions, so we implement it on our own # hat-tip to https://stackoverflow.com/questions/192249/how-do-i-parse-command-line-arguments-in-bash @@ -43,6 +44,10 @@ while [[ $# -gt 0 ]]; do KNOWNSUFFIX="$2" shift; shift ;; + -c|--chunksize) + CHUNKSIZE="$2" + shift; shift + ;; *) # unknown option - we assume it is the target literal TARGETFILE="$key" shift @@ -70,6 +75,7 @@ if [ "$SHOWHELP" == 1 ]; then echo " -w | --win-addr 0xDEF042 a location reached if your input is correct" echo " -< | --prefix CTF{ a known prefix, e.g. the prefix of your flag" echo " -> | --suffix } a known suffix, e.g. the suffix of your flag" + echo " -c | --chunksize 1 amount of characters to try at once" echo " -h | --help a great and useful help message, you should try it!" echo " ./path/to/your/crackme the path to the target to be fuzzed" echo "Note that you need to either specify --positive-addr or --negative-addr and your target of course." @@ -77,5 +83,5 @@ if [ "$SHOWHELP" == 1 ]; then fi # ready for take-off -gdb --quiet -nx --eval-command "py barf_positive_addr='$POSITIVEADDR';barf_negative_addr='$NEGATIVEADDR';barf_win_addr='$WINADDR';barf_known_prefix='$KNOWNPREFIX';barf_known_suffix='$KNOWNSUFFIX';barf_path='$BARFPATH'" --command barf.py $TARGETFILE +gdb --quiet -nx --eval-command "py barf_positive_addr='$POSITIVEADDR';barf_negative_addr='$NEGATIVEADDR';barf_win_addr='$WINADDR';barf_known_prefix='$KNOWNPREFIX';barf_known_suffix='$KNOWNSUFFIX';barf_path='$BARFPATH';barf_chunksize=$CHUNKSIZE" --command barf.py $TARGETFILE diff --git a/examples/double-trouble b/examples/double-trouble new file mode 100755 index 0000000000000000000000000000000000000000..2f0b77734238ea0841e376d8d25d86d3a3a3c9bf GIT binary patch literal 16760 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 F{{qOMsAK>D literal 0 HcmV?d00001 diff --git a/examples/double-trouble.c b/examples/double-trouble.c new file mode 100644 index 0000000..68de155 --- /dev/null +++ b/examples/double-trouble.c @@ -0,0 +1,53 @@ +// double-trouble.c +// ---------------- +// +// The binary reads some chars from stdin and checks it against a hard-coded flag. +// It checks two chars at a time, this time with a positive counter :) +// If the entered flag is correct, a corresponding message will be printed out. +// +// Compile with +// gcc -o double-trouble double-trouble.c +// +// Quick binary analysis +// - load into gdb +// - execute "start", so the binary is mapped to the final position +// - execute "disas main" +// Look at 0x00005555555551f5 <+160>. It moves 2 to rbp-0x4, that's the correctChars += 2 below. +// Right after that, the i value is also increased with 2, so double-check to get the right address ;) +// Anyway, that's the right address for --positive-address +// Finding the win function is easy as always. We need to search for the point where puts("yay, ...") is called. +// And that is at 0x000055555555523d! +// +// With the addresses identified above, we call barf with: +// ./barf.sh --positive-addr 0x5555555551f5 --win-addr 0x55555555523d --chunksize 2 ./double-trouble +// +// Please note that your addresses will likely differ, e.g. if you edit the source file below. + +#include +#include + +#define BUFSIZE 32 + +int main(int argc ,char* argv[]) { + char buf[BUFSIZE]; + char flag[BUFSIZE] = "CTF{w3_h4ck_1n_du4l1ty!}"; + + // read flag + fgets(buf, BUFSIZE, stdin); + + // walk flag + int correctChars = 0; + int i = 0; + while(buf[i] != '\0' && flag[i] != '\0' && i < BUFSIZE) { + if(buf[i] == flag[i] && buf[i+1] == flag[i+1]) { + correctChars += 2; + } + i += 2; + } + + // check flag + if(strlen(flag) == correctChars) { + puts("yay, that's the flag! :)"); + } +} + diff --git a/src/Bruteforce.py b/src/Bruteforce.py index d74f2dc..34b9d14 100644 --- a/src/Bruteforce.py +++ b/src/Bruteforce.py @@ -7,7 +7,7 @@ charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789{}_!?" # bruteforces a single character, sandwiched between the known parts. # Returns the most promising string. -def BruteforceChar(bm, knownPrefix, knownSuffix): +def BruteforceChar(bm, knownPrefix, knownSuffix, chunksize): # keyFragment is the variable were we store our found-to-be-correct chars keyFragment = "" @@ -19,11 +19,11 @@ def BruteforceChar(bm, knownPrefix, knownSuffix): # 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) + TryInput(knownPrefix + keyFragment + "^" * chunksize + knownSuffix) refScore = bm.PopScore() # iterate over every character in the charset - for c in charset: + for c in generateCharset(chunksize): # generate full input string inp = knownPrefix + keyFragment + c + knownSuffix @@ -33,7 +33,7 @@ def BruteforceChar(bm, knownPrefix, knownSuffix): score = bm.PopScore() # yay, that's a hit - if score > refScore: + if score > refScore or bm.HitWin(): keyFragment += c found = True break @@ -45,9 +45,9 @@ def BruteforceChar(bm, knownPrefix, knownSuffix): # 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): +def Bruteforce(bm, knownPrefix, knownSuffix, chunksize): while True: - res = BruteforceChar(bm, knownPrefix, knownSuffix) + res = BruteforceChar(bm, knownPrefix, knownSuffix, chunksize) if res is False: # no character from the given charset matched. :( EnableLogging() @@ -78,3 +78,11 @@ def Bruteforce(bm, knownPrefix, knownSuffix): return knownPrefix + knownSuffix +# 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): + c = charset + for i in range(chunksize - 1): + c = [ a + b for a in c for b in charset ] + return c +