├── .gitignore ├── Dockerfile ├── LICENSE.txt ├── README.md ├── mehrai.py ├── netlinks.py ├── requirements.txt ├── telnetd └── utils.py /.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc 2 | venv/* 3 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM gliderlabs/alpine 2 | MAINTAINER Jaime Cochran 3 | ADD telnetd /bin/telnetd 4 | RUN echo "http://dl-cdn.alpinelinux.org/alpine/v3.4/community" | tee /etc/apk/repositories && \ 5 | echo "http://dl-cdn.alpinelinux.org/alpine/v3.4/main" | tee -a /etc/apk/repositories && \ 6 | apk update && \ 7 | rm -f /etc/motd /etc/issue && \ 8 | chmod +x /bin/telnetd && \ 9 | rm -f /etc/securetty 10 | EXPOSE 23 11 | CMD telnetd -b 0.0.0.0:23; \ 12 | /bin/sh 13 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | 2 | This software is licensed under the "Anyone But Richard M Stallman" 3 | (ABRMS) license, described below. No other licenses may apply. 4 | 5 | 6 | -------------------------------------------- 7 | The "Anyone But Richard M Stallman" license 8 | -------------------------------------------- 9 | 10 | Do anything you want with this program, with the exceptions listed 11 | below under "EXCEPTIONS". 12 | 13 | THIS SOFTWARE IS PROVIDED "AS IS" WITH NO WARRANTY OF ANY KIND. 14 | 15 | In the unlikely event that you happen to make a zillion bucks off of 16 | this, then good for you; consider buying a homeless person a meal. 17 | 18 | 19 | EXCEPTIONS 20 | ---------- 21 | 22 | Richard M Stallman (the guy behind GNU, etc.) may not make use of or 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Version 2 2 | Much less janky, more robust(not just targeting mirai's, but mirai centric) and utilizes the kernels netlink API to monitor procs in a much smoother fashion. Now, DONE. 3 | 4 | This version is almost completely different. The new approach is taking advantage of the linux kernels Netlink API, thanks to help from homie justin barrick, to get the juarez pumpin. It will catch and print events(EXEC, FORK, EXIT are the main ones we're looking at, and PTRACE, COREDUMP, COMM, SID, GID and UID) and parse them. We catch the typical Mirai behavior and more if you want to put it in monitor mode(not kill the procs). If so, I suggest getting some pcaps. 5 | 6 | The files are both picked off from docker's rootfs and /proc/pid/exe, except on the host this time, not in the container. A much more sane approach. They're collected in /tmp and still it's assuming you're using the Viper API(set the URL in utils.py). This is all host based, so you don't even need to enter the container if you don't want to. 7 | 8 | To use this version: 9 | ``` 10 | # docker build -t honeypots/mehrai . 11 | # docker run -dit --rm -p 23:23 honeypots/mehrai 12 | ``` 13 | And then from your host: 14 | ``` 15 | # python mehrai.py run $(docker ps -l --no-trunc | grep 'mehrai' | awk '{print $1}') [--recurse, --monitor] 16 | ``` 17 | Note: Depending on the version of Docker, you may get a Path status error. In which case, you will have to change the path in mehra.py to the correct one for your install :) 18 | 19 | Then it should start spitting out events as seem below. If you don't see this, then something is broken and you will have to troubleshoot by yourself... cuz I AIN'T DOIN SHIT ;) 20 | ``` 21 | - process exe: 22 | - process cmdline: 23 | 24 | {'comm': 'o2ibfd5hja55vfe', 'process_tgid': 22953, 'event': 'COMM', 'process_pid': 22953} 25 | 26 | {'parent_tgid': 22802, 'child_tgid': 22954, 'parent_pid': 22802, 'event': 'FORK', 'child_pid': 22954} 27 | FORK (parent: 22802, child: 22954): 28 | - parent exe: /home/ubuntu/honeypot/mehrai/venv/bin/python2.7 29 | - parent cmdline: ['python', 'mehrai.py', '25f391a62ffd8b2827f9165c300f81a4ab066243e25af82d26539419596e1fba', ''] 30 | \_ child exe: 31 | \_ child cmdline: 32 | 33 | {'process_tgid': 22954, 'event': 'EXEC', 'process_pid': 22954} 34 | EXEC (22954): 35 | - process exe: 36 | - process cmdline: 37 | 38 | {'parent_tgid': 22954, 'child_tgid': 22955, 'parent_pid': 22954, 'event': 'FORK', 'child_pid': 22955} 39 | FORK (parent: 22954, child: 22955): 40 | - parent exe: 41 | - parent cmdline: 42 | \_ child exe: 43 | \_ child cmdline: 44 | 45 | {'process_tgid': 22955, 'event': 'EXEC', 'process_pid': 22955} 46 | EXEC (22955): 47 | - process exe: 48 | - process cmdline: 49 | 50 | {'parent_tgid': 22953, 'child_tgid': 22956, 'parent_pid': 22953, 'event': 'FORK', 'child_pid': 22956} 51 | FORK (parent: 22953, child: 22956): 52 | - parent exe: 53 | - parent cmdline: 54 | \_ child exe: /dvrHelper (deleted) 55 | \_ child cmdline: ['63453245te55', '', '', '', '', '', '', '', '', '', '', ''] 56 | [!] killing 22956 57 | 58 | {'exit_signal': 17L, 'process_tgid': 22953, 'event': 'EXIT', 'process_pid': 22953, 'exit_code': 0L} 59 | EXIT (22953): 60 | - process tgid: 22953 61 | - process exit code 0 62 | - process signal 17 63 | 64 | {'parent_tgid': 22877, 'child_tgid': 22957, 'parent_pid': 22877, 'event': 'FORK', 'child_pid': 22957} 65 | FORK (parent: 22877, child: 22957): 66 | - parent exe: 67 | - parent cmdline: 68 | \_ child exe: 69 | \_ child cmdline: 70 | 71 | {'process_tgid': 22957, 'event': 'EXEC', 'process_pid': 22957} 72 | EXEC (22957): 73 | - process exe: 74 | - process cmdline: 75 | 76 | {'exit_signal': 17L, 'process_tgid': 22957, 'event': 'EXIT', 'process_pid': 22957, 'exit_code': 32512L} 77 | EXIT (22957): 78 | - process tgid: 22957 79 | - process exit code 32512 80 | - process signal 17 81 | 82 | {'process_tgid': 22956, 'event': 'SID', 'process_pid': 22956} 83 | 84 | {'parent_tgid': 22956, 'child_tgid': 22958, 'parent_pid': 22956, 'event': 'FORK', 'child_pid': 22958} 85 | FORK (parent: 22956, child: 22958): 86 | - parent exe: 87 | - parent cmdline: [''] 88 | \_ child exe: /dvrHelper (deleted) 89 | \_ child cmdline: ['63453245te55', '', '', '', '', '', '', '', '', '', '', ''] 90 | [!] killing 22958 91 | ``` 92 | thasit. 93 | 94 | 95 | # mehrai v1 96 | mehrai is a Docker based honeypot whose purpose is catching Mirai binaries. I tossed this together because cowrie shits the bed whenever it gets Mirai connections. It's meant to work in tandem with [Viper](http://viper-framework.readthedocs.io/en/latest/)'s API. As of now, this honeypot is medium-interaction as there's some weirdness that goes on that may involve your interaction. Regardless, there's so many Mirai bots scanning everywhere(seriously. It even loves ec2 IP space for IoT devices.) that you'll be able to grab a few different bins in the first couple of minutes. 97 | 98 | This uses Alpine Linux Docker image, which works extremely well for mimicing an IoT device. The telnetd binary is from elsewhere, as the Alpine image does not supply one. The python script uses py-watchdog and watches / for any file additions or modifications, posts them to Viper and kills any running Mirai procs. Sometimes Mirai deletes itself so quickly that the script can't grab everything in time, so it will try to get bins from /proc/pid/exe as well. telnetd will be restarted 15 seconds after the Mirai procs are killed, because Mirai gets pissy when expunged and comes back just to kill telnetd. To run: 99 | 100 | ``` 101 | sudo docker build -t honeypot/mehrai . 102 | sudo docker run -it --rm -p 23:23 honeypot/mehrai /bin/sh 103 | 104 | / # sh /tmp/run.sh 105 | ``` 106 | 107 | Feel free to set a password, or don't. 108 | 109 | 110 | -------------------------------------------------------------------------------- /mehrai.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | import time, sys, string, json, random 5 | import urllib, urllib2, hashlib, os 6 | import itertools, mimetools, mimetypes, subprocess 7 | import utils 8 | import netlinks 9 | import argh 10 | import pipes 11 | from argh.decorators import arg 12 | from watchdog.observers import Observer 13 | from watchdog.events import PatternMatchingEventHandler 14 | 15 | # Kicks shit dropped by skids on yr honeypots over to yr Viper/Snakepit instance 16 | 17 | class FileHandler(PatternMatchingEventHandler): 18 | 19 | def process(self, event): 20 | #wordchars += '@{}~-./*?=$:+^' 21 | fileName = os.path.basename(event.src_path) 22 | 23 | 24 | if event.is_directory is False and os.path.exists(event.src_path) and os.path.basename(event.src_path).startswith('.') is False and os.path.getsize(event.src_path) != 0: 25 | rand = ''.join(random.SystemRandom().choice(string.ascii_uppercase + string.digits) for _ in range(6)) 26 | cmd = ["cp", event.src_path, "/tmp/" + fileName + '.' + rand] 27 | args = utils.args_to_string(cmd) 28 | p = subprocess.check_output(cmd, shell=False) 29 | sha256 = utils.get_sha256('/tmp/' + fileName + '.' + rand) 30 | print '[!] Sending ' + event.src_path + '.' + rand + ' to Viper\n[!] sha256: ' + sha256 31 | utils.upload('/tmp/' + fileName + '.' + rand) 32 | 33 | 34 | def on_modified(self, event): 35 | self.process(event) 36 | 37 | 38 | def on_created(self, event): 39 | self.process(event) 40 | 41 | 42 | @arg('dockerid', help='the untruncated dockerid for the container') 43 | @arg('--recurse', help='recursively monitor the filesystem. WARNING! NOISEY!') 44 | @arg('--monitor', help='monitor mode: not killing the procs, but just monitoring. pcap time.') 45 | @arg('--overlayfs', help='changes default storage device from devicemapper to overlay2 (requires special lookup process') 46 | 47 | def map_overlayfs(overlayid): 48 | fsid = open('/var/lib/docker/image/overlay2/layerdb/mounts/'+overlayid+'/mount-id','r').read() 49 | fspath = '/var/lib/docker/overlay2/'+fsid+'/diff' 50 | return fspath 51 | 52 | def run(dockerid, monitor=False, recurse=False, overlayfs=False): 53 | print """\n 54 | _ _ 55 | _ __ ___ ___| |__ _ __ __ _(_) 56 | | '_ ` _ \ / _ \ '_ \| '__/ _` | | 57 | | | | | | | __/ | | | | | (_| | | 58 | |_| |_| |_|\___|_| |_|_| \__,_|_| 59 | 60 | \n""" 61 | 62 | # default devicemapper 63 | # this line may need to be changed, dending on yr docker install 64 | fspath='/var/lib/docker/devicemapper/' + dockerid + '/diff' 65 | 66 | if overlayfs: 67 | fspath=map_overlayfs(dockerid) 68 | 69 | connector = netlinks.NetlinkConnector() 70 | observer = Observer() 71 | observer.schedule(FileHandler(), path=fspath, recursive=recurse) 72 | observer.start() 73 | 74 | telnet = utils.getTelnetPid 75 | 76 | try: 77 | while True: 78 | events = connector.recv() 79 | for event in events: 80 | print event 81 | 82 | if event['event'] == 'EXEC': 83 | print 'EXEC (%d):' % (event['process_pid']) 84 | print ' - process exe: %s' % (netlinks.pid_to_exe(event['process_pid'])) 85 | print ' - process cmdline: %s' % (netlinks.pid_to_cmdline(event['process_pid'])) 86 | if 'kill' and 'telnetd' in netlinks.pid_to_cmdline(event['process_pid']): 87 | print ' [!] respawning telnetd' 88 | cmd = ['docker', 'exec', dockerid, 'telnetd', '-b', '0.0.0.0:23'] 89 | args = utils.args_to_string(cmd) 90 | telnet = subprocess.check_output(args, shell=False) 91 | 92 | elif event['event'] == 'FORK': 93 | print 'FORK (parent: %d, child: %d):' % (event['parent_pid'], event['child_pid']) 94 | print ' - parent exe: %s' % (netlinks.pid_to_exe(event['parent_pid'])) 95 | print ' - parent cmdline: %s' % (netlinks.pid_to_cmdline(event['parent_pid'])) 96 | print ' \_ child exe: %s' % (netlinks.pid_to_exe(event['child_pid'])) 97 | print ' \_ child cmdline: %s' % (netlinks.pid_to_cmdline(event['child_pid'])) 98 | if 'deleted' in netlinks.pid_to_exe(event['child_pid']) and monitor is False: 99 | childpid = str(event['child_pid']) 100 | print ' [!] killing %s' % childpid 101 | rand = ''.join(random.SystemRandom().choice(string.ascii_uppercase + string.digits) for _ in range(6)) 102 | path = '/proc/%s/exe' % childpid 103 | tmp = '/tmp/exe.%s' % rand 104 | cmd = ['cp', path, tmp] 105 | #args = utils.args_to_string(cmd) 106 | cp = subprocess.check_output(cmd, shell=False) 107 | utils.upload('/tmp/exe.' + rand) 108 | cmd = ['kill', '-9', childpid] 109 | #args = utils.args_to_string(cmd) 110 | proc = subprocess.check_output(cmd, shell=False) 111 | cmd = ['docker', 'exec', dockerid, 'telnetd', '-b', '0.0.0.0:23'] 112 | args = utils.args_to_string(cmd) 113 | telnet = subprocess.check_output(cmd, shell=False) 114 | 115 | elif event['event'] == 'EXIT': 116 | print 'EXIT (%d):' % (event['process_pid']) 117 | print ' - process tgid: %s' % (event['process_tgid']) 118 | print ' - process exit code %s' % (event['exit_code']) 119 | print ' - process signal %s' % (event['exit_signal']) 120 | if event['process_pid'] == telnet: 121 | print ' [!] respawning telnetd' 122 | cmd = ['docker', 'exec', dockerid, 'telnetd', '-b', '0.0.0.0:23'] 123 | args = utils.args_to_strings(cmd) 124 | proc = subprocess.check_output(cmd, shell=False) 125 | telnet = utils.getTelnetPid 126 | 127 | print '' 128 | 129 | except KeyboardInterrupt: 130 | observer.stop() 131 | 132 | observer.join() 133 | 134 | if __name__ == "__main__": 135 | argh.dispatch_commands([run]) 136 | 137 | 138 | -------------------------------------------------------------------------------- /netlinks.py: -------------------------------------------------------------------------------- 1 | from ctypes import * 2 | import socket 3 | import os 4 | 5 | AF_NETLINK = PF_NETLINK = 16 6 | NETLINK_CONNECTOR = 11 7 | NLMSG_DONE = 3 8 | CN_IDX_PROC = 1 9 | CN_VAL_PROC = 1 10 | PROC_CN_MCAST_LISTEN = 1 11 | PROC_CN_MCAST_IGNORE = 2 12 | 13 | event_types = { 14 | 'FORK': 0x00000001, 15 | 'EXEC': 0x00000002, 16 | 'UID': 0x00000004, 17 | 'GID': 0x00000040, 18 | 'SID': 0x00000080, 19 | 'PTRACE': 0x00000100, 20 | 'COMM': 0x00000200, 21 | 'COREDUMP': 0x40000000, 22 | 'EXIT': 0x80000000 23 | } 24 | 25 | class nlmsghdr(Structure): 26 | _fields_ = [ 27 | ('nlmsg_len', c_uint), 28 | ('nlmsg_type', c_ushort), 29 | ('nlmsg_flags', c_ushort), 30 | ('nlmsg_seq', c_uint), 31 | ('nlmsg_pid', c_uint), 32 | ] 33 | 34 | class cb_id(Structure): 35 | _fields_ = [ 36 | ('idx', c_uint), 37 | ('val', c_uint), 38 | ] 39 | 40 | class cn_msg(Structure): 41 | _fields_ = [ 42 | ('id', cb_id), 43 | ('seq', c_uint), 44 | ('ack', c_uint), 45 | ('len', c_uint), 46 | ('flags', c_ushort), 47 | ] 48 | 49 | class event_data_ack(Structure): 50 | _fields_ = [ 51 | ('err', c_uint) 52 | ] 53 | 54 | class event_data_fork_proc_event(Structure): 55 | _fields_ = [ 56 | ('parent_pid', c_int), 57 | ('parent_tgid', c_int), 58 | ('child_pid', c_int), 59 | ('child_tgid', c_int), 60 | ] 61 | 62 | class event_data_exec_proc_event(Structure): 63 | _fields_ = [ 64 | ('process_pid', c_int), 65 | ('process_tgid', c_int), 66 | ] 67 | 68 | class uid_gid(Union): 69 | _fields_ = [ 70 | ('uid', c_uint), 71 | ('gid', c_uint), 72 | ] 73 | 74 | class event_data_id_proc_event(Structure): 75 | _fields_ = [ 76 | ('process_pid', c_int), 77 | ('process_tgid', c_int), 78 | ('r', uid_gid), 79 | ('e', uid_gid), 80 | ] 81 | 82 | class event_data_sid_proc_event(Structure): 83 | _fields_ = [ 84 | ('process_pid', c_int), 85 | ('process_tgid', c_int), 86 | ] 87 | 88 | class event_data_ptrace_proc_event(Structure): 89 | _fields_ = [ 90 | ('process_pid', c_int), 91 | ('process_tgid', c_int), 92 | ('tracer_pid', c_int), 93 | ('tracer_tgid', c_int), 94 | 95 | ] 96 | 97 | class event_data_comm_proc_event(Structure): 98 | _fields_ = [ 99 | ('process_pid', c_int), 100 | ('process_tgid', c_int), 101 | ('comm', c_char * 16) 102 | ] 103 | 104 | class event_data_coredump_proc_event(Structure): 105 | _fields_ = [ 106 | ('process_pid', c_int), 107 | ('process_tgid', c_int) 108 | ] 109 | 110 | class event_data_exit_proc_event(Structure): 111 | _fields_ = [ 112 | ('process_pid', c_int), 113 | ('process_tgid', c_int), 114 | ('exit_code', c_uint), 115 | ('exit_signal', c_uint), 116 | ] 117 | 118 | class event_data(Union): 119 | _fields_ = [ 120 | ('ack', event_data_ack), 121 | ('fork', event_data_fork_proc_event), 122 | ('_exec', event_data_exec_proc_event), 123 | ('id', event_data_id_proc_event), 124 | ('sid', event_data_sid_proc_event), 125 | ('ptrace', event_data_ptrace_proc_event), 126 | ('comm', event_data_comm_proc_event), 127 | ('coredump', event_data_coredump_proc_event), 128 | ('exit', event_data_exit_proc_event), 129 | ] 130 | 131 | class proc_event(Structure): 132 | _fields_ = [ 133 | ('what', c_uint), 134 | ('cpu', c_uint), 135 | ('timestamp_ns', c_ulonglong), 136 | ('event_data', event_data) 137 | ] 138 | 139 | class nlcn_msg_mcast(Structure): 140 | _fields_ = [ 141 | ('nl_hdr', nlmsghdr), 142 | ('cn_msg', cn_msg), 143 | ('cn_mcast', c_uint) 144 | ] 145 | 146 | class nlcn_msc_proc_event(Structure): 147 | _fields_ = [ 148 | ('nl_hdr', nlmsghdr), 149 | ('cn_msg', cn_msg), 150 | ('proc_ev', proc_event) 151 | ] 152 | 153 | class NetlinkConnector(): 154 | def __init__(self): 155 | self.sock = socket.socket(PF_NETLINK, socket.SOCK_DGRAM, NETLINK_CONNECTOR) 156 | self.sock.bind((os.getpid(), CN_IDX_PROC)) 157 | 158 | self.toggle_mcast() 159 | 160 | def toggle_mcast(self, enabled=True): 161 | listen_msg = nlcn_msg_mcast() 162 | listen_msg.nl_hdr.nlmsg_len = sizeof(nlcn_msg_mcast) 163 | listen_msg.nl_hdr.nlmsg_pid = os.getpid() 164 | listen_msg.nl_hdr.nlmsg_type = NLMSG_DONE 165 | 166 | listen_msg.cn_msg.id.idx = CN_IDX_PROC 167 | listen_msg.cn_msg.id.val = CN_VAL_PROC 168 | listen_msg.cn_msg.len = sizeof(c_uint) 169 | 170 | listen_msg.cn_mcast = PROC_CN_MCAST_LISTEN if enabled else PROC_CN_MCAST_IGNORE 171 | 172 | self.sock.send(listen_msg) 173 | 174 | def recv(self): 175 | sock_data = self.sock.recv(sizeof(nlcn_msc_proc_event)) 176 | 177 | event_data = proc_event() 178 | memmove(addressof(event_data), sock_data[-40:], sizeof(proc_event)) 179 | 180 | what = event_data.what 181 | 182 | events = [] 183 | 184 | if not what: 185 | events.append({ 186 | 'event': 'NONE', 187 | 'error': event_data.event_data.ack.err 188 | }) 189 | if what & event_types['FORK']: 190 | events.append({ 191 | 'event': 'FORK', 192 | 'parent_pid': event_data.event_data.fork.parent_pid, 193 | 'parent_tgid': event_data.event_data.fork.parent_tgid, 194 | 'child_pid': event_data.event_data.fork.child_pid, 195 | 'child_tgid': event_data.event_data.fork.child_tgid 196 | }) 197 | if what & event_types['EXEC']: 198 | events.append({ 199 | 'event': 'EXEC', 200 | 'process_pid': event_data.event_data._exec.process_pid, 201 | 'process_tgid': event_data.event_data._exec.process_tgid 202 | }) 203 | if what & event_types['UID']: 204 | events.append({ 205 | 'event': 'ID', 206 | 'process_pid': event_data.event_data.id.process_pid, 207 | 'process_tgid': event_data.event_data.id.process_tgid, 208 | 'real_uid': event_data.event_data.id.r.uid, 209 | 'effective_uid': event_data.event_data.id.e.uid, 210 | }) 211 | if what & event_types['GID']: 212 | events.append({ 213 | 'event': 'GID', 214 | 'process_pid': event_data.event_data.id.process_pid, 215 | 'process_tgid': event_data.event_data.id.process_tgid, 216 | 'real_gid': event_data.event_data.id.r.gid, 217 | 'effective_gid': event_data.event_data.id.e.gid, 218 | }) 219 | if what & event_types['SID']: 220 | events.append({ 221 | 'event': 'SID', 222 | 'process_pid': event_data.event_data.sid.process_pid, 223 | 'process_tgid': event_data.event_data.sid.process_tgid, 224 | }) 225 | if what & event_types['PTRACE']: 226 | events.append({ 227 | 'event': 'PTRACE', 228 | 'process_pid': event_data.event_data.ptrace.process_pid, 229 | 'process_tgid': event_data.event_data.ptrace.process_tgid, 230 | 'tracer_pid': event_data.event_data.ptrace.tracer_pid, 231 | 'tracer_tgid': event_data.event_data.ptrace.tracer_tgid, 232 | }) 233 | if what & event_types['COMM']: 234 | events.append({ 235 | 'event': 'COMM', 236 | 'process_pid': event_data.event_data.comm.process_pid, 237 | 'process_tgid': event_data.event_data.comm.process_tgid, 238 | 'comm': event_data.event_data.comm.comm 239 | }) 240 | if what & event_types['COREDUMP']: 241 | events.append({ 242 | 'event': 'COREDUMP', 243 | 'process_pid': event_data.event_data.coredump.process_pid, 244 | 'process_tgid': event_data.event_data.coredump.process_tgid 245 | }) 246 | if what & event_types['EXIT']: 247 | events.append({ 248 | 'event': 'EXIT', 249 | 'process_pid': event_data.event_data.exit.process_pid, 250 | 'process_tgid': event_data.event_data.exit.process_tgid, 251 | 'exit_code': event_data.event_data.exit.exit_code, 252 | 'exit_signal': event_data.event_data.exit.exit_signal 253 | }) 254 | 255 | return events 256 | 257 | 258 | def close(self): 259 | self.toggle_mcast(False) 260 | self.sock.close() 261 | 262 | 263 | def fileno(self): 264 | return self.sock.fileno() 265 | 266 | 267 | def pid_to_exe(pid): 268 | try: 269 | return os.readlink('/proc/%d/exe' % pid) 270 | except OSError: 271 | return '' 272 | 273 | 274 | def pid_to_cmdline(pid): 275 | try: 276 | return open('/proc/%d/cmdline' % pid).read().split('\0') 277 | except IOError: 278 | return '' 279 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | urllib3 2 | watchdog 3 | argh -------------------------------------------------------------------------------- /telnetd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/compoterhacker/mehrai/4ab3362731969f5bb845a84deaed795ae0b76ea0/telnetd -------------------------------------------------------------------------------- /utils.py: -------------------------------------------------------------------------------- 1 | import time, sys, string, json 2 | import urllib, urllib2, hashlib, os 3 | import itertools, mimetools, mimetypes, pipes 4 | PRINTABLE_CHARACTERS = string.letters + string.digits + string.punctuation + " " 5 | VIPER_URL_ADD = "http://viper:8080/file/add" 6 | 7 | 8 | def convert2printable(s): 9 | if not isinstance(s, basestring) or isPrintable(s): 10 | return s 11 | return "".join(convertChar(c) for c in s) 12 | 13 | 14 | def convertChar(c): 15 | if c in PRINTABLE_CHARACTERS: 16 | return c 17 | else: 18 | return "?" 19 | 20 | 21 | def isPrintable(s): 22 | for c in s: 23 | if not c in PRINTABLE_CHARACTERS: 24 | return False 25 | return True 26 | 27 | 28 | def get_sha256(fileName): 29 | hash = hashlib.sha256() 30 | with open(fileName) as f: 31 | for chunk in iter(lambda: f.read(4096), ""): 32 | hash.update(chunk) 33 | return hash.hexdigest() 34 | 35 | 36 | def getTelnetPid(self): 37 | pids = [pid for pid in os.listdir('/proc') if pid.isdigit()] 38 | for pid in pids: 39 | leProc = open('/proc/%s/cmdline' % pid).read().split('\0') 40 | if leProc[0] is '/bin/telnetd': 41 | return int(pid) 42 | 43 | 44 | def args_to_string(args): 45 | return ' '.join(map(lambda x: pipes.quote(str(x)), args) or []) 46 | 47 | 48 | def convertDirtyDict2ASCII(data): 49 | if data is None or isinstance(data, (bool, int, long, float)): 50 | return data 51 | if isinstance(data, basestring): 52 | return convert2printable(data) 53 | if isinstance(data, list): 54 | return [convertDirtyDict2ASCII(val) for val in data] 55 | if isinstance(data, OrderedDict): 56 | return [[convertDirtyDict2ASCII(k), convertDirtyDict2ASCII(v)] for k, v in data.iteritems()] 57 | if isinstance(data, dict): 58 | if all(isinstance(k, basestring) for k in data): 59 | return {k: convertDirtyDict2ASCII(v) for k, v in data.iteritems()} 60 | return [[convertDirtyDict2ASCII(k), convertDirtyDict2ASCII(v)] for k, v in data.iteritems()] 61 | if isinstance(data, tuple): 62 | return [convertDirtyDict2ASCII(val) for val in data] 63 | if isinstance(data, set): 64 | return [convertDirtyDict2ASCII(val) for val in data] 65 | 66 | return data 67 | 68 | 69 | class MultiPartForm(object): 70 | """Accumulate the data to be used when posting a form.""" 71 | 72 | def __init__(self): 73 | self.form_fields = [] 74 | self.files = [] 75 | self.boundary = mimetools.choose_boundary() 76 | return 77 | 78 | 79 | def get_content_type(self): 80 | return 'multipart/form-data; boundary=%s' % self.boundary 81 | 82 | 83 | def add_field(self, name, value): 84 | value = convertDirtyDict2ASCII(value) 85 | 86 | """Add a simple field to the form data.""" 87 | self.form_fields.append((name, value)) 88 | return 89 | 90 | 91 | def add_file(self, fieldname, filename, fileHandle, mimetype=None): 92 | filename = convertDirtyDict2ASCII(filename) 93 | 94 | """Add a file to be uploaded.""" 95 | body = fileHandle.read() 96 | if mimetype is None: 97 | mimetype = mimetypes.guess_type(filename)[0] or 'application/octet-stream' 98 | self.files.append((fieldname, filename, mimetype, body)) 99 | return 100 | 101 | 102 | def add_file_data(self, fieldname, filename, file_data, mimetype=None): 103 | filename = convertDirtyDict2ASCII(filename) 104 | 105 | """Add a file to be uploaded.""" 106 | if mimetype is None: 107 | mimetype = mimetypes.guess_type(filename)[0] or 'application/octet-stream' 108 | self.files.append((fieldname, filename, mimetype, file_data)) 109 | return 110 | 111 | 112 | def __str__(self): 113 | """Return a string representing the form data, including attached files.""" 114 | # Build a list of lists, each containing "lines" of the 115 | # request. Each part is separated by a boundary string. 116 | # Once the list is built, return a string where each 117 | # line is separated by '\r\n'. 118 | parts = [] 119 | part_boundary = '--' + self.boundary 120 | 121 | # Add the form fields 122 | parts.extend( 123 | [ part_boundary, 124 | 'Content-Disposition: form-data; name="%s"' % name, 125 | '', 126 | value, 127 | ] 128 | for name, value in self.form_fields 129 | ) 130 | 131 | # Add the files to upload 132 | parts.extend( 133 | [ part_boundary, 134 | 'Content-Disposition: file; name="%s"; filename="%s"' % \ 135 | (field_name, filename), 136 | 'Content-Type: %s' % content_type, 137 | '', 138 | body, 139 | ] 140 | for field_name, filename, content_type, body in self.files 141 | ) 142 | 143 | # Flatten the list and add closing boundary marker, 144 | # then return CR+LF separated data 145 | flattened = list(itertools.chain(*parts)) 146 | flattened.append('--' + self.boundary + '--') 147 | flattened.append('') 148 | return '\r\n'.join(flattened) 149 | 150 | 151 | def upload(filePath): 152 | rawFile = open(filePath, 'rb') 153 | 154 | try: 155 | form = MultiPartForm() 156 | form.add_file('file', filePath, fileHandle=rawFile) 157 | form.add_field('tags', 'mehrai') 158 | 159 | request = urllib2.Request(VIPER_URL_ADD) 160 | body = str(form) 161 | 162 | request.add_header('Content-type', form.get_content_type()) 163 | request.add_header('Content-length', len(body)) 164 | request.add_data(body) 165 | 166 | response_data = urllib2.urlopen(request).read() 167 | reponsejson = json.loads(response_data) 168 | 169 | except urllib2.URLError as e: 170 | print "[!] File already exists: %s" % e 171 | pass 172 | except ValueError as e: 173 | print "Unable to convert response to JSON: %s" % e 174 | pass --------------------------------------------------------------------------------