Add chunk support

This commit is contained in:
maride 2021-05-31 15:15:42 +02:00
parent c397b3640e
commit 31ab515a01
5 changed files with 76 additions and 8 deletions

View File

@ -41,7 +41,7 @@ def main():
# start the bruteforcing madness ;) # start the bruteforcing madness ;)
# DisableLogging() # DisableLogging()
Bruteforce(bm, args["knownPrefix"], args["knownSuffix"]) Bruteforce(bm, args["knownPrefix"], args["knownSuffix"], args["chunksize"])
# g'night, gdb # g'night, gdb
gdb.execute("quit") gdb.execute("quit")
@ -55,6 +55,7 @@ def getArguments():
a["winAddr"] = barf_win_addr a["winAddr"] = barf_win_addr
a["knownPrefix"] = barf_known_prefix a["knownPrefix"] = barf_known_prefix
a["knownSuffix"] = barf_known_suffix a["knownSuffix"] = barf_known_suffix
a["chunksize"] = barf_chunksize
return a return a

View File

@ -12,6 +12,7 @@ WINADDR=""
KNOWNPREFIX="" KNOWNPREFIX=""
KNOWNSUFFIX="" KNOWNSUFFIX=""
BARFPATH="$(dirname $(realpath $0))/src" BARFPATH="$(dirname $(realpath $0))/src"
CHUNKSIZE=1
# getopt is kind-of unstable across distributions and versions, so we implement it on our own # 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 # 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" KNOWNSUFFIX="$2"
shift; shift shift; shift
;; ;;
-c|--chunksize)
CHUNKSIZE="$2"
shift; shift
;;
*) # unknown option - we assume it is the target literal *) # unknown option - we assume it is the target literal
TARGETFILE="$key" TARGETFILE="$key"
shift shift
@ -70,6 +75,7 @@ if [ "$SHOWHELP" == 1 ]; then
echo " -w | --win-addr 0xDEF042 a location reached if your input is correct" 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 " -< | --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 " -> | --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 " -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 " ./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." 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 fi
# ready for take-off # 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

BIN
examples/double-trouble Executable file

Binary file not shown.

53
examples/double-trouble.c Normal file
View File

@ -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 <stdio.h>
#include <string.h>
#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! :)");
}
}

View File

@ -7,7 +7,7 @@ charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789{}_!?"
# bruteforces a single character, sandwiched between the known parts. # bruteforces a single character, sandwiched between the known parts.
# Returns the most promising string. # 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 is the variable were we store our found-to-be-correct chars
keyFragment = "" 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. # 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 # 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() bm.ResetBreakpoints()
TryInput(knownPrefix + keyFragment + "^" + knownSuffix) TryInput(knownPrefix + keyFragment + "^" * chunksize + knownSuffix)
refScore = bm.PopScore() refScore = bm.PopScore()
# iterate over every character in the charset # iterate over every character in the charset
for c in charset: for c in generateCharset(chunksize):
# generate full input string # generate full input string
inp = knownPrefix + keyFragment + c + knownSuffix inp = knownPrefix + keyFragment + c + knownSuffix
@ -33,7 +33,7 @@ def BruteforceChar(bm, knownPrefix, knownSuffix):
score = bm.PopScore() score = bm.PopScore()
# yay, that's a hit # yay, that's a hit
if score > refScore: if score > refScore or bm.HitWin():
keyFragment += c keyFragment += c
found = True found = True
break break
@ -45,9 +45,9 @@ def BruteforceChar(bm, knownPrefix, knownSuffix):
# Bruteforce calls BruteforceChar until: # Bruteforce calls BruteforceChar until:
# - BruteforceChar was unable to increase the score using any character in the charset, OR # - BruteforceChar was unable to increase the score using any character in the charset, OR
# - the "win" breakpoint is hit :) # - the "win" breakpoint is hit :)
def Bruteforce(bm, knownPrefix, knownSuffix): def Bruteforce(bm, knownPrefix, knownSuffix, chunksize):
while True: while True:
res = BruteforceChar(bm, knownPrefix, knownSuffix) res = BruteforceChar(bm, knownPrefix, knownSuffix, chunksize)
if res is False: if res is False:
# no character from the given charset matched. :( # no character from the given charset matched. :(
EnableLogging() EnableLogging()
@ -78,3 +78,11 @@ def Bruteforce(bm, knownPrefix, knownSuffix):
return 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