作者名:Demo不是emo

主页面链接:主页传送门
创作初心:舞台再大,你不上台,永远是观众,没人会关心你努不努力,摔的痛不痛,他们只会看你最后站在什么位置,然后羡慕或鄙夷
座右铭:不要让时代的悲哀成为你的悲哀
专研方向:网络安全,数据结构

每日emo:总想把自己变得更好再来找你,却不知你已越走越远

如果你以前没有 Python 编程经验,这篇博客将带你浏览一下 Python 的背景,语 法,函数,迭代器等语法问题,如果你已经有 Python 的编程经验,可以跳过这 一章。以后的章节将不会介绍更多的语言细节,你可以根据兴趣自行学习。

目录

一、建立 Python 开发环境

1、下载环境

2、安装第三方库

3、解释型 python与交互型 python

[1]、解释型

[2]、交互型

二、Python 语言简介

三、变量,字符串,列表,字典介绍

1、变量

2、字符串

3、列表

4、字典

四、使用用网络,迭代器,异常处理,模块等

1、网络

2、条件选择

3、异常处理

4、函数

5、迭代

6、文件I/O

7、SYS 模块

8、OS模块


一、建立 Python 开发环境

1、下载环境

Python 的下载网站(http://www.python.org/download/)提供了 Python 在 Windows,Mac OS X 和 Linux 上的安装包。

如果您运行的是 Mac OS X 或 Linux,Python 的解释器已经预先安装在了系统上。

安装包为程序开发者提供 了 Python 解释器,标准库和几个内置模块。 Python 标准库和内置模块提供的 功能范围广泛,包括内建的数据类型,异常处理,数字和数学模块,文件处理 功能,如

加密服务,与操作系统互操作性,网络数据处理,并与 IP 协议交互,还包括许 多其他有用模块。同时,程序开发者可以很容易地安装任何第三方软件包。 第三方软件包的完整列表可在(http://pypi.python.org/pypi/) 上看到

2、安装第三方库

在后面,我们将利用 python 的 python-nmap 包来处理NMAP扫描工具 的结果。 下面的例子描述了如何下载和安装 python-nmap 包,这种方法也适用与安装其他包

因为这里我用的是kali系统,就用kali系统来演示了,也推荐大家使用kali系统,毕竟是渗透测试专用系统,后续我们编写的脚本很多都需要配合里面的渗透测试工具。

kali系统会预安装pip,所以我们直接执行下面这个代码就可以了

pip install python-nmap

结果如下就是安装成功了

后续在编写脚本时有需要安装的包我都会提前说,大家现在只要知道怎么安装就可以了。

最近几年 python 源代码已经延伸成了 2.x 和 3.x 两个分支。一般情况我用的都是python3.10,如果有特别的情况我会提前说,(版本不用跟我相同,都是3.x即可)。

3、解释型 python与交互型 python

解释型交互型的区别就是非交互式交互式的区别,简单举个例子

[1]、解释型

其实就相当于文件生成后再调用解释器来解释,即执行里面的代码

例如我们新建一个hello.py文件,内容如下

print("hello world!")

此时文件已经生成,再在该目录终端下执行下面这个命令,就可以调动解释器执行其中的代码

python hello.py

此时终端就会呈现出输出结果,输出“hello world!”,

[2]、交互型

此外,python 具有交互能力,程序设计师可以调用 python 解释器,并直接与解释 器“交流”。就相当于一直调用解释器,每输入一次命令后交互解释器就会立即执行

在终端输入python即可进入交互型python,此时输入的命令就会被直接执行,效果如下

二、Python 语言简介

在以后的内容中,我们会讲解变量,数据类型,字符串,复杂的数据结构,网络, 选择,循环,文件处理,异常处理,与操作系统进行交互。为了显示这一点,我们将构建一个简单的 TCP 类型的漏洞扫描器,读取来自服务的提示消息,并把他们与已知的存在漏洞的服务版本做比较,作为一个有经验的程序设计师,你可能会发现一些最 初的示例代码的设计非常难看,事实上,我们希望你能在代码基础上进行发展, 使他变得优雅。

三、变量,字符串,列表,字典介绍

那么,让我们从任何编程语言的基础——变量开始吧!

1、变量

在 python 中,变量对应的数据存储在内存中,这种在内存中的位置可以存储不同 的值,如整型,实数,布尔值,字符串,或更复杂的数据结构,例如列表或字典。在 下面的代码中,我们定义一个存储整形的变量和一个存储字符串的提示消息。

port = 21banner = "FreeFloat FTP Server"print("[+] Checking for "+banner+" on port "+str(port))

为了把 这两个变量连接到一个字符串中,我们必须用 str()函数将port转换为字符型,结果如下

[+] Checking for FreeFloat FTP Server on port 21

怎么样,这个语句相信渗透的小伙伴都不会陌生吧,就是在这样来的,我们后面呢还会用到。

此外python定义变量与其他语言不同,它不必声明变量的类型,相反,python 解释器决定了变量类型何在内存中为他保留的空间的 大小

思考下面的例子,我们正确的声明了一个字符串,一个整数,一个列表和一个 布尔值,解释器都自动的正确的识别了每个变量的类型(type函数用于返回变量的类型)。

banner = "FreeFloat FTP Server" # 字符串类型type(banner)# port = 21 # 整型type(port)# portList=[21,22,80,110] # 列表类型type(portList)# portOpen = True # 布尔类型type(portOpen)# 

2、字符串

在 python 中字符串模块提供了一系列非常强大的字符串操作方法。阅读 http://docs.python.org/library/string.html 可以查看完整的用法。

让我们来看几个常用的函数。思考下面这些函数的用法,

upper() 方法将字符串中 的小写字母转为大写字母,

lower()方法转换字符串中所有大写字母为小写,

replace(old,new)方法把字符串中的 old(旧字符串) 替换成 new(新字符串),

find()方法 检测字符串中是否包含指定的子字符串。

比如下面的代码

banner = "FreeFloat FTP Server"print(banner.upper())# FREEFLOAT FTP SERVERprint(banner.lower())# freefloat ftp serverprint(banner.replace('FreeFloat','Ability'))# Ability FTP Serverprint(banner.find('FTP'))# 10

3、列表

Python 的数据结构——列表,提供了一种存储一组数据的方式。这组数据里的元素可以是任意数据类型。另外,有一些内置的操作列表的方法,例如元素的添加,删除,插入,弹出,获取索引,排序,计数,排序和反转

请看下面的例子,一个程序通过使用 append()添加元素来建立一个列表,打印项目,然后在 再次输出前给他们排序。程序设计师可以找到特殊元素的索引(例如样例中的 80),此外,指定的元素也可以被移动。

portList = []portList.append(21)portList.append(80)portList.append(443)portList.append(25)print(portList)# [21, 80, 443, 25]portList.sort()print(portList)# [21, 25, 80, 443]pos = portList.index(80)print("[+] There are "+str(pos)+" ports to scan before 80.")# [+] There are 2 ports to scan before 80.portList.remove(443)print(portList)# [21, 25, 80]cnt = len(portList)print("[+] Scanning "+str(cnt)+" Total Ports.")# [+] Scanning 3 Total Ports.

4、字典

Python 的数据结构——字典,提供了一个可以存储任何数量 python 对象的哈希表。 字典的元素由键和值组成,让我们继续用我们的漏洞扫描器的例子来讲解 python 的字 典。当扫描指定的 TCP 端口时,用字典包含每个端口对应的常见的服务名会很有用。 建立一个字典,我们能查找像 ftp 这样的键并返回端口关联的值 21。

当我们建立一个字典时,每一个键和他的值被冒号隔开,同时,我们用逗号分隔元素。 注意,.keys()这个函数将返回字典的所有键的列表,.items()这个方法将返回字典的元素的列表。接下来,我们验证字典是否包含了指定的键(ftp),伴随着键,值 21 返回了。

services = {'ftp':21,'ssh':22,'smtp':25,'http':80}services.keys()# ['ftp', 'smtp', 'ssh', 'http']services.items()# [('ftp', 21), ('smtp', 25), ('ssh', 22), ('http', 80)]services.has_key('ftp')# Trueservices['ftp']# 21print("[+] Found vuln with FTP on port "+str(services['ftp']))#Found vuln with FTP on port 21

四、使用用网络,迭代器,异常处理,模块等

1、网络

套接字模块(socket)提供了一个可以使 python 建立网络连接的库,用于在客户端程序和服务器程序之间创建连接.

让我们快速的编写一个获取目标端口信息的脚本,连接到特定 IP 地址和端口后,我们的脚本将打印提示信息,之后, 我们使用 connect()函数连接到 IP 地址端口。一旦连接成功,就可以通过套接字进行读写。我们把获取的结果存到一个变量中,然后打印到服务器。

import socket               # 引入套接字模块socket.setdefaulttimeout(2)        # 经过两秒还未连接到,就进入下一操作s = socket.socket()            # 创建套接字s.connect(("192.168.95.148",21))      # 初始化tcp连接ans = str(s.recv(1024))          # 接收tcp数据,字节型数据返回,每次最多接收1024字节print(ans)                # 220 FreeFloat Ftp Server (Version 1.00).

上面这段代码就可以实现一个简单的21端口服务探测功能,将ip换成你想探测的目标,就可以探测到目标的21端口的具体服务信息。

2、条件选择

像大多数编程语言一样,python 提供了条件选择的方式,通过 if 语句,建立一个逻辑表达式来判断选择的结果。继续写我们的脚本,我们想知道,是否指定的 FTP 服务 器是容易受到攻击的。要做到这一点,我们要拿我们的结果和已知的易受攻击的 FTP 服务器版本作比较。

这里给出了四个易受攻击的ftp服务版本,修改后的代码如下

import socketsocket.setdefaulttimeout(2)s = socket.socket()s.connect(("192.168.95.148",21))ans = str(s.recv(1024))if "FreeFloat Ftp Server (Version 1.00)" in ans:    print("[+] FreeFloat FTP Server is vulnerable.")elif "3Com 3CDaemon FTP Server Version 2.0" in ans:    print("[+] 3CDaemon FTP Server is vulnerable.")elif "Ability Server 2.34" in ans:    print("[+] Ability FTP Server is vulnerable.")elif "Sami FTP Server 2.0.2" in ans:    print("[+] Sami FTP Server is vulnerable.")else:    print("[-] FTP Server is not vulnerable.\n")

3、异常处理

即使一个程序设计师编写的程序语法正确,该程序仍然可能在运行或执行时发生错误。 考虑经典的一种运行错误——除以零。因为零不能做除数,所以 python 解释器显示一 条消息,把错误信息告诉程序设计师:该错误使程序停止执行。如下

可以看到程序直接结束了,并出现了报错内容,但是我们不想让程序结束,想让他报错后继续执行就应该引入我们的捕捉异常操作

捕捉异常可以使用try/except语句

以下为简单的try….except…else的语法:

try:        #运行别的代码except :        #如果在try部份引发了'name'异常except ,:        #如果引发了'name'异常,获得附加的数据else:        #如果没有异常发生

例如下面这段代码,就能成功捕捉到异常,这样就可以起到程序错误但是

try:    print("1237/0=" + str(1237 / 0))except:    print("error")else:    print("right")

这样的话当1237/0仍然会被识别出错误,但是不会直接结束程序输出报错信息,而是会输出我们定义的error。

现在我们继续更新我们的脚本

import socketsocket.setdefaulttimeout(2)s = socket.socket()try:    s.connect(("192.168.95.149", 21))except Exception as e:    print("[-] Error = "+str(e))

4、函数

在 python 中,函数提供了组建好的,可反复使用的代码片段。通常,这允许程序设 计师写代码来执行单独或关联的行为。

尽管 python 提供了许多内置函数,程序设计师仍然可以创建自定义的函数。关键字 def()开始了一个函数,程序设计师可以把任何变量放到括号里。这些变量随后被传递, 这意味着在函数内部对这些变量的任何变化,都将影响调用的函数的值。继续以我们 的 FTP 漏洞扫描器为例,让我们创建一个函数来执行只连接到 FTP 服务器的操作返回提示信息

import socketdef retBanner(ip, port):    try:        socket.setdefaulttimeout(2)        s = socket.socket()        s.connect((ip, port))        banner = s.recv(1024)        return banner    except:        returndef main():    ip1 = '192.168.95.148'    ip2 = '192.168.95.149'    port = 21    banner1 = retBanner(ip1, port)    if banner1:        print('[+] ' + ip1 + ': ' + banner1)    banner2 = retBanner(ip2, port)    if banner2:        print('[+] ' + ip2 + ': ' + banner2)if __name__ == '__main__':    main()

在返回信息后,我们的脚本需要与已知存在漏洞的程序进行核对。这也反映了函数 的单一性和相关性。该函数 checkVulns()用获得的信息来对服务器存在的漏洞进行判断

def checkVulns(banner):    if 'FreeFloat Ftp Server (Version 1.00)' in banner:        print('[+] FreeFloat FTP Server is vulnerable.')    elif '3Com 3CDaemon FTP Server Version 2.0' in banner:        print('[+] 3CDaemon FTP Server is vulnerable.')    elif 'Ability Server 2.34' in banner:        print('[+] Ability FTP Server is vulnerable.')    elif 'Sami FTP Server 2.0.2' in banner:        print('[+] Sami FTP Server is vulnerable.')    else:        print('[-] FTP Server is not vulnerable.')    return

5、迭代

上一章中,你可能会发现我们几乎重复三次写了相同的代码,来检测三个不同的 IP 地 址。

代替反复做一件事,使用 for 循环便利多个元素会更加容易。举个例子:如果我们想便利整个整个 IP 地址从 192.168.98.1 到 192.168.95.254 的子网,我们要用一个 for 循 环从 1 到 255 进行遍历,来打印出子网内的信息。

for x in range(1,255):    print("192.168.95."+str(x))

同样,我们可能需要遍历已知的端口列表来检查漏洞。代替一系列的数字,我们可以通过一个元素列表遍历他们。

portList = [21,22,25,80,110]for port in portList:    print(port)

继续更新我们的脚本,更新后代码如下,随着程序有了遍历 IP 和端口的能力,我们也将个更新我们的漏洞检测脚本,现在, 我们的脚本将测试全部 254 个 IP 地址所提供的 telnet, SSH, smtp, http,

import socketdef retBanner(ip, port):    try:        socket.setdefaulttimeout(2)        s = socket.socket()        s.connect((ip, port))        banners = s.recv(1024)        return str(banners)    except Exception as e:        print("扫描错误: ", e)        returndef checkVulns(banners):    if 'FreeFloat Ftp Server (Version 1.00)' in banners:        print('[+] FreeFloat FTP Server is vulnerable.')    elif '3Com 3CDaemon FTP Server Version 2.0' in banners:        print('[+] 3CDaemon FTP Server is vulnerable.')    elif 'Ability Server 2.34' in banners:        print('[+] Ability FTP Server is vulnerable.')    elif 'Sami FTP Server 2.0.2' in banners:        print('[+] Sami FTP Server is vulnerable.')    else:        print('[-] FTP Server is not vulnerable.')    returndef main():    portList = [21, 22, 25, 80, 110, 443]    for x in range(106, 107):        ip = '192.168.1.' + str(x)        for port in portList:            banner = retBanner(ip, port)            if banner:                print('[+] ' + ip + ':' + str(port) + banner)                checkVulns(banner)            else:                print('[+] ' + ip + ":" + str(port) + " :do not have vuln")if __name__ == '__main__':    main()

6、文件I/O

虽然我们的脚本已有了一些能帮助检测漏洞信息的 if 语句,但加进一个漏洞列表会更好,举个例子,假设我们有一个叫做 vuln_banners.txt 的文本文件。

在每一行该文件列出了具体的服务版本和已知的之前的漏洞,我们不需要构建一个庞大的 if 语句, 让我们读取这个文本文件,并用他来判断是否我们的提示信息存在漏洞

就是下面这样包含很多历史漏洞的txt文件

我们将会把我们更新后的代码放到函数 checkVulns()中。在这里我们将用只读模式 (’r’)打开文本文件。然后使用函数 readlines()遍历文件的每一行,对每一行,我们把他 与我们的提示信息作比较,注意我们必须用方法.strip(‘\r’)去掉每行的回车符,如果发现一对匹配了,我们打印出有漏洞的服务信息。 更新后的checkVulns函数代码如下(此时历史漏洞文件在同一目录下)

def checkVulns(banner):    f = open("vuln_banners.txt", 'r')    for line in f.readlines():        if line.strip('\n') in banner:            print("[+] Server is vulnerable: " + banner.strip('\n'))

7、SYS 模块

内置的 sys 模块提供访问和维护 python 解释器的能力。这包括了提示信息,版本, 整数的最大值,可用模块,路径钩子,标准错误,标准输入输出的定位和解释器调用 的命令行参数。你能够在 python 的在线模块文档上找到更多与此相关的信息 (http://docs.python.org/library/sys)。

在创建 python 脚本时与 sys 模块交互会十分 有用。我们可以,例如,想在程序运行时解析命令行参数。思考下我们的漏洞扫描器,

如果我们想要把文本文件的名字作为命令行参数传递会怎么样呢?领标 sys.argv 包含了全部的命令含参数。第一个索引 sys.argv[0]包含了 python 脚本解释器的名称。列表中剩余的元素包含了以下全部的命令行参数。因此,如果我们只想传递附加的参数, sys.argv 应该包含两个元素。

来看下面这个例子

import sys    if len(sys.argv)==2:        filename = sys.argv[1]        print "[+] Reading Vulnerabilities From: "+filename

我们使用命令行执行

简单理解就是

sys.argv[1]就是demo2.py

sys.argv[2]就是第一个参数a.txt

依次类推

8、OS模块

内置的 OS 模块提供了丰富的与 MAC,NT,Posix 等操作系统进行交互的能力。这个模 块允许程序独立的与操作系统环境。文件系统,用户数据库和权限进行交互。

思考一 下,比如,上一章中,用户把文件名作为命令行参数来传递。他可以验证文件是否存 在以及当前用户是否有权限处理这个文件。如果失败,他将显示一条信息,来显示一个适当的错误信息给用户。

import sysimport osif len(sys.argv) == 2:  # 命令行传入了一个参数    filename = sys.argv[1]  # 提取第一个参数    if not os.path.isfile(filename):  # 路径不存在        print('[-] ' + filename + ' does not exist.')        exit(0)    if not os.access(filename, os.R_OK):  # 没有访问权限        print('[-] ' + filename + ' access denied.')        exit(0)    print('[+] Reading Vulnerabilities From: ' + filename)  # 正常读取文件

现在我们可以重新组合漏洞扫描程序的各个零件。不用担心他会错误终止或是在执 行时缺少使用线程的能力或是更好的分析命令行的能力,我们将会在后面的博客继续改进这个脚本,博主后续的脚本成品都会在github上更新