Can Lupa be used to run untrusted lua code in python? - python

Let's say I create LuaRuntime with register_eval=False and an attribute_filter that prevents access to anything except a few python functions. Is it safe to assume that lua code won't be able to do os.system("rm -rf *") or something like that?

From looking at the Lupa doc:
Restricting Lua access to Python objects
Lupa provides a simple mechanism to control access to Python objects. Each attribute access can be passed through a filter function as follows...
It doesn't say anything about preventing or limiting access to facilities provided by Lua itself. If no other modifications are done to the LuaRuntime environment then a lua script can indeed do something like os.execute("rm -rf *").
To control what kind of environment the lua script works in you can use the setfenv and getfenv to sandbox the script before running it. For example:
import lupa
L = lupa.LuaRuntime()
sandbox = L.eval("{}")
setfenv = L.eval("setfenv")
sandbox.print = L.globals().print
sandbox.math = L.globals().math
sandbox.string = L.globals().string
sandbox.foobar = foobar
# etc...
setfenv(0, sandbox)
Now doing something like L.execute("os.execute('rm -rf *')") will result in a script error.

Related

Twisted server: monkey-patch file

I'm running Twisted (Python 2.7.x) on Alpine Linux 3.7 inside Docker.
I now wanted to use the twisted.internet.inotify module, but it fails loading.
It's triggering the following exception in twisted.python._inotify:
name = ctypes.util.find_library('c')
if not name:
raise ImportError("Can't find C library.")
libc = ctypes.cdll.LoadLibrary(name)
initializeModule(libc)
The problem is that Alpine Linux 3.x has a bug which makes ctypes.util.find_library('c') return None.
I've compared the code with the inotify module, which I've successfully used in Alpine before, and that one deals with the issue in the following way:
_FILEPATH = ctypes.util.find_library('c')
if _FILEPATH is None:
_FILEPATH = 'libc.so.6'
instance = ctypes.cdll.LoadLibrary(_FILEPATH)
So i've tried calling ctypes.util.find_library('libc.so.6') in the interpreter, and that call succeeds.
What I now want to do is to monkey-patch twisted.python._inotify so that it loads libc.so.6 instead of c, but I'm unaware of how I can do that, because I can't load the module at all.
I have one option, which is to sed the source code during docker build, or possibly even inside the server right after it starts, but that feels like a hack.
I've seen that Twisted contains a MonkeyPatch module, but I have no idea on how to use it, or if it is even suited for this task.
How can I solve this problem in the cleanest possible way?
Note: The server is running as non-root, so it has no write access to /usr/lib/python2.7/site-packages/twisted/python/_inotify.py.
This means that I either have to sed it in the Dockerfile, or patch in in-memory when the server starts, before it loads the module (if that's possible, I'd prefer that).
In addition to anything else, I hope that you contribute a patch to Twisted to either solve this problem outright or make it easier to solve from application code or at an operations level.
That said, here's a monkey-patch that should do for you:
import ctypes.util
def fixed_find_library(name):
if name == "c":
result = original_find_library(name)
if result is not None:
return result
else:
return "libc.so.6"
return original_find_library(name)
original_find_library = ctypes.util.find_library
ctypes.util.find_library = fixed_find_library
# The rest of your application code...
This works simply by codifying the logic from your question which you suggest works around the problem. As long as this code runs before _inotify.py is imported then when it does get imported it will end up using the "fixed" version instead of the original.
While monkey-patching as Jean-Paul indicates seems to be the best fix, here is an approach which modifies Twisted's source code.
When using the Python Docker API to run the container:
container = client.containers.run(...)
patch = 'sed -i.bak s/raise\ ImportError/name\ =\ \\"libc.so.6\\"\ #\ raise\ ImportError/g /usr/lib/python2.7/site-packages/twisted/python/_inotify.py'
print container.exec_run(patch, user='root')
or when in bash inside the container:
sed -i.bak s/raise\ ImportError/name\ =\ \"libc.so.6\"\ #\ raise\ ImportError/g /usr/lib/python2.7/site-packages/twisted/python/_inotify.py

Accessing Robot Framework global variables from a prerun modifier

I am invoking Robot Framework on a folder with a command like following:
robot --name MyTestSuite --variablefile lib/global_variables.py --variable TARGET_TYPE:FOO --variable IMAGE_TYPE:BAR --prerunmodifier MyCustomModifier.py ./tests
MyCustomModifier.py contains a simple SuiteVisitor class, which includes/excludes tags and does a few other things based on some of the variable values set.
How do I access TARGET_TYPE and IMAGE_TYPE in that class? The method shown here does not work, because I want access to the variables before tests start executing, and therefore I get a RobotNotRunningError with message Cannot access execution context.
After finding this issue report, I tried to downgrade to version 2.9.1 but nothing changed.
None of public API's seem to provide this information but debugging the main code does provide an alternative way of obtaining it. It has to be said that this example code will work with version 3.0.2, but may not work in the future as these are internal functions subject to change. That said, I do think that the approach will remain.
As Robot Framework is an application, it obtains the command line arguments through it's main function: run_cli (when running from command line). This function is filled with the arguments from the system itself and can be obtained throughout every python script via:
import sys
cli_args = sys.argv[1:]
Robot Framework has a function that interprets the commandline argument list and make it into a more readable object:
from robot.run import RobotFramework
import sys
options, arguments = RobotFramework().parse_arguments(sys.argv[1:])
The argument variable is a list where all the variables from the command line are added. An example:
arguments[0] = IMAGE_TYPE:BAR
This should allow you to access the information you need.

Python interpreters and Alias's

Is there any mechanism similar to alias's (with something like BASH) that can be used in Ipython or the Python Interpreter?
For instance if I find myself frequently doing something like:
var = urllib2.urlopen('http://programmers.stackexchange.com')
But I don't want to continually type out those strings.
Is there any method of (Persistently between exits) shortening the request other than writing a script for it?
No, but in your interpreter, write this:
def pse_url():
global var
var = urllib2.urlopen('http://programmers.stackexchange.com')
Then, write pse_url() whenever you need to affect your variable.
It would be cleaner to not use a global variable:
var = pse_url()
If you have many such utilities, put them in your own module and load them once when you start the REPL.
My guess is for such one line expressions you can create lambdas functions ( and functions for bigger one as #coredump suggested), see code below:
se_open = (lambda: urllib2.urlopen('http://programmers.stackexchange.com'))
so_open = (lambda: urllib2.urlopen('http://programmers.stackexchange.com'))
Know if you have to create new var you have to simply run command:
var_se = se_open()
var_so = so_open()
Also you can create script which contains all thst shortcuts and start python with imported script by command:
$ python -i script.py
All functions defined in script.py would be available in your REPL.

Odoo - how to use it interactively in python interpreter?

I read here that it might be possible to use python interpreter to access Odoo and test things interactively (https://www.odoo.com/forum/help-1/question/how-to-get-a-python-shell-with-the-odoo-environment-54096), but doing this in terminal:
ipython
import sys
import openerp
sys.argv = ['', '--addons-path=~/my-path/addons', '--xmlrpc-port=8067', '--log-level=debug', '-d test',]
openerp.cli.main()
it starts Odoo server, but I can't write anything in that terminal tab to use it interactively. If for example I write anything like print 'abc', I don't get any output. Am I missing something here?
Sometime I use "logging" library for print output on the console/terminal.
For example:
import logging
logging.info('Here is your message')
logging.warning('Here is your message')
For more details, You may checkout this reference link.
The closest thing I have found to interactive is put the line
import pdb; pdb.set_trace()
in the method I want to inspect, and then trigger that method.
It's clunky, but it works.
As an example, I was just enhancing the OpenChatter implementation for our copy of OpenERP, and during the "figure things out" stage I had that line in .../addons/mail/mail_thread.py::mail_thread.post_message so I could get a better idea of what was happening in that method.
The correct way to do this is with shell:
./odoo-bin shell -d <yourdatabase>
Please, be aware that if you already have an instance of odoo, the port will be busy. In that case, the instance you are opening should be using a different port. So the command should be something like this:
./odoo-bin shell --xmlrpc-port=8888 -d <yourdatabase>
But if you want to have your addons available in the new instance, yo can make something similar to the following:
./odoo-bin shell -c ~/odooshell.conf -d <yourdatabase>
This way you can have in your odooshell.conf whatever you need to have configured (port, addons_path, etc). This way you can work smoothly with your shell.
As I always use docker, this is what I do to have my shell configured in docker:
docker exec -ti <mycontainer> odoo shell -c /etc/odoo/odooshell.conf -d <mydatabase>
You will have the env available to do anything. You can create express python code to make whatever you need. The syntax is very similar to server actions. For example:
partner_ids = env['res.partner'].search([])
for partner in partner_ids:
partner['name'] = partner.name + '.'
env.cr.commit()
Remember to env.cr.commit() if you make any data change.

Access a script's variables and functions in interpreter after runtime

So let's say I have a script script1. Is there a way to interact with script1's variables and functions like an interpreter after or during its runtime?
I'm using IDLE and Python 2.7, but I'm wondering if I could do this in any interpreter not just IDLE's.
Say in my script, get = requests.get("example.com"). I'd like to hit F5 or whatever to run my script, and then instead of the console unloading all of the variables from memory, I'd like to be able to access the same get variable.
Is this possible?
That's a serious question. You might need to consult this page:
https://docs.python.org/2/using/cmdline.html#miscellaneous-options
Note the -i option, it makes interpreter enter interactive mode after executing given script.
you can do like this:
#file : foo.py
import requests
def req():
get = requests.get("example.com")
return get
and then run the script from a console
import foo
get = foo.req()

Categories

Resources