When writing a AWS lambda function, we need to be careful about secure coding issues.

If your lambda function takes an input and use it to run a command, you need to avoid using os.system(...). You should use subprocess.run(...) but without the shell. The commands provided to subprocess should be in arguments.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
import subprocess
import uuid

def lambda_handler(event, context):
    rand_value = uuid.uuid4().hex[:6]
    file_name = f'{event['file_name']}_{rand_value}'
    print('Creating:', file_name)

    result = subprocess.run(f'cd /tmp && touch {file_name} && ls -la', shell=True, stdout=subprocess.PIPE)
    print(result.stdout.decode('utf-8'))
1
2
3
4
5
6
7
8
9
ubuntu@ubuntu-virtual-machine:~$ python3 command_injection.py 
Enter file name: hello && env | base64 #
Creating: hello && env | base64 #_526feb
R0pTX0RFQlVHX1RPUElDUz1KUyBFUlJPUjtKUyBMT0cKTEVTU09QRU49fCAvdXNyL2Jpbi9sZXNz
cGlwZSAlcwpVU0VSPXVidW50dQpTU0hfQUdFTlRfUElEPTE0MDIKWERHX1NFU1NJT05fVFlQRT14
MTEKU0hMVkw9MQpIT01FPS9ob21lL3VidW50dQpPTERQV0Q9L2hvbWUvdWJ1bnR1CkRFU0tUT1Bf
U0VTU0lPTj11YnVudHUKR05PTUVfU0hFTExfU0VTU0lPTl9NT0RFPXVidW50dQpHVEtfTU9EVUxF
Uz1nYWlsOmF0ay1icmlkZ2UKTUFOQUdFUlBJRD0xMDI5CkRCVVNfU0VTU0lPTl9CVVNfQUREUkVT
Uz11bml4OnBhdGg9L[...]

We should refactor the vulnerable code by adding two defences:

Input validation

Dependings on the context, try to whitelist the allowed characters.

If you do not know in advanced then it is crucial that you follow the next defence of using arguments command for subprocess.

Usage of arguments in subprocess

Instead of providing the commands in concatenated string or string format, provide an argument format ['touch', file_name]. This means you need to break down the command in different subprocess calls. You cannot run the multiple commands in one single subprocess.

One common routine is that you need to run a sequence of command at a specific same directory. With the use of cwd argument in subprocess.run(...), you can specify where the command should be executed.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
import subprocess
import uuid

def lambda_handler(event, context):
    rand_value = uuid.uuid4().hex[:6]
    file_name = f'{event['file_name']}_{rand_value}'
    print('Creating:', file_name)

    working_dir = '/tmp'
    subprocess.run(['touch', file_name], cwd=working_dir, stdout=subprocess.PIPE)
    result = subprocess.run(['ls', '-la'], cwd=working_dir, stdout=subprocess.PIPE)
    print(result.stdout.decode('utf-8'))