def parse_shellcode(self, data): # Hajime exclusive! if len(data) == 480: sockaddr = data[0xf0:0xf0+8] sockaddr = struct.unpack(">HHBBBB", sockaddr) if sockaddr[0] == 0x0200: ip = str(sockaddr[2]) + "." + str(sockaddr[3]) + "." + str(sockaddr[4]) + "." + str(sockaddr[5]) port = sockaddr[1] url = "tcp://" + ip + ":" + str(port) dbg("Stub downloader started: " + url) if config.get("fake_dl", optional=True, default=False): self.record.add_file(str(hash(url)), url=url) else: try: s = socket.create_connection((ip, port), timeout=10) data = "" while True: chunk = s.recv(1024) if len(chunk) == 0: break data += chunk s.close() self.record.add_file(data, url=url) except: traceback.print_exc()
def end(self): dbg("Session End") print(self.text_combined) print("URLS GATHARED: " + repr(self.urls)) # Do not report non-login connections if self.user != None: self.samples.put_session(self)
def need(self, byte_need): byte = ord(self.sock.recv(1)) #if byte in Telnetd.cmds: # dbg("RECV " + str(Telnetd.cmds[byte])) #else: # dbg("RECV " + str(byte)) if byte != byte_need: dbg("BAD " + "PROTOCOL ERROR. EXIT.") raise ValueError() return byte
def download(self, data): path = data["path"] url = data["url"] info = data["info"] dbg("Downloaded " + url + " to " + path) data = self.env.readFile(path) self.record.add_file(data, url=url, name=path, info=info) self.files.append(path)
def handle(self): conn = False try: conn, addr = self.sock.accept() dbg("Client connected at " + str(addr)) sess = TelnetSess(self, conn, addr) start_new_thread(sess.loop, ()) except: traceback.print_exc()
def found_file(self, path, data): if path in self.files: pass else: if len(data) > MIN_FILE_SIZE: dbg("File created: " + path) self.parse_shellcode(data) self.record.add_file(data, name=path) else: dbg("Ignore small file: " + path + " (" + str(len(data)) + ") bytes")
def end(self): dbg("Session End") for path in self.env.files: self.found_file(path, self.env.files[path]) for (path, data) in self.env.deleted: self.found_file(path, data) self.record.commit()
def shell(self, l): self.record.addInput(l + "\n") try: tree = run(l, self.env) except: dbg("Could not parse \""+l+"\"") self.send_string("sh: syntax error near unexpected token `" + " " + "'\n") traceback.print_exc() self.send_string(PROMPT)
def shell(self, l): self.record.addInput(l + "\n") try: tree = run(l) tree.run(self.env) except: dbg("Could not parse \"" + l + "\"") self.send_string("sh: syntax error near unexpected token `" + " " + "'\n") self.send_string(self.prompt)
def handle(self): try: conn, addr = self.sock.accept() dbg("Client connected at " + str(addr)) sess = TelnetSess(self, conn, addr) sess.loop() except: traceback.print_exc() if conn: conn.close()
def run(self): self.sock.bind((self.host, self.port)) self.sock.listen(10) self.sock.settimeout(None) dbg("Socket open on " + str(self.host) + ":" + str(self.port)) while self.do_run: try: self.handle() except: traceback.print_exc() self.sock.close() dbg("Socket Closed")
def __init__(self, output, remote_addr): dbg("New Session") self.output = output self.remote_addr = remote_addr self.record = SessionRecord() self.env = Env(self.send_string) self.env.listen("download", self.download) # Files already commited self.files = []
def download(self, data): path = data["path"] url = data["url"] info = data["info"] data = data["data"] dbg("Downloaded " + url + " to " + path) if data: self.record.add_file(data, url=url, name=path, info=info) self.files.append(path) else: self.record.add_file(None, url=url, name=path, info=info)
def run(self): self.sock.bind((self.host, self.port)) self.sock.listen(10) dbg("Socket open on port " + str(self.port)) while self.do_run: try: self.handle() except: traceback.print_exc() # ONLY HANDLE ONE CLIENT # self.stop() self.sock.close() dbg("Socket Closed")
def __init__(self, output, remote_addr): dbg("New Session") self.output = output self.remote_addr = remote_addr self.samples = get_sample_db() # Data gathered self.urls = [] self.date = int(time.time()) self.text_in = "" self.text_out = "" self.text_combined = "" self.user = None self.password = None
def end(self): dbg("Session End") for path in self.env.files: if path in self.files: pass else: dbg("File created: " + path) data = self.env.files[path] if len(data) > MIN_FILE_SIZE: self.record.add_file(data, name=path) # Do not report non-login connections if self.text_combined != "": self.record.commit(self.text_in, self.text_out, self.text_combined)
def handle(self): conn = False try: conn, addr = self.sock.accept() dbg("Client connected at " + str(addr)) if self.ipfilter.is_allowed(addr[0]): self.ipfilter.add_ip(addr[0]) sess = TelnetSess(self, conn, addr) start_new_thread(sess.loop, ()) else: dbg("Connection limit for " + addr[0] + " exceeded, closing") conn.close() except: traceback.print_exc()
def commit(self, text_in, text_out, text_combined): self.session_obj["text_in"] = text_in.decode('ascii', 'ignore') self.session_obj["text_out"] = text_out.decode('ascii', 'ignore') self.session_obj["text_combined"] = text_combined.decode('ascii', 'ignore') upload_req = self.back.put_session(self.session_obj) for url in upload_req: dbg("Upload requested: " + url) sample = self.urls[url] data = sample["data"] del sample["data"] self.back.put_sample_info(sample) self.back.put_sample(data)
def download(self, url): dbg("Downloading " + url) try: if url.startswith("http://") or url.startswith("https://"): f, data = self.download_http(url) else: return None except requests.exceptions.ReadTimeout: return None except: traceback.print_exc() return None dbg("Downlod finished. length: " + str(f["length"]) + " sha256: " + f["sha256"]) return f, data
def commit(self): self.log_raw(self.json()) for url in self.urls: self.log_raw(self.urlset[url].json()) # Ignore connections without any input if len(self.stream) > 1 and self.back != None: upload_req = self.back.put_session(self.json()) for url in upload_req: dbg("Upload requested: " + url) sample = self.urlset[url] self.back.put_sample_info(sample.json()) self.back.put_sample(sample.data)
def put_sample(self, data, retry=True): try: r = requests.post(self.url + "/file", data=data, timeout=20.0) except requests.exceptions.RequestException: dbg("Cannot connect to backend") return if r.status_code == 200: return elif retry: msg = r.raw.read() dbg("Backend upload failed, retrying (" + str(msg) + ")") return self.put_sample(sha256, filename, False) else: msg = r.raw.read() raise IOError(msg)
def put_session(self, session, retry=True): try: r = requests.put(self.url + "/conns", json=session, timeout=20.0) except requests.exceptions.RequestException: dbg("Cannot connect to backend") return [] if r.status_code == 200: return r.json() elif retry: msg = r.raw.read() dbg("Backend upload failed, retrying (" + str(msg) + ")") return self.put_session(session, False) else: msg = r.raw.read() raise IOError(msg)
def put_sample_info(self, f, retry=True): try: sha256 = f["sha256"] r = requests.put(self.url + "/sample/" + sha256, auth=self.auth, json=f, timeout=20.0) except requests.exceptions.RequestException: dbg("Cannot connect to backend") return if r.status_code == 200: return r.json() elif retry: msg = r.raw.read() dbg("Backend upload failed, retrying (" + str(msg) + ")") return self.put_sample_info(f, False) else: msg = r.raw.read() raise IOError(msg)
def put_session(self, session): session_obj = { "ip" : session.remote_addr, "user" : session.user, "pass" : session.password, "date" : session.date, "urls" : session.urls, "text_in" : session.text_in.decode('ascii', 'ignore'), "text_out" : session.text_out.decode('ascii', 'ignore'), "text_combined" : session.text_combined.decode('ascii', 'ignore') } upload_req = self.back.put_session(session_obj) for url in upload_req: dbg("Upload requested: " + url) self.get_sample(url)
def loop(self): self.session = Session(self.send_string, self.remote[0]) dbg("Setting timeout to " + str(self.timeout) + " seconds") self.sock.settimeout(self.timeout) try: self.test_opt(1) # Kill of Session if longer than self.maxtime ts_start = int(time.time()) self.send_string("Login: "******"Password: "******"\r\nWelcome to EmbyLinux 3.13.0-24-generic\r\n") self.session.login(u, p) while True: self.send_string(" # ") l = self.recv_line() try: self.session.shell(l) except: traceback.print_exc() self.send_string("sh: error\r\n") if ts_start + self.maxtime < int(time.time()): dbg("Session too long. Killing off.") break except socket.timeout: dbg("Connection timed out") except EOFError: dbg("Connection closed") self.session.end()
def loop(self): self.session = Session(self.send_string, self.remote[0]) dbg("Setting timeout to " + str(self.timeout) + " seconds") self.sock.settimeout(self.timeout) try: # Kill of Session if longer than self.maxtime ts_start = int(time.time()) #Welcome Protocol Welcome(self).generateWelcome() self.send_string(TELNET_ISSUE) self.send_string("\r\nWelcome to EmbyLinux 3.13.0-24-generic\r\n") self.send_string(Session.prompt) while True: l = self.recv_line() try: self.session.shell(l) except: traceback.print_exc() self.send_string("sh: error\r\n") if ts_start + self.maxtime < int(time.time()): dbg("Session too long. Killing off.") break except socket.timeout: dbg("Connection timed out") except EOFError: dbg("Connection closed") Session.end(self.session)
def shell(self, l): self.text_combined = self.text_combined + " # " + l + "\n" self.text_in = self.text_in + l + "\n" if mount_regex.match(l): self.send_string( "/dev/root /rom squashfs ro,relatime 0 0\r\nproc /proc proc rw,nosuid,nodev,noexec,noatime 0 0\r\nsysfs /sys sysfs rw,nosuid,nodev,noexec,noatime 0 0\r\ntmpfs /tmp tmpfs rw,nosuid,nodev,noatime 0 0\r\n/dev/mtdblock10 /overlay jffs2 rw,noatime 0 0\r\noverlayfs:/overlay / overlay rw,noatime,lowerdir=/,upperdir=/overlay/upper,workdir=/overlay/work 0 0\r\ntmpfs /dev tmpfs rw,nosuid,relatime,size=512k,mode=755 0 0\r\ndevpts /dev/pts devpts rw,nosuid,noexec,relatime,mode=600 0 0\r\ndebugfs /sys/kernel/debug debugfs rw,noatime 0 0\r\n" ) if nc_regex.match(l): self.send_string( "BusyBox v1.24.2 () multi-call binary.\r\n\r\nUsage: nc [IPADDR PORT]\r\n\r\nOpen a pipe to IP:PORT\r\n" ) if sh_regex.match(l): self.send_string( "\r\n\r\nBusyBox v1.24.2 () built-in shell (ash)\r\n\r\n") if wget_regex.match(l): self.send_string("Usage: wget [options] <URL>\r\nOptions:\r\n") if dd_regex.match(l) or elfcat_regex.match(l): # Select random binary header, so we get multiple samples bin = ELF_BINS[random.randint(0, len(ELF_BINS) - 1)] self.send_string(bin) self.send_string("41+0 records in\r\n1+0 records out\r\n") if cat_regex.match(l): self.send_string( "cat: can't open '.s': No such file or directory\r\n") m = token_regex.match(l) if m: token = m.group(1) self.send_string(token + ": applet not found\r\n") m = downl_regex.match(l) if m: url = m.group(1) dbg("DOWNLOAD URL " + url) self.urls.append(url) m = tftp_regex.match(l) if m: opts = self.getopt(m.group(1), ["-g", "-p"]) ip = opts[0] port = opts[1] if 1 in opts else 69 f = opts["-r"] url = "tftp://" + str(ip) + ":" + str(port) + "/" + str(f) self.urls.append(url) m = nc_dl_regex.match(l) if m: opts = self.getopt(m.group(1), ["-l", "-ll"]) ip = opts[0] port = opts[1] self.urls.append("nc://" + ip + ":" + port) m = ftp_dl_regex.match(l) if m: opts = self.getopt(m.group(1), ["-c", "-v"]) ip = opts[0] port = opts["-p"] if "-p" in opts else "21" f = opts[1] self.urls.append("ftp://" + ip + ":" + port + "/" + f)
def need(self, byte_need): byte = ord(self.sock.recv(1)) if byte != byte_need: dbg("BAD " + "PROTOCOL ERROR. EXIT.") raise ValueError() return byte
def signal_handler(signal, frame): dbg('Ctrl+C') srv.stop()
def login(self, user, password): dbg("Session login: user="******" password=" + password) self.record.set_login(self.remote_addr, user, password) self.send_string(PROMPT)