Passing argument containg nullbyte (\x00) to subprocess.call - linux

#!/usr/bin/env python
from subprocess import call
try:
call(['echo', "aabbccddee".decode('hex')])
print 'Input without \\x00 works!'
except Exception as e:
print 'Input without \\x00 throws exception: ' + str(e)
try:
call(['echo', "aabbccdd00ee".decode('hex')]) # The input contains \x00
print 'Input with \\x00 works!'
except Exception as e:
print 'Input with \\x00 throws exception: ' + str(e)
Returns the following (tested with Python 2.7 on RHEL 6):
▒▒▒▒▒
Input without \x00 works!
Input with \x00 throws exception: execv() arg 2 must contain only strings
Questions:
Is this expected behavior by subprocess.call or might this be a bug?
Is there any way I can pass binary data (directly) containing \x00 to another executable within a python script? It will probably work using shell=True, but I would prefer another way, if there is any.
Note:
>>> type("00".decode('hex'))
<type 'str'>
Running echo $'\x00' directly works as expected.
EDIT
This seems to be correct behavior after more research. Due to the execve(2) semantics it is not possible to pass a string containing a null byte as argument.
See:
$ echo $'\x55\x55\x55\x00\x55\x55'
UUU
However, I couldn't really find anymore info on this (second question especially, as it seems shell=True won't help either (all data after the null byte wouldn't be passed)). I leave this question open for a while, maybe someone can provide a deeper insight or share some useful resources on this.

Related

Except python does not catch Windows error FileNotFoundError | "The system cannot find the specified path." [duplicate]

I have this python code:
import os
try:
os.system('wrongcommand')
except:
print("command does not work")
The code prints:
wrongcommand: command not found
Instead of command does not work. Does anyone know why it's not printing my error message?
If you want to have an exception thrown when the command doesn't exist, you should use subprocess:
import subprocess
try:
subprocess.run(['wrongcommand'], check = True)
except subprocess.CalledProcessError:
print ('wrongcommand does not exist')
Come to think of it, you should probably use subprocess instead of os.system anyway ...
Because os.system() indicates a failure through the exit code of the method
return value == 0 -> everything ok
return value != 0 -> some error
The exit code of the called command is directly passed back to Python.
There is documentation telling you that os.system() would raise an exeption in case of a failure. os.system() just calls the underlaying system() call of the OS and returns its return value.
Please read the os.system() documentation carefully.
Although subprocess might be your best friend. os.system is still useful in somewhere, especially to the programmer play C/C++ mode.
Hence, the code will be below.
import os
try:
os_cmd = 'wrongcommand'
if os.system(os_cmd) != 0:
raise Exception('wrongcommand does not exist')
except:
print("command does not work")
There are two problems in your code snippet. First of all, never just do try: ... except:, always be specific about which exception you want to handle. Otherwise, your program simply swallows any kind of error, also those that you do not expect. In most cases, this will lead to unexpected behavior at some other point during runtime.
Furthermore, os.system() calls should most of the time be replaced by their counterparts from the subprocess module.
To see what goes wrong, leave out the try/except block and actually look at the traceback/exception. As others have pointed out, you will notice that there is no exception in your case which is why your custom string is not printed.
Bottom line: think about which specific exceptions can occur in your code block. Think hard about which of them you expect to happen for certain reasons and handle those appropriately. Do not handle those that you do not expect.
wrongcommand: command not found is the output of the shell os.system is using to invoke the command. os.system did not throw an exception
EDIT: edited by copy-and-pasting part of mgilson's comment
There is one more easiest ways is:
import os
def dat():
if os.system('date') == 0:
print("Command successfully executed")
else:
print("Command failed to execute")
dat()

Python Error Handling while base decoding

I tried to do the following :
I have read a code in base64 via QR Code and then I converted it.
If I get an error while I do the convert, I will write a error variable to 1 and then continue without exiting the program.
I don't find a solution for me. Did anyone has an idea how I can handle it?
I tried it with the Python Try Command but I didn't get it working or I have done something wrong.
here is a snip of my code:
secure = base64.b64decode(secure_base).decode("utf-8", "ignore")
number = base64.b64decode(number_base).decode("utf-8", "ignore")
start = int(base64.b64decode(start_base).decode("utf-8", "ignore"))
end = int(base64.b64decode(end_base).decode("utf-8", "ignore"))
thanks a lot.
You can use the try and Except in python in the following manner.
try:
"""some intelligent program here, which some times may FOOBAR"""
except Exception as e:
error_recieved = e
"""Do whatever you want here incase of an error"""
Remember that the program in try skips to except just after the line in which the error/exception occured.

How to fix this syntax error and Eof? [duplicate]

I have the following python code:
print 'This is a simple game.'
input('Press enter to continue . . .')
print 'Choose an option:'
...
But when I press Enter button, I get the following error:
Traceback (most recent call last):
File "E:/4.Python/temp.py", line 2, in <module>
input('Press enter to continue . . .')
File "<string>", line 0
^
SyntaxError: unexpected EOF while parsing
P.S. I am using python IDLE version 2.6 on Windows 7.
Related problem in IPython: Why does the IPython REPL tell me "SyntaxError: unexpected EOF while parsing" as I input the code?
For Python 2, you want raw_input, not input. The former will read a line. The latter will read a line and try to execute it, not advisable if you don't want your code being corrupted by the person entering data.
For example, they could do something like call arbitrary functions, as per the following example:
def sety99():
global y
y = 99
y = 0
input ("Enter something: ")
print y
If you run that code under Python 2 and enter sety99(), the output will 99, despite the fact that at no point does your code (in its normal execution flow) purposefully set y to anything other than zero (it does in the function but that function is never explicitly called by your code). The reason for this is that the input(prompt) call is equivalent to eval(raw_input(prompt)).
See here for the gory details.
Keep in mind that Python 3 fixes this. The input function there behaves as you would expect.
In Python 2, input() strings are evaluated, and if they are empty, an exception is raised. You probably want raw_input() (or move on to Python 3).
In Python 2.x, input() is equivalent to eval(raw_input()). And eval gives a syntax error when you pass it an empty string.
You want to use raw_input() instead.
If you use input on Python 2.x, it is interpreted as a Python expression, which is not what you want. And since in your case, the string is empty, an error is raised.
What you need is raw_input. Use that and it will return a string.

Properly Implement Shutil.Error in Python

I'm learning Python 3 and trying to write a script that will copy a directory. I'm using shutil.copytree. From the Python documentation it says:
If exception(s) occur, an Error is raised with a list of reasons.
This exception collects exceptions that are raised during a multi-file
operation. For copytree(), the exception argument is a list of
3-tuples (srcname, dstname, exception).
In the example they do this:
except Error as err:
errors.extend(err.args[0])
Here is my script:
def copyDirectory(src, dest):
errors = []
try:
shutil.copytree(src, dest)
except Error as err:
errors.extend(err.args[0])
source="C:/Users/MrRobot/Desktop/Copy"
destination="C:/Users/MrRobot/Desktop/Destination"
copyDirectory(source, destination)
moveDirectory(destination,"I:/")
Questions:
How do you properly catch an exception that might occur when using shutil.copytree (assuming my above script is incorrect)?
How then would you view the errors that occurred, would I loop through the errors array?
You need to either include the module name when you catch the exception:
except shutil.Error as err:
Or import it explicitly:
from shutil import copytree, Error
# the rest of your code...
try:
copytree(src, dest)
except Error as err:
errors.extend(err.args[0])
To view the traceback and exception information, you have a few options:
Don't catch the exception. Your script will be halted and all the error information will be printed.
If you want the script to continue, then you're really asking a duplicate of this SO question. I would reference that question; the accepted answer is written very well.
And by the way, you should avoid calling it an array. This particular exception object has a list of tuples, and arrays are an entirely different data structure.
You can use OSError to handle it :
import shutil
def removeDirectory(directory):
try:
shutil.rmtree(directory)
except OSError as err:
print(err)
removeDirectory('PathOfDirectoryThatDoesntExist')
OUTPUT :
[Errno 2] No such file or directory:
'./PathOfDirectoryThatDoesntExist'

Unpickling from converted string in python/numpy

I have a ton of numpy ndarrays that are stored picked to strings. That may have been a poor design choice but it's what I did, and now the picked strings seem to have been converted or something along the way, when I try to unpickle I notice they are of type str and I get the following error:
TypeError: 'str' does not support the buffer interface
when I invoke
numpy.loads(bin_str)
Where bin_str is the thing I'm trying to unpickle. If I print out bin_strit looks like
b'\x80\x02cnumpy.core.multiarray\n_reconstruct\nq\x00cnumpy\nndarray\nq\x01K\x00\x85q\x02c_codecs\nencode\nq\x03X\x01\x00\x00\ ...
continuing for some time, so the info seems to be there, I'm just not quite sure how to convert it into whatever string format numpy/pickle need. On a whim I tried
numpy.loads( bytearray(bin_str, encoding='utf-8') )
and
numpy.loads( bin_str.encode() )
which both throw an error _pickle.UnpicklingError: unpickling stack underflow. Any ideas?
PS: I'm on python 3.3.2 and numpy 1.7.1
Edit
I discovered that if I do the following:
open('temp.txt', 'wb').write(...)
return numpy.load( 'temp.txt' )
I get back my array, and ... denotes copying and pasting the output of print(bin_str) from another window. I've tried writing bin_str to a file directly to unpickle but that doesn't work, it complains that TypeError: 'str' does not support the buffer interface. A few sane ways of converting bin_str to something that can be written directly to a binary file result in pickle errors when trying to read it back.
Edit 2
So I guess what's happened is that my binary pickle string ended up encoded inside of a normal string, something like:
"b'pickle'"
which is unfortunate and I haven't figured out how to deal with that, except this ridiculous and convoluted way to get it back:
open('temp.py', 'w').write('foo = ' + bin_str)
from temp import foo
numpy.loads( foo )
This seems like a very shameful solution to the problem, so please give me a better one!
It sounds like your saved strings are the reprs of the original bytes instances returned by your pickling code. That's a bit unfortunate, but not too bad. repr is intended to return a "machine friendly" representation of an object, and it can often be reversed by using eval:
import numpy as np
import pickle
# this part has already happened
orig_obj = np.array([1,2,3])
orig_pickle = pickle.dumps(orig_obj)
saved_str = repr(orig_pickle) # this was a mistake, but it's already done
# this is what you need to do to get something equivalent to orig_obj back
reconstructed_pickle = eval(saved_str)
reconstructed_obj = pickle.loads(reconstructed_pickle)
# test
if np.all(reconstructed_obj == orig_obj):
print("It worked!")
Obligatory note that using eval can be dangerous: Be aware that eval can run any Python code it wants, so don't call it with untrusted data. However, pickle data has the same risks (a malicious Pickle string can run arbitrary code upon unpickling), so you're not losing much safety in this situation. I'm guessing that you trust your data in this case anyway.

Resources