utils.go 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278
  1. package utils
  2. import (
  3. "crypto/tls"
  4. "io/ioutil"
  5. "log"
  6. "net"
  7. "strconv"
  8. "strings"
  9. "time"
  10. "fmt"
  11. "regexp"
  12. "github.com/710leo/urlooker/dataobj"
  13. "github.com/710leo/urlooker/modules/agent/g"
  14. "github.com/astaxie/beego/httplib"
  15. )
  16. const (
  17. NO_ERROR = 0
  18. REQ_TIMEOUT = 1
  19. INVALID_RESP_CODE = 2
  20. KEYWORD_UNMATCH = 3
  21. )
  22. func CheckTargetStatus(item *dataobj.DetectedItem) {
  23. defer func() {
  24. <-g.WorkerChan
  25. }()
  26. checkResult := checkTargetStatus(item)
  27. g.CheckResultQueue.PushFront(checkResult)
  28. }
  29. func checkTargetStatus(item *dataobj.DetectedItem) (itemCheckResult *dataobj.CheckResult) {
  30. itemCheckResult = &dataobj.CheckResult{
  31. Sid: item.Sid,
  32. Domain: item.Domain,
  33. Creator: item.Creator,
  34. Tag: item.Tag,
  35. Endpoint: item.Endpoint,
  36. Target: item.Target,
  37. RespTime: item.Timeout,
  38. Step: int64(g.Config.Web.Interval),
  39. RespCode: "-",
  40. }
  41. reqStartTime := time.Now()
  42. defer func() {
  43. log.Printf("[detect]:sid:%d domain:%s result:%d\n", item.Sid, item.Domain, itemCheckResult.Status)
  44. }()
  45. req := httplib.Get(item.Target)
  46. if item.Method == "post" {
  47. req = httplib.Post(item.Target)
  48. } else if item.Method == "put" {
  49. req = httplib.Put(item.Target)
  50. }
  51. req.SetTLSClientConfig(&tls.Config{InsecureSkipVerify: true})
  52. req.SetTimeout(3*time.Second, 10*time.Second)
  53. req.Header("Content-Type", "application/json")
  54. req.SetHost(item.Domain)
  55. if item.Data != "" {
  56. req.Header("Cookie", item.Data)
  57. }
  58. if item.PostData != "" {
  59. req.Body(item.PostData)
  60. }
  61. if item.Header != "" {
  62. headers := parseHeader(item.Header)
  63. for _, h := range headers {
  64. req.Header(h.Key, h.Value)
  65. if h.Key == "Host" {
  66. req.SetHost(h.Value)
  67. }
  68. }
  69. }
  70. resp, err := req.Response()
  71. itemCheckResult.PushTime = time.Now().Unix()
  72. if err != nil {
  73. itemCheckResult.Status = REQ_TIMEOUT
  74. return
  75. }
  76. defer resp.Body.Close()
  77. respCode := strconv.Itoa(resp.StatusCode)
  78. itemCheckResult.RespCode = respCode
  79. respTime := int(time.Now().Sub(reqStartTime).Nanoseconds() / 1000000)
  80. itemCheckResult.RespTime = respTime
  81. if respTime > item.Timeout {
  82. itemCheckResult.Status = REQ_TIMEOUT
  83. return
  84. }
  85. if strings.Index(respCode, item.ExpectCode) == 0 || (len(item.ExpectCode) == 0 && respCode == "200") {
  86. if len(item.Keywords) > 0 {
  87. contents, _ := ioutil.ReadAll(resp.Body)
  88. contentsFormat := string(contents)
  89. for _, keywordsItem := range strings.Split(item.Keywords, "|||") {
  90. log.Printf("[keywords-item]:%s", keywordsItem)
  91. if strings.Contains(keywordsItem, ":::") {
  92. keywordsItemArr := strings.Split(keywordsItem, ":::")
  93. rule := keywordsItemArr[0]
  94. if rule == "replace" {
  95. contentsFormat = strings.Replace(contentsFormat, keywordsItemArr[1], keywordsItemArr[2], 1)
  96. log.Printf("[replace]:%s to %s", keywordsItemArr[1], keywordsItemArr[2])
  97. continue
  98. }
  99. if len(keywordsItemArr) > 2 {
  100. // get regexp rule from keywordsItem(not:::regexp:::<regexp>)
  101. rule = keywordsItemArr[1]
  102. }
  103. switch rule {
  104. case "not":
  105. // not contains
  106. if strings.Contains(contentsFormat, keywordsItemArr[1]) {
  107. itemCheckResult.Status = KEYWORD_UNMATCH
  108. return
  109. }
  110. case "regexp":
  111. // regexp contains
  112. if rule == keywordsItemArr[0] {
  113. reg := regexp.MustCompile(fmt.Sprintf(`%s`, keywordsItemArr[1]))
  114. reg_arr := reg.FindAllStringSubmatch(contentsFormat, -1)
  115. if reg_arr == nil {
  116. log.Printf("[regexp]:`%s` not match data: %s", keywordsItemArr[1], contentsFormat)
  117. itemCheckResult.Status = KEYWORD_UNMATCH
  118. return
  119. }
  120. } else {
  121. // not regexp contains
  122. reg := regexp.MustCompile(fmt.Sprintf(`%s`, keywordsItemArr[2]))
  123. reg_arr := reg.FindAllStringSubmatch(contentsFormat, -1)
  124. if reg_arr != nil {
  125. log.Printf("[regexp]:`%s` match data: %#v in %s", keywordsItemArr[2], reg_arr, contentsFormat)
  126. itemCheckResult.Status = KEYWORD_UNMATCH
  127. return
  128. }
  129. }
  130. default:
  131. log.Printf("[rule]: %s not found!", rule)
  132. }
  133. continue
  134. }
  135. if !strings.Contains(contentsFormat, keywordsItem) {
  136. itemCheckResult.Status = KEYWORD_UNMATCH
  137. return
  138. }
  139. }
  140. }
  141. itemCheckResult.Status = NO_ERROR
  142. return
  143. } else {
  144. itemCheckResult.Status = INVALID_RESP_CODE
  145. }
  146. return
  147. }
  148. type header struct {
  149. Key string
  150. Value string
  151. }
  152. func parseHeader(h string) []header {
  153. headers := []header{}
  154. kvs := strings.Split(h, "\n")
  155. for _, kv := range kvs {
  156. arr := strings.Split(kv, ":")
  157. if len(arr) == 2 {
  158. tmp := header{
  159. Key: arr[0],
  160. Value: arr[1],
  161. }
  162. headers = append(headers, tmp)
  163. }
  164. }
  165. return headers
  166. }
  167. func IntranetIP() (ips []string, err error) {
  168. ips = make([]string, 0)
  169. ifaces, e := net.Interfaces()
  170. if e != nil {
  171. return ips, e
  172. }
  173. for _, iface := range ifaces {
  174. if iface.Flags&net.FlagUp == 0 {
  175. continue // interface down
  176. }
  177. if iface.Flags&net.FlagLoopback != 0 {
  178. continue // loopback interface
  179. }
  180. // ignore docker and warden bridge
  181. if strings.HasPrefix(iface.Name, "docker") || strings.HasPrefix(iface.Name, "w-") {
  182. continue
  183. }
  184. addrs, e := iface.Addrs()
  185. if e != nil {
  186. return ips, e
  187. }
  188. for _, addr := range addrs {
  189. var ip net.IP
  190. switch v := addr.(type) {
  191. case *net.IPNet:
  192. ip = v.IP
  193. case *net.IPAddr:
  194. ip = v.IP
  195. }
  196. if ip == nil || ip.IsLoopback() {
  197. continue
  198. }
  199. ip = ip.To4()
  200. if ip == nil {
  201. continue // not an ipv4 address
  202. }
  203. ipStr := ip.String()
  204. if IsIntranet(ipStr) {
  205. ips = append(ips, ipStr)
  206. }
  207. }
  208. }
  209. return ips, nil
  210. }
  211. func IsIntranet(ipStr string) bool {
  212. if strings.HasPrefix(ipStr, "10.") {
  213. return true
  214. }
  215. if strings.HasPrefix(ipStr, "192.168.") {
  216. return true
  217. }
  218. if strings.HasPrefix(ipStr, "172.") {
  219. // 172.16.0.0-172.31.255.255
  220. arr := strings.Split(ipStr, ".")
  221. if len(arr) != 4 {
  222. return false
  223. }
  224. second, err := strconv.ParseInt(arr[1], 10, 64)
  225. if err != nil {
  226. return false
  227. }
  228. if second >= 16 && second <= 31 {
  229. return true
  230. }
  231. }
  232. return false
  233. }