Skip to content

Tag: Python

AWS Lambda (Python) – Preventing Command Injection

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 but without the shell. The commands provided to subprocess should be in arguments.

Explaining the injection

I will use an example of AWS Lambda function that takes an input from event and uses it in a subprocess to run a command. Notice the command is used in a f-string.

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 ='cd /tmp && touch {file_name} && ls -la', shell=True, stdout=subprocess.PIPE)

We can inject a malicious filename to steal the values in env

ubuntu@ubuntu-virtual-machine:~$ python3
Enter file name: hello && env | base64 #
Creating: hello && env | base64 #_526feb


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, you can specify where the command should be executed.

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'['touch', file_name], cwd=working_dir, stdout=subprocess.PIPE)
    result =['ls', '-la'], cwd=working_dir, stdout=subprocess.PIPE)

Walkthrough – Solidity Local Development setup (with Python)


  • Install python3 and the following python packages:
pip install web3 py-solc-x
  • VS code IDE and extensions: Solidity (Juan Blanco), Python (Microsoft)

We are going to walkthrough a tutorial created by Patrick Collins (

  • Install nodejs
  • Install ganache using yarn or npm (to simulate a local blockchain VM)

Setting and Deploying the Smart Contract

Create a new project folder and copy the sample solidity code to a new file SimpleStorage.sol:

// SPDX-License-Identifier: MIT

pragma solidity >=0.6.0 <0.9.0;

contract SimpleStorage {
    uint256 favoriteNumber;

    // This is a comment!
    struct People {
        uint256 favoriteNumber;
        string name;

    People[] public people;
    mapping(string => uint256) public nameToFavoriteNumber;

    function store(uint256 _favoriteNumber) public {
        favoriteNumber = _favoriteNumber;

    function retrieve() public view returns (uint256) {
        return favoriteNumber;

    function addPerson(string memory _name, uint256 _favoriteNumber) public {
        people.push(People(_favoriteNumber, _name));
        nameToFavoriteNumber[_name] = _favoriteNumber;

Create a file. We are going to walkthrough step-by-step to understand each part of the code.

1. Import these required modules.

from solcx import compile_standard
from solcx import install_solc
import json
import os
from web3 import Web3

2. We use solcx to compile the smart contract code. This is a python wrapper for the Solidity compiler.

First we open and read the content of the smart contract code.

Then install the solidity compiler version. It will download the compiler from the project’s Github download link.

Configure the compile standards:

  • language
  • sources
  • settings
  • solidity compiler version

We can dump the compiled code to see the structure of the code.

with open("./SimpleStorage.sol", "r") as file:
    simple_storage_file =

print("Installing solc...")

# Configure compile standards
compiled_sol = compile_standard(
        "language": "Solidity",
        "sources": {"SimpleStorage.sol": {"content": simple_storage_file}},
        "settings": {
            "outputSelection": {
                "*": {
                    "*": ["abi", "metadata", "evm.bytecode", "evm.bytecode.sourceMap"]

# Dump the compiled code to see the structure of the code
with open("compiled_code.json", "w") as file:
    json.dump(compiled_sol, file)

3. Get the bytecode and abi from the compiled code. How do we know the structure of the JSON? Refer to the compiled_code.json file

bytecode = compiled_sol["contracts"]["SimpleStorage.sol"]["SimpleStorage"]["evm"]["bytecode"]["object"]

abi = compiled_sol["contracts"]["SimpleStorage.sol"]["SimpleStorage"]["abi"]

4. Now start ganache server and we can see the generated dummy accounts and private keys. Note down where the server is listening.

$ ganache
ganache v7.0.2 (@ganache/cli: 0.1.3, @ganache/core: 0.1.3)
Starting RPC server

Available Accounts
(0) 0xB136383615B477B1B816f4227A509ea8F0C0c9DD (1000 ETH)
(1) 0xB6c6BDb34A834BAcc8e07c9765E2f85D1619beDc (1000 ETH)
(2) 0xb2e141ed4EF4F30BC7a1848FFbd623b19B08608C (1000 ETH)
(3) 0x32c0DB620E7355feE0254813932a4E7a454D74f8 (1000 ETH)
(4) 0xB19D507aEE3BdA3c9da9b360E491B88FFd857f14 (1000 ETH)
(5) 0x7B0929a005B39Cce2C9795558371F3865Cff1Bf9 (1000 ETH)
(6) 0x13665EC9cEE2915402BD7Ce69c05F70E9CBCF2ef (1000 ETH)
(7) 0x2C2c3C4585c9425969C03055554dD0C15f5a57b8 (1000 ETH)
(8) 0xdAD8Ae2871Cb242C001A68EB5Bc6941BFDB0d2A7 (1000 ETH)
(9) 0x85214561dCD632581a0b60BeE5989607005BE663 (1000 ETH)

Private Keys
(0) 0xa4c6bac88b45ba1e21eafbd736c92ca60b67bbfb956ccd3da37fa6f83ebe38c1
(1) 0xfa197f239d6df371b0242b8fe96b0d1883a392ff5ab4502cefae0e972f07f081
(2) 0x6c96d2d7b0fb9b56cad49887e3f198de2faa93d321240201d0572732f83bbcc8
(3) 0xd9eb1ec171c1aee37b0603b85d58b615d678f3f9c85c4e5fe31c322113d009d3
(4) 0xd6c212925da4e19a4708b43d1728efef1cf5c839fd44ee411107837b30d8e38c
(5) 0x048c50d14357791a5cbf1ecbf1febda6bf215f946bac50fac410524cde6cb397
(6) 0xb9eeb83abac9b23a5bc801e584c646f92ecb37cd4b7770100f84ea2ccdf3a304
(7) 0xad157fbf68f3e7fb3047ca653c073b4389f5020ce8d397c7c8f3533c491a15ba
(8) 0x01caede47d8ad5d0e5c125b9d4ceba7abd201a26be10730fc926f673f275fd42
(9) 0x07da7e22ff6a56ce2c07bf724913e507621181f369d481fd94ebb12d577d4650

HD Wallet
Mnemonic:      team shoot anchor limit inform imitate melody decrease wing sadness orange mammal
Base HD Path:  m/44'/60'/0'/0/{account_index}

Default Gas Price

BlockGas Limit

Call Gas Limit

Chain Id

RPC Listening on

5. Setup connection to the ganache server

w3 = Web3(Web3.HTTPProvider(""))
chain_id = 1337
my_addr = "0xB136383615B477B1B816f4227A509ea8F0C0c9DD"
private_key = os.getenv("PRIVATE_KEY")


If we want to connect to Testnet environment, we can use an ETH gateway such as Infura or Alchemy.

6a. Create the contract with the provider using the abi and bytecode.

SimpleStorage = w3.eth.contract(abi=abi, bytecode=bytecode)

6b. Get latest transaction count and use it as the nonce

nonce = w3.eth.getTransactionCount(my_addr)

6c. Submit the transaction that deploys contract using the chainId, gasPrice, from (which addr) and nonce

transaction = SimpleStorage.constructor().buildTransaction(
        "chainId": chain_id,
        "gasPrice": w3.eth.gas_price,
        "from": my_addr,
        "nonce": nonce

6d. Sign the transaction with private key

signed_txn = w3.eth.account.sign_transaction(transaction, private_key=private_key)

7. Deploy the contract

tx_hash = w3.eth.send_raw_transaction(signed_txn.rawTransaction)tx_receipt = w3.eth.wait_for_transaction_receipt(tx_hash)contract_addr = tx_receipt.contractAddressprint(f"Contract is deployed to {contract_addr}")

Using the Smart Contract

Since the Smart Contract is deployed, we can provide the contract address and abi to create the smart contract (“simple_storage”).

simple_storage = w3.eth.contract(address=contract_addr, abi=abi)

We can make a function call without changing any state in the smart contract. In this example, we are trying to retrieve the stored value in the smart contract.

print(f"Initial Stored Value = {simple_storage.functions.retrieve().call()}")

Now, we call the store function in the smart contract to update favoriteNumber variable.

greeting_transaction =
        "chainId": chain_id,
        "gasPrice": w3.eth.gas_price,
        "from": my_addr,
        "nonce": nonce + 1

We will sign this transaction with the private key, send the transaction to the Ganache server and then wait for the transaction receipt.

Notice if you execute the transaction in local blockchain VM, the transaction speed will be very fast. But in actual Testnet or Mainnet, the transaction is likely to be slower.

signed_greeting_txn = w3.eth.account.sign_transaction(greeting_transaction, private_key=private_key)

tx_greeting_hash = w3.eth.send_raw_transaction(signed_greeting_txn.rawTransaction)

tx_receipt = w3.eth.wait_for_transaction_receipt(tx_greeting_hash)

Let’s print the stored value and we can see it is changed to 15


Python: Asyncio and Aiohttp


Suppose your program is trying to execute a series of tasks (1 – 6). If each task takes different time to complete, then your program will need to wait for each task to be completed sequentially before it can proceed.

Asyncio will be useful in such scenarios because it enables the program to continue running other tasks while waiting for the specific task to be completed. In order to use Asyncio, you will need to use compatible libraries. For example, instead of using requests (a popular HTTP library in Python), you will use aiohttp.

Note: In order to install aiohttp library in Windows system, you will need to download and install Microsoft C++ Build Tools.

When to use Asyncio?

  • You want to speed up a specific part of your program where you are running a list of tasks sequentially for large-N items.
  • Suppose you are making API calls based on a list of different values for a parameter, you can use asyncio and aiohttp to make the API requests.
  • You do not need to change your entire program to use async/await syntax. Try to observe which part of the program is a bottleneck and explore how asyncio can improve performance on this particular flow.

Example: Crawling Wikipedia for info on Football (Soccer) Clubs

In this demo, we are going to perform the list of tasks below:

  1. Read the list of football clubs from a csv file.
  2. Get the Wikipedia URL of each Football club.
  3. Get the Wikipedia HTML page of each Football club.
  4. Write the HTML page into a HTML file for each Football Club.
  5. From the HTML page, we need to parse for information (Full Name, Ground, Founded Date etc.) using BeautifulSoup library.
  6. For the information of each club, we want to append the information into a Dataframe.
  7. Finally, print out the Dataframe to see if the information is correct.

See the Synchronous example and Asynchronous example from my Github repo. If we execute both scripts, we can an estimated difference here where Asyncio complete the execution faster by about 20-30%.

Execution time for Asyncio : 17.885913610458374
Execution time for Synchronous: 23.075875997543335

Refactor Tips

  • As a practice, a co-routine main is often defined and used in an event loop (e.g. Then in the co-routine main function, all the other co-routines are await.
  • If the request has a consistent response time, then you should stick to the synchronous approach. For example, if you are using Pandas, then you should use apply() on a function. For parts of the program which are bottleneck, you should try with asyncio to see if the speed performance is improved.

Key Terms

Event Loop. You must use an event loop to run the co-routine.

# Running event loop for Python 3.7+

# Older syntax before Python 3.7+
loop = asyncio.get_event_loop()


async / await. This is the syntax for defining co-routines in python. You can declare a co-routine by using async def in front of a function. await is used inside a co-routine and tells the program to come back to foo() when do_something() is ready. Make sure that do_something() is also a co-routine.

async def foo():
    x = await do_something()
    return x

Recommended Resources

Black Hat Programming Series

Recently, I plan to work through two technical books (Black Hat Python and Black Hat Go).

One of the motivations of going through these books is to understand how to build tools for content discovery and brute-forcing. Also I will like to develop my Python scripting skills further.

In Black Hat Python, the sample code for the chapters are in Python 2. I decided to convert the Python 2 code to Python 3 code. I will also use libraries such as requests to replace some of the steps were performed by urllib and urllib2.

Here are some sample projects from Black Hat Python that were converted to Python 3:

Web Application Mapper
Once you identified the open source technology used by the target web app, you can download the open source code to your directory. The mapper will send request to the target and spider the target using the directories and file names used in the open source code.

The script uses the known directories of the particular to map out the attack surfaces of the web app

Content Brute Forcing
In cases where you do not know the exact technology stack, you will need to brute force using a common word list. The word list can contain the common directory and file names. In the book, the script allow extension brute forcing as well. I have added filter method that allow the script to display responses that have specific status codes (e.g. 200).

Notice only response with status 200 are displayed?

A common workflow that we can observe from these tooling scripts:

  • A word list or list of test cases are generated or taken from open source. These are added to the queue.
  • A filter or specific information list is given based on what we are interested during our recon.
  • Brute forcing can be done faster with threads.
  • The code might be simpler with the use of requests instead of urllib

All source code in this blog post can be found here