diff --git a/PSODolphinConfig.py b/PSODolphinConfig.py new file mode 100644 index 00000000..60eb63ba --- /dev/null +++ b/PSODolphinConfig.py @@ -0,0 +1,99 @@ +#!/bin/env python3 + +import os +import sys +import time +import stat +import pwd +import subprocess + + +def change_user(username): + try: + user_info = pwd.getpwnam(username) + except KeyError: + print("user %s does not exist" % (username,)) + raise + os.setregid(user_info.pw_gid, user_info.pw_gid) + os.setreuid(user_info.pw_uid, user_info.pw_uid) + + +def main(argv): + dolphin_path = './Dolphin.app/Contents/MacOS/Dolphin' + try: + username = os.environ['SUDO_USER'] + print(username) + except KeyError: + print('$SUDO_USER not set; use sudo -E') + + # 1. open tap0 and configure it + print("starting and configuring tap0") + tap0_fd = os.open('/dev/tap0', os.O_RDWR) + os.set_inheritable(tap0_fd, True) + subprocess.check_call(['ifconfig', 'tap0', argv[1]], stderr=subprocess.DEVNULL) + subprocess.check_call(['ifconfig', 'tap0', 'up'], stderr=subprocess.DEVNULL) + + # 2. fork a Dolphin process, dropping privileges first + print("starting dolphin") + dolphin_proc = subprocess.Popen([dolphin_path], + preexec_fn=lambda: change_user(username), pass_fds=(tap0_fd,)) + time.sleep(1) + + # 3. create a temp file for dolphin to open instead of /dev/tap0 + print("creating temp file") + tmpfile_fd = os.open("/tmp/dnet", os.O_CREAT | os.O_RDWR, stat.S_IRWXU | stat.S_IRWXG | stat.S_IRWXO) + os.close(tmpfile_fd) + os.chmod("/tmp/dnet", stat.S_IRWXU | stat.S_IRWXG | stat.S_IRWXO) + + # 4. modify dolphin's memory to make it upen the temp file + print("redirecting /dev/tap0 for dolphin") + addresses_str = subprocess.check_output(['memwatch', str(dolphin_proc.pid), 'find', '\"/dev/tap0\"'], stderr=subprocess.DEVNULL) + for line in addresses_str.splitlines(): + tokens = line.split() + if len(tokens) != 3: + continue + print("redirecting /dev/tap0 to /tmp/dnet at %s in dolphin" % (tokens[1],)) + subprocess.check_call(["memwatch", str(dolphin_proc.pid), "access", tokens[1], "rwx"], stderr=subprocess.DEVNULL) + subprocess.check_call(["memwatch", str(dolphin_proc.pid), "write", tokens[1], "\"/tmp/dnet\""], stderr=subprocess.DEVNULL) + subprocess.check_call(["memwatch", str(dolphin_proc.pid), "access", tokens[1], "r-x"], stderr=subprocess.DEVNULL) + + # step 5: use lsof to find out when dolphin opens /tmp/dnet + print("waiting for temp file to open") + dolphin_tap0_fd = -1 + while dolphin_tap0_fd < 0: + time.sleep(1) + result = subprocess.check_output(["lsof", "-p", str(dolphin_proc.pid)], stderr=subprocess.DEVNULL) + for line in result.splitlines(): + if b'/tmp/dnet' not in line: + continue + + fd_str = line.split()[3] + dolphin_tap0_fd = int(fd_str[0:-len(fd_str.lstrip(b'0123456789'))]) + print("found open tap fd %d in dolphin" % (dolphin_tap0_fd,)) + + # step 6: use memwatch to move the tap0 fd into place + print("replacing temp fd %d with tap fd %d in dolphin" % (dolphin_tap0_fd, + tap0_fd)) + assembly_contents = b"""start: + mov rax, 0x000000000200005A # dup2(from_fd, to_fd) + mov rdi, %d + mov rsi, %d + syscall + + # close the original fd. if dup2 failed, this will break the connection and + # dolnet will notice. note that rdi is preserved during the syscall so we + # don't need to reload it + mov rax, 0x0000000002000006 # close(fd) + syscall + + ret +""" % (tap0_fd, dolphin_tap0_fd) + subprocess.run(["memwatch", str(dolphin_proc.pid), "--", "run", "-"], input=assembly_contents, stderr=subprocess.DEVNULL) + + # ok we're done - dolphin is running as a non-privileged user with tap0 open + + return 0 + + +if __name__ == '__main__': + sys.exit(main(sys.argv))