Skip to content

Commit

Permalink
🗓 Jul 8, 2024 10:50:40 PM
Browse files Browse the repository at this point in the history
🤖 types added/updated
✨ walk_dir
✨ search_dir
🧪 tests added/updated
  • Loading branch information
securisec committed Jul 9, 2024
1 parent d3e7c72 commit e2a9284
Show file tree
Hide file tree
Showing 8 changed files with 93 additions and 23 deletions.
2 changes: 1 addition & 1 deletion chepy/__version__.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
__version__ = "7.2.0" # pragma: no cover
__version__ = "7.3.0" # pragma: no cover
__author__ = "@securisec" # pragma: no cover
35 changes: 35 additions & 0 deletions chepy/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -1666,3 +1666,38 @@ def encode_bytes(obj):

self.state = json.dumps(encode_bytes(self.state))
return self

@ChepyDecorators.call_stack
def walk_dir(self):
"""Walk a directory and get all file paths
Returns:
Chepy: The Chepy object.
"""
p = self._convert_to_str()
paths = Path(p).glob("**/*")
self.state = [str(p) for p in paths]
return self

@ChepyDecorators.call_stack
def search_dir(self, pattern: Union[bytes, str]):
"""Search all files in a directory. Pattern is case insensitive
Args:
pattern (Union[bytes, str]): regex to search
Returns:
Chepy: The Chepy object.
"""
paths = self._convert_to_str()
rgx = re.compile(self._str_to_bytes(pattern), flags=re.I)
hold = []
for path in Path(paths).glob("**/*"):
if path.is_dir(): # pragma: no cover
continue
data = path.read_bytes()
matched = rgx.findall(data)
if matched:
hold += matched
self.state = hold
return self
2 changes: 2 additions & 0 deletions chepy/core.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -88,3 +88,5 @@ class ChepyCore:
def get_register(self: ChepyCoreT, key: str) -> Union[str, bytes]: ...
def set_register(self: ChepyCoreT, key: str, val: Union[str, bytes]) -> ChepyCoreT: ...
def dump_json(self: ChepyCoreT) -> ChepyCoreT: ...
def walk_dir(self: ChepyCoreT) -> ChepyCoreT: ...
def search_dir(self: ChepyCoreT, pattern: Union[str, bytes]) -> ChepyCoreT: ...
1 change: 0 additions & 1 deletion chepy/modules/dataformat.py
Original file line number Diff line number Diff line change
Expand Up @@ -551,7 +551,6 @@ def from_base64(
Chepy: The Chepy object.
Examples:
Base64 decode using a custom string
>>> c = Chepy("QqxhNG/mMKtYPqoz64FVR42=")
>>> c.from_base64(alphabet="./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz")
>>> c.out
Expand Down
48 changes: 34 additions & 14 deletions chepy/modules/encryptionencoding.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import base64
import binascii
import codecs
import itertools
import string
import random
Expand Down Expand Up @@ -162,7 +161,9 @@ def rotate_bruteforce(self) -> EncryptionEncodingT:
return self

@ChepyDecorators.call_stack
def rot_13(self, amount=13, rotate_lower=True, rotate_upper=True, rotate_numbers=False) -> EncryptionEncodingT:
def rot_13(
self, amount=13, rotate_lower=True, rotate_upper=True, rotate_numbers=False
) -> EncryptionEncodingT:
"""Rot 13
Args:
Expand All @@ -172,20 +173,20 @@ def rot_13(self, amount=13, rotate_lower=True, rotate_upper=True, rotate_numbers
rotate_numbers (bool, optional): Rotate numbers. Defaults to False.
Returns:
Chepy: The Chepy object.
Chepy: The Chepy object.
"""
text = self._convert_to_str()
result = []
for char in text:
if rotate_lower and 'a' <= char <= 'z': # Lowercase letters
result.append(chr((ord(char) - ord('a') + amount) % 26 + ord('a')))
elif rotate_upper and 'A' <= char <= 'Z': # Uppercase letters
result.append(chr((ord(char) - ord('A') + amount) % 26 + ord('A')))
elif rotate_numbers and '0' <= char <= '9': # Numbers
result.append(chr((ord(char) - ord('0') + amount) % 10 + ord('0')))
if rotate_lower and "a" <= char <= "z": # Lowercase letters
result.append(chr((ord(char) - ord("a") + amount) % 26 + ord("a")))
elif rotate_upper and "A" <= char <= "Z": # Uppercase letters
result.append(chr((ord(char) - ord("A") + amount) % 26 + ord("A")))
elif rotate_numbers and "0" <= char <= "9": # Numbers
result.append(chr((ord(char) - ord("0") + amount) % 10 + ord("0")))
else:
result.append(char) # Non-alphabetical characters remain unchanged
self.state = ''.join(result)
self.state = "".join(result)
return self

@ChepyDecorators.call_stack
Expand Down Expand Up @@ -311,19 +312,19 @@ def rot_8000(self):
def xor(
self,
key: str,
key_type: Literal["hex", "utf", "base64", "decimal"] = "hex",
key_type: Literal["hex", "utf8", "base64", "decimal"] = "hex",
) -> EncryptionEncodingT:
"""XOR state with a key
Args:
key (str): Required. The key to xor by
key_type (str, optional): The key type. Valid values are hex, utf, decimal and base64. Defaults to "hex".
key_type (str, optional): The key type. Valid values are hex, utf8, decimal and base64. Defaults to "hex".
Returns:
Chepy: The Chepy object.
Examples:
>>> Chepy("secret").xor(key="secret", key_type="utf").to_hex()
>>> Chepy("secret").xor(key="secret", key_type="utf8").to_hex()
000000000000
"""

Expand All @@ -334,7 +335,7 @@ def xor(
x.append(char ^ key_val)

else:
if key_type == "utf":
if key_type == "utf8":
key = str(key)
key = binascii.hexlify(key.encode())
elif key_type == "base64":
Expand Down Expand Up @@ -1918,3 +1919,22 @@ def railfence_decode(self, key=2, offset=0) -> EncryptionEncodingT:

self.state = "".join(plaintext).strip()
return self

@ChepyDecorators.call_stack
def gpp_decrypt(self):
"""Decrypt Group Policy Preferences (GPP) password
Returns:
Chepy: The Chepy object.
"""
password = self._convert_to_bytes()
password = base64.b64decode(password + b"=" * 3)
key = (
b"\x4e\x99\x06\xe8\xfc\xb6\x6c\xc9\xfa\xf4\x93\x10\x62\x0f\xfe\xe8"
b"\xf4\x96\xe8\x06\xcc\x05\x79\x90\x20\x9b\x09\xa4\x33\xb6\x6c\x1b"
)
iv = b"\x00" * 16
aes = AES.new(key, AES.MODE_CBC, iv)
self.state = Padding.unpad(aes.decrypt(password), 16)
self.remove_nullbytes()
return self
5 changes: 3 additions & 2 deletions chepy/modules/encryptionencoding.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,10 @@ class EncryptionEncoding(ChepyCore):
def rotate(self: EncryptionEncodingT, rotate_by: int) -> EncryptionEncodingT: ...
def rotate_bruteforce(self: EncryptionEncodingT) -> EncryptionEncodingT: ...
def rot_13(self: EncryptionEncodingT, amount: int=13, rotate_lower: bool=True, rotate_upper: bool=True, rotate_numbers: bool=False) -> EncryptionEncodingT: ...
def rot_47(self: EncryptionEncodingT, amount: int=...) -> EncryptionEncodingT: ...
def rot_47(self: EncryptionEncodingT, amount: int=47) -> EncryptionEncodingT: ...
def rot_47_bruteforce(self: EncryptionEncodingT) -> EncryptionEncodingT: ...
def rot_8000(self: EncryptionEncodingT) -> EncryptionEncodingT: ...
def xor(self: EncryptionEncodingT, key: Union[str, bytearray], key_type: Literal['hex', 'utf', 'base64', 'decimal']=...) -> EncryptionEncodingT: ...
def xor(self: EncryptionEncodingT, key: Union[str, bytearray], key_type: Literal['hex', 'utf8', 'base64', 'decimal']='hex') -> EncryptionEncodingT: ...
def xor_bruteforce(self: EncryptionEncodingT, length: int=..., crib: Union[str, bytes, None]=...) -> EncryptionEncodingT: ...
def jwt_decode(self: EncryptionEncodingT) -> EncryptionEncodingT: ...
def jwt_verify(self: EncryptionEncodingT, secret: str, algorithm: list=...) -> EncryptionEncodingT: ...
Expand Down Expand Up @@ -69,3 +69,4 @@ class EncryptionEncoding(ChepyCore):
def fernet_decrypt(self: EncryptionEncodingT, key:Union[bytes, str], encode_key: bool=False) -> EncryptionEncodingT: ...
def railfence_encode(self: EncryptionEncodingT, key: Union[int, str]=2, offset: Union[int, str]=0) -> EncryptionEncodingT: ...
def railfence_decode(self: EncryptionEncodingT, key: Union[int, str]=2, offset: Union[int, str]=0) -> EncryptionEncodingT: ...
def gpp_decrypt(self: EncryptionEncodingT) -> EncryptionEncodingT: ...
10 changes: 9 additions & 1 deletion tests/test_core.py
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@ def test_run_recipe():
recipes=[
{
"function": "from_base64",
"args": {"alphabet": 'standard'},
"args": {"alphabet": "standard"},
},
{"function": "swap_case", "args": {}},
]
Expand Down Expand Up @@ -356,3 +356,11 @@ def test_dump_json():
Chepy(data).dump_json().json_to_dict().get_by_key("byte_key").o == b"\x00\x01"
)
assert Chepy(True).dump_json().o == b"true"


def test_walk_dir():
assert b"script.py" in Chepy("tests/files/").walk_dir().join("\n").o


def test_search_dir():
assert len(Chepy("tests/files/qr/").search_dir("PNG").o) == 2
13 changes: 9 additions & 4 deletions tests/test_encryptionencoding.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ def test_rotate_bruteforce():


def test_xor_utf():
assert Chepy("some data").xor("UD", "utf").o == b"&+8!u 404"
assert Chepy("some data").xor("UD", "utf8").o == b"&+8!u 404"


def test_xor_base64():
Expand All @@ -74,17 +74,17 @@ def test_xor_binary():
Chepy("./tests/files/hello")
.load_file()
.to_hex()
.xor("A", "utf")
.xor("A", "utf8")
.to_hex()
.o.decode()[0:6]
== "222727"
)
assert (
Chepy("./tests/files/hello").load_file().xor(41, "utf").to_hex().o[0:6]
Chepy("./tests/files/hello").load_file().xor(41, "utf8").to_hex().o[0:6]
== b"fbcbd9"
)
assert (
Chepy("./tests/files/hello").xor(key=41, key_type="utf").to_hex().o[0:6]
Chepy("./tests/files/hello").xor(key=41, key_type="utf8").to_hex().o[0:6]
== b"1a1e40"
)

Expand Down Expand Up @@ -910,3 +910,8 @@ def test_railfence():

def test_rot13():
assert Chepy("Abc1").rot_13(rotate_numbers=True).o == b"Nop4"


def test_gpp_decrypt():
p = "B+iL/dnbBHSlVf66R8HOuAiGHAtFOVLZwXu0FYf+jQ6553UUgGNwSZucgdz98klzBuFqKtTpO1bRZIsrF8b4Hu5n6KccA7SBWlbLBWnLXAkPquHFwdC70HXBcRlz38q2"
assert Chepy(p).gpp_decrypt().o == b"DUCTF{D0n7_Us3_P4s5w0rds_1n_Gr0up_P0l1cy}"

0 comments on commit e2a9284

Please sign in to comment.