**For my cybersecurity lab, I have to write a python program to iterate through a .txt file of passwords and a .txt file of usernames and check them against a Login.pyc file (that takes as its arguments), returning "Login successful.' if the matchup is correct. **
I'm trying to use the subprocess module to run python3 Login.pyc <user> <password>
on the command line for each iteration. The passwords file has 100,000 passwords on it, so it is obviously taking extremely long.
import subprocess
if __name__ == "__main__":
gang = open("gang") #usernames .txt file (20 lines)
pws = open("PwnedPWs100k") #passwords .txt file (100,000 lines)
for name in gang:
print("USER = ", name)
for item in pws:
output = subprocess.run(["python3", "Login.pyc", "{}".format(name.rstrip()), "{}".format(item.rstrip())], capture_output=True, text=True).stdout.strip("\n")
if output == 'Login successful.':
print("USER:" + name + "PASSWORD:" +item)
break
pws.close()
gang.close()
UPDATE: I'm now importing the Login() function from Login.pyc, and since it uses command line arguments, I'm updating the sys.argv variables in nested loops and passing them against the Login() function. It is taking a similarly long time as my previous approach, however.
if __name__ == "__main__":
with open("gang") as gang:
with open("PwnedPWs100k") as pws:
sys.argv = [sys.argv[0], 1, 2]
for name in gang:
sys.argv[1] = name.rstrip()
for item in pws:
sys.argv[2] = item.rstrip()
while not Login.Login():
continue
else:
print("USER:" + name + "PASSWORD:" +item)
break
'''
Any ideas on optimizing the runtime?
Subprocess and multiprocessing are fine modules. But they don't seem like the right tool for this job.
The overhead of starting a new python interpreter and doing some imports and function definitions is killing you. No need to do that more than a few times.
I cannot simply import a Login() function because it is encrypted.
I reject that premise. Twice.
When you said "encrypted", I believe you mean the source text has been compiled to bytecode. That is not an impediment.
Just import Login
, and look around with dir(Login)
(or even help(Login)
).
I bet a function like check_password
leaps out at you.
Call it. Two million times. In the same process.
Additionally, dis.dis()
is available to you.
So you can see what the "if name is main:" guard ran,
and so you can see what happens within check_password
.
It offers you enough information to write your own
source code that performs the same check.
Which I'm pretty sure is the insight your
professor was hoping you would eventually arrive at.
https://docs.python.org/3/library/dis.html
BTW, who ever writes things like gang.close()
these days?
Use a with open...
context manager, already.
There's more than one library that supports import
and similar operations. Look around on pypi.
There's a whole ecosystem, which includes the standard
importlib,
devoted to making sense of binary bytecode artifacts.
Notice that you might need to use the same python interpreter version when generating and when consuming the .pyc file. There's a limited number to try: 3.8, 3.9, some others, it won't take long.
Maybe things don't go completely smoothly the first time out. Don't worry. Think like an attacker. You are Mallet.
Construct some source code that resembles an imagined Login.py. Convert it to .pyc bytecode. Pretend you can no longer see the source. Exploit the bytecode.
If it didn't quite go to your liking, adjust the source, produce another .pyc, lather, repeat, until you can confidently navigate through these waters.