{"id":19300799,"url":"https://github.com/jiguangsdf/netcat","last_synced_at":"2025-04-22T10:32:04.572Z","repository":{"id":59144779,"uuid":"247780836","full_name":"jiguangsdf/netcat","owner":"jiguangsdf","description":"netcat by golang - Netcat网络工具Golang实现","archived":false,"fork":false,"pushed_at":"2022-08-04T11:21:24.000Z","size":9428,"stargazers_count":68,"open_issues_count":1,"forks_count":15,"subscribers_count":3,"default_branch":"master","last_synced_at":"2024-06-20T17:53:52.076Z","etag":null,"topics":["golang","netcat"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/jiguangsdf.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2020-03-16T17:45:31.000Z","updated_at":"2024-05-30T07:05:12.000Z","dependencies_parsed_at":"2022-09-13T02:12:50.095Z","dependency_job_id":null,"html_url":"https://github.com/jiguangsdf/netcat","commit_stats":null,"previous_names":["jiguangin/netcat","jiguangrst/netcat"],"tags_count":2,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jiguangsdf%2Fnetcat","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jiguangsdf%2Fnetcat/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jiguangsdf%2Fnetcat/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jiguangsdf%2Fnetcat/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jiguangsdf","download_url":"https://codeload.github.com/jiguangsdf/netcat/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":223892991,"owners_count":17220834,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["golang","netcat"],"created_at":"2024-11-09T23:15:51.550Z","updated_at":"2024-11-09T23:15:51.610Z","avatar_url":"https://github.com/jiguangsdf.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"### Netcat介绍\n\n`Netcat` 号称 TCP/IP 的瑞士军刀并非浪得虚名，以体积小（可执行 200KB）功能灵活而著称，在各大发行版中都默认安装，你可以用它来做很多网络相关的工作，熟练使用它可以不依靠其他工具做一些很有用的事情。\n\n最初作者是叫做“霍比特人”的网友 Hobbit \u003chobbit@avian.org\u003e 于 1995 年在 UNIX 上以源代码的形式发布，Posix 版本的 netcat 主要有 GNU 版本的 netcat 和 OpenBSD 的 netcat 两者都可以在 debian/ubuntu 下面安装，但是 Windows 下面只有 GNU 版本的 port。\n\n### 在Go中创建Netcat应用\n\n`Netcat`在安全测试尤其是渗透测试过程中经常用到，比如在内网中需要上传下载文件，命令执行等功能都可能用到。\n基于Go语言内置的`net`库编写`netcat`应用，需要实现的功能点有：\n\n- 发起TCP/UDP连接\n- 监听TCP端口\n- 监听UDP端口\n- 处理标准输入输出流\n- 命令执行功能\n- 字符编码转换[windows命令执行结果因为GBK编码问题可能会出现乱码]\n\n#### 发起TCP/UDP连接\n\n使用标准库的`net.Dial`方法根据传入参数发起一个`TCP/UDP`连接请求：\n\n```\n//@param [string] [host] - 连接对方主机的IP地址\n//@param [int] [port] - 连接对方的主机的端口\n//@param [net.Conn] [conn] - 根据建立的conn连接管道，就可以向对方发送数据与接受对方数据，\n//比如文件传输，文件下载，命令反弹，标准输入/输出流传送等\ndailAddr := net.JoinHostPort(host, strconv.Itoa(port))\nconn, err := net.Dial(network, dailAddr)\nif err != nil {\n    logf(\"Dail failed: %s\", err)\n    return\n}\nlogf(\"Dialed host: %s://%s\",network, dailAddr)\ndefer func(c net.Conn){\n    logf(\"Closed: %s\", dailAddr)\n\tc.Close()\n}(conn)\n```\n\n#### 监听TCP/UDP端口\n然后使用标准库的`net.Listen`方法根据传入参数监听`TCP/UDP`端口：\n\n```\n//@param [string] [host] - 连接对方主机的IP地址\n//@param [int] [port] - 连接对方的主机的端口\n//@param [net.Conn] [conn] - 根据建立的conn连接管道，就可以向对方发送数据与接受对方数据，\n//比如文件传输，文件下载，命令反弹，标准输入/输出流传送等\nlistenAddr := net.JoinHostPort(host, strconv.Itoa(port))\nlistener, err := net.Listen(network, listenAddr)\nlogf(\"Listening on: %s://%s\",network, listenAddr)\nif err != nil {\n\tlogf(\"Listen failed: %s\", err)\n\treturn\n}\nconn, err := listener.Accept()\nif err != nil {\n\tlogf(\"Accept failed: %s\", err)\n\treturn\n}\n```\n\n#### 处理标准输入输出流\n\n标准输入输出流在传输文件，命令执行过程中均会涉及到，可以使用标准库`fmt.Fprintf`, `io.Copy`两个函数处理，它们的函数签名如下：\n\n```\n// io.Copy可以用在把TCP/UDP连接传输的数据流写入文件，或者定位到标准输出[os.Stdout]中，其中参数为两个接口，可以使用go doc io.Writer/io.Reader查看，只要实现\n// Writer, Read两个方法就可以\nfunc Copy(dst Writer, src Reader) (written int64, err error)\n\nio.Copy(os.Stdout, conn)\nio.Copy(conn, os.Stdin)\n\n// fmt.Fprintf可以用在\nfunc Fprintf(w io.Writer, format string, a ...interface{}) (n int, err error)\n\nfmt.Fprintf(os.Stdout, string(buf))\n```\n\n#### 命令执行功能\n\n命令执行功能根据`runtime.GOOS`选择相应的平台，然后使用内置库`exec.Command`实现命令执行\n\n```\nswitch runtime.GOOS {\ncase \"linux\":\n    shell = \"/bin/sh\"\ncase \"freebsd\":\n    shell = \"/bin/csh\"\ncase \"windows\":\n\tshell = \"cmd.exe\"\ndefault:\n    shell = \"/bin/sh\"\n}\ncmd := exec.Command(shell)\nconvert := newConvert(conn)\ncmd.Stdin  = convert\ncmd.Stdout = convert\ncmd.Stderr = convert\ncmd.Run()\n```\n\n命令执行的结果可以直接输入到发起连接到`TCP/UDP`流中,也就是连接到`conn`中，具体为什么能这样?,可以看看`go doc exec.Command` 返回的结构体类型为`*exec.Cmd`,通过查看，该结构体的`Stdin`, `Stdout`, `Stderr`,类型分别为`io.Reader`, `io.Writer`，刚好`conn net.Conn`实现了这两个接口的函数签名，所以命令执行的结果就可以直接进去`TCP/UDP`连接流\n\n```\ntype Cmd struct {\n\t\n\t......\n\n\tStdin io.Reader\n\n\t// Stdout and Stderr specify the process's standard output and error.\n\t//\n\t// If either is nil, Run connects the corresponding file descriptor\n\t// to the null device (os.DevNull).\n\t//\n\t// If either is an *os.File, the corresponding output from the process\n\t// is connected directly to that file.\n\t//\n\t// Otherwise, during the execution of the command a separate goroutine\n\t// reads from the process over a pipe and delivers that data to the\n\t// corresponding Writer. In this case, Wait does not complete until the\n\t// goroutine reaches EOF or encounters an error.\n\t//\n\t// If Stdout and Stderr are the same writer, and have a type that can\n\t// be compared with ==, at most one goroutine at a time will call Write.\n\tStdout io.Writer\n\tStderr io.Writer\n\n\t......\n}\n```\n\n\n\n#### 字符编码转换\n\n涉及到windows命令执行结果时，因为windows自身编码问题和Go语言的标准编码`UTF-8`存在差异，所以在windows下执行的结果可能会乱码，这里可以使用第三方库`github.com/axgle/mahonia`进行编码转换，需要注意的是,由于需要在命令执行结果中实时实现编码转换，所以需要重写`conn`连接流，方法很简单，只要实现了`io.Reader`, `io.Writer`两个接口的函数签名，然后就可以直接赋值给命令执行流：`cmd.Stdin`, `cmd.Stdout`,`cmd.Stderr`\n\n```\ncmd := exec.Command(shell)\nconvert := newConvert(conn)\ncmd.Stdin  = convert\ncmd.Stdout = convert\ncmd.Stderr = convert\ncmd.Run()\n```\n\n具体实现方法如下：\n\n```\ntype Convert struct {\n\tconn net.Conn\n}\n\nfunc newConvert(c net.Conn) *Convert {\n\tconvert := new(Convert)\n\tconvert.conn = c\n\treturn convert\n}\n\nfunc (convert *Convert) translate(p []byte, encoding string) []byte {\n\tsrcDecoder := mahonia.NewDecoder(encoding)\n\t_, resBytes, _ := srcDecoder.Translate(p, true)\n\treturn resBytes\n}\n\nfunc (convert *Convert) Write(p []byte) (n int, err error) {\n\tswitch runtime.GOOS {\n\tcase \"windows\":\n\t\tresBytes := convert.translate(p, \"gbk\")\n\t\tm, err := convert.conn.Write(resBytes)\n\t\tif m != len(resBytes) {\n\t\t\treturn m, err\n\t\t}\n\t\treturn len(p), err\n\tdefault:\n\t\treturn convert.conn.Write(p)\n\t}\n}\n\nfunc (convert *Convert) Read(p []byte) (n int, err error) {\n\t// m, err := convert.conn.Read(p)\n\t// switch runtime.GOOS {\n\t// case \"windows\":\n\t// \tp = convert.Translate(p[:m], \"utf-8\")\n\t// \treturn len(p), err\n\t// default:\n\t// \treturn m, err\n\t// }\n\treturn convert.conn.Read(p)\n}\n```\n\n### 应用\n\n经过以上几步，大致实现了`Netcat`应用的骨架。下面可以进行应用测试。\n\n#### 命令执行\n\nnetcat最重要的一个功能就是提供命令执行功能，这在渗透测试过程中经常用到，具体分为`正向Shell`:目标服务器具备外网IP, 可以直接连接进行命令执行, `反向Shell`:目标服务器在内网中，需要反向连接vps控制台服务器\n\n- 正向命令执行\n\n![](images/p1@2x.png)\n\n- 反向命令执行\n\n![](images/p2@2x.png)\n\n- 文件传输\n\n![](images/p3@2x.png)\n\n- 标准输入输出\n\n![](images/p4@2x.png)\n\n#### web静态服务器\n\n使用netacat轻松实现index目录索引，在实际环境用可以用作下载和上传资源使用\n\n![](images/p5.png)\n\n### 总结\n\n本文使用`Golang`语言实现了简单的`Netcat`功能，文章提及了接口的实现，如：自定义结构体方法用于命令执行结果编码实时转换，以及`io.Copy`等方法的参数查看与具体使用。完整的代码：[netcat - github.com](https://github.com/jiguangsdf/netcat)","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjiguangsdf%2Fnetcat","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjiguangsdf%2Fnetcat","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjiguangsdf%2Fnetcat/lists"}