HTTP Proxy using Amazon Lambda for source IP cycling
This tool is a mitmproxy plugin that will intercept your HTTP/S requests and redirect them to an Amazon Lambda function. This way your request can be proxied through many IP addresses.
Thus plugin takes a number of arguments.
roleArn - Required - The AWS ARN for your Lambda Role. Create this in IAM.
scope - Optional - Comma-separated list of in-scope URLs.
maxWorkers - Optional - Integer specifying the number of Lambda workers to spin up. Default is 1.
maxInvocations - Optional - Requests will not be forwarded to Lambda after this number is reached.
regions - Optional - Comma-separated list of AWS regions to cycle for each request. Default is all supported regions.
trigger - Optional - If this string shows up in the response, your IP is considered burned. Lambproxy rebuilds that worker and resends the request automatically.
mitmproxy -p 8000 -s lambproxy.py --set scope='http://api.ipify.org,https://api.ipify.org' --set roleArn='arn:aws:iam::123456789012:role/service-role/lambproxy-role-abcdefgh' --set maxWorkers=10 --set regions='us-west-1,us-west-2,us-east-1'
Lambproxy will create Lambda functions within your AWS account. Therefore, it will require limited access to an AWS account in order to function properly. Lambproxy relies on Boto3 for AWS authentication. AWS access keys can be placed in environment variables, a credential file, etc as permitted by Boto3. Newly created Lambda functions will require an execution role. Below is a basic working exeecution role template. This role gives the Lambda functions access to the defined AWS resources. Your user account does not need this access.
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "logs:CreateLogGroup",
"Resource": "arn:aws:logs:*:123456789012:*"
},
{
"Effect": "Allow",
"Action": [
"logs:CreateLogStream",
"logs:PutLogEvents"
],
"Resource": [
"arn:aws:logs:*:123456789012:log-group:/aws/lambda/lambproxy:*"
]
}
]
}
Lambproxy must be run as a user with access to four Lambda permissions and two IAM permissions. The below policy template can be applied to your Lambproxy user account to provide it with minimal working permissions.
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"lambda:CreateFunction",
"lambda:InvokeFunction",
"lambda:DeleteFunction"
],
"Resource": "arn:aws:lambda:*:123456789012:function:lambproxy_*"
},
{
"Effect": "Allow",
"Action": "lambda:ListFunctions",
"Resource": "*"
},
{
"Effect": "Allow",
"Action": [
"iam:GetRole",
"iam:PassRole"
],
"Resource": "arn:aws:iam::123456789012:role/service-role/lambproxy-role-abcdefgh"
}
]
}
A "Worker" is a Lambda function that acts as an HTTP/S proxy. Each worker has a chance of obtaining its own unique IP address. Each worker's IP address is set automatically by AWS when the function is invoked, though in practice each worker tends to have the same IP address with multiple invocations. Therefore, the more workers you have, the higher chance you will have a larger number of unique source IPs. It is possible for multiple workers to have the same source iP address as a coincidence. Lambproxy will create workers with the name "lambproxy_X" where X is a number 1 through (maxWorkers). Every time a new request comes in, Lambproxy will cycle to the next worker in the next region. When it reaches the maxmimum number then it cycles back to one.
You can specify as many scope items as you like. Scoping is not strict, but you can be more restrictive by specifying directories and subdirectories. If no scope is specified then all URLs are in-scope.
scope='http://www.foo.com/' - Matches http://www.foo.com/*
scope='http://www.foo.com/test/only/here' - Matches http://www.foo.com/test/only/here*
scope='https://www.foo.com,https://www.foo.com' - Matches HTTP and HTTPS traffic for www.foo.com
scope='http' - Matches any URL containing "http" (all URLs)
Lambproxy has a hard time cleaning up the lambda workers automatically when mitmproxy exits. You can clean them manually within the mitmproxy console by issuing the Lambproxy.cleanup command. This command searches Lambda for for all functions matching "lambscan_x" where x is an integer. All matching functions will be deleted.
:Lambproxy.cleanup
- Lambproxy is slow. It can take 2-3 seconds for a Lambda function to execute and return, which introduces delay to your HTTP request.
- This tool fails open, so don't expect it to hide your real IP from a given target. This is not a privacy tool.
- This tool probably breaks the AWS Acceptable Use Policy.
- Due to the nature of how this tool works, websockets are not supported.
- mitmproxy intercepts (and decrypts, if necessary) HTTP/S traffic.
- If the URL is out of scope, it is forwarded along to the destination as normal.
- If the URL is in scope, the entire raw request is base64 encoded.
- The lambda worker is then invoked with the encoded request sent as part of the Lambda event payload.
- The lambda worker then opens a socket to the host on the specified port (using TLS if needed).
- The lambda worker decodes the request and forwards it to the destination server via the socket.
- The lambda worker receives a response, base64 encodes it, and returns this value to mitmproxy.
- Lambproxy decodes the response and parses it to build a mitmproxy HTTPResponse object it can then return to the browser.
- The mitmproxy "done" function is supposed to automatically cleanup Lambda functions when the add-on exits. For some reason mitmproxy closes before this can happen. You have to maually execute the :Lambproxy.cleanup function from the mitmproxy console to ensure they are removed from Lambda.
- Lambproxy creates and deletes functions one at a time. Meaning that if you create a large number of workers, it will be slower to startup and to issue the cleanup command.
- Sometimes you have to issue the :Lambproxy.cleanup command multiple times to ensure all functions are removed. I think this may be related to API rate-limiting (The irony!)