Skip to content

Commit

Permalink
Merge branch 'main' of https://github.com/mas6y6/CipherOS
Browse files Browse the repository at this point in the history
  • Loading branch information
mas6y6 committed Dec 13, 2024
2 parents 44ea350 + 7608bb9 commit fad0051
Show file tree
Hide file tree
Showing 9 changed files with 281 additions and 11 deletions.
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ An hacknet inspired hacking program
### Windows
You can use the standalone .exe from [releases](https://github.com/mas6y6/CipherOS/releases), or you can clone the repository locally and use [pyinstaller](https://pyinstaller.org/en/stable/) with `compile.bat`

Note: the standalone .exe will generate the `plugins` and `data` folder in the directory that the executable is run in, so it is recommended to drop the .exe in a dedicated folder before running.
> [!NOTE]
> the standalone .exe will generate the `plugins` and `data` folder in the directory that the executable is run in, so it is > > > recommended to drop the .exe in a dedicated folder before running.
### macOS / Linux
You can run:
Expand Down
39 changes: 39 additions & 0 deletions cipher.spec
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# -*- mode: python ; coding: utf-8 -*-


a = Analysis(
['main.py'],
pathex=[],
binaries=[],
datas=[],
hiddenimports=[],
hookspath=[],
hooksconfig={},
runtime_hooks=[],
excludes=['cipher'],
noarchive=False,
optimize=0,
)
pyz = PYZ(a.pure)

exe = EXE(
pyz,
a.scripts,
a.binaries,
a.datas,
[],
name='cipher',
debug=False,
bootloader_ignore_signals=False,
strip=False,
upx=True,
upx_exclude=[],
runtime_tmpdir=None,
console=True,
disable_windowed_traceback=False,
argv_emulation=False,
target_arch=None,
codesign_identity=None,
entitlements_file=None,
icon=['icon.ico'],
)
8 changes: 4 additions & 4 deletions cipher/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -165,18 +165,18 @@ def load_plugin(self, filepath):
print("\n\n")

def disable_plugin(self, plugin):
print(f"Disabling {plugin.__class__.name}")
plugin_instance = self.plugins[plugin.__class__.name]
print(f"Disabling {plugin}")
plugin_instance = self.plugins[plugin]
if hasattr(plugin_instance, "on_disable") and callable(
plugin_instance.on_disable
):
plugin_instance.on_disable()
else:
pass

for i in self.plugincommands[plugin.__class__.name]:
for i in self.plugincommands[plugin]:
self.commands.pop(i)
self.plugins.pop(plugin.__class__.name)
self.plugins.pop(plugin)
self.updatecompletions()

def updatecompletions(self):
Expand Down
37 changes: 37 additions & 0 deletions cipher/elevate/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import sys, platform, os, ctypes

def is_root():
system = platform.system()
if system in ["Linux", "Darwin"]:
try:
return os.getuid() == 0
except AttributeError:
return False
elif system == "Windows":
try:
return ctypes.windll.shell32.IsUserAnAdmin() != 0
except AttributeError:
return False
else:
raise NotImplementedError(f"Unsupported OS: {system}")

def elevate(show_console=True, graphical=True):
"""
Re-launch the current process with root/admin privileges
When run as root, this function does nothing.
When not run as root, this function replaces the current process (Linux,
macOS) or creates a child process, waits, and exits (Windows).
:param show_console: (Windows only) if True, show a new console for the
child process. Ignored on Linux / macOS.
:param graphical: (Linux / macOS only) if True, attempt to use graphical
programs (gksudo, etc). Ignored on Windows.
"""
if sys.platform.startswith("win"):
from elevate.windows import elevate
else:
from elevate.posix import elevate
elevate(show_console, graphical)

Binary file not shown.
54 changes: 54 additions & 0 deletions cipher/elevate/posix.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import errno
import os
import sys
try:
from shlex import quote
except ImportError:
from pipes import quote


def quote_shell(args):
return " ".join(quote(arg) for arg in args)


def quote_applescript(string):
charmap = {
"\n": "\\n",
"\r": "\\r",
"\t": "\\t",
"\"": "\\\"",
"\\": "\\\\",
}
return '"%s"' % "".join(charmap.get(char, char) for char in string)


def elevate(show_console=True, graphical=True):
if os.getuid() == 0:
return

args = [sys.executable] + sys.argv
commands = []

if graphical:
if sys.platform.startswith("darwin"):
commands.append([
"osascript",
"-e",
"do shell script %s "
"with administrator privileges "
"without altering line endings"
% quote_applescript(quote_shell(args))])

if sys.platform.startswith("linux") and os.environ.get("DISPLAY"):
commands.append(["pkexec"] + args)
commands.append(["gksudo"] + args)
commands.append(["kdesudo"] + args)

commands.append(["sudo"] + args)

for args in commands:
try:
os.execlp(args[0], *args)
except OSError as e:
if e.errno != errno.ENOENT or args[0] == "sudo":
raise
89 changes: 89 additions & 0 deletions cipher/elevate/windows.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
import ctypes
from ctypes import POINTER, c_ulong, c_char_p, c_int, c_void_p
from ctypes.wintypes import HANDLE, BOOL, DWORD, HWND, HINSTANCE, HKEY
from ctypes import windll
import subprocess
import sys

# Constant defintions


SEE_MASK_NOCLOSEPROCESS = 0x00000040
SEE_MASK_NO_CONSOLE = 0x00008000


# Type definitions

PHANDLE = ctypes.POINTER(HANDLE)
PDWORD = ctypes.POINTER(DWORD)


class ShellExecuteInfo(ctypes.Structure):
_fields_ = [
('cbSize', DWORD),
('fMask', c_ulong),
('hwnd', HWND),
('lpVerb', c_char_p),
('lpFile', c_char_p),
('lpParameters', c_char_p),
('lpDirectory', c_char_p),
('nShow', c_int),
('hInstApp', HINSTANCE),
('lpIDList', c_void_p),
('lpClass', c_char_p),
('hKeyClass', HKEY),
('dwHotKey', DWORD),
('hIcon', HANDLE),
('hProcess', HANDLE)]

def __init__(self, **kw):
super(ShellExecuteInfo, self).__init__()
self.cbSize = ctypes.sizeof(self)
for field_name, field_value in kw.items():
setattr(self, field_name, field_value)


PShellExecuteInfo = POINTER(ShellExecuteInfo)


# Function definitions

ShellExecuteEx = windll.shell32.ShellExecuteExA
ShellExecuteEx.argtypes = (PShellExecuteInfo, )
ShellExecuteEx.restype = BOOL

WaitForSingleObject = windll.kernel32.WaitForSingleObject
WaitForSingleObject.argtypes = (HANDLE, DWORD)
WaitForSingleObject.restype = DWORD

CloseHandle = windll.kernel32.CloseHandle
CloseHandle.argtypes = (HANDLE, )
CloseHandle.restype = BOOL


# At last, the actual implementation!

def elevate(show_console=True, graphical=True):
if windll.shell32.IsUserAnAdmin():
return

params = ShellExecuteInfo(
fMask=SEE_MASK_NOCLOSEPROCESS | SEE_MASK_NO_CONSOLE,
hwnd=None,
lpVerb=b'runas',
lpFile=sys.executable.encode('cp1252'),
lpParameters=subprocess.list2cmdline(sys.argv).encode('cp1252'),
nShow=int(show_console))

if not ShellExecuteEx(ctypes.byref(params)):
raise ctypes.WinError()

handle = params.hProcess
ret = DWORD()
WaitForSingleObject(handle, -1)

if windll.kernel32.GetExitCodeProcess(handle, ctypes.byref(ret)) == 0:
raise ctypes.WinError()

CloseHandle(handle)
sys.exit(ret.value)
60 changes: 55 additions & 5 deletions main.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import argparse
import ctypes
import os
import socket
import sys

import runpy
import rich
import rich.traceback

Expand Down Expand Up @@ -63,6 +64,7 @@ def get_resource_path(relative_path):
from rich.tree import Tree
from rich.markdown import Markdown


colorama.init()
running_on_mac = False # Meant as the cipher library is not installed (for macOS)
macpwd = None
Expand Down Expand Up @@ -109,6 +111,7 @@ def get_resource_path(relative_path):
import cipher.network
from cipher.parsers import ArgumentParser, ConfigParser
import cipher.api
from cipher.elevate import elevate, is_root

# variables
version = 1
Expand Down Expand Up @@ -144,7 +147,7 @@ def printerror(msg):
parser = argparse.ArgumentParser()
parser.add_argument("--debug",action="store_true",help="Enables debug mode")
parser.add_argument("--startdir",action="store",help="Overrides the cache directory")

parser.add_argument("--sudo",action="store_true",help="Enables sudo mode")
executeargs = parser.parse_args()

def is_running_in_appdata():
Expand Down Expand Up @@ -301,6 +304,38 @@ def scan_ports(ip, port):
table.add_row(str(port))
console.print(table)

@api.command(alias=["exe","cmd"])
def executables(argsraw):
parser = ArgumentParser(api, description="Lists all commands")

args = parser.parse_args(argsraw)

#If the --help (-h) is passes it kills the rest of the script
if parser.help_flag:
return None

tab = Table()
tab.add_column("Commands")
for i in api.commands:
tab.add_row(i)
console.print(tab)

@api.command()
def sudomode(argsraw):
parser = ArgumentParser(api, description="Elevates permissions to admin permissions for CipherOS")

args = parser.parse_args(argsraw)

if parser.help_flag:
return None

if not is_root():
console.print("Entering Sudomode",style="bright_red")
console.print("Acquiring Admin privileges (This may open a password prompt)",style="bright_red")
elevate(graphical=False)
else:
printerror("Error: Admin permissions already acquired")

@api.command(alias=["scn", "netscan"])
def scannet(argsraw):
parser = ArgumentParser(api, description="Scan your network for devices")
Expand Down Expand Up @@ -574,8 +609,8 @@ def plugins(argsraw):
elif args.subcommand == "reloadall":
console.print("Reloading all plugins...")
for plugin_name in list(api.plugins):
api.disable_plugin(api.plugins[plugin_name])
for plugin_file in os.listdir(os.path.join(api.starterdir,"CipherOS", "plugins")):
api.disable_plugin(api.plugins[plugin_name].config.name)
for plugin_file in os.listdir(os.path.join(api.starterdir, "plugins")):
api.load_plugin(os.path.join(api.starterdir, "plugins", plugin_file))
console.print("Reload complete.")

Expand Down Expand Up @@ -630,7 +665,6 @@ def plugins(argsraw):
else:
print("Unknown subcommand.")


@api.command()
def tree(argsraw):
parser = ArgumentParser(api, description="List the contents of a path in a tree-like structure, making it easier to read.")
Expand Down Expand Up @@ -726,6 +760,18 @@ def touch(argsraw):
args.file,
"exists" + colorama.Fore.RESET + colorama.Style.NORMAL,
)

@api.command(name="python",alias=["py"])
def pythoncode(argsraw):
parser = ArgumentParser(api,description="Executes a python file")
parser.add_argument("file", type=str, help_text="The file to display", required=True)

args = parser.parse_args(argsraw)

#If the --help (-h) is passes it kills the rest of the script
if parser.help_flag:
return None
runpy.run_path(args.file)

@api.command(alias=["cat"])
def viewfile(argsraw):
Expand Down Expand Up @@ -772,6 +818,8 @@ def remove(argsraw):

if debugmode:
console.print("Starting CipherOS in [purple]debug mode[/purple]")
if is_root():
console.print("Admin privileges detected starting as admin",style="bright_magenta")
api.debug = True
@api.command()
def arbc(argsraw):
Expand Down Expand Up @@ -813,6 +861,8 @@ def vdump(argsraw):
print(f"vdump encountered an error: {e}")
else:
console.print("Starting CipherOS")
if is_root():
console.print("Admin privileges detected starting as admin",style="bright_magenta")

if not len(os.listdir(os.path.join(api.starterdir,"plugins"))) == 0:
for i in os.listdir(os.path.join(api.starterdir,"plugins")):
Expand Down
2 changes: 1 addition & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,4 @@ ping3
netifaces
markdown
rich
hostprobe
hostprobe

0 comments on commit fad0051

Please sign in to comment.