Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to allow script to be executed but not read?

This question is how to have a python script that other (non-root) users can run but not inspect.

Example use case:

#!/usr/bin/env python
import requests
params = { 'user':'fred', 'password':'123' }
url = 'https://.......'
print(requests.get(url, params).content)

In this example (but it is only an example), I want to let users run the script in order to get the web content that was fetched, but not see the credentials that were used to fetch that content.

Setting execute permission but not read permission does not achieve the same result that it does for a compiled executable. Here is a "hello world" example.

In C:

$ cat test.c
#include <stdio.h>
int main() {
    puts("secret message");
    return 0;
}

$ gcc -o secret test.c

$ chmod 711 secret

$ sudo -u nobody ./secret
secret message

$ sudo -u nobody strings ./secret
strings: ./secret: Permission denied

In Python:

$ cat test.py
#!/usr/bin/python
print("secret message")

$ chmod 711 test.py

$ sudo -u nobody ./test.py
/usr/bin/python: can't open file './test.py': [Errno 13] Permission denied

(Of course the python executable itself could be set to octal mode 711, but this is not the thing that I want to protect.)

So then, what can I do about it?

Possible solutions I thought about, but I think won't work:

(1) Translate the entire Python program into C.

Possible in principle but not a practical solution. Even for this simple example, it would mean having to look for an equivalent of the requests library.

(2) Have a helper C program that is called by Python.

What should the helper C program actually do though? If it just prints the password, then the user can run it directly to obtain the password. If it also fetches the web page (in this example) then we are back to problem 1.

(3) Have a C program that starts python and passes the secret data to python:

  • (a) via the command line

    • open to inspection via ps or /proc/<pid>/cmdline
  • (b) via the environment

    • open to inspection via ps or /proc/<pid>/environ
  • (c) via standard input

    • prevents the use of standard input for other purposes in the python script, e.g. user input
  • (d) via a named pipe

    • user could race the python process to read from the named pipe (if they first do killall -STOP python in a tight loop, then with the python process suspended it is trivial to win the race to read from the named pipe)

Actually I did think of one other thing - an adaptation of 3c - a C program forks and execs a python process and sends to it (via stdin) a secret followed by the data from its own stdin. The python process starts by reading the secret, and is then free to read other user input from stdin. But all this it is starting to seem clunky (we now have this extra process sitting there copying data from stdin for the duration of the python process) and anyway I have no clue how to write such a C program.

What can I do please?

like image 531
Angus In My Tent Avatar asked Sep 16 '25 18:09

Angus In My Tent


1 Answers

Can you not use your Python code as an interpreted script, but compile it into command-line executable? It is similar to your first proposed solution, but in that case it would not be needed to compile .py file into .c file, and then .c file into executable. You will compile .py file directly into executable.

like image 182
Enrico Avatar answered Sep 19 '25 09:09

Enrico