大家好,eCapture项目距上次新版发布也已经过去2-3个月了,在这期间,社区论坛里很多网友提了一些问题以及需求,等我来解决。这几个月博主工作特别忙,一直没时间更新eCapture。这个周末特地抽时间解决了社区中反应的一些bug、优化点等。至于新功能,主要的就是流量转发功能,这个功能还是比较复杂的。

今天,博主先把发布一个修复bug的版本,等过段时间博主不是那么忙了,再构思流量转发功能,分享给大家。

新版发布

功能介绍

  1. 增加了Linux 5.2一下内核的异常提示
  2. 移除了curl/wget等参数路径指定
  3. 恢复了关联数据包目标IP功能。
  4. 修复了Openssl FD总是为0的错误。

其中,第二条可能会有影响,移除curl\wget路径参数,也顺带移除了自动搜索这两个软件所使用的Openssl动态链接库版本,以及所属路径问题。意味着大家需要自己检查期望被捕获的程序所用的SSL类库版本,并手动使用--libssl参数指定。

下载

下载地址:eCapture v0.6.2

流量转发

流量转发功能有很多使用场景,包括测试、渗透、研发、运维等,国内外都有用户提到过这个需求。

流量转发功能,必不可少的数据就是IP五元组,而这个问题,是eCapture最头疼的问题,拿不到远程地址的IP、端口数据。

eCapture实现介绍

  1. 基于TC的流量包获取,使用Uprob eBPF来完成捕获捕获。借助于wireshark的pcapng模式,进行解析展示。
  2. 基于uprobe hook,eBPF程序挂钩到libssl动态链接库文件中,针对 SSL_writeSSL_read函数进行Hook,读取其参数、返回值。

uprobe hook也就是函数的调用hook,意味着只有这个函数触发时,才能执行eBPF的程序。并且是没法调用外部的SSL的外部函数的。

int SSL_write(SSL *s, const void *buf, int num)
{
    // eBPF uprobe 
    return ret;
   // eBPF uretprobe
}
int SSL_read(SSL *s, void *buf, int num)
{
    // eBPF uprobe 
    return ret;
   // eBPF uretprobe
}

比如,eBPF uprobe代码是插入到SSL_write函数的入口点,可以读取SSL *sconst void *bufint num这三个参数。也就是说,这里并没有关于这个数据包所属IP、port等信息的参数。要想拿到IP等信息,必需从这三个参数里读取。

eCapture的数据包关联IP实现

eCapture的实现,是根据SSL *s 的内存地址,再根据结构体中的偏移地址进行二次定位、三次定位等,查找最终的目标数值。

但是,但是来了,SSL *s对应ssl_st结构体,里面并不存储IP\addr等信息 。现在的实现是读取SSL *s里的rbio\wbio结构体,他们里面有个num字段,也就是FD信息。 再hook connect函数,

int __connect (int fd, __CONST_SOCKADDR_ARG addr, socklen_t len)

读取FD,以及addr信息存储到 eBPF manp里。

eCapture再根据进程PID、fd来关联addr信息。 这样的实现有个缺点,就是__connect函数一般都在libpthread.so里,意味着除了hook libssl.so,还需要再多hook一个动态链接库,而且在部分Linux发行版或者Android中,还不确定会被放到哪个链接库下。

缺陷

SSL_read时,是可以正常工作的。但在SSL_write时,fd可能读到0,是因为SSL_write函数它可能是一个异步的BIO实现。 这就导致发送的包拿不到目标IP信息。 未来做数据包转发时,目标代理软件就无法解析、无法关联到一个TCP会话中。

难点

只好另寻其他办法。 但从libssl.so这一个文件来看,不管是Read还是Write函数,第一个参数是SSL *结构体,最好能从这个结构体中找到存储了远程IP端口的信息。但我读了很久的Openssl类库源码,也没找到哪里存了这个数据。

取舍

如果说,Hook一个函数的方式实现不了,只能回到前面的hook两个函数的方向上了。但区别是说,仍要保持只hook openssl这一个动态链接库,否则兼容成本太大。 目前有一些思路,比如SSL_set_fd函数等。

int SSL_set_fd(SSL *s, int fd)
int SSL_set_wfd(SSL *s, int fd)
int SSL_set_rfd(SSL *s, int fd)

需要确认的是,每个TCP链接,都必须要在绑定FD时,调用一次SSL_Set_fd,或者SSL_set_wfdSSL_set_rfd等函数,而这个是无法单从openssl的代码能确定的,而是取决于使用openssl类库的程序,可控性就很差。

耐心等待

是的,又到了你看不见工作量的需求上了,又需要博主拼命肝功能了,等我好消息。

知识共享许可协议CFC4N的博客CFC4N 创作,采用 知识共享 署名-非商业性使用-相同方式共享(3.0未本地化版本)许可协议进行许可。基于https://www.cnxct.com上的作品创作。转载请注明转自:eCapture支持流量转发的进展同步