-1

I understand that relying on Python 2's built-in input() function (as opposed to raw_input(), which was renamed to input() in Python 3) is prone to security bugs. In this question, I'm trying to determine how to demonstrate this class of vulnerability.


Specifically, I'm trying to determine how to generate input to the code below which will cause "Access granted" to be emitted, without modifying the program itself, only by changing the value passed to stdin in response to the input() call.

import random
pass_true = input("What is the password?")
password = random.randint(0,2**30)

if password == pass_true:
    print("Access granted.")
else: 
    print ("Access denied.")

If the random number were generated before the input call (that is, if the second and third lines were switched), one could merely enter pass_true as the string, which would subsequently be evaluated to the value of the variable by that name -- but since the random number isn't yet known at the input() invocation, this approach doesn't work.

17
  • 1
    Put comments before the lines maybe Commented May 26, 2017 at 17:56
  • 1
    First off, I don't think it's going to work because you're trying to compare a string to an integer. Use password = str(random.randint(0,2**30)). Secondly, you're trying to guess a number between 0 and 2^30..? Commented May 26, 2017 at 17:57
  • I think that @DeepSpace mis-identified the problem; that question doesn't seem to apply at all. I've voted to reopen. Commented May 26, 2017 at 17:58
  • What is the problem you're trying to solve. The code you posted runs just fine -- for what it actually does. The user has to guess a 9-digit random number, in advance. This is not a "password" situation, since the access code changes every time. Please clarify. I was going to vote to close this as "unclear what you're asking". Commented May 26, 2017 at 18:00
  • 2
    You have failed to convey your problem Commented May 26, 2017 at 18:01

1 Answer 1

6

Approach 1: Overriding random.randint() Completely

Assuming the interpreter is Python 2, the following input will cause the result of the comparison to be True, without modifying the program at all:

[42 for random.randint in [lambda x,y: 42]][0]

Witness the execution transcript:

$ python test.py
What is the password?[42 for random.randint in [lambda x,y: 42]][0]
Access granted.

Digression: How It Works

To explain this -- in Python 2, input() -- as opposed to raw_input() -- runs content entered by the user through an evaluation pass. This means code can access defined variables, or have side effects on them.

lambda x,y: 42

is a function that takes two arguments, and always returns 42.

[42 for random.randint in [lambda x,y: 42]]

is a list comprehension that goes through a list of items containing only that lambda expression, assigning each of them in turn to the variable random.randint, and then adding the value 42 to its list; tacking on a [0] on the end thus makes the end effect be an evaluation to that value.


Approach 2: Setting a Known Seed

[random.seed(1), random.randint(0, 2**30), random.seed(1)][1]

Again, the transcript:

$ python test.py
What is the password?[random.seed(1), random.randint(0, 2**30), random.seed(1)][1]
Access granted.

In this case, we caused the random number generator to be initialized with a known seed; generated a value from the same range; and then reinitialized from that seed again -- and return the second value from that list, corresponding with the first random number generated with the given range and the given seed.

Sign up to request clarification or add additional context in comments.

12 Comments

@KDEx, does the explanation I've added help?
@AndrésPérez-AlbelaH., it can be done -- __import__('modulename') is applicable.
@AndrésPérez-AlbelaH., ...so, if the OP's code didn't import random until after the input(), you could still exploit it with [42 for __import__('random').randint in [lambda x,y: 42]][0]
@juanpa.arrivillaga, indeed -- though that was just the first means of generating a side effect and also returning a chosen value from within an expression that came to mind. One could also use, for instance, [setattr(random, 'randint', lambda x,y:42), 42][1] with no list comprehension involved. Surely there are terser forms as well, but finding them would be a question for Code Golf.
@AndrésPérez-AlbelaH., ...that said, if you really want to add a handle on the module to local scope, you can do that too as a side effect: [globals().__setitem__('random', __import__('random')), setattr(__import__('random'), 'randint', lambda x,y:42), 42][-1]
|

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.