跳转到主内容
新派编程网 - 新潮编程理念,全新技术课堂!

如何在Golang中实现一个反向Shell工具 Go语言网络安全攻防演示

反向Shell在Go中无法直接用os/exec.Command起交互式shell,因默认不分配PTY导致shell降级为非交互模式;需手动抢PTY或原生实现shell语义,并配置TCP Keepalive、禁用命令缓冲、适配Windows控制台环境。 反向Shell在Go里为什么不能直接用
os/exec.Command
起交互式shell 因为
os/exec.Command
默认不分配伪终端(PTY),目标机上跑
/bin/sh
或
/bin/bash
时,会降级成非交互模式:没有命令历史、
Ctrl+C
不生效、
sudo
提示符卡住、
vim
等全屏程序直接崩溃。这不是Go的问题,是Unix进程模型决定的——没PTY,shell就拒绝给你“交互权”。 实操建议: 立即学习 “ go语言免费学习笔记(深入) ”; 别硬塞
os/exec.Command("bash", "-i")
,它根本不会真交互 真正可行的路径只有两条:用
syscall.Syscall
调
setsid
+
ioctl(TIOCSCTTY)
手动抢PTY(Linux/macOS可行但跨平台麻烦) 更稳的选择是绕过本地shell,用Go原生实现基础shell语义:读命令 → 执行 → 捕获stdout/stderr → 写回,靠
os/exec.CommandContext
控制生命周期 如何用
net.Conn
稳定维持反向连接不被NAT/防火墙断开 常见错误现象:
read tcp 192.168.x.x:port: i/o timeout
或连接几秒后静默断开。本质是中间网络设备(家用路由器、云厂商SLB)对空闲TCP连接做了超时回收,不是你的代码bug。 实操建议: 立即学习 “ go语言免费学习笔记(深入) ”; 服务端(攻击者机器)必须开启TCP Keepalive:
conn.SetKeepAlive(true)
+
conn.SetKeepAlivePeriod(30 * time.Second)
客户端(被控机)发心跳包比依赖系统keepalive更可靠:每25秒发一个
\n
或
echo -n "."
结果,避免被当成死连接 别用
http.Get
之类封装层——它们默认关闭底层TCP keepalive,且HTTP/1.1长连接在代理环境下行为不可控 如果走TLS(比如
tls.Dial
),记得调
conn.(*tls.Conn).SetKeepAlive
,否则TLS层会屏蔽底层keepalive信号
io.Copy
双向转发时为什么命令输出延迟严重甚至卡死 典型表现:输入
ls
后要等3–5秒才看到结果,或者
cat /etc/passwd
只显示前半截。根本原因是
os/exec.Cmd.Stdout
和
Stderr
默认是带缓冲的管道,而很多命令(如
ls
)在stdout不是tty时自动启用全缓冲,导致输出滞留在内核pipe buffer里出不来。 go语言参考手册 中文CHM版 Go 是一个开源的编程语言,它能让构造简单、可靠且高效的软件变得容易。本文给大家带来Go参考手册,需要的可以来下载! Go是从2007年末由Robert Griesemer, Rob Pike, Ken Thompson主持开发,后来还加入了Ian Lance Taylor, Russ Cox等人,并最终于2009年11月开源,在2012年早些时候发布了Go 1稳定版本。现在Go的开发已经是完全开放的,并且拥有一个活跃的社区。 Go 语言特色 简洁、快速、安全 并行、有趣、开源 内存管理、v数组安全、编译 下载 实操建议: 立即学习 “ go语言免费学习笔记(深入) ”; 强制命令行工具禁用缓冲:
stdbuf -oL -eL /bin/sh
(Linux)或
gstdbuf -oL -eL /bin/sh
(macOS需brew install coreutils) Go侧别用
io.Copy(dst, src)
直连,改用
io.CopyBuffer
配小buffer(如1024字节),减少等待积压 关键点:
StdoutPipe()
和
StderrPipe()
返回的
io.ReadCloser
必须在
cmd.Start()
之后、
cmd.Wait()
之前调用,否则管道未建立就Copy会立即EOF 别忽略
cmd.Process.Signal(syscall.SIGWINCH)
——窗口大小变化消息不转发,
top
、
htop
会显示错乱 Windows目标机上执行
cmd.exe
为何常卡在“Microsoft Windows [版本 x.x]”不动 这是因为
cmd.exe
启动时检测到stdin不是console,会挂起等待输入,但Go的
StdinPipe()
默认不模拟真实控制台句柄,导致它永远等不到“第一行命令”。Linux下
/bin/sh
没这问题,但Windows cmd/powershell极其依赖控制台环境。 实操建议: 立即学习 “ go语言免费学习笔记(深入) ”; 放弃
cmd.exe
,改用
powershell.exe -NoProfile -ExecutionPolicy Bypass -Command -
,它对管道输入友好得多 如果必须用cmd,加
/c
参数并确保首条命令存在:
cmd.exe /c "echo OK"
,避免纯启动 PowerShell中
$host.UI.RawUI.BufferSize
无法通过管道设置,所以
Get-Host
显示的窗口大小总是(120,30),影响
dir
分页——得靠
Out-String -Width 999
绕过 Windows Defender默认拦截含
net.Dial
和
os/exec
组合的二进制,编译时加
-ldflags "-H=windowsgui"
可降低启发式评分(但不保证免杀) 最麻烦的其实是信号传递——Go进程收到
SIGINT
,怎么让子shell也退出?
cmd.Process.Signal
在Windows上基本无效,得靠提前写死超时+主动Close stdin pipe来软中断。

相关文章