if params.len < 1 or params.len > 2 or params[0] == "-h" or params[0] == "--help" then current_program = get_shell.host_computer.File(program_path) exit "Usage: " + current_program.name + " [host ip]\n\nWithout host ip, scan the gateway and choose a port.\nWith host ip, try router bounce exploits on gateway:0 against host ip." end if mx = include_lib("/lib/metaxploit.so") if not mx then mx = include_lib(current_path + "/metaxploit.so") if not mx then exit("Unable to load metaxploit.so") crypto = include_lib("/lib/crypto.so") if not crypto then crypto = include_lib(current_path + "/crypto.so") local_shell = get_shell local_cp = local_shell.host_computer ip = params[0] bounce_host = "" if params.len == 2 then bounce_host = params[1] bounce_mode = bounce_host != "" login_ip = ip if bounce_mode then login_ip = bounce_host KNOWN_PASS = "Root1234" rank_of = function(user) if user == "root" then return 3 if user == "guest" then return 1 if user == "" then return 0 return 2 end function is_requested_host = function(comp) if not bounce_mode then return 1 if not comp then return 0 return comp.local_ip == bounce_host end function extract_value = function(line) start = line.indexOf("") finish = line.indexOf("") if start != -1 and finish != -1 and finish > start then return line[start + 3 : finish] end if before_dot = line.split("\.")[0] words = before_dot.split(" ") value = "" for word in words if word != "" then value = word end for return value end function object_user = function(comp) if not comp then return "guest" root_dir = comp.File("/root") if root_dir and root_dir.has_permission("w") then return "root" passwd = comp.File("/etc/passwd") if passwd and passwd.has_permission("w") then return "root" home = comp.File("/home") if not home then return "guest" folders = home.get_folders if not folders then return "guest" for folder in folders if folder.name == "guest" then continue if folder.has_permission("w") then return folder.name end for return "guest" end function has_item = function(list, value) for item in list if item == value then return 1 end for return 0 end function lib_name_of = function(name) n = name.lower if n.indexOf("ssh") != -1 then return "ssh" if n.indexOf("ftp") != -1 then return "ftp" return "" end function state = { "best_shell": null, "best_user": "guest", "best_computer": null, "passwd_file": null, "password_changed": 0, } logs = [] last_clear = [0] chosen_port = 0 redraw = function() gap = 0.11 elapsed = time - last_clear[0] if elapsed < gap then delay = gap - elapsed if delay < 0.01 then delay = 0.01 wait delay end if clear_screen last_clear[0] = time if bounce_mode then print ip + " 0 -> " + bounce_host else print ip + " " + chosen_port end if for line in logs print line end for end function note = function(line) logs.push(line) redraw end function drop_root = function(sh) if not sh then return if object_user(sh.host_computer) != "root" then return note("root shell") sh.start_terminal exit end function take_shell = function(sh) if typeof(sh) != "shell" then return if not is_requested_host(sh.host_computer) then return user = object_user(sh.host_computer) if state.best_shell == null or rank_of(user) > rank_of(state.best_user) then state.best_shell = sh state.best_user = user note("shell user:" + user) end if drop_root(sh) end function take_computer = function(comp) if typeof(comp) != "computer" then return if not is_requested_host(comp) then return user = object_user(comp) if state.best_computer == null or rank_of(user) > rank_of(object_user(state.best_computer)) then state.best_computer = comp note("computer user:" + user) end if end function take_file = function(f) if typeof(f) != "file" then return if f.is_folder then files = f.get_files if not files then return for inner in files if inner.name == "passwd" then take_file(inner) end for return end if if f.name != "passwd" then return if not f.has_permission("r") then return state.passwd_file = f note("file " + f.path) end function consider = function(of) t = typeof(of) if t == "shell" then take_shell(of) else if t == "computer" then take_computer(of) else if t == "file" then take_file(of) else if t == "number" then if of == 1 then state.password_changed = 1 end if end function access_computer = function() if state.best_shell then comp = state.best_shell.host_computer if comp then return comp end if return state.best_computer end function read_passwd_text = function(comp) if state.passwd_file then content = state.passwd_file.get_content if content then return content end if if not comp then return "" passwd = comp.File("/etc/passwd") if not passwd then return "" if not passwd.has_permission("r") then return "" content = passwd.get_content if not content then return "" return content end function parse_passwd = function(content) accounts = [] if not content then return accounts for line in content.split(char(10)) if line == "" then continue parts = line.split(":") if parts.len < 2 then continue user = parts[0] hash = parts[1] if user == "" or hash == "" then continue accounts.push({"user": user, "hash": hash}) end for ordered = [] for acc in accounts if acc.user == "root" then ordered.push acc end for for acc in accounts if acc.user == "root" then continue if acc.user == "guest" then continue ordered.push acc end for for acc in accounts if acc.user == "guest" then ordered.push acc end for return ordered end function scan_rows = [] lan_ips = [] ssh_ports = [] push_lan = function(lan) if lan == "" then return if has_item(lan_ips, lan) then return lan_ips.push lan end function push_ssh = function(port_num, libname) kind = lib_name_of(libname) if kind != "ssh" and port_num != 22 then return if has_item(ssh_ports, port_num) then return ssh_ports.push port_num end function add_scan_row = function(port_num, state_name, libname, version, lan) scan_rows.push({ "port": port_num, "state": state_name, "lib": libname, "version": version, "lan": lan, }) push_lan lan push_ssh port_num, libname end function if bounce_mode then chosen_port = 0 note("bouncing through " + ip + " to " + bounce_host) else print "scanning " + ip router_sess = mx.net_use(ip) if router_sess then router_lib = router_sess.dump_lib if router_lib then add_scan_row 0, "open", router_lib.lib_name, router_lib.version, "" end if end if router = get_router(ip) if router then used = router.used_ports if used then for p in used if p.is_closed == 0 then st = "open" else st = "closed" lan = p.get_lan_ip sess = mx.net_use(ip, p.port_number) if not sess then add_scan_row p.port_number, st, "N/A", "N/A", lan continue end if lib = sess.dump_lib if not lib then add_scan_row p.port_number, st, "N/A", "N/A", lan continue end if add_scan_row p.port_number, st, lib.lib_name, lib.version, lan end for end if end if if scan_rows.len == 0 then exit("Unable to scan target") table = "PORT STATE LIBRARY VERSION LAN" for row in scan_rows table = table + "\n" + row.port + " " + row.state + " " + row.lib + " " + row.version + " " + row.lan end for print format_columns(table) port_in = user_input("port: ") chosen_port = port_in.to_int if typeof(chosen_port) != "number" then exit("Invalid port") end if if ssh_ports.len == 0 then ssh_ports.push 22 try_login = function(user, password) if user == "" or password == "" then return null if not bounce_mode then sh = get_shell(user, password) if typeof(sh) == "shell" then return sh end if for ssh_port in ssh_ports sh = local_shell.connect_service(login_ip, ssh_port, user, password) if typeof(sh) == "shell" then return sh end for return null end function login_accounts = function(accounts) if not crypto then return for acc in accounts plain = crypto.decipher(acc.hash) redraw if not plain then continue note(acc.user + ":" + plain) sh = try_login(acc.user, plain) take_shell sh end for end function crack_passwd_on = function(comp) content = read_passwd_text(comp) if not content then return 0 note("reading /etc/passwd") accounts = parse_passwd(content) if accounts.len == 0 then return 0 login_accounts accounts return 1 end function steal_home_creds = function(comp) if not comp then return if not crypto then return home = comp.File("/home") if not home then return if not home.has_permission("r") then return folders = home.get_folders if not folders then return for folder in folders names = ["Mail.txt", "Bank.txt"] for fname in names cfg = comp.File(folder.path + "/Config/" + fname) if not cfg then continue if not cfg.has_permission("r") then continue text = cfg.get_content if not text then continue line = text.split(char(10))[0] parts = line.split(":") if parts.len < 2 then continue hash = parts[1] if hash == "" then continue plain = crypto.decipher(hash) redraw if not plain then continue note(folder.name + " " + fname + ":" + plain) take_shell try_login(folder.name, plain) take_shell try_login("root", plain) end for end for end function root_computer_accounts = function(comp) if not comp then return if object_user(comp) != "root" then return changed = comp.change_password("root", KNOWN_PASS) if changed == 1 then state.password_changed = 1 note("changed root password") take_shell try_login("root", KNOWN_PASS) end if created = comp.create_user("rsu", KNOWN_PASS) if created == 1 then note("created user rsu") take_shell try_login("rsu", KNOWN_PASS) end if end function writable_dir = function(comp, user) paths = [] if user == "root" then paths.push "/root" if user != "guest" and user != "root" then paths.push "/home/" + user paths.push "/home/guest" paths.push "/tmp" paths.push "/var/tmp" for p in paths f = comp.File(p) if not f then continue if not f.is_folder then continue if not f.has_permission("w") then continue return p end for return null end function find_local = function(name, places) for place in places f = local_cp.File(place + "/" + name) if f then return f end for return null end function remote_privesc = function(sh) if typeof(sh) != "shell" then return 0 comp = sh.host_computer if not comp then return 0 libdir = comp.File("/lib") if not libdir then return 0 if not libdir.has_permission("r") then return 0 user = object_user(comp) dest = writable_dir(comp, user) if not dest then return 0 mx_file = find_local("metaxploit.so", ["/lib", current_path, home_dir, home_dir + "/guest"]) privesc_file = find_local("privesc", ["/bin", current_path, home_dir + "/guest"]) if not mx_file then return 0 if not privesc_file then return 0 note("uploading privesc to " + dest) if libdir.has_permission("w") then local_shell.scp(mx_file.path, "/lib", sh) end if copied_mx = local_shell.scp(mx_file.path, dest, sh) copied_pr = local_shell.scp(privesc_file.path, dest, sh) if typeof(copied_mx) == "string" then return 0 if typeof(copied_pr) == "string" then return 0 note("launching remote privesc") sh.launch dest + "/privesc" return 1 end function overflow_target = function(port_num, extras) if port_num == 0 then sess = mx.net_use(ip) else sess = mx.net_use(ip, port_num) end if if not sess then note("Unable to establish session") return end if lib = sess.dump_lib if not lib then note("Unable to dump library") return end if adds = mx.scan(lib) redraw if not adds then return candidates = [] for add in adds info = mx.scan_address(lib, add) if not info then continue lines = info.split(char(10)) for line in lines pos = line.indexOf("Unsafe check:") if pos == null then continue if pos == -1 then continue value = extract_value(line) if value == "" then continue candidates.push add + " " + value end for end for for candidate in candidates parts = candidate.split(" ") add = parts[0] value = parts[1] for extra in extras if port_num == 0 then sess = mx.net_use(ip) else sess = mx.net_use(ip, port_num) end if if not sess then redraw continue end if lib = sess.dump_lib if not lib then redraw continue end if if extra == "" then of = lib.overflow(add, value) else of = lib.overflow(add, value, extra) end if consider of redraw end for end for end function if bounce_mode then extras = [bounce_host] else extras = [""] if chosen_port == 0 then for lan in lan_ips if has_item(extras, lan) then continue extras.push lan end for end if end if if not bounce_mode then if not has_item(extras, KNOWN_PASS) then extras.push KNOWN_PASS mail = user_mail_address if mail then extras.push mail end if note("exploiting port " + chosen_port) overflow_target chosen_port, extras if state.password_changed then note("trying " + KNOWN_PASS) take_shell try_login("root", KNOWN_PASS) end if comp = access_computer if crack_passwd_on(comp) == 0 then note("no readable /etc/passwd") end if steal_home_creds comp root_computer_accounts comp if state.best_user == "root" then drop_root state.best_shell end if if state.best_shell then if state.best_user != "root" then note("escalating from " + state.best_user) remote_privesc state.best_shell drop_root state.best_shell end if end if if state.best_user == "root" and state.best_shell then drop_root state.best_shell end if print "You're so fucked even your momma's breaking out the bandaids." print "This host is toast." if state.best_shell then print "dropping into " + state.best_user + " anyway" state.best_shell.start_terminal end if