Abusing Python Input
In a not so distant past, I was a highly competitive endurance sports athlete. I'm still very involved in endurance sports but not at that level because eventually you have to grow up and go back to work. But during that time, I was highly obsessed with every aspect of endurance sports. That is my nature though. I become passionate and I obsess to become the absolute best I can be.
I've been into technology since I was a kid and it is the single constant in my life. Obsessions come and go but tech has always been there. Maybe not to the level of that first contact -- it ebbs and flows. When I discovered information security, that stoked the fire once more and my obsession rages on. With the exception of endurance sports which play a large role in my life, the only free space in my life is consumed by infosec.
I mention all of this because I'm constantly tinkering with something and the other day I read a random blog that mentioned a CTF challenge which I then proceeded to download. My intention was just to play around with it but as I hunted through the challenge, I came across an interesting Python problem.
On port 10000, we find a question:
"Please enter the number of packets:"
We enter: 1
In return, we get a single ping response.
But what happens if we feed it something unexpected:
It crashes. Reading through the crash, we see the following:
ping.py
num_packets = int(input(' Please enther number of packets: ')
I'm not so interested in much else at this point but this is where we learn we're dealing with Python and input function.
What is the difference between raw_input and input? Let's ask Google:
As I began to read the response, the mention of eval made me think -- Eval is Evil. Which is even funnier when you get down to the line that says just that.
I've always used raw_input with Python2 so let's create a script using input instead:
Similar to what we're dealing with in the challenge, we take input and we print the variable. When enter a number:
It prints the variable. But if you recall from above, it's evaluating the input so if instead we feed it something like this:
It evaluates the expression.
In order to abuse this behavior, we can use __import__ to import a module and ultimately, we want it to eval the following:
With a handler setup on our local machine:
We catch a shell. Now let's point it to our victim:
With our handler setup:
We catch our shell from the victim.
If we wanted to fix our Python script, we'd use raw_input instead of input:
When we send it our original request:
We see that it returns the input rather than evaluating it.