5 changed files with 215 additions and 1 deletions
			
			
		| @ -0,0 +1,56 @@ | |||||
|  | import abc | ||||
|  | from pathlib import Path | ||||
|  | import subprocess | ||||
|  | import shlex | ||||
|  | 
 | ||||
|  | 
 | ||||
|  | class BaseObfuscation(abc.ABC): | ||||
|  | 
 | ||||
|  |     def __init__(self, binary_name=None, binary_path=None, algorithm=None): | ||||
|  | 
 | ||||
|  |         assert binary_name is not None or binary_path is not None | ||||
|  |         self.binary_name = binary_name if binary_name is not None else Path(self.binary_path).name | ||||
|  |         self.binary_path = binary_path if binary_path else "" | ||||
|  |         self.algorithm = algorithm | ||||
|  | 
 | ||||
|  |     def ensure_installed(self): | ||||
|  | 
 | ||||
|  |         # Attempt to find process by path | ||||
|  |         binary = Path(self.binary_path) | ||||
|  |         if not binary.is_file(): | ||||
|  |             # Did not find by path, attempt to find using which | ||||
|  |             proc_which = subprocess.Popen(["which", self.binary_name], stdout=subprocess.PIPE, stderr=subprocess.PIPE) | ||||
|  |             data = [x.decode().strip() for x in proc_which.communicate() if x != b''][0] | ||||
|  | 
 | ||||
|  |             if proc_which.returncode != 0: | ||||
|  |                 raise RuntimeError("Could not find binary '%s'" % data) | ||||
|  | 
 | ||||
|  |             self.binary_path = data | ||||
|  | 
 | ||||
|  |     def execute(self, *args, kill_first=False, override_command=None): | ||||
|  | 
 | ||||
|  |         if kill_first: | ||||
|  |             # TODO try to delete by full name as we dont want to kill other processes. | ||||
|  |             pattern = self.binary_name | ||||
|  |             self.execute(*[pattern], override_command="pkill") | ||||
|  |             #pattern = self.binary_path + " " + ' '.join(args) | ||||
|  |             #print(pattern) | ||||
|  |             #kill_output, kill_code = self.execute(*[pattern], override_command="pkill") | ||||
|  | 
 | ||||
|  |         command = override_command if override_command is not None else self.binary_path | ||||
|  |         print(shlex.join([command] + list(args))) | ||||
|  |         proc_which = subprocess.Popen([command] + list(args), stdout=subprocess.PIPE, stderr=subprocess.PIPE) | ||||
|  |         raw_data = proc_which.communicate() | ||||
|  | 
 | ||||
|  |         data = [x.decode().strip() for x in raw_data if x != b''] | ||||
|  |         if len(data) == 0: | ||||
|  |             data = "" | ||||
|  |         else: | ||||
|  |             data = data[0] | ||||
|  |         return data, proc_which.returncode | ||||
|  | 
 | ||||
|  | 
 | ||||
|  | 
 | ||||
|  | 
 | ||||
|  | 
 | ||||
|  | 
 | ||||
| @ -0,0 +1,30 @@ | |||||
|  | from script.obfuscate import BaseObfuscation | ||||
|  | import re | ||||
|  | 
 | ||||
|  | 
 | ||||
|  | class ObfuscateOBFS4(BaseObfuscation): | ||||
|  | 
 | ||||
|  |     def __init__(self): | ||||
|  |         super().__init__( | ||||
|  |             binary_name="obfs4proxy", | ||||
|  |             binary_path="/usr/bin/obfs4proxy", | ||||
|  |             algorithm="obfs4" | ||||
|  |         ) | ||||
|  | 
 | ||||
|  |         self.ensure_installed() | ||||
|  | 
 | ||||
|  |     def ensure_installed(self): | ||||
|  |         super().ensure_installed() | ||||
|  | 
 | ||||
|  |         output, code = self.execute("-version") | ||||
|  | 
 | ||||
|  |         if re.match(f'{self.binary_name}-[0-9]+.[0-9]+.[0-9]+', output) and code == 0: | ||||
|  |             return True | ||||
|  |         else: | ||||
|  |             raise RuntimeError(f"Could not verify that {self.binary_name} is installed correctly.") | ||||
|  | 
 | ||||
|  | 
 | ||||
|  | if __name__ == "__main__": | ||||
|  | 
 | ||||
|  |     x = ObfuscateOBFS4() | ||||
|  |     x.ensure_installed() | ||||
| @ -0,0 +1,119 @@ | |||||
|  | from pathlib import Path | ||||
|  | 
 | ||||
|  | import requests | ||||
|  | 
 | ||||
|  | import const | ||||
|  | from script.obfuscate import BaseObfuscation | ||||
|  | import re | ||||
|  | import os | ||||
|  | import qrcode | ||||
|  | import socket | ||||
|  | 
 | ||||
|  | from script.obfuscate.obfs4 import ObfuscateOBFS4 | ||||
|  | 
 | ||||
|  | 
 | ||||
|  | class ObfuscationViaTOR(BaseObfuscation): | ||||
|  | 
 | ||||
|  |     def __init__(self, algorithm: BaseObfuscation): | ||||
|  |         super().__init__( | ||||
|  |             binary_name="tor" | ||||
|  |         ) | ||||
|  |         self.algorithm = algorithm | ||||
|  |         self.tor_data_dir = "/tmp/wg-manager-tor-proxy" | ||||
|  |         self.tor_config_file = "/tmp/wg-manager-tor-proxy/torrc" | ||||
|  |         self.tor_fingerprint_file = f"{self.tor_data_dir}/fingerprint" | ||||
|  |         self.tor_bridge_file = f"{self.tor_data_dir}/pt_state/obfs4_bridgeline.txt" | ||||
|  | 
 | ||||
|  |         Path(self.tor_config_file).touch() | ||||
|  |         os.makedirs(self.tor_data_dir, exist_ok=True) | ||||
|  | 
 | ||||
|  |     def __del__(self): | ||||
|  |         pass | ||||
|  | 
 | ||||
|  |     def ensure_installed(self): | ||||
|  |         super().ensure_installed() | ||||
|  |         output, code = self.execute("--version") | ||||
|  | 
 | ||||
|  |         if re.match(f'Tor version .*', output) and code == 0: | ||||
|  |             return True | ||||
|  |         else: | ||||
|  |             raise RuntimeError(f"Could not verify that {self.binary_name} is installed correctly.") | ||||
|  | 
 | ||||
|  |     def start(self): | ||||
|  | 
 | ||||
|  |         output, code = self.execute( | ||||
|  |             "-f", self.tor_config_file, | ||||
|  |             "--DataDirectory", self.tor_data_dir, | ||||
|  |             "--RunAsDaemon", "1", | ||||
|  |             "--ExitPolicy", "reject *:*", | ||||
|  |             "--ORPort", str(const.OBFUSCATE_SOCKS_TOR_PORT), | ||||
|  |             "--BridgeRelay", "1", | ||||
|  |             "--PublishServerDescriptor", "0", | ||||
|  |             "--ServerTransportPlugin", f"{self.algorithm.algorithm} exec {self.algorithm.binary_path}", | ||||
|  |             "--ServerTransportListenAddr", f"{self.algorithm.algorithm} 0.0.0.0:{const.OBFUSCATE_TOR_LISTEN_ADDR}", | ||||
|  |             "--ExtORPort", "auto", | ||||
|  |             "--ContactInfo", "wg-manager@github.com", | ||||
|  |             "--Nickname", "wgmanager", | ||||
|  |             kill_first=True | ||||
|  |         ) | ||||
|  | 
 | ||||
|  |         print(output) | ||||
|  | 
 | ||||
|  |     def generate_bridge_line(self, local=False): | ||||
|  | 
 | ||||
|  |         if local: | ||||
|  |             ip_address = socket.gethostbyname(socket.gethostname()) | ||||
|  |         else: | ||||
|  |             ip_address = requests.get("https://api.ipify.org").text | ||||
|  | 
 | ||||
|  |         with open(self.tor_fingerprint_file, "r") as f: | ||||
|  |             fingerprint = f.read().split(" ") | ||||
|  |             assert len(fingerprint) == 2, "Could not load fingerprint correctly. " \ | ||||
|  |                                           "Should be a list of 2 items (name, fingerprint)" | ||||
|  |             fingerprint = fingerprint[1] | ||||
|  | 
 | ||||
|  |         with open(self.tor_bridge_file, "r") as f: | ||||
|  |             bridge_line_raw = f.read() | ||||
|  | 
 | ||||
|  |         bridge_line = re.search(r"^Bridge .*", bridge_line_raw, re.MULTILINE).group(0) | ||||
|  |         bridge_line = bridge_line\ | ||||
|  |             .replace("<IP ADDRESS>", ip_address)\ | ||||
|  |             .replace("<PORT>", str(const.OBFUSCATE_TOR_LISTEN_ADDR))\ | ||||
|  |             .replace("<FINGERPRINT>", fingerprint)\ | ||||
|  |             .replace("Bridge ", "bridge://")\ | ||||
|  |             .replace("\n", "") | ||||
|  |         #bridge_line = f"bridge://{self.algorithm.algorithm} {ip_address}:{const.OBFUSCATE_SOCKS_TOR_PORT} {fingerprint}" | ||||
|  |         print(bridge_line) | ||||
|  |         return bridge_line | ||||
|  | 
 | ||||
|  |     def output_qr(self, text, image=False): | ||||
|  | 
 | ||||
|  |         qr = qrcode.QRCode( | ||||
|  |             version=10, | ||||
|  |             error_correction=qrcode.constants.ERROR_CORRECT_L, | ||||
|  |             box_size=10, | ||||
|  |             border=4, | ||||
|  |         ) | ||||
|  |         qr.add_data(text) | ||||
|  |         qr.make(fit=True) | ||||
|  | 
 | ||||
|  |         if image: | ||||
|  |             img = qr.make_image(fill_color="black", back_color="white") | ||||
|  |             img.show() | ||||
|  |         else: | ||||
|  |             try: | ||||
|  |                 qr.print_tty() | ||||
|  |             except: | ||||
|  |                 qr.print_ascii() | ||||
|  | 
 | ||||
|  | 
 | ||||
|  | if __name__ == "__main__": | ||||
|  | 
 | ||||
|  |     x = ObfuscationViaTOR( | ||||
|  |         algorithm=ObfuscateOBFS4() | ||||
|  |     ) | ||||
|  |     x.ensure_installed() | ||||
|  |     x.start() | ||||
|  |     bridge_line = x.generate_bridge_line(local=False) | ||||
|  |     x.output_qr(bridge_line, image=True) | ||||
|  |     #x.generate_bridge_line(local=False) | ||||
					Loading…
					
					
				
		Reference in new issue