基于HTTPS的中间人攻击-BaseProxy
前言
在上一篇文章BaseProxy:异步http/https代理中,我介绍了自己的开源项目BaseProxy,这个项目的初衷其实是为了渗透测试,抓包改包。在知识星球中,有很多朋友问我这个项目的原理及实现代码,本篇文章就讲解一下和这个项目相关的HTTPS的中间人攻击。
HTTPS隧道代理
HTTPS隧道代理简单来说是基于TCP协议数据透明转发,在RFC中,为这类代理给出了规范,Tunneling TCP based protocols through Web proxy servers。浏览器客户端发送的原始 TCP 流量,代理发送给远端服务器后,将接收到的 TCP 流量原封不动返回给浏览器。交互流程如下图所示:

以连接百度为例,浏览器首先发起 CONNECT 请求:
CONNECT baidu.com:443 HTTP/1.1
代理收到这样的请求后,根据 host 地址与服务器建立 TCP 连接,并返回给浏览器连接成功的HTTP 报文(没有报文体):
HTTP/1.1 200 Connection Established
浏览器一旦收到这个响应报文,就可认为与服务器的 TCP 连接已打通,后续可直接透传。
在BaseProxy项目中,https=False是对于https实行透传。
HTTPS中间人攻击
HTTPS 代理本质上是隧道透传,仅仅是转发 TCP 流量,无法获取其中的GET/POST请求的具体内容。这就很麻烦,现在 HTTPS 越来越普遍,做安全测试也就拿不到 HTTP 请求。那怎么做呢? 代理需要对 TCP 流量进行解密,然后对明文的HTTP请求进行分析,这样的代理就称为HTTPS中间人。
正常的HTTPS隧道

在上图中,隧道代理负责浏览器和服务器之间的TCP流量的转发。
HTTPS中间人
如果需要对TCP流量进行分析和修改,就要将上图中的代理功能一分为二,即代理既要当做TLS服务端,又要当做TLS客户端,如下图所示。

在上图中,用一个 TLS 服务器伪装成远端的真正的服务器,接收浏览器的 TLS 流量,解析成明文。这个时候可以对明文进行分析修改,然后用明文作为原始数据,模拟 TLS 客户端将原始数据向远端服务器转发。
CA证书问题
CA证书是我当时遇到的坑,之前没接触过。HTTPS传输是需要证书的,用来对HTTP明文请求进行加解密。一般正常网站的证书都是由合法的 CA 签发,则称为合法证书。在上图中,浏览器会验证隧道代理中 TLS 服务器 的证书:
- 验证是否是合法 CA 签发。
- 验证该证书 CN 属性是否是所请求的域名。即若浏览器打开
www.baidu.com,则返回的证书 CN 属性必须是www.baidu.com。
对于第一点,合法的 CA 机构不会给我们签发证书的,否则HTTPS安全性形同虚设,因此我们需要自制CA证书,并导入到浏览器的信任区中。
对于第二点,我们由于需要对各个网站进行HTTPS拦截,因此我们需要实时生成相应域名的服务器证书,并使用自制的CA证书进行签名。
BaseProxy源码分析
通过以上的讲解,HTTPS中间人的原理已经基本清楚,下面简要地说明一下BaseProxy源码。
HTTP服务器
代理其实就是一个HTTPS服务器,使用了Python中的HTTPServer类,为了增加异步特性,将其放到线程池中。
class MitmProxy(HTTPServer):
def __init__(self,server_addr=('', 8788),RequestHandlerClass=ProxyHandle, bind_and_activate=True,https=True):
HTTPServer.__init__(self,server_addr,RequestHandlerClass,bind_and_activate)
logging.info('HTTPServer is running at address( %s , %d )......'%(server_addr[0],server_addr[1]))
self.req_plugs = []##请求拦截插件列表
self.rsp_plugs = []##响应拦截插件列表
self.ca = CAAuth(ca_file = "ca.pem", cert_file = 'ca.crt')
self.https = https
def register(self,intercept_plug):
if not issubclass(intercept_plug, InterceptPlug):
raise Exception('Expected type InterceptPlug got %s instead' % type(intercept_plug))
if issubclass(intercept_plug,ReqIntercept):
self.req_plugs.append(intercept_plug)
if issubclass(intercept_plug,RspIntercept):
self.rsp_plugs.append(intercept_plug)
class AsyncMitmProxy(ThreadingMixIn,MitmProxy):
pass
HTTPS请求与响应
对HTTP请求的解析与响应,关键在于ProxyHandle类,实现其中的do_CONNECT和do_GET方法,并在do_CONNECT方法中判断是使用透传模式还是中间人模式。
class ProxyHandle(BaseHTTPRequestHandler):
def __init__(self,request,client_addr,server):
self.is_connected = False
BaseHTTPRequestHandler.__init__(self,request,client_addr,server)
def do_CONNECT(self):
'''
处理https连接请求
:return:
'''
self.is_connected = True#用来标识是否之前经历过CONNECT
if self.server.https:
self.connect_intercept()
else:
self.connect_relay()
def do_GET(self):
'''
处理GET请求
:return:
'''
......
do_HEAD = do_GET
do_POST = do_GET
do_PUT = do_GET
do_DELETE = do_GET
do_OPTIONS = do_GET
CA证书生成以及代理证书的自签名
与CA证书相关的内容都放在了CAAuth类中。生成CA证书代码如下:
def _gen_ca(self,again=False):
# Generate key
#如果证书存在而且不是强制生成,直接返回证书信息
if os.path.exists(self.ca_file_path) and os.path.exists(self.cert_file_path) and not again:
self._read_ca(self.ca_file_path) #读取证书信息
return
self.key = PKey()
self.key.generate_key(TYPE_RSA, 2048)
# Generate certificate
self.cert = X509()
self.cert.set_version(2)
self.cert.set_serial_number(1)
self.cert.get_subject().CN = 'baseproxy'
self.cert.gmtime_adj_notBefore(0)
self.cert.gmtime_adj_notAfter(315360000)
self.cert.set_issuer(self.cert.get_subject())
self.cert.set_pubkey(self.key)
self.cert.add_extensions([
X509Extension(b"basicConstraints", True, b"CA:TRUE, pathlen:0"),
X509Extension(b"keyUsage", True, b"keyCertSign, cRLSign"),
X509Extension(b"subjectKeyIdentifier", False, b"hash", subject=self.cert),
])
self.cert.sign(self.key, "sha256")
with open(self.ca_file_path, 'wb+') as f:
f.write(dump_privatekey(FILETYPE_PEM, self.key))
f.write(dump_certificate(FILETYPE_PEM, self.cert))
with open(self.cert_file_path, 'wb+') as f:
f.write(dump_certificate(FILETYPE_PEM, self.cert))
根据域名实时生成服务器证书,并对服务器证书进行自签名。代码如下:
def _sign_ca(self,cn,cnp):
#使用合法的CA证书为代理程序生成服务器证书
# create certificate
try:
key = PKey()
key.generate_key(TYPE_RSA, 2048)
# Generate CSR
req = X509Req()
req.get_subject().CN = cn
req.set_pubkey(key)
req.sign(key, 'sha256')
# Sign CSR
cert = X509()
cert.set_version(2)
cert.set_subject(req.get_subject())
cert.set_serial_number(self.serial)
cert.gmtime_adj_notBefore(0)
cert.gmtime_adj_notAfter(31536000)
cert.set_issuer(self.cert.get_subject())
ss = ("DNS:%s" % cn).encode(encoding="utf-8")
cert.add_extensions(
[X509Extension(b"subjectAltName", False, ss)])
cert.set_pubkey(req.get_pubkey())
cert.sign(self.key, 'sha256')
with open(cnp, 'wb+') as f:
f.write(dump_privatekey(FILETYPE_PEM, key))
f.write(dump_certificate(FILETYPE_PEM, cert))
except Exception as e:
raise Exception("generate CA fail:{}".format(str(e)))
最后
关注公众号:七夜安全博客

- 回复【1】:领取 Python数据分析 教程大礼包
- 回复【2】:领取 Python Flask 全套教程
- 回复【3】:领取 某学院 机器学习 教程
- 回复【4】:领取 爬虫 教程
知识星球已经50多人了,随着人数的增多,价格之后会上涨,越早关注越多优惠。星球的福利有很多:
- 比如上面的教程,已经提前在知识星球中分享
- 可以发表一些问题,大家一块解决
- 我之后写的电子书,录制的教学视频,对于知识星球的朋友都是优惠的(基本上免费)
- 一些节假日会给大家发个红包或者赠书

基于HTTPS的中间人攻击-BaseProxy的更多相关文章
- HTTPS中间人攻击实践(原理·实践)
前言 很早以前看过HTTPS的介绍,并了解过TLS的相关细节,也相信使用HTTPS是相对安全可靠的.直到前段时间在验证https代理通道连接时,搭建了MITM环境,才发现事实并不是我想的那样.由于 ...
- 转:中间人攻击利用框架bettercap测试
0x00前言 上篇提到内网渗透很有趣,这次就从一款新工具说起: bettercap 0x01简介 bettercap可用来实现各种中间人攻击,模块化,便携.易扩展 0x02特点 提到中间人攻击,最知名 ...
- 中间人攻击之ettercap嗅探
中间人攻击: 中间人攻击(Man-in-the-MiddleAttack,简称“MITM攻击”)是一种“间接”的入侵攻击,这种攻击模式是通过各种技术手段将受入侵者控制的一台计算机虚拟放置在网络连接中的 ...
- 中间人攻击利用框架bettercap测试
0x00前言 上篇提到内网渗透很有趣,这次就从一款新工具说起: bettercap 0x01简介 bettercap可用来实现各种中间人攻击,模块化,便携.易扩展 0x02特点 提到中间人攻击,最知名 ...
- Linux下中间人攻击利用框架bettercap测试
0x01简介 bettercap可用来实现各种中间人攻击,模块化,便携.易扩展 0x02特点 提到中间人攻击,最知名的莫过于ettercap,而开发bettercap的目的不是为了追赶它,而是替代它 ...
- Android安全之Https中间人攻击漏洞
Android安全之Https中间人攻击漏洞 0X01 概述 HTTPS,是一种网络安全传输协议,利用SSL/TLS来对数据包进行加密,以提供对网络服务器的身份认证,保护交换数据的隐私与完整性. ...
- 中间人攻击破解HTTPS传输内容
最近App安全受到不小的關注,有人問我,說某某App不安全,究竟是真的還假的啊...所謂有被攻擊的風險,是不是危言聳聽,只是為了嚇人來著的? 現在就來為各位說明一下,是怎麼個不安全法.就來說說攻擊是怎 ...
- iOS 安全:UIWebView访问Https站点防止中间人攻击
尽管Https协议能够提供数据的加密.身份的认证等安全服务,但并不是没有漏洞.HTTPS协议安全隐患的存在可能使用户受到各种极具破坏力的网络攻击.其中中间人攻击(Man In The Middle, ...
- 一个基于nodejs,支持http/https的中间人(MITM)代理,便于渗透测试和开发调试。
源码地址:https://github.com/wuchangming/node-mitmproxy node-mitmproxy node-mitmproxy是一个基于nodejs,支持http/h ...
随机推荐
- .Net WebRequest异步请求与WebClient异步请求
很多情况下一般会使用同步方式发出请求,直到响应后再做后续的逻辑处理等,但有时候后续的逻辑处理不依赖于请求的结果或者是可以挂起等到响应后再处理,又或者是为了解决UI“假死”的现象,这时可以使用异步请求 ...
- 转:Newtonsoft.Json高级用法
原文地址:http://www.cnblogs.com/yanweidie/p/4605212.html 手机端应用讲究速度快,体验好.刚好手头上的一个项目服务端接口有性能问题,需要进行优化.在接口多 ...
- .NET实现自动编译
前言 因每次发布版本的时候,都需要打开vs项目,然后进行编译.如果刚好手里有文件在修改,就需要先签入之类的.所以想找个可以实现自动编译的工具. 在网上查询了不少资料,终于基本上实现了自动编译的功能.因 ...
- Sr Software Engineer - Big Data Team
Sr Software Engineer - Big Data Team About UberWe’re changing the way people think about transport ...
- security/pam_appl.h:没有那个文件或目录
在编译开源库时, 提示 pam.h:4:10: 致命错误:security/pam_appl.h:没有那个文件或目录 #include <security/pam_appl.h> 解决方法 ...
- 安装composer出现链接补上的问题
下载 Composer-Setup.exe 后安装出错: Composer Download Error Connection Error [ERR_CONNECTION]: Unable to co ...
- python2.7 threading RLock/Condition文档翻译 (RLock/Condition详解)
RLock Objects 可重入锁是一个同步原语,它可以被同一个线程多次获取.在内部,除了原始锁使用的锁定/解锁状态之外,它还使用“线程拥有”和“递归级别”的概念.在锁定状态下,某些线程拥有锁:在未 ...
- mpvue 使用echarts动态绘制图表(数据改变重新渲染图表)
最近在公司开发一款微信小程序,按照客户需求用饼状图显示当前设备状态(开机.故障.关机),于是就在网上寻找各种资料,找了很多mpvue使用关于echarts绘制图表,最终功夫不负有心人,找到一篇关于mp ...
- 2.2.3 TableLayout(表格布局)
3.如何确定行数与列数 ①如果我们直接往TableLayout中添加组件的话,那么这个组件将占满一行!!! ②如果我们想一行上有多个组件的话,就要添加一个TableRow的容器,把组件都丢到里面! ③ ...
- Nginx端口占用问题
错误信息:nginx: [emerg] listen() to 0.0.0.0:80, backlog 511 failed (98: Address already in use) 主要是端口被占用 ...