paramiko-python-(3)审计服务器开发

    xiaoxiao2021-03-25  141

    源码都粘贴出来,有点长,但是真正改动的就只有几行

    环境配置:我的另一片博客推荐用指令安装,然后下载相应的源码(我们需要源码里的demo),源码版本与安装的版本最好一样。我安装的是2.2,下载的是2.1,之前无脑用1.7一直报错。 #用源码安装后进入终端用以下指令查看paramiko的版本 >>> import paramiko >>> paramiko.__version__ '2.1.2' paramiko源码里有几个例子,稍微改一下就成了一个简版的审计服务器。我们的目的就是【使用者】使用我们的几台重要的主机,我们追踪记录操作者的痕迹信息,在简版中我们记录时间,使用的指令等。 demo.py interactive.py #这两个文件是我们需要的 创建堡垒机账户 #登录root sudo su #创建一个新账户 adduser access_gateway #之后设置密码等信息就行(假设创建了一个账户access_gateway) 使【使用者】一登陆这个堡垒机账户就启动一个脚本,让其选择登录那个客户机 #/home/access_gateway/.bashrc文件末尾添加一句指令 /usr/bin/python /home/access_gateway/menu.py #前者可以用指令which python获知 #后者是菜单文件的路径

    供【使用者】选择的菜单文件menu.py

    #!/usr/bin/env python import os,sys msg = """ \033[42;1mWelcome to Use the NCU Auditing System!\033[0m """ print msg host_dict = { #条件有限,只有【'huawei':'139.159.217.176'】这个选项有用 'huawei':'139.159.217.176', 'root':'192.168.180.128', 'wanghao':'10.0.1.139' } while True: for hostname, ip in host_dict.items(): print hostname,ip try: host = raw_input('Please Input Host Name:') if host == '': continue elif host == 'quit': print 'GoodBye(T_T)' break elif not host_dict.has_key(host): print 'No host matched, try again.' continue else: print 'Going to connect %s with ip [%s]'%(host, host_dict[host]) os.system('python demo.py %s'%host_dict[host]) sys.exit(1) except KeyboardInterrupt: continue except EOFError: continue 源码的修改 #!/usr/bin/env python import base64 from binascii import hexlify import getpass import os import select import socket import sys import threading import time import traceback import paramiko import interactive def agent_auth(transport, username): """ Attempt to authenticate to the given transport using any of the private keys available from an SSH agent. """ agent = paramiko.Agent() agent_keys = agent.get_keys() if len(agent_keys) == 0: return for key in agent_keys: print 'Trying ssh-agent key %s' % hexlify(key.get_fingerprint()), try: transport.auth_publickey(username, key) print '... success!' return except paramiko.SSHException: print '... nope.' def manual_auth(username, hostname): default_auth = 'p' auth = raw_input('Auth by (p)assword, (r)sa key, or (d)ss key? [%s] ' % default_auth) if len(auth) == 0: auth = default_auth if auth == 'r': default_path = os.path.join(os.environ['HOME'], '.ssh', 'id_rsa') path = raw_input('RSA key [%s]: ' % default_path) if len(path) == 0: path = default_path try: key = paramiko.RSAKey.from_private_key_file(path) except paramiko.PasswordRequiredException: password = getpass.getpass('RSA key password: ') key = paramiko.RSAKey.from_private_key_file(path, password) t.auth_publickey(username, key) elif auth == 'd': default_path = os.path.join(os.environ['HOME'], '.ssh', 'id_dsa') path = raw_input('DSS key [%s]: ' % default_path) if len(path) == 0: path = default_path try: key = paramiko.DSSKey.from_private_key_file(path) except paramiko.PasswordRequiredException: password = getpass.getpass('DSS key password: ') key = paramiko.DSSKey.from_private_key_file(path, password) t.auth_publickey(username, key) else: pw = getpass.getpass('Password for %s@%s: ' % (username, hostname)) t.auth_password(username, pw) # setup logging paramiko.util.log_to_file('demo.log') username = '' if len(sys.argv) > 1: hostname = sys.argv[1] if hostname.find('@') >= 0: username, hostname = hostname.split('@') else: hostname = raw_input('Hostname: ') if len(hostname) == 0: print '*** Hostname required.' sys.exit(1) port = 22 if hostname.find(':') >= 0: hostname, portstr = hostname.split(':') port = int(portstr) # now connect try: sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.connect((hostname, port)) except Exception, e: print '*** Connect failed: ' + str(e) traceback.print_exc() sys.exit(1) try: t = paramiko.Transport(sock) try: t.start_client() except paramiko.SSHException: print '*** SSH negotiation failed.' sys.exit(1) try: keys = paramiko.util.load_host_keys(os.path.expanduser('~/.ssh/known_hosts')) except IOError: try: keys = paramiko.util.load_host_keys(os.path.expanduser('~/ssh/known_hosts')) except IOError: print '*** Unable to open host keys file' keys = {} # check server's host key -- this is important. key = t.get_remote_server_key() if not keys.has_key(hostname): print '*** WARNING: Unknown host key!' elif not keys[hostname].has_key(key.get_name()): print '*** WARNING: Unknown host key!' elif keys[hostname][key.get_name()] != key: print '*** WARNING: Host key has changed!!!' sys.exit(1) else: print '*** Host key OK.' # get username if username == '': default_username = getpass.getuser() username = raw_input('Username [%s]: ' % default_username) if len(username) == 0: username = default_username agent_auth(t, username) if not t.is_authenticated(): manual_auth(username, hostname) if not t.is_authenticated(): print '*** Authentication failed. :(' t.close() sys.exit(1) chan = t.open_session() chan.get_pty() chan.invoke_shell() print '*** Here we go!' print #下面这条语句做了修改 interactive.interactive_shell(chan, username, hostname) #上面这条语句做了修改 chan.close() t.close() except Exception, e: print '*** Caught exception: ' + str(e.__class__) + ': ' + str(e) traceback.print_exc() try: t.close() except: pass sys.exit(1)

    interative.py

    import socket import sys import time # windows does not have termios... try: import termios import tty has_termios = True except ImportError: has_termios = False def interactive_shell(chan, username, hostname): if has_termios: posix_shell(chan, username, hostname) else: windows_shell(chan) #这个函数改动较大 #在/tmp/audit/logs目录下创建日志记录文件,记录时间,指令操作等 def posix_shell(chan, username, hostname): import select day_time = time.strftime('%y-%m-%d') f=open('/tmp/audit/logs/audit_%s.log'%(day_time), 'a') oldtty = termios.tcgetattr(sys.stdin) try: tty.setraw(sys.stdin.fileno()) tty.setcbreak(sys.stdin.fileno()) chan.settimeout(0.0) record = [] while True: day = time.strftime('%y-%m-%d %H:%M:%S') r, w, e = select.select([chan, sys.stdin], [], []) if chan in r: try: x = chan.recv(1024) if len(x) == 0: print '\r\n*** EOF\r\n', break sys.stdout.write(x) sys.stdout.flush() except socket.timeout: pass if sys.stdin in r: x = sys.stdin.read(1) if len(x) == 0: break chan.send(x) #print x record.append(x) if x == '\r': cmd = ''.join(record).split('\r')[-2] f.write(username + ' ' + hostname + ' ' + day + ' ' + cmd + '\n') f.flush() record = [] finally: f.close() termios.tcsetattr(sys.stdin, termios.TCSADRAIN, oldtty) # thanks to Mike Looijmans for this code def windows_shell(chan): import threading sys.stdout.write("Line-buffered terminal emulation. Press F6 or ^Z to send EOF.\r\n\r\n") def writeall(sock): while True: data = sock.recv(256) if not data: sys.stdout.write('\r\n*** EOF ***\r\n\r\n') sys.stdout.flush() break sys.stdout.write(data) sys.stdout.flush() writer = threading.Thread(target=writeall, args=(chan,)) writer.start() try: while True: d = sys.stdin.read(1) if not d: break chan.send(d) except EOFError: # user hit ^Z or F6 pass 测试结果 #日志记录的情况 root 139.159.217.176 17-03-08 12:13:15 df root 139.159.217.176 17-03-08 12:13:18 ls -a root 139.159.217.176 17-03-08 12:13:59 exit root 139.159.217.176 17-03-08 12:14:57 df root 139.159.217.176 17-03-08 12:14:59 ls -a root 139.159.217.176 17-03-08 12:15:01 df root 139.159.217.176 17-03-08 12:15:04 ll root 139.159.217.176 17-03-08 12:15:09 top -bn 1 root 139.159.217.176 17-03-08 12:15:26 exit

    如果你在连接远程主机遇到问题 不妨参考我在开头提到那篇文章,里面提到paramiko安装,用密码或者密钥远程登录主机

    为了更高BIGE 安装【shellinabox】,能够在WEB端登录终端。 安装: #这里只给出指令安装的方式 #想要源码安装的,请自行百度 sudo apt-get install shellinabox #Then restart the shellinabox daemon: sudo invoke-rc.d shellinabox restart #Now you can access your shellinabox server with an easier URL: https://yourcomputername #编辑这个文件,可以更改端口,WEB界面背景,字体大小颜色等 sudo gedit /etc/default/shellinabox

    安装过程:

    derek@ubuntu:~$ sudo apt-get install shellinabox [sudo] password for derek: Reading package lists... Done Building dependency tree Reading state information... Done The following NEW packages will be installed: shellinabox 0 to upgrade, 1 to newly install, 0 to remove and 28 not to upgrade. Need to get 122 kB of archives. After this operation, 510 kB of additional disk space will be used. Get:1 http://us.archive.ubuntu.com/ubuntu xenial/universe amd64 shellinabox amd64 2.19 [122 kB] Fetched 122 kB in 2s (49.0 kB/s) Selecting previously unselected package shellinabox. (Reading database ... 227125 files and directories currently installed.) Preparing to unpack .../shellinabox_2.19_amd64.deb ... Unpacking shellinabox (2.19) ... Processing triggers for man-db (2.7.5-1) ... Processing triggers for systemd (229-4ubuntu16) ... Processing triggers for ureadahead (0.100.0-19) ... Setting up shellinabox (2.19) ... Processing triggers for systemd (229-4ubuntu16) ... Processing triggers for ureadahead (0.100.0-19) ...

    用指令【ps -ef | grep shellinabox】找到进程ID,登录root然后kill掉。。。有点麻烦

    最终的一个效果图 看见没有!通过登录堡垒机账户,提供给【使用者】几个登录选项,【使用者】登陆上。这边就记录了【使用者】的行为信息。
    转载请注明原文地址: https://ju.6miu.com/read-2955.html

    最新回复(0)