使用 Bash 编写的 TCP 端口扫描器

红薯 发布于 2012/08/28 23:25
阅读 7K+
收藏 109

我突然有一个用 Bash 来编写 TCP 端口扫描器的想法。Bash 支持可读写的特殊文件 /dev/tcp/host/port ,往这个文件写内容可以让 bash 打开一个 TCP 连接到 host:port ,如果写文件成功则表示此端口是打开的,否则说明该端口没有打开。

因此我们先简单的写一个测试脚本:

for port in {1..65535}; do
  echo >/dev/tcp/google.com/$port &&
    echo "port $port is open" ||
    echo "port $port is closed"
done

该脚本将扫描 google.com 服务器端口,从 1 到 65535。当然,如果端口没打开的话是没法工作的,bash 花了 2 分钟时间意识到这点。

为了解决这个问题我们需要一些类似 alarm(2) 的方法来中断 bash,而 bash 没有内置的 alarm 函数,因此我们用 Perl 语言写了一个:

alarm() {
  perl -e '
    eval {
      $SIG{ALRM} = sub { die };
      alarm shift;
      system(@ARGV);
    };
    if ($@) { exit 1 }
  ' "$@";
}

这个 alarm 函数需要两个参数:alarm 调用的秒数和要执行的代码,如果执行的代码没有在指定的时间内执行完毕则该函数调用失败。

有了这个 alarm 函数,我们就可以修改上面的代码如下:

for port in {1..65535}; do
  alarm 1 "echo >/dev/tcp/google.com/$port &&
    echo \"port $port is open\"" ||
    echo "port $port is closed"
done

这个终于可以运行了,当扫描到某个端口是关闭的, bash 将在 1 秒后执行下一个端口的扫描。

然后我们将这些代码封装到一个 scan 函数中:

scan() {
  if [[ -z $1 || -z $2 ]]; then
    echo "Usage: $0 <host> <port, ports, or port-range>"
    return
  fi

  local host=$1
  local ports=()
  case $2 in
    *-*)
      IFS=- read start end <<< "$2"
      for ((port=start; port <= end; port++)); do
        ports+=($port)
      done
      ;;
    *,*)
      IFS=, read -ra ports <<< "$2"
      ;;
    *)
      ports+=($2)
      ;;
  esac


  for port in "${ports[@]}"; do
    alarm 1 "echo >/dev/tcp/$host/$port &&
      echo \"port $port is open\"" ||
      echo "port $port is closed"
  done
}

这样就可以在 shell 中使用 scan 函数,需要的参数包括要扫描的主机地址、端口列表(可以时端口组合和端口范围,或者是某个特定端口)

下面是扫描 google.com 服务器的 78 - 82 端口:

$ scan google.com 78-82 
port 78 is closed
port 79 is closed
port 80 is open
port 81 is closed
port 82 is closed

如果你想测试 UDP 端口,只需要将前面提及的 /dev/tcp 改为 /dev/udp/

最后:大家手下留情,看在我辛苦翻译下,不要用它来扫描 oschina 的服务器。

英文原文OSCHINA原创翻译

加载中
0
Jason阿坚
Jason阿坚
沙发,好文
0
天国之翼
天国之翼
(for (port (int ($main-args 3)) (int ($main-args 4))) (println port (if (net-connect ($main-args 2) port 10) " Open" "")))  
>newlisp scan.lsp localhost 1 4200

result:
.
134
135 Open
136
.
;;工整点?

(set 'host ($main-args 2))
(set 'start-port ($main-args 3))
(set 'end-port ($main-args 4))
(for (port (int start-port) (int end-port))
    (if (net-connect host port 10)
        (println port " Open")
        (println port "")
)
)

0
蟋蟀哥哥
蟋蟀哥哥
nmap多快多方便嘛
0
皮总
皮总
我用nmap来扫描
蟋蟀哥哥
蟋蟀哥哥
我这还有款压力测试工具,需要不.
0
fei
fei
有nmap还需要这个?
0
麦田小圈圈
麦田小圈圈

引用来自“fei”的答案

有nmap还需要这个?

你确定每个Linux上都有nmap,你确定每个Linux上都可以装nmap

 

麦田小圈圈
麦田小圈圈
@红薯 good job
红薯
红薯
主要是提供另外一种思路,也挺有意思:)
0
SeanWright
SeanWright

好文!还是用了perl

0
化境
化境
看大伙分享的代码,最感兴趣的是其实现的思路。
0
Brooks
Brooks

一直很期待看到shell下直接操作端口的方法,这篇文章终于接近了这个目标,非常好的方法。

 

不知道在shell下,是否可以直接将数据写到端口,完成端口通讯?有谁做过这样的尝试吗

OSCHINA
登录后可查看更多优质内容
返回顶部
顶部