Ejemplo n.º 1
0
def login():
    """
    The login view of this application. Return a login page or login a user if authentication
    is successful.
    """

    # Redirect if the current user is logged in
    if g.user and g.user.is_authenticated:
        next = get_local_redirect()
        return redirect(next or url_for('index'))

    # Prepare the login form
    form = LoginForm()

    # If the form is filled
    if form.validate_on_submit():
        # Part 1
        # A terrible way to implement login
        # The administrator of Great Bank is very confident in his application and has published the
        # source code on the internet. That is what you are reading right now. You can thus see how
        # the code is implemented and try to find a vulnerability.
        # The code below execute a request to the database where it tries to match a username and
        # the password provided by the user in the form.
        # Unfortunately, he did not escape the values from the user in any way and you can thus
        # control the query by inserting the right values.

        # Try to input some code  in the login page and see how the code changes in the console.
        # Can you bypass the password check?

        # See below for the answer.

        query = "SELECT * FROM user WHERE username = '******' AND password = '******'"

        # Print the current query into the console for you to see
        print(query)

        result = list(db.engine.execute(query))
        if result:
            for row in result:
                login_user(User.get_by_username(row['username']),
                           remember=form.remember_me.data)
                flash('Logged in!', 'success')
                return form.redirect('index')
        else:
            flash('Wrong username or password.', 'error')

        # By exploiting the fact that none of the code is escaped properly, we can control the SQL
        # statement and basically, make it always true. By using for instance:
        # Example of SQL injection: 1' OR '1'='1
        # we can make the database say: "Give me 'admin' where password is '1' OR 1=1"
        # As 1=1 is always true, the second part of the predicament is always true and we bypass the
        # authentication entirely. You successfully logged in as an admin!
        # This is one of the simplest form of SQL injection and it is unfortunately still too
        # common today.

        # Part 2 #
        # The admin is pissed as you managed to login as him and take some money from the bank. He
        # discovered the flaw and patched it. (Please comment the whole code above and uncomment the
        # code below.)
        # You can no longer login using the magic password as he now verifies the user exist first
        # and then check the password.
        # See below for the next part.

        ### Patched version of the login:

        # print("Username: {username}".format(username=form.username.data))
        # print("Password: {password}".format(password=form.password.data))
        #
        # user = User.get_by_username(form.username.data)
        # if user and user.check_password(form.password.data):
        #     login_user(user, remember=form.remember_me.data)
        #     flash('Logged in!', 'success')
        #     return form.redirect('index')
        # else:
        #     flash('Wrong username or password.', 'error')

    return render_template('login.html', form=form)