Custom Attacks Part 4:

Elsaid Salem
5 min readJan 26, 2021

--

Photo by Stephen Leonardi on Unsplash

Welcome back to the 20th iteration of this blog series. In this series, we’re growing our cybersecurity knowledge starting from the very basics using the overthewire.org challenges as a guide. First, I’d like to thank everyone for their feedback based on the last post! I’ll do my best to implement it and as always, more feedback is always welcome.

In this post, we’ll continue the process of writing our own custom program to crack passwords. We’ll take it in steps and I’ll do my best to explain the choices we’ll make. We’ll also address some issues and discuss some security concepts that relate to programming and password cracking. Let’s get started!

Our program so far should look like this:

# send password to binary using subprocess
# we don't need ALL of subprocess, so to keep our program efficient we'll just import the part that we need:
from subprocess import check_output as checkoutput
# this will take a password and the "path" to send to and do the magic
def shellGuesser(guess, path):
attempt = "echo " + guess + " | " + path
return checkoutput(attempt, shell=TRUE)
# be able to test the password guessing and command sending
def testGuesser(guess):
gotIt = ""
if guess == "testPassword":
gotIt = "Found the password! It's " + guess
else:
gotIt = "Whoops! Try again...."
return gotIt

# iterate over password possibilities without using nested "for loops"
guessCharacters = []
passwordCharacters = { \
"upper" : ("A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"), \
"lower" : ("a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"), \
"numbers" : (0, 1, 2, 3, 4, 5, 6, 7, 8, 9) \
}
def possibilityGenerator(possibilities):
for possibility in passwordCharacters[possibilities]:
guessCharacters.append(possibilities)guess = []
def guessLength(length):
for i in range(0, length):
guess.append(0)
def guessMaker(guessList):
guessWord = ""
for character in guessList:
guessWord += guessCharacters[character]
return guessWord
# be able to keep guessing longer passwords if original length doesn't work
# make it interactive

Today we’ll finally finish setting up the foundations of our program. So far our program can:

  • Generate guesses based on a length we provide
  • Generate guesses using characters we deem as “legal”
  • Send our password guess to the terminal
  • Test itself against a password that we provide

Our last steps are to give our program the ability to keep guessing passwords if our first guess length was too short. Lastly, we should make the program somewhat more interactive: both for the sake of practicing that and to make it easier to use.

Guessing longer passwords should be relatively simple given our current program structure of using lists. Since lists in python are mutable, we can simply make our list longer to guess longer passwords. Since we already have a function that increases the length of our guess list, we just need to give it some more functionality, through yet another function:

# be able to keep guessing longer passwords if original length doesn't workdef increment(guessList):
for character in guessList:
guessList[character] = 0
#this resets our password guessing
guessLength(1) # adds one more character to our guess

Now when we detect that we’ve run out of guesses for a certain length, we can call this function to start over with a new length.

Lastly, to make it interactive. Interactivity is having the program ask the user for information and then using that information for running the code. I’ll give you a basic and simple way to do certain things but I’ll leave the actual design up to you. First, let’s start with receiving user input:

ask = input("What would you like to input?")

The input function is amazingly versatile. It can fit pretty much anywhere a variable can. If you need to store the value, however, you need to assign a variable as shown above. When python is evaluating the value of our variable “ask”, it’ll ask the user for an input to store. We can also use input in loops or in functions.

So far, our program can send guesses but it won’t really tell us what the password is when it guesses correctly. We can have it store the password but memory stored in variables are deleted when a program exits. It’s enough to have the program output the correct password when it finds it. Better yet, we can configure the program to email us the password or store it in a file if we’re running it remotely and won’t be around to see the terminal output.

For now, we’ll keep it simple and just print our password to the terminal window. So we just need to use the print function:

print("".join(guess))

That’ll use our guess list and print it in a word. The problem with doing it this way is that the screen will quickly fill up with our attempts. We’ll make use of print’s “end” argument to fix that:

print("Trying " + "".join(guess) + " ..., end="")

By default, “print” “ends” with a “\n” which represents a new line. By setting it to an empty string, the output won’t create new lines. This still prints the output back to back though so it’ll look like this:

Trying guess1 ...Trying guess2 ...Trying guess3 ...

We can fix that by adding a “\r” to the beginning of the print statement. This returns the cursor to the beginning of the line so that it overwrites the old guess.

This is great for displaying our current guess and we can use another print statement to print the password once it’s discovered.

One more thing we’re going to need is to implement some kind of password success check (similar to what we have with our test guesser). We already have a function that returns the output of our attempt, so we just need to check that output for a “wrong” phrase. The overthewire challenges give us a “wrong” phrase but perhaps another program would only return a phrase for successful password entries. We can use this phrase (either one) to then guide our program to keep running until we find the password.

If you’ve been following along closely, there are some deliberate errors in the code. Finally, your final challenge is to put these code “chunks” together in a way that works as a cohesive program. Next week, I’ll post my personal take on the challenge which you can use as a comparison. You should use both the test function to make sure that the program is working as intended and the Leviathan password-based challenges to check your program.

For your own “productive struggle”, don’t read further until you’ve attempted completing the program!

If you’re still having trouble after attempting to find and resolve the errors, refer to the following hints as a guide:

One of those errors is that we need to add a delay in our code execution, especially around sending password attempts. To prevent RACE conditions and memory leaks, some programs “lockout” resources and so need time to exit before being restarted. There are other logical errors such as in the “guessLength” function.

Sign up to discover human stories that deepen your understanding of the world.

Free

Distraction-free reading. No ads.

Organize your knowledge with lists and highlights.

Tell your story. Find your audience.

Membership

Read member-only stories

Support writers you read most

Earn money for your writing

Listen to audio narrations

Read offline with the Medium app

--

--

No responses yet

Write a response