Frp实现网络的内外穿透

[TOC]

在没有Frp穿透开源出来的时候,链接远程网络通常是采用向日葵或者TeamViewer,并且在做渗透测试的时候面对的目标常常是处于内网之中;在以往的渗透中拿到了服务器权限后,个人最常使用的内网代理方式是 reGeorg + Proxifier/proxychains,虽然是脚本代理的方式,但使用快捷方便,能够迅速访问到内部网;但是但是随着目标内网环境越来越大,这种脚本形式代理的局限性越来越明显;

描述:frp 是一个可用于内网穿透的高性能的反向代理应用(采用Go语言进行开发),支持 tcp, udp ,stcp协议,为 http 和 https 应用协议提供了额外的能力,且尝试性支持了点对点穿透;

应用场景:满足通过公网服务器访问处于内网的服务,如访问内网web服务,远程ssh内网服务器,远程控制内网NAS,流量转发等,实现类似花生壳、ngrok等功能;

Frp工具有两端CS架构:

  • 服务端:服务端部署在我们具有公网IP的服务器上;
  • 客户端:客户端放在我们内网的服务器上;

WeiyiGeek.20191230222637188

注意事项:

  • Windows与Linux启动Frps/c的不同的是,Windows默认启动frps的配置文件绑定的端口是7000,而frpc默认启动的配置文件是frpc.ini;

基础命令:

描述:首先最简单常用的就是socks协议代理这一功能在 frp 中是以插件的形式实现的;

描述:frp 也同时能够对 UDP 协议进行转发,配置上与 tcp 也是差不多的,基本上就是端口转发(没难度),对于UDP协议的测试我们使用比较常见的SNMP协议和DNS协议来测试; 思路:

  • 在做渗透测试的时候有时候会遇到打印机以及其它采用snmp通讯的设备,我们可以通过 snmp 协议和 惠普的 pjl 来获得敏感信息,通过 frp 隧道对公司内网打印机 10.10.65.9 进行攻击,使用的是打印机攻击框架 PRET 简单的打印一个文档;
  • 得到一台内网机器的权限后,通过扫描53端口或者其它手段找到内网的DNS服务器,接下来我们将DNS解析到指定内网服务器上,因此我们就可以通过域名访问内网服务器,也可以指定 DNS 服务器进行子域名爆破来发现更多的资产;首先对内目标网段的 53 端口进行扫描探测,扫描端口使用 TCP 协议就可以,所以先使用原先的代理扫描,

WeiyiGeek.

描述:安全地暴露内网服务(secret tcp)以及 xtcp 都是frp提供的点对点传输服务;

xtcp:用于应对在希望传输大量数据且流量不经过服务器的场景,直接是一个 p2p 的隧道,frp 所谓的 xtcp 协议底层应该是 UDP 打洞的过程;

  • 根据官方文档这种协议不能穿透所有类型的 NAT 设备,所以穿透成功率较低,穿透失败时可以尝试 stcp 的方式

stcp:相当于再添加一次认证,改一次配置文件即可

流程说明:

  • 甲 <-> 公 <-> 乙 :记录客户端甲和乙的 IP 和端口信息,但是IP和端口并非甲和乙在内网的IP(外网)和随机端口,而是通过NAT方式映射到路由器上的IP和端口。
  • 客户端甲向服务器发送udp消息,请求和客户端乙通信。
  • 服务器向客户端甲发送消息,消息内容包含客户端乙的IP和端口信息。
  • 服务器向客户端乙发送消息,消息内容包含客户端甲的IP和端口信息。
  • 客户端甲根据3步骤获得的信息向客户端乙发送udp消息,同一时刻客户端乙根据3步骤获得的信息向客户端甲发送udp消息(尝试多次udp打洞就能成功)

注意事项:

  • 该打洞方案只支持 ConeNAT(锥形 NAT),不支持 Symmetric NAT (对称NAT)因此没办法能够支持全部的 NAT方式,更何况,你知道你在访问公网的时候中间经过了多少层 NAT 吗?

描述:在内网拿到了多台能够访问互联网机器,可以启用多台客户端进行负载均衡,毕竟突然从一台机器迸发出大量流量很容易引起管理员的注意,也可以负载分担一下机器的CPU资源消耗;

比如:使用两台被入侵的服务器作为负载均衡,IP分别为 10.10.99.33 和 10.10.100.81

WeiyiGeek.负载均衡Group

  • 转发 Unix 域套接字:单个主机通信协议一般用不上
  • 对外提供文件访问服务:这估计是渗透测试工程师最不需要的功能
  • http转https:没用
  • 加密与压缩:这两个功能可以看到我都启用了
  • TLS加密:这个我也开了,安全性更高
  • 客户端UI/热加载配置/查看状态:普通情况下是可以不用的,但是前期资产发现过程需要多次配置的情况,或者上线新机器做负载均衡的时候可以使用,不过热加载还是需要等一段时间才能够生效,性子急的我表示等不了
  • 端口白名单:这里我指定了 40000-50000
  • web相关的:很多功能是为了将内网web转至公网
  • 通过代理连接 frps:在特殊情况下可能是有用的,但是暂时没用
  • 范围端口映射:这个貌似也没什么用
  • 子域名:在找到内网DNS解析服务器的情况下可以不进行配置,如果没找到,但是知道内网 IP 和域名的对应关系,且服务器只可以通过域名访问的情况下可以使用这项配置,但我觉得都不如绑个host来的快
  • KCP协议:KCP是一个快速可靠协议,能以比 TCP浪费10%-20%的带宽的代价,换取平均延迟降低 30%-40%,且最大延迟降低三倍的传输效果,在带宽很足但延迟较高的情况下可以使用 kcp 协议进行数据通信,未测试

描述:主要正对于Frps服务端和客户端进行配置文件的说明;

# [common] 是必需的 [common] # ipv6的文本地址或主机名必须括在方括号中 # 如"[::1]:80", "[ipv6-host]:http" 或 "[ipv6-host%zone]:80" server_addr = 0.0.0.0 server_port = 7000 # 认证 token token = 12345678 # 如果 tls_enable 为 true, frpc 将会通过 tls 连接 frps tls_enable = true # 用于连接到服务器的通信协议,目前支持 tcp/kcp/websocket, 默认 tcp protocol = tcp # 将提前建立连接,默认值为 0 pool_count = 5 # 是否使用 tcp 流多路复用,默认值为 true,必需与服务端相同 tcp_mux = true # 决定第一次登录失败时是否退出程序,否则继续重新登录到 frps默认为 true login_fail_exit = true # 控制台或真实日志文件路径,如./frps.log log_file = ./frpc.log # 日志级别,分为trace(跟踪)、debug(调试)、info(信息)、warn(警告)、error(错误) log_level = info # 最大日志记录天数 log_max_days = 3 # 设置能够通过 http api 控制客户端操作的管理地址 # admin_addr = 127.0.0.1 # admin_port = 7400 # admin_user = admin # admin_pwd = admin # 心跳配置, 不建议对默认值进行修改 # heartbeat_interval 默认为 10 heartbeat_timeout 默认为 90 # heartbeat_interval = 30 # heartbeat_timeout = 90 # 代理名, 使用 ',' 分隔 默认为空, 表示全部代理 # start = ssh,dns # 在此处设置用户名后,代理名称将设置为 {用户名}.{代理名} # user = your_name # 如果要通过 http 代理或 socks5 代理连接 frps,可以在此处或全局代理中设置 http_proxy 只支持 tcp协议 # http_proxy = http://user:passwd@192.168.1.128:8080 # http_proxy = socks5://user:passwd@192.168.1.128:1080 # 指定 DNS 服务器 # dns_server = 8.8.8.8 # 'ssh' 是一个特殊代理名称 [ssh] # 协议 tcp | udp | http | https | stcp | xtcp, 默认 tcp type = tcp local_ip = 127.0.0.1 local_port = 22 # 是否加密, 默认为 false use_encryption = false # 是否压缩 use_compression = false # 服务端端口 remote_port = 6001 # frps 将为同一组中的代理进行负载平衡连接 group = test_group # 组应该有相同的组密钥 group_key = 123456 # 为后端服务开启健康检查, 目前支持 'tcp' 和 'http' # frpc 将连接本地服务的端口以检测其健康状态 health_check_type = tcp # 健康检查连接超时 health_check_timeout_s = 3 # 连续 3 次失败, 代理将会从服务端中被移除 health_check_max_failed = 3 # 健康检查时间间隔 health_check_interval_s = 10 [ssh_random] type = tcp local_ip = 127.0.0.1 local_port = 22 # 如果 remote_port 为 0 ,frps 将为您分配一个随机端口,设置为其它端口则是frps服务器地址:2222 remote_port = 2222 # 如果要暴露多个端口, 在区块名称前添加 'range:' 前缀 # frpc 将会生成多个代理,如 'tcp_port_6010', 'tcp_port_6011' [range:tcp_port] type = tcp local_ip = 127.0.0.1 local_port = 6010-6020,6022,6024-6028 remote_port = 6010-6020,6022,6024-6028 use_encryption = false use_compression = false [dns] type = udp local_ip = 114.114.114.114 local_port = 53 remote_port = 6002 use_encryption = false use_compression = false [range:udp_port] type = udp local_ip = 127.0.0.1 local_port = 6010-6020 remote_port = 6010-6020 use_encryption = false use_compression = false # 将域名解析到 [server_addr] 可以使用 http://web01.yourdomain.com 访问 web01 [web01] type = http local_ip = 127.0.0.1 local_port = 80 use_encryption = false use_compression = true # http 协议认证 http_user = admin http_pwd = admin # 如果服务端域名为 frps.com, 可以通过 http://test.frps.com 来访问 [web01] subdomain = web01 custom_domains = web02.yourdomain.com # locations 仅可用于HTTP类型 locations = /,/pic host_header_rewrite = example.com # params with prefix "header_" will be used to update http request headers header_X-From-Where = frp health_check_type = http # frpc 将会发送一个 GET http 请求 '/status' 来定位http服务 # http 服务返回 2xx 状态码时即为存活 health_check_url = /status health_check_interval_s = 10 health_check_max_failed = 3 health_check_timeout_s = 3 [web02] type = https local_ip = 127.0.0.1 local_port = 8000 use_encryption = false use_compression = false subdomain = web01 custom_domains = web02.yourdomain.com # v1 或 v2 或 空 proxy_protocol_version = v2 #插件掩饰 [plugin_unix_domain_socket] type = tcp remote_port = 6003 plugin = unix_domain_socket plugin_unix_path = /var/run/docker.sock [plugin_http_proxy] type = tcp remote_port = 6004 plugin = http_proxy plugin_http_user = abc plugin_http_passwd = abc [plugin_socks5] type = tcp remote_port = 6005 plugin = socks5 plugin_user = abc plugin_passwd = abc [plugin_static_file] type = tcp remote_port = 6006 plugin = static_file plugin_local_path = /var/www/blog plugin_strip_prefix = static plugin_http_user = abc plugin_http_passwd = abc [plugin_https2http] type = https custom_domains = test.yourdomain.com plugin = https2http plugin_local_addr = 127.0.0.1:80 plugin_crt_path = ./server.crt plugin_key_path = ./server.key plugin_host_header_rewrite = 127.0.0.1 [secret_tcp] # 如果类型为 secret tcp, remote_port 将失效 type = stcp # sk 用来进行访客认证 sk = abcdefg local_ip = 127.0.0.1 local_port = 22 use_encryption = false use_compression = false # 访客端及服务端的用户名应该相同 (frpc的角色访客) [secret_tcp_visitor] # frpc role visitor -> frps -> frpc role server role = visitor type = stcp # 要访问的服务器名称 server_name = secret_tcp sk = abcdefg # 将此地址连接到访客 stcp 服务器 bind_addr = 127.0.0.1 bind_port = 9000 use_encryption = false use_compression = false [p2p_tcp] type = xtcp sk = abcdefg local_ip = 127.0.0.1 local_port = 22 use_encryption = false use_compression = false [p2p_tcp_visitor] role = visitor type = xtcp server_name = p2p_tcp sk = abcdefg bind_addr = 127.0.0.1 bind_port = 9001 use_encryption = false use_compression = false

描述:我们为了不每次重启机器后都需要手动的进行打开frp服务或者说客户端,我们需要将其作为服务进行运行,主要针对于Windows和Linux进行操作;

  • Linux 后台运行方式 方式1:后台运行启动(加入到/etc/init.d/中即可)

方式2:服务启动方式(可以使用systemctl的方式管理frps)

方式3:使用supervisor来控制

Windows服务自启动 方式1:bat方式放入Windows启动目录

方式2:服务启动项(将bat打包或者直接利用其它编程语言调用)

方式3:计划任务在系统启动时(登录前)运行frpc

描述:Frp可以很好的与Cobalt Strike和MSF联合使用,进行后渗透测试;

CS 持续维权

MSF方式: 当“专属通道”打通后,可直接在msf中挂该代理。因为msf的模块较多,所以在内网横向移动中更是一把利器若socks5设置口令,可结合proxychains

其它Proxy全局流量代理软件结合实用(shadowsocks/Proxifier/proxychains(Kail))

Proxifier 全局流量转发软件(需要进注册使用)

总体思路: 一个中心三个辅助,CS总控中心, frp 作为数据通信隧道, ,proxychains 代理服务,msf/NMAP进行扫描攻击获取 session 后再转给 CS;

描述:Frp与reGeorg之间的比较说明;

  • 利用难度:前者需要获取机器执行命令的权限,后者需要上传专用的Shell到网站中(常用)
  • 利用环境: 前者要求入侵服务器能够访问外部网络以及需要一台公网IP的服务器运行服务端,后者不需要就如同正反向 shell 的差别
  • 功能对比: 前者提供提供繁多功能,后者代理访问内网但是相比弱爆了;
  • 性能对比: 从 frp 支持负载均衡和点对点传输上简直完爆其他内网穿透工具;

原文链接:https://cloud.tencent.com/developer/article/2129494

© 版权声明
THE END
喜欢就支持一下吧
点赞11 分享