By taking a look at the source code we can see that it is obfuscated (hard to read).
import sysa ="!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ"+\"[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~ "defarg133(arg432):if arg432 == a[71]+a[64]+a[79]+a[79]+a[88]+a[66]+a[71]+a[64]+a[77]+a[66]+a[68]:returnTrueelse:print(a[51]+a[71]+a[64]+a[83]+a[94]+a[79]+a[64]+a[82]+a[82]+a[86]+a[78]+\a[81]+a[67]+a[94]+a[72]+a[82]+a[94]+a[72]+a[77]+a[66]+a[78]+a[81]+\a[81]+a[68]+a[66]+a[83]) sys.exit(0)returnFalsedefarg111(arg444):returnarg122(arg444.decode(), a[81]+a[64]+a[79]+a[82]+a[66]+a[64]+a[75]+\a[75]+a[72]+a[78]+a[77])defarg232():returninput(a[47]+a[75]+a[68]+a[64]+a[82]+a[68]+a[94]+a[68]+a[77]+a[83]+\a[68]+a[81]+a[94]+a[66]+a[78]+a[81]+a[81]+a[68]+a[66]+a[83]+\a[94]+a[79]+a[64]+a[82]+a[82]+a[86]+a[78]+a[81]+a[67]+a[94]+\a[69]+a[78]+a[81]+a[94]+a[69]+a[75]+a[64]+a[70]+a[25]+a[94])defarg132():returnopen('flag.txt.enc', 'rb').read()defarg112():print(a[54]+a[68]+a[75]+a[66]+a[78]+a[76]+a[68]+a[94]+a[65]+a[64]+a[66]+\a[74]+a[13]+a[13]+a[13]+a[94]+a[88]+a[78]+a[84]+a[81]+a[94]+a[69]+\a[75]+a[64]+a[70]+a[11]+a[94]+a[84]+a[82]+a[68]+a[81]+a[25])defarg122(arg432,arg423): arg433 = arg423 i =0whilelen(arg433)<len(arg432): arg433 = arg433 + arg423[i] i = (i +1) %len(arg423)return"".join([chr(ord(arg422) ^ord(arg442)) for (arg422,arg442) inzip(arg432,arg433)])arg444 =arg132()arg432 =arg232()arg133(arg432)arg112()arg423 =arg111(arg444)print(arg423)sys.exit(0)
Okay. If you didn't notice that already, at the top of the file there is the alphabet that the application uses to obfuscate strings in the code. The obfuscation method that is used, constructs the strings by substituting the main alphabet.
a ="!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ"+\"[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~ "
We can uncover the strings easily if we use a simple python script.
a ="!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ"+\"[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~ "obfuscated_strings = []for i in obfuscated_strings:print(i)
Let's add to our obfuscated_strings list every substitute of the alphabet present in the bloat.flag.py file.
Great. We can now safely replace all these substitutions with the strings generated by the program. The source will be quite clean.
import sysa ="!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ"+\"[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~ "defarg133(arg432):if arg432 =="happychance":returnTrueelse:print("The password is incorrect.") sys.exit(0)returnFalsedefarg111(arg444):returnarg122(arg444.decode(), "rapscallion")defarg232():returninput("Please enter correct password for flag:")defarg132():returnopen('flag.txt.enc', 'rb').read()defarg112():print("Welcome back... your flag, user:")defarg122(arg432,arg423): arg433 = arg423 i =0whilelen(arg433)<len(arg432): arg433 = arg433 + arg423[i] i = (i +1) %len(arg423)return"".join([chr(ord(arg422) ^ord(arg442)) for (arg422,arg442) inzip(arg432,arg433)])arg444 =arg132()arg432 =arg232()arg133(arg432)arg112()arg423 =arg111(arg444)print(arg423)sys.exit(0)
Notice there's still this weird naming convention we need to figure out. The best way to do this is by starting from the bottom and making our way up to the top.
We can see that arg444 is set to the arg132() function. Let's take a look at it.
This function reads the flag. We can get rid of that weird function name and replace it with something readable like decoded_flag. I use neovim so I will do that using the :%s/arg132/decoded_flag command in NORMAL mode. In most GUI-based editors the replacement can be done by pressing Ctrl + h. Now repeat the process for the variable name too (:%s/arg444/flag).
If we do this with all the other functions we will be in a really really good place.
arg432 is set to the arg232() function which asks us for the password (we rename the function to input_password() and the variable to password).
We pass the password as an argument to the arg133 function. This function checks if the password matches the string happychance (rename function to check_password() and the variable)
If it doesnโt matches, the system will exit with code 0, if it does then it runs the arg112() function which will print a welcome message (rename function to welcome()).
Finally the arg423 variable is set to the arg111() function which decodes the flag (rename function to prepare_flag and the variable to prepared_flag)
To be honest, as soon as we deobfuscated the check_password() function we could get the flag, but it is better we did it the long way.
We are now familiar with this silly kind of obfuscation.