[re] Snake (10)
Description
Short info about task:
- Name: Snake
- Difficulty: easy
- Score: 10
Flag should be in the format: HTB{username:password}
Overview
We have got the python script that is waiting for some username and password:
$ python snake.py
___________.__ _________ __
\__ ___/| |__ ____ / _____/ ____ _____ | | __ ____
| | | | \_/ __ \ \_____ \ / \__ \ | |/ // __ \
| | | Y \ ___/ / \ | \/ __ \| <\ ___/
|____| |___| /\___ > /_______ /___| (____ /__|_ \___ >
\/ \/ \/ \/ \/ \/ \/
The Snake Created by 3XPL017
Your number is 809
Authentication required
Enter your username
QWE
Wrong username try harder
Let’s look into code to get more info about how to get username and password.
Bypass code
We can see partially obfuscated variables, that are later xored with some values, let’s try to get username.
Username
Username is combined from random dropped variables that are of course hex-encoded letters (i.e db = '\x6e'
).
user_input = raw_input('Enter your username\n')
if user_input == slither:
pass
else:
print 'Wrong username try harder'
exit()
To get correct username we should know the slither value, we can easly get it by printing before verification check.
I’ve decided to ‘patch’ above code into:
user_input = slither
print "====> Username: {}".format(user_input)
if user_input == slither:
pass
> python snake.py
___________.__ _________ __
\__ ___/| |__ ____ / _____/ ____ _____ | | __ ____
| | | | \_/ __ \ \_____ \ / \__ \ | |/ // __ \
| | | Y \ ___/ / \ | \/ __ \| <\ ___/
|____| |___| /\___ > /_______ /___| (____ /__|_ \___ >
\/ \/ \/ \/ \/ \/ \/
The Snake Created by 3XPL017
Your number is 351
Authentication required
====> Username: anaconda
Enter your password
PASSWORD
Wrong password try harder
Yay, so the username is anaconda
, now we need to guess password.
Password
pass_input = raw_input('Enter your password\n')
for passes in pass_input:
for char in chars:
if passes == str(chr(char)):
print 'Good Job'
break
else:
print 'Wrong password try harder'
exit(0)
break
This part is much harder, because every input which starts with 'u'
is accepted (we can realize it by checking runtime to which letter input is compared). This is probably “programming mistake”, now we should guess what author wanted to achieve - what kind of verification.
We can also get all chars array ([117, 100, 118, 118, 114, 106, 119, 97, 36, 36, 126, 114, 115, 125, 42, 115, 125, 42, 107, 42, 126, 124, 121, 118, 118]
) and print this as string: "udvvrjwa$$~rs}*s}*k*~|yvv"
, but this is not our password :/
Making a step back, by ignoring loop where chars are incremented by 0xA
we can read that chars is just a message: "this is a troll"
, so the real password is somewhere else.
We can also notice unused variable password: password = [0x69, 0x74, 0x73, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x65, 0x61, 0x73, 0x79]
, but this is just another rabbit hole:
>>> password = [0x69, 0x74, 0x73, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x65, 0x61, 0x73, 0x79]
>>> s = ""
>>> for c in password:
... s += chr(c)
...
>>> s
'its not that easy'
With some additional prints we can notice that output and lock = 5
variable are the same:
==> chains: this is a troll
==> keys: password!!
==> auth: keep trying
Your number is 774
Lock 5
==> chars1: udvvrjwa$$
==> chars2: udvvrjwa$$~rs}*s}*k*~|yvv
My simplified code which gives above result:
#!/usr/bin/python2.7
import random
def print_array(name, chars):
r = ""
for c in chars:
r += chr(c)
print "==> {}: {}".format(name, r)
chains = [0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x61, 0x20, 0x74, 0x72, 0x6f, 0x6c, 0x6c]
keys = [0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x21, 0x21]
auth = [0x6b, 0x65, 0x65, 0x70, 0x20, 0x74, 0x72, 0x79, 0x69, 0x6e, 0x67]
print_array("chains", chains)
print_array("keys", keys)
print_array("auth", auth)
chars = []
lock_pick = random.randint(0, 0x3e8)
lock = lock_pick * 2
lock = lock + 10
lock = lock / 2
lock = lock - lock_pick
print 'Your number is ' + str(lock_pick)
print 'Lock ' + str(lock)
for key in keys:
keys_encrypt = lock ^ key
chars.append(keys_encrypt)
print_array("chars1", chars)
for chain in chains:
chains_encrypt = chain + 0xA
chars.append(chains_encrypt)
print_array("chars2", chars)
pass_input = raw_input('Enter your password\n')
for passes in pass_input:
print chars
for char in chars:
if passes == str(chr(char)):
print 'Good Job'
break
else:
print 'Wrong password try harder'
exit(0)
break
After we delete ’troll-part’ of password we can check the flag : HTB{anaconda:udvvrjwa$$}
we will get a success.
Summary
After we will make some understanding of all strings, variables and code we can get the flag, but to be clear: this is more like try every possible flag challenge, than challenge which will allow you to learn something.
It’s just internet troll - but not very funny.