netcat 命令行使用
2012-05-12 15:41:39 阿炯

Netcat 或者叫 nc 是 Unix/Linux 下的一个用于调试和检查网络工具包。可用于创建 TCP/IP 连接,最大的用途就是用来处理 TCP/UDP 套接字。netcat的原理很简单,它就是从网络的一端读入数据,然后输出到网络的另一端,它可以使用tcp和udp协议。之所以叫做netcat,因为它是网络上的cat,想象一下cat的功能,读出一个文件的内容,然后输出到屏幕上(默认的stdout是屏幕,当然可以重定向到其他地方)。netcat也是如此,它读取一端的输入,然后传送到网络的另一端,就这么简单。但是千万不要小看了它,netcat可以完成很多任务,尤其是和其他程序组合时。

Netcat is a featured networking utility which reads and writes data across network connections, using the TCP/IP protocol.

It is designed to be a reliable "back-end" tool that can be used directly or easily driven by other programs and scripts. At the same time, it is a feature-rich network debugging and exploration tool, since it can create almost any kind of connection you would need and has several interesting built-in capabilities.

It provides access to the following main features:
Outbound and inbound connections, TCP or UDP, to or from any ports.

Featured tunneling mode which allows also special tunneling such as UDP to TCP, with the possibility of specifying all network parameters (source port/interface, listening port/interface, and the remote host allowed to connect to the tunnel.

Built-in port-scanning capabilities, with randomizer.

Advanced usage options, such as buffered send-mode (one line every N seconds), and hexdump (to stderr or to a specified file) of trasmitted and received data.

Optional RFC854 telnet codes parser and responder.


The GNU Netcat is distributed freely under the GNU General Public License (GPL).

在网络工具中有“瑞士军刀”美誉的NetCat, 在我们用了N年了至今仍是爱不释手。因为它短小精悍(这个用在它身上很适合,现在有人已经将其修改成大约10K左右,而且功能不减少)。

目前有两种版本的netcat,一个是@stake公司的也就是最初的版本,还有一个是GNU的netcat,更倾向于使用GNU的netcat,因为它的功能更多。

参数简介
这仅是一个1.10版本的简单说明,详细的参数使用还是需要看man手册。

想要连接到某处: nc [-options] hostname port[s] [ports] …
绑定端口等待连接: nc -l -p port [-options] [hostname] [port]

参数:
-g gateway source-routing hop point[s], up to 8
-G num source-routing pointer: 4, 8, 12, …
-h 帮助信息
-i secs 延时的间隔
-l 监听模式,用于入站连接
-n 指定数字的IP地址,不能用hostname
-o file 记录16进制的传输
-p port 本地端口号
-r 任意指定本地及远程端口
-s addr 本地源地址
-u UDP模式
-v 详细输出——用两个-v可得到更详细的内容
-w secs timeout的时间
-z 将输入输出关掉——用于扫描时,其中端口号可以指定一个或者用lo-hi式的指定范围。

使用实例

1. 在服务器-客户端架构上使用 Netcat

netcat 工具可运行于服务器模式,侦听指定端口$ nc -l 12389

然后你可以使用客户端模式来连接到 12389 端口:$ nc otherhost 12389

现在如果你输入一些文本,它将被发送到服务器端:$ nc otherhost 12389
HI, World

在服务器的终端窗口将会显示下面内容:$ nc -l 12389
HI, World

2. 使用 Netcat 来传输文件

netcat 工具还可用来传输文件,在客户端,假设我们有一个 testfile 文件:$ cat testfile
hello world

而在服务器端有一个空文件名为 test

然后我们使用如下命令来启用服务器端:$ nc -l 12389 > test

紧接着运行客户端:    cat testfile | nc otherhost 12389

然后你停止服务器端,你可以查看 test 内容就是刚才客户端传过来的 testfile 文件的内容:$ cat test
hello world

将文件压缩后再传送.如果你的文件很大,何不先压缩它呢,利用管道,我们甚至不用生成压缩后的中间文件。

源主机: tar czf - work|nc -l -c -p 1234

目的主机: nc otherhost 12389|tar xzvf -

3. Netcat 支持超时控制

多数情况我们不希望连接一直保持,那么我们可以使用 -w 参数来指定连接的空闲超时时间,该参数紧接一个数值,代表秒数,如果连接超过指定时间则连接会被终止。

服务器:    nc -l 12389

客户端:$ nc -w 10 otherhost 12389

该连接将在 10 秒后中断。

注意: 不要在服务器端同时使用 -w 和 -l 参数,因为 -w 参数将在服务器端无效果。

4. Netcat 支持 IPv6

netcat 的 -4 和 -6 参数用来指定 IP 地址类型,分别是 IPv4 和 IPv6:

服务器端:$ nc -4 -l 12389

客户端:$ nc -4 otherhost 12389

然后我们可以使用 netstat 命令来查看网络的情况:$ netstat | grep 12389
tcp        0      0 otherhost:12389          otherhost:50851         ESTABLISHED
tcp        0      0 otherhost:50851         otherhost:12389          ESTABLISHED

接下来我们看看IPv6 的情况:
服务器端:$ nc -6 -l 12389

客户端:$ nc -6 otherhost 12389

再次运行 netstat 命令:$ netstat | grep 12389
tcp6       0      0 otherhost:12389          otherhost:33234         ESTABLISHED
tcp6       0      0 otherhost:33234         otherhost:12389          ESTABLISHED

前缀是 tcp6 表示使用的是 IPv6 的地址。

5. 在 Netcat 中禁止从标准输入中读取数据

该功能使用 -d 参数,请看下面例子:
服务器端:$ nc -l 12389

客户端:$ nc -d otherhost 12389
Hi

你输入的 Hi 文本并不会送到服务器端。

6. 强制 Netcat 服务器端保持启动状态

如果连接到服务器的客户端断开连接,那么服务器端也会跟着退出。

服务器端:$ nc -l 12389

客户端:$ nc otherhost 12389
^C

服务器端:$ nc -l 12389
$

上述例子中,但客户端断开时服务器端也立即退出。

我们可以通过 -k 参数来控制让服务器不会因为客户端的断开连接而退出。

服务器端:$ nc -k -l 12389

客户端:$ nc otherhost 12389
^C

服务器端:$ nc -k -l 12389

7. 配置 Netcat 客户端不会因为 EOF 而退出

Netcat 客户端可以通过 -q 参数来控制接收到 EOF 后隔多长时间才退出,该参数的单位是秒:
客户端使用如下方式启动:nc  -q 5  otherhost 12389

现在如果客户端接收到 EOF ,它将等待 5 秒后退出。

8. 使用 Netcat 来处理 UDP 协议

netcat 默认是使用 TCP 协议,但也支持 UDP,可使用 -u 参数来启用 UDP 协议通讯。

服务器端:$ nc -4 -u -l 12389

客户端:$ nc -4 -u otherhost 12389

这样客户端和服务器端都使用了 UDP 协议,可通过 netstat 命令来查看:$ netstat | grep 12389
udp        0      0 otherhost:42634         otherhost:12389          ESTABLISHED

9. 克隆硬盘或分区

操作与上面的拷贝是雷同的,只需要由dd获得硬盘或分区的数据,然后传输即可。
克隆硬盘或分区的操作,不应在已经mount的的系统上进行。所以,需要使用安装光盘引导后,进入拯救模式(或使用工具光盘)启动系统后,在server2上进行类似的监听动作:
# nc -l -p 1234 | dd of=/dev/sda

server1上执行传输,即可完成从server1克隆sda硬盘到server2的任务:
# dd if=/dev/sda | nc server2 12389

10. 端口扫描

可以执行:
nc -v 192.168.16.6 -z 1-1000
pridns.freeoa.net [192.168.16.6] 389 (ldap) open
pridns.freeoa.net [192.168.16.6] 111 (sunrpc) open
pridns.freeoa.net [192.168.16.6] 80 (www) open
pridns.freeoa.net [192.168.16.6] 53 (domain) open
pridns.freeoa.net [192.168.16.6] 22 (ssh) open

11. 保存Web页面

while true; do nc -l -p 80 -q 1 < index.html; done

12. 模拟HTTP Headers

引用
[root@hatest1 ~]# nc www.freeoa.net 80
GET / HTTP/1.1
Host: ispconfig.org
Referrer: 163.com
User-Agent: u-browser

HTTP/1.1 200 OK
......

13. 执行远程命令

在nc命令后,上面部分的内容,然后按两次回车,即可从对方获得HTTP Headers内容。

nc有一个-e的选项,用来指定在连接后执行的程序.在windows平台上可以指定-e cmd.exe.linux则指定-e bash,或者任何你喜欢的shell,或者是你自己编写的程序,通常是做为后门指定-e的效果是由你指定的程序代替了nc自己来接受另一端的输入,并把输入(命令)后反馈的结果显示到另一端.

server: nc -l -p 12389 -e /bin/bash

client: nc otherhost 12389
就可以远程登陆server了,其实我们不一定非要在server端指定-e,也可以在client端指定.

server: nc -l -p 12389
client: nc -e /bin/bash otherhost 12389.这样,就相当于在server上远程登陆client了,有关client和server的区分是没有什么意义的,谁做为telnet server的标准只有一个,谁执行了-e [shell]。


其号称 TCP/IP 的瑞士军刀并非浪得虚名,以体积小(可执行 200KB)功能灵活而著称,在各大发行版中都默认安装,可以用它来做很多网络相关的工作,熟练使用它可以不依靠其他工具做一些很有用的事情。它最初的作者是叫做“霍比特人”的网友 Hobbit hobbit@avian.org 于 1995 年在 UNIX 上以源代码的形式发布,Posix 版本的 netcat 主要有 GNU 和 OpenBSD 版本;两者都可以在 debian/ubuntu 下面安装,但是 Windows 下面只有 GNU 版本的移植。

不管是程序员还是运维,熟悉这个命令都可以让很多工作事半功倍,然而网上有相当的文章说的都是老版本的 OpenBSD 的 netcat,已经没法在主流 linux 上使用了,所以先要检查版本:

在 debian/ubuntu 下面:readlink -f $(which nc)

一般会有两种:
/bin/nc.traditional: 默认 GNU 基础版本,一般系统自带。

/bin/nc.openbsd: openbsd 版本,强大很多。

都可以用 apt-get install nc-traditional 或者 apt-get install nc-openbsd 来选择安装。不管是 GNU 版本还是 OpenBSD 版本,都有新老的区别,主要是传送文件时 stdin 发生 EOF 了,老版本会自动断开,而新的 gnu/openbsd 还会一直连着,多年前 debian jessie 时统一升过级,导致网上的所有教程几乎同时失效。下面主要以最新的 GNU 版本为主同时对照更强大的 openbsd 版本进行说明。

端口测试

在服务器 A主机(172.16.0.2) 上面 8080 端口启动了一个服务,有没有通用的方法检测服务的 TCP 端口是否启动成功?或者在 B 主机上能不能正常访问该端口?

进一步,如果而 A 主机上用 netstat -an 发现端口成功监听了,你在 B 主机上的客户端却无法访问,那么到底是服务错误还是网络无法到达呢?当然可以在 B 主机上用 telnet 探测一下:
telnet 172.16.0.2 8080

但 telnet 并不是专门做这事情的,还需要额外安装,所以在 B 主机上用 netcat:nc -vz 172.16.0.2 8080

即可。v 的意思是显示多点信息(verbose),z 代表不发送数据。那么如果 B 主机连不上 A 主机的 8080 端口,此时就该检查网络和安全设置了,如果连的上那么再去查服务日志去。nc 命令后面的 8080 可以写成一个范围进行扫描:
nc -v -v -w3 -z 172.16.0.2 8080-8083

两次 -v 是让它报告更详细的内容,-w3 是设置扫描超时时间为 3 秒。

传输测试
你在配置 iptable 或者安全组策略,禁止了所有端口,但是仅仅开放了 8080 端口,你想测试一下该设置成功与否怎么测试?安装个 nginx 改下端口,外面再用 chrome 访问下或者 telnet/curl 测试下?其实不用那么麻烦,在需要测试的 A 主机上:nc -l -p 8080

这样就监听了 8080 端口,然后在 B 主机上连接过去:
nc 172.16.0.2 8080

两边就可以会话了,随便输入点什么按回车,另外一边应该会显示出来,注意,openbsd 版本 netcat 用了 -l 以后可以省略 -p 参数,写做:nc -l 8080 ,但在 GNU netcat 下面无法运行,所以既然推荐写法是加上 -p 参数,两个版本都通用。

老版本的 nc 只要 CTRL+D 发送 EOF 就会断开,新版本一律要 CTRL+C 结束,不管是服务端还是客户端只要任意一边断开了,另一端也就结束了,但是 openbsd 版本的 nc 可以加一个 -k 参数让服务端持续工作。

那么就可以先用 nc 监听 8080 端口,再远端检查可用,然后又再次随便监听个 8081 端口,远端检测不可用,说明你的安全策略配置成功了,完全不用安装任何其它的服务。

测试 UDP 会话
两台主机 UDP 数据发送不过去,问题在哪呢?得先确认一下两台主机之间 UDP 可以到达,这时候没有 nginx 给用了,怎么测试呢?于是 netcat 又登场了,在 A 主机上:nc -u -l -p 8080

监听 udp 的 8080 端口,然后 B 主机上连上去:nc -u 172.16.0.2 8080

然后像前面测试 tcp 的方法进行检测,结束了 CTRL+C 退出,看看一边输入消息另外一边能否收到,收得到的话可能是你自己的服务原因,收不到的话把 nc 测试结果扔给运维/系统管理员,让其赶快检查网关和防火墙配置,系统自带的工具测试的结果,既简单又权威。

文件传输
在一台 B 主机上想往 A 主机上发送一个文件怎么办?不能用 scp/szrz 的话可在 A 主机上监听端口:nc -l -p 8080 > image.jpg

然后在 B 主机上:nc 172.16.0.2 8080 < image.jpg

netcat 嘛,就是用于通过网络把东西 cat 过去,注意,老版本 GNU/OpenBSD 的 netcat 再文件结束(标准输入碰到EOF),发送文件一端就会关闭连接,而新版本不会,需要再开个窗口到 A 主机上看看接收下来的文件尺寸和源文件比较一下判断传输是否结束。

当传输完成后,再任意一端 CTRL+C 结束它。对于新版 OpenBSD 的 netcat 有一个 -N 参数,可以指明 stdin 碰到 EOF 就关闭连接(和老版本一致),可写作:/bin/nc.openbsd -N 172.16.0.2 8080 < image.jpg

机器上的 nc 命令有可能指向 /bin/nc.traditional 或者 /bin/nc.openbsd 任意一个,这里显示指明调用 openbsd 版本的 netcat。

这样在 openbsd 新版本的 netcat 中使用 -N 参数,就不需要再开个终端去手工检查传输是否完成,传输结束了就会自动退出。其实 GNU 版本的 netcat 也有可以加个 -q0 参数,达到和 openbsd 版本 -N 的效果:/bin/nc.traditional -q0 172.16.0.2 8080 < image.jpg

只不过是 Linux 下面最新的 GNU netcat,对应 Windows 版本 没有该参数,所以从 Windows 传文件过去时,少不了再开个终端看一下进度,如果是 Linux 端发送就没问题了。通过管道协作,搭配 tar 命令,还可以方便的传一整个目录过去,有兴趣可以自己研究。

使用 netcat 这个系统默认安装的工具进行文件传输,可以算作保底的手段,尤其是 scp/ftp 都没法使用的情况下。

网速吞吐量测试
最简单的方法,GNU 版本的 netcat 加上 -v -v 参数后,结束时会统计接收和发送多少字节,那么此时 A 主机上显示运行 GNU 版本的 nc 监听端口:
/bin/nc.traditional -v -v -n -l -p 8080 > /dev/null

加 n 的意思是不要解析域名,避免解析域名浪费时间造成统计误差,然后 B 主机上:
time nc -n 172.16.0.2 8080 < /dev/zero

回车后执行十秒钟按 CTRL+C 结束,然后在 A 主机那里就可以看到接收了多少字节了,此时根据 time 的时间自己做一下除法即可得知,注意 GNU 的 netcat 统计的数值是 32 位 int,如果传输太多就回环溢出成负数了。

对于 OpenBSD 版本的 nc 可以用管道搭配 dd 命令进行统计,服务端运行:
nc -l -p 8080 > /dev/null

客户端运行 dd 搭配 nc:
dd if=/dev/zero bs=1MB count=100 | /bin/nc.openbsd -n -N 172.16.0.2 8080

结束以后会有结果出来,注意这里使用了 -N 代表 stdin 碰到 EOF 后就关闭连接,这里凡是写 nc 命令的地方,代表 GNU/OpenBSD 任意版本的 netcat 都可以,显示的指明路径,就代表必须使用特定版本的 netcat,上条命令等效的 GNU 版本是:
dd if=/dev/zero bs=1MB count=100 | /bin/nc.traditional -n -q0 172.16.0.2 8080

其实上面两种方法都把建立连接的握手时间以及 TCP 窗口慢启动的时间给计算进去了,不是特别精确,最精确的方式是搭配 pv 命令(监控统计管道数据的速度),在 A 主机运行:nc -l -p 8080 | pv

然后再 B 主机运行:nc 172.16.0.2 8080 < /dev/zero

此时 A 主机那端持续收到 B 主机发送过来的数据并通过管道投递给 pv 命令后,就能看到实时的带宽统计了,下为pv输出的一个实时状态:
153MiB 0:00:17 [22.8MiB/s] [          <=>  ]

可让人看到最新的带宽吞吐量,这是最准确的吞吐量测试方法,在不需要 iperf 的情况下,直接使用 nc 就能得到一个准确的数据。

系统后门
假设用串口登录到 A 主机,上面十分原始,包管理系统都没有,sshd/telnetd 都跑不起来,这时候想用 B 主机通过网络登录 A 主机有没有办法?

GNU 版本的 netcat 有一个 -e 参数,可以在连接建立的时候执行一个程序,并把它的标准输入输出重定向到网络连接上来,于是可以在 A 主机上 -e 一个 bash:/bin/nc.traditional -l -p 8080 -e /bin/bash

按回车打开系统后门,然后再 B 主机那里照常:
nc 172.16.0.2 8080

就可以在 B 主机上登录 A 主机的 shell 了,操作完成 CTRL+C 结束。

对于 openbsd 版本的 netcat的-e 参数被删除了,没关系可以用管道来完成,和刚才一样,在 A 主机上:
mkfifo /tmp/f
cat /tmp/f | /bin/bash 2>&1 | /bin/nc.openbsd -l -p 8080 > /tmp/f

然后 B 主机和刚才一样:nc 172.16.0.2 8080

即可访问,用完注意将 /tmp/f 这个 fifo 文件删除。

小结
netcat 就是可以在命令行直接的方式操作 tcp/udp 进行原始的:监听,连接,数据传输等工作。然后搭配管道,实现灵活多样的功能,或者进行各种网络测试。其实上面几个例子,并不是说明 “netcat 可以干这些事情”而是通过举例来看看搭配管道的 netcat 究竟有多强。

还有很多其他用法,比如可以用 netcat + shell script 写一个 http 服务器,使用 fifo 搭配两层 nc 可以实现 tcp 端口转发,搭配 openssl 命令行工具和 nc 加管道可以把 ssl 的套接字解码并映射成裸的 socket 端口供没有 ssl 功能的工具访问。

当然有人要说这么多复杂的用法记不住,大部分都可以用专业软件来代替,那至少可以先尝试使用 nc 来做 tcp/udp 端口测试,不要再用 telnet/chrome 来测试端口是否可用了,后者太过业余。其他功能可作为备份手段,在条件恶劣的环境下使用一下,也许能有所帮助;搭配管道与其他工具可进行一些高阶操作就行。


参考URL:
http://netcat.sourceforge.net/

http://nc110.sourceforge.net/