Observe:
I didn’t end the final a part of the problem because it clashed with CNY 2025 and I received covid mid-way and was down for nearly every week.. I’d say I am 90% accomplished although.. what a waste..
Pre-requistes
Earlier than we begin reverse engineering the executables in ancient-runes.zip, now we have to obtain just a few instruments first.
WireShark
Obtain the suitable model from https://www.wireshark.org/obtain.html.
First clone the Github repository at https://github.com/extremecoders-re/pyinstxtractor.git.
git clone https://github.com/extremecoders-re/pyinstxtractor.git
Decompyle++
First clone the Github repository at https://github.com/zrax/pycdc.git.
git clone https://github.com/zrax/pycdc.git
Since I’ve homebrew put in on my Macbook, I’ll set up CMake and make to compile the supply code above.
brew set up cmake make
As soon as the formulation are put in, we’re able to go!
cmake -DCMAKE_BUILD_TYPE=Debug
make
sudo cp pycdc /usr/native/bin
sudo cp pycdas /usr/native/bin
Evaluation of the Artifact
After downloading the file, I extracted the zip file and located the next content material:
➜ pyinstxtractor git:(grasp) ✗ ll ../ancient-runes
complete 35792
-rwxr-xr-x@ 1 alex employees 8.7M Jan 13 22:23 consumer
-rwxr-xr-x@ 1 alex employees 8.7M Jan 13 22:22 dev_server
-rwxrwxrwx@ 1 alex employees 29K Jan 20 22:24 蛇年吉祥.pcapng
Let’s attempt to run the executables. Since I am utilizing M2 Macbook Professional, I am on the ARM64 structure. I have to test the executable to see if it is compiled for ARM64 or x64.
➜ ancient-runes file consumer
consumer: ELF 64-bit LSB executable, x86-64, model 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=8485f6953c06d12b9865185ba3466fdbf9b4a65c, for GNU/Linux 2.6.32, stripped
➜ ancient-runes file dev_server
dev_server: ELF 64-bit LSB executable, x86-64, model 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=8485f6953c06d12b9865185ba3466fdbf9b4a65c, for GNU/Linux 2.6.32, stripped
On this case, I should use a docker container in x64 arch to execute the recordsdata. Let’s begin by making a community:
docker community create csit-test-network
Then create the container to look at the executables:
docker run -it --platform linux/amd64 --network csit-test-network -v /ancient-runes:/recordsdata debian /bin/bash
Operating consumer:
root@a94da9751b86:/recordsdata# ./consumer
2025-01-23 20:27:56,979 - INFO - DEV_client.crt not discovered. Downloading...
2025-01-23 20:27:57,427 - INFO - Downloaded file from http://34.57.139.144:80/REVW/DEV_client.crt to DEV_client.crt
2025-01-23 20:27:57,428 - INFO - DEV_client.key not discovered. Downloading...
2025-01-23 20:27:57,987 - INFO - Downloaded file from http://34.57.139.144:80/REVW/DEV_client.key to DEV_client.key
2025-01-23 20:27:57,987 - INFO - DEV_ca.crt not discovered. Downloading...
2025-01-23 20:27:58,455 - INFO - Downloaded file from http://34.57.139.144:80/REVW/DEV_ca.crt to DEV_ca.crt
Operating server:
root@a94da9751b86:/recordsdata# ./dev_server
2025-01-23 20:28:24,684 - INFO - DEV_server.crt not discovered. Downloading...
2025-01-23 20:28:25,301 - INFO - Downloaded file from http://34.57.139.144:80/REVW/DEV_server.crt to DEV_server.crt
2025-01-23 20:28:25,302 - INFO - DEV_server.key not discovered. Downloading...
2025-01-23 20:28:25,876 - INFO - Downloaded file from http://34.57.139.144:80/REVW/DEV_server.key to DEV_server.key
2025-01-23 20:28:25,877 - INFO - DEV_ca.crt discovered.
2025-01-23 20:28:25,952 - INFO - server listening on 0.0.0.0:45605
2025-01-23 20:28:25,952 - INFO - server listening on [::]:45025
2025-01-23 20:28:25,952 - INFO - Server began...
That is begin. It downloaded DEV_client.crt, DEV_client.key, DEV_server.crt, DEV_server.key, DEV_ca.crt from http://34.57.139.144:80/REVW/
Let’s attempt to analyze the executables by decompiling to grasp the way it works.
For the reason that trace was given these 2 executable was created with PyInstaller, we will use PyInstaller Extractor to extract the content material of the executables (consumer & dev_server).
➜ pyinstxtractor git:(grasp) python3 pyinstxtractor.py ../ancient-runes/consumer
[+] Processing ../ancient-runes/consumer
[+] Pyinstaller model: 2.1+
[+] Python model: 3.10
[+] Size of bundle: 9084051 bytes
[+] Discovered 98 recordsdata in CArchive
[+] Starting extraction...please standby
[+] Attainable entry level: pyiboot01_bootstrap.pyc
[+] Attainable entry level: pyi_rth_inspect.pyc
[+] Attainable entry level: pyi_rth_pkgutil.pyc
[+] Attainable entry level: pyi_rth_multiprocessing.pyc
[+] Attainable entry level: consumer.pyc
[!] Warning: This script is working in a distinct Python model than the one used to construct the executable.
[!] Please run this script in Python 3.10 to stop extraction errors throughout unmarshalling
[!] Skipping pyz extraction
[+] Efficiently extracted pyinstaller archive: ../ancient-runes/consumer
Now you can use a python decompiler on the pyc recordsdata inside the extracted listing
➜ pyinstxtractor git:(grasp) ✗ python3 pyinstxtractor.py ../ancient-runes/dev_server
[+] Processing ../ancient-runes/dev_server
[+] Pyinstaller model: 2.1+
[+] Python model: 3.10
[+] Size of bundle: 9084774 bytes
[+] Discovered 98 recordsdata in CArchive
[+] Starting extraction...please standby
[+] Attainable entry level: pyiboot01_bootstrap.pyc
[+] Attainable entry level: pyi_rth_inspect.pyc
[+] Attainable entry level: pyi_rth_pkgutil.pyc
[+] Attainable entry level: pyi_rth_multiprocessing.pyc
[+] Attainable entry level: dev_server.pyc
[!] Warning: This script is working in a distinct Python model than the one used to construct the executable.
[!] Please run this script in Python 3.10 to stop extraction errors throughout unmarshalling
[!] Skipping pyz extraction
[+] Efficiently extracted pyinstaller archive: ../ancient-runes/dev_server
Now you can use a python decompiler on the pyc recordsdata inside the extracted listing
PyInstaller Extractor is telling us that the consumer and dev_server is utilizing Python 3.10, so I re-did the extraction once more with Python 3.10.
➜ pyinstxtractor git:(grasp) ✗ python3.10 pyinstxtractor.py ../ancient-runes/dev_server
[+] Processing ../ancient-runes/dev_server
[+] Pyinstaller model: 2.1+
[+] Python model: 3.10
[+] Size of bundle: 9084774 bytes
[+] Discovered 98 recordsdata in CArchive
[+] Starting extraction...please standby
[+] Attainable entry level: pyiboot01_bootstrap.pyc
[+] Attainable entry level: pyi_rth_inspect.pyc
[+] Attainable entry level: pyi_rth_pkgutil.pyc
[+] Attainable entry level: pyi_rth_multiprocessing.pyc
[+] Attainable entry level: dev_server.pyc
[+] Discovered 282 recordsdata in PYZ archive
[+] Efficiently extracted pyinstaller archive: ../ancient-runes/dev_server
Now you can use a python decompiler on the pyc recordsdata inside the extracted listing
➜ pyinstxtractor git:(grasp) ✗ python3.10 pyinstxtractor.py ../ancient-runes/consumer
[+] Processing ../ancient-runes/consumer
[+] Pyinstaller model: 2.1+
[+] Python model: 3.10
[+] Size of bundle: 9084051 bytes
[+] Discovered 98 recordsdata in CArchive
[+] Starting extraction...please standby
[+] Attainable entry level: pyiboot01_bootstrap.pyc
[+] Attainable entry level: pyi_rth_inspect.pyc
[+] Attainable entry level: pyi_rth_pkgutil.pyc
[+] Attainable entry level: pyi_rth_multiprocessing.pyc
[+] Attainable entry level: consumer.pyc
[+] Discovered 282 recordsdata in PYZ archive
[+] Efficiently extracted pyinstaller archive: ../ancient-runes/consumer
Now you can use a python decompiler on the pyc recordsdata inside the extracted listing
Inspection of Shopper
Let’s examine the recordsdata of consumer executable:
➜ pyinstxtractor git:(grasp) ✗ cd client_extracted
➜ client_extracted git:(grasp) ✗ ll
complete 29232
drwxr-xr-x@ 8 alex employees 256B Jan 24 01:39 Crypto
-rw-r--r--@ 1 alex employees 1.6M Jan 24 01:38 PYZ-00.pyz
drwxr-xr-x@ 2 alex employees 64B Jan 24 01:38 PYZ-00.pyz_extracted
-rw-r--r--@ 1 alex employees 860K Jan 24 01:38 base_library.zip
-rw-r--r--@ 1 alex employees 2.5K Jan 24 01:38 consumer.pyc
drwxr-xr-x@ 26 alex employees 832B Jan 24 01:39 lib-dynload
-rw-r--r--@ 1 alex employees 73K Jan 24 01:38 libbz2.so.1.0
-rw-r--r--@ 1 alex employees 4.2M Jan 24 01:38 libcrypto.so.3
-rw-r--r--@ 1 alex employees 190K Jan 24 01:38 libexpat.so.1
-rw-r--r--@ 1 alex employees 47K Jan 24 01:38 libffi.so.8
-rw-r--r--@ 1 alex employees 166K Jan 24 01:38 liblzma.so.5
-rw-r--r--@ 1 alex employees 183K Jan 24 01:38 libmpdec.so.3
-rw-r--r--@ 1 alex employees 5.6M Jan 24 01:38 libpython3.10.so
-rw-r--r--@ 1 alex employees 328K Jan 24 01:38 libreadline.so.8
-rw-r--r--@ 1 alex employees 652K Jan 24 01:38 libssl.so.3
-rw-r--r--@ 1 alex employees 195K Jan 24 01:38 libtinfo.so.6
-rw-r--r--@ 1 alex employees 30K Jan 24 01:38 libuuid.so.1
-rw-r--r--@ 1 alex employees 106K Jan 24 01:38 libz.so.1
-rw-r--r--@ 1 alex employees 909B Jan 24 01:38 pyi_rth_inspect.pyc
-rw-r--r--@ 1 alex employees 1.1K Jan 24 01:38 pyi_rth_multiprocessing.pyc
-rw-r--r--@ 1 alex employees 964B Jan 24 01:38 pyi_rth_pkgutil.pyc
-rw-r--r--@ 1 alex employees 873B Jan 24 01:38 pyiboot01_bootstrap.pyc
-rw-r--r--@ 1 alex employees 3.0K Jan 24 01:38 pyimod01_archive.pyc
-rw-r--r--@ 1 alex employees 21K Jan 24 01:38 pyimod02_importers.pyc
-rw-r--r--@ 1 alex employees 3.6K Jan 24 01:38 pyimod03_ctypes.pyc
-rw-r--r--@ 1 alex employees 287B Jan 24 01:38 struct.pyc
drwxr-xr-x@ 3 alex employees 96B Jan 24 01:39 websockets
drwxr-xr-x@ 9 alex employees 288B Jan 24 01:39 websockets-14.1.dist-info
Let’s decompile the bytecode for consumer.pyc.
➜ client_extracted git:(grasp) ✗ pycdc consumer.pyc > consumer.py
Unsupported opcode: BEFORE_ASYNC_WITH (94)
Unsupported opcode: BEFORE_ASYNC_WITH (94)
Let’s take a look at the content material for consumer.py
# Supply Generated with Decompyle++
# File: consumer.pyc (Python 3.10)
from dotenv import load_dotenv
import asyncio
import websockets
import logging
import threading
import ssl
import os
import urllib.request as urllib
import sys
import socket
from widespread import validate, generate_client_context, generate_random_string
from constants import LOGGING_VERBOSITY, HINT_3
load_dotenv()
logging.basicConfig(LOGGING_VERBOSITY, '%(asctime)s - %(levelname)s - %(message)s', **('stage', 'format'))
SERVER_IP = os.getenv('SERVER_IP', '127.127.127.127')
SERVER_PORT = os.getenv('SERVER_PORT', '9999')
WS_IP = os.getenv('WS_IP', '0.0.0.0')
WS_PORT = os.getenv('WS_PORT', '8000')
TIMEOUT = 5
CA_CERT = 'DEV_ca.crt'
CLIENT_CERT = 'DEV_client.crt'
CLIENT_KEY = 'DEV_client.key'
CLIENT_SERVER = f'''http://{SERVER_IP}:{SERVER_PORT}/REVW/'''
CLIENT_PATH = ''
CERT_URL = f'''{CLIENT_SERVER}{CLIENT_CERT}'''
CERT_PATH = f'''{CLIENT_PATH}{CLIENT_CERT}'''
KEY_URL = f'''{CLIENT_SERVER}{CLIENT_KEY}'''
KEY_PATH = f'''{CLIENT_PATH}{CLIENT_KEY}'''
CA_URL = f'''{CLIENT_SERVER}{CA_CERT}'''
CA_PATH = f'''{CLIENT_PATH}{CA_CERT}'''
validate(CERT_URL, CERT_PATH, logging)
validate(KEY_URL, KEY_PATH, logging)
validate(CA_URL, CA_PATH, logging)
context = generate_client_context(CERT_PATH, KEY_PATH, CA_PATH, logging)
async def listen_messages(uri, headers, log):
go
# WARNING: Decompyle incomplete
async def send_commands(uri, headers, log):
go
# WARNING: Decompyle incomplete
def start_client():
_string = generate_random_string()
headersl = {
'X-ARBOC': f'''{_string}-listener''' }
headerss = {
'X-ARBOC': f'''{_string}-sender''' }
uri = f'''wss://{WS_IP}:{WS_PORT}/'''
listener_thread = None((lambda : asyncio.run(listen_messages(uri, headersl, logging))), **('goal',))
listener_thread.daemon = True
listener_thread.begin()
asyncio.run(send_commands(uri, headerss, logging))
if __name__ == '__main__':
start_client()
return None
We are able to see that the async capabilities listen_messages() and send_commands() fails to decompile.
Let’s strive with one other device PyLingual. I get the next. It seems to be like a quite simple websocket consumer.
# Decompiled with PyLingual (https://pylingual.io)
# Inside filename: consumer.py
# Bytecode model: 3.10.0rc2 (3439)
# Supply timestamp: 1970-01-01 00:00:00 UTC (0)
from dotenv import load_dotenv
import asyncio
import websockets
import logging
import threading
import ssl
import os
import urllib.request
import sys
import socket
from widespread import validate, generate_client_context, generate_random_string
from constants import LOGGING_VERBOSITY, HINT_3
load_dotenv()
logging.basicConfig(stage=LOGGING_VERBOSITY, format="%(asctime)s - %(levelname)s - %(message)s")
SERVER_IP = os.getenv('SERVER_IP', '127.127.127.127')
SERVER_PORT = os.getenv('SERVER_PORT', '9999')
WS_IP = os.getenv('WS_IP', '0.0.0.0')
WS_PORT = os.getenv('WS_PORT', '8000')
TIMEOUT = 5
CA_CERT = 'DEV_ca.crt'
CLIENT_CERT = 'DEV_client.crt'
CLIENT_KEY = 'DEV_client.key'
CLIENT_SERVER = f'http://{SERVER_IP}:{SERVER_PORT}/REVW/'
CLIENT_PATH = ''
CERT_URL = f'{CLIENT_SERVER}{CLIENT_CERT}'
CERT_PATH = f'{CLIENT_PATH}{CLIENT_CERT}'
KEY_URL = f'{CLIENT_SERVER}{CLIENT_KEY}'
KEY_PATH = f'{CLIENT_PATH}{CLIENT_KEY}'
CA_URL = f'{CLIENT_SERVER}{CA_CERT}'
CA_PATH = f'{CLIENT_PATH}{CA_CERT}'
validate(CERT_URL, CERT_PATH, logging)
validate(KEY_URL, KEY_PATH, logging)
validate(CA_URL, CA_PATH, logging)
context = generate_client_context(CERT_PATH, KEY_PATH, CA_PATH, logging)
async def listen_messages(uri, headers, log):
strive:
async with websockets.join(uri, additional_headers=headers, ssl=context) as websocket:
whereas True:
message = await websocket.recv()
print(f'>> {message}0')
besides asyncio.TimeoutError:
return None
besides Exception as E:
log.debug(f'{HINT_3}')
async def send_commands(uri, headers, log):
strive:
async with websockets.join(uri, additional_headers=headers, ssl=context) as websocket:
whereas True:
message = enter('')
if message.strip():
await websocket.ship(message)
besides asyncio.TimeoutError:
return None
besides Exception as E:
log.debug(f'{HINT_3}')
def start_client():
_string = generate_random_string()
headersl = {'X-ARBOC': f'{_string}0-listener'}
headerss = {'X-ARBOC': f'{_string}0-sender'}
uri = f'wss://{WS_IP}:{WS_PORT}/'
listener_thread = threading.Thread(goal=lambda: asyncio.run(listen_messages(uri, headersl, logging)))
listener_thread.daemon = True
listener_thread.begin()
asyncio.run(send_commands(uri, headerss, logging))
if __name__ == '__main__':
start_client()
We are able to see that there is a widespread module that was imported and never a part of the usual python module. Let’s attempt to decompile widespread.pyc bytecode!
# Decompiled with PyLingual (https://pylingual.io)
# Inside filename: widespread.py
# Bytecode model: 3.10.0rc2 (3439)
# Supply timestamp: 1970-01-01 00:00:00 UTC (0)
import os
import urllib.request
import ssl
import random
import string
from Crypto.Cipher import DES3
from Crypto.Random import get_random_bytes
from Crypto.Util.Padding import pad, unpad
from constants import HINT_1, HINT_2
def generate_random_string(size=8):
return ''.be a part of(random.decisions(string.ascii_letters + string.digits, okay=size))
def download_file(url, dest_path, log):
strive:
with urllib.request.urlopen(url) as response:
with open(dest_path, 'wb') as f:
f.write(response.learn())
log.data(f'Downloaded file from {url}0 to {dest_path}0')
return True
besides Exception as e:
return False
def validate(URL, FILE, log):
if not os.path.exists(FILE):
log.data(f'{FILE} not discovered. Downloading...')
if not download_file(URL, FILE, log):
log.debug(f'{HINT_1}')
else:
log.data(f'{FILE} discovered.')
def decrypt_3des(ciphertext: bytes, key: bytes):
iv = ciphertext[:DES3.block_size]
cipher = DES3.new(key, DES3.MODE_CBC, iv=iv)
decrypted_data = unpad(cipher.decrypt(ciphertext[DES3.block_size:]), DES3.block_size)
return decrypted_data.decode()
def generate_client_context(CERT_PATH, KEY_PATH, CA_PATH, log):
strive:
context = ssl.create_default_context(ssl.Function.SERVER_AUTH, cafile=CA_PATH)
context.choices |= ssl.OP_NO_SSLv2
context.choices |= ssl.OP_NO_SSLv3
context.load_cert_chain(certfile=CERT_PATH, keyfile=KEY_PATH)
context.choices |= ssl.OP_NO_TLSv1_3
context.set_ciphers('RSA')
return context
besides Exception as e:
print(e)
log.debug(f'{HINT_2}')
def generate_server_context(CERT_PATH, KEY_PATH, CA_PATH, log):
strive:
context = ssl.create_default_context(ssl.Function.CLIENT_AUTH)
context.load_cert_chain(certfile=CERT_PATH, keyfile=KEY_PATH)
context.load_verify_locations(cafile=CA_PATH)
context.verify_mode = ssl.CERT_REQUIRED
context.choices |= ssl.OP_NO_TLSv1_3
context.set_ciphers('RSA')
return context
besides Exception as e:
log.debug(f'{HINT_2}')
def init():
if not os.path.exists('.env'):
env_content="nLOGGING_VERBOSITY=REG0DnnSERVER_IP=34.57.139.144nSERVER_PORT=80nnWS_IP=nWS_PORT=n"
with open('.env', 'w') as env_file:
env_file.write(env_content.strip())
init()
We see that there is additionally a constants module that isn’t normal. Let’s attempt to decompile that too!
# Decompiled with PyLingual (https://pylingual.io)
# Inside filename: constants.py
# Bytecode model: 3.10.0rc2 (3439)
# Supply timestamp: 1970-01-01 00:00:00 UTC (0)
import logging
import os
from dotenv import load_dotenv
load_dotenv()
LOGGING_VERBOSITY = os.getenv('LOGGING_VERBOSITY', 'NONE')
LOGGING_MORE_VERBOSITY = os.getenv('LOGGING_MORE_VERBOSITY', 'NONE')
if LOGGING_VERBOSITY == 'REG0D' and LOGGING_MORE_VERBOSITY == 'y0uReOnToSomEThinG':
LOGGING_VERBOSITY = logging.DEBUG
elif LOGGING_VERBOSITY == 'REG0D':
LOGGING_VERBOSITY = logging.INFO
else:
LOGGING_VERBOSITY = logging.ERROR
HINT_1 = '[HINT] Have you ever tried REading the binaries? The place are you downloading them from?'
HINT_2 = '[HINT] Have you ever tried REading the binaries? Is your SSL Context malformed or what?'
HINT_3 = "[HINT] Have you ever tried REading the binaries? Bruh we won't make a connection..."
Ahh.. sneaky. We are able to see that within the init sequence, a .env file is robotically created with LOGGING_VERBOSITY=REG0D. Nonetheless, analyzing constants.py, we realised that that may configure the logger to INFO solely. If we set the LOGGING_VERBOSITY to another values, it’ll set to ERROR solely.
def init():
if not os.path.exists('.env'):
env_content="nLOGGING_VERBOSITY=REG0DnnSERVER_IP=34.57.139.144nSERVER_PORT=80nnWS_IP=nWS_PORT=n"
with open('.env', 'w') as env_file:
env_file.write(env_content.strip())
init()
We might want to allow DEBUG stage as many hints and errors are reported at DEBUG stage primarily based on the decompiled code. It is also sneaky that it’ll attempt to get ENV variables for LOGGING_VERBOSITY and LOGGING_MORE_VERBOSITY and set to NONE if no ENV variables exists. This implies setting it in .env is not going to work!
Let’s add the ENV variables!
export LOGGING_VERBOSITY=REG0D
export LOGGING_MORE_VERBOSITY=y0uReOnToSomEThinG
Now, let’s run the consumer!
Observe: I’ve already ran the dev_server executable after I’m scripting this. Please run the executable under to get the identical output as me.
root@4b3dc7eb6580:/recordsdata# export LOGGING_VERBOSITY=REG0D
export LOGGING_MORE_VERBOSITY=y0uReOnToSomEThinG
root@4b3dc7eb6580:/recordsdata# ./consumer
2025-01-27 17:59:55,906 - INFO - DEV_client.crt discovered.
2025-01-27 17:59:55,907 - INFO - DEV_client.key discovered.
2025-01-27 17:59:55,907 - INFO - DEV_ca.crt discovered.
2025-01-27 17:59:55,927 - DEBUG - Utilizing selector: EpollSelector
2025-01-27 17:59:55,927 - DEBUG - Utilizing selector: EpollSelector
2025-01-27 17:59:55,951 - DEBUG - = connection is CONNECTING
2025-01-27 17:59:55,952 - DEBUG - = connection is CONNECTING
2025-01-27 17:59:56,012 - DEBUG - > GET / HTTP/1.1
2025-01-27 17:59:56,012 - DEBUG - > Host: 0.0.0.0:8000
2025-01-27 17:59:56,012 - DEBUG - > Improve: websocket
2025-01-27 17:59:56,012 - DEBUG - > Connection: Improve
2025-01-27 17:59:56,012 - DEBUG - > Sec-WebSocket-Key: WZfM4iInYIqmmdTuKKo01A==
2025-01-27 17:59:56,012 - DEBUG - > Sec-WebSocket-Model: 13
2025-01-27 17:59:56,012 - DEBUG - > Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits
2025-01-27 17:59:56,012 - DEBUG - > X-ARBOC: jIkMgQPk-sender
2025-01-27 17:59:56,013 - DEBUG - > Consumer-Agent: Python/3.10 websockets/14.1
2025-01-27 17:59:56,013 - DEBUG - > GET / HTTP/1.1
2025-01-27 17:59:56,013 - DEBUG - > Host: 0.0.0.0:8000
2025-01-27 17:59:56,013 - DEBUG - > Improve: websocket
2025-01-27 17:59:56,014 - DEBUG - > Connection: Improve
2025-01-27 17:59:56,014 - DEBUG - > Sec-WebSocket-Key: 9rd5iIBBz9Hr1mGfEOxj2A==
2025-01-27 17:59:56,014 - DEBUG - > Sec-WebSocket-Model: 13
2025-01-27 17:59:56,014 - DEBUG - > Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits
2025-01-27 17:59:56,014 - DEBUG - > X-ARBOC: jIkMgQPk-listener
2025-01-27 17:59:56,014 - DEBUG - > Consumer-Agent: Python/3.10 websockets/14.1
2025-01-27 17:59:56,018 - DEBUG - > Welcome to the chat!
Inspection of Dev_Server
Let’s examine the recordsdata of dev_server executable:
➜ dev_server_extracted git:(grasp) ✗ ll
complete 29240
drwxr-xr-x@ 8 alex employees 256B Jan 24 01:39 Crypto
-rw-r--r--@ 1 alex employees 1.6M Jan 24 01:38 PYZ-00.pyz
drwxr-xr-x@ 2 alex employees 64B Jan 24 01:38 PYZ-00.pyz_extracted
-rw-r--r--@ 1 alex employees 860K Jan 24 01:38 base_library.zip
-rw-r--r--@ 1 alex employees 3.5K Jan 24 01:38 dev_server.pyc
drwxr-xr-x@ 26 alex employees 832B Jan 24 01:39 lib-dynload
-rw-r--r--@ 1 alex employees 73K Jan 24 01:38 libbz2.so.1.0
-rw-r--r--@ 1 alex employees 4.2M Jan 24 01:38 libcrypto.so.3
-rw-r--r--@ 1 alex employees 190K Jan 24 01:38 libexpat.so.1
-rw-r--r--@ 1 alex employees 47K Jan 24 01:38 libffi.so.8
-rw-r--r--@ 1 alex employees 166K Jan 24 01:38 liblzma.so.5
-rw-r--r--@ 1 alex employees 183K Jan 24 01:38 libmpdec.so.3
-rw-r--r--@ 1 alex employees 5.6M Jan 24 01:38 libpython3.10.so.1.0
-rw-r--r--@ 1 alex employees 328K Jan 24 01:38 libreadline.so.8
-rw-r--r--@ 1 alex employees 652K Jan 24 01:38 libssl.so.3
-rw-r--r--@ 1 alex employees 195K Jan 24 01:38 libtinfo.so.6
-rw-r--r--@ 1 alex employees 30K Jan 24 01:38 libuuid.so.1
-rw-r--r--@ 1 alex employees 106K Jan 24 01:38 libz.so.1
-rw-r--r--@ 1 alex employees 909B Jan 24 01:38 pyi_rth_inspect.pyc
-rw-r--r--@ 1 alex employees 1.1K Jan 24 01:38 pyi_rth_multiprocessing.pyc
-rw-r--r--@ 1 alex employees 964B Jan 24 01:38 pyi_rth_pkgutil.pyc
-rw-r--r--@ 1 alex employees 873B Jan 24 01:38 pyiboot01_bootstrap.pyc
-rw-r--r--@ 1 alex employees 3.0K Jan 24 01:38 pyimod01_archive.pyc
-rw-r--r--@ 1 alex employees 21K Jan 24 01:38 pyimod02_importers.pyc
-rw-r--r--@ 1 alex employees 3.6K Jan 24 01:38 pyimod03_ctypes.pyc
-rw-r--r--@ 1 alex employees 287B Jan 24 01:38 struct.pyc
drwxr-xr-x@ 3 alex employees 96B Jan 24 01:39 websockets
drwxr-xr-x@ 9 alex employees 288B Jan 24 01:39 websockets-14.1.dist-info
Let’s decompile the bytecode for dev_server.pyc.
➜ dev_server_extracted git:(grasp) ✗ pycdc dev_server.pyc > dev_server.py
Unsupported use of GET_AITER exterior of SETUP_LOOP
Unsupported opcode: END_ASYNC_FOR (98)
Unsupported opcode: JUMP_IF_NOT_EXC_MATCH (210)
Unsupported Node kind: 28
Let’s take a look at the content material for dev_server.py
# Supply Generated with Decompyle++
# File: dev_server.pyc (Python 3.10)
from dotenv import load_dotenv
import asyncio
import websockets
import logging
import os
from widespread import validate, generate_server_context, decrypt_3des
from constants import LOGGING_VERBOSITY
load_dotenv()
logging.basicConfig(LOGGING_VERBOSITY, '%(asctime)s - %(levelname)s - %(message)s', **('stage', 'format'))
SERVER_IP = os.getenv('SERVER_IP', '127.127.127.127')
SERVER_PORT = os.getenv('SERVER_PORT', '9999')
WS_IP = os.getenv('WS_IP', '0.0.0.0')
WS_PORT = os.getenv('WS_PORT', '8000')
CA_CERT = 'DEV_ca.crt'
SERVER_CERT = 'DEV_server.crt'
SERVER_KEY = 'DEV_server.key'
SERVER_SERVER = f'''http://{SERVER_IP}:{SERVER_PORT}/REVW/'''
SERVER_PATH = ''
CERT_URL = f'''{SERVER_SERVER}{SERVER_CERT}'''
CERT_PATH = f'''{SERVER_PATH}{SERVER_CERT}'''
KEY_URL = f'''{SERVER_SERVER}{SERVER_KEY}'''
KEY_PATH = f'''{SERVER_PATH}{SERVER_KEY}'''
CA_URL = f'''{SERVER_SERVER}{CA_CERT}'''
CA_PATH = f'''{SERVER_PATH}{CA_CERT}'''
validate(CERT_URL, CERT_PATH, logging)
validate(KEY_URL, KEY_PATH, logging)
validate(CA_URL, CA_PATH, logging)
context = generate_server_context(CERT_PATH, KEY_PATH, CA_PATH, logging)
purchasers = { }
FLAG = '7eb66acfb3652e80ef006143b4e5b6565b84b51355b26e39d2979a3bc873ba394ecae0061bd9522a9639ac4488733ad97d5e5acfb1e3e6f7'
def header_extraction(websocket):
headers = websocket.request.headers['X-ARBOC']
elements = headers.break up('-', 1)
clientId = elements[0]
clientType = elements[1]
return [
clientId,
clientType]
async def handler(websocket):
elements = header_extraction(websocket)
clientId = elements[0]
clientType = elements[1]
if clientId not in purchasers:
purchasers[clientId] = {
clientType: websocket }
else:
purchasers[clientId][clientType] = websocket
# WARNING: Decompyle incomplete
async def broadcast(message, websocket):
to_remove = []
senderId = header_extraction(websocket)[0]
# WARNING: Decompyle incomplete
async def principal():
if context != None:
await websockets.serve(handler, WS_IP, WS_PORT, context, 3600, 3600, 600, **('ssl', 'ping_interval', 'ping_timeout', 'close_timeout'))
server =





红火热闹汉语拼音
红火热闹






