mirror of
https://github.com/Li4n0/revsuit.git
synced 2026-09-21 22:30:46 +08:00
feat: complete basic functions
Support http,dns and mysql connection. Support custom http, dns response. Support dns rebinding. Support mysql load local files and jdbc deserialize exploit.
This commit is contained in:
@@ -0,0 +1,158 @@
|
||||
/*
|
||||
Copyright 2017 Google Inc.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreedto in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package vmysql
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"flag"
|
||||
"net"
|
||||
"sync"
|
||||
|
||||
querypb "vitess.io/vitess/go/vt/proto/query"
|
||||
)
|
||||
|
||||
var (
|
||||
mysqlAuthServerStaticFile = flag.String("mysql_auth_server_static_file", "", "JSON File to read the users/passwords from.")
|
||||
mysqlAuthServerStaticString = flag.String("mysql_auth_server_static_string", "", "JSON representation of the users/passwords config.")
|
||||
mysqlAuthServerStaticReloadInterval = flag.Duration("mysql_auth_static_reload_interval", 0, "Ticker to reload credentials")
|
||||
)
|
||||
|
||||
const (
|
||||
localhostName = "localhost"
|
||||
)
|
||||
|
||||
// AuthServerStatic implements AuthServer using a static configuration.
|
||||
type AuthServerStatic struct {
|
||||
// Method can be set to:
|
||||
// - MysqlNativePassword
|
||||
// - MysqlClearPassword
|
||||
// - MysqlDialog
|
||||
// It defaults to MysqlNativePassword.
|
||||
Method string
|
||||
// This mutex helps us prevent data races between the multiple updates of Entries.
|
||||
mu sync.Mutex
|
||||
// Entries contains the users, passwords and user data.
|
||||
Entries map[string][]*AuthServerStaticEntry
|
||||
}
|
||||
|
||||
// AuthServerStaticEntry stores the values for a given user.
|
||||
type AuthServerStaticEntry struct {
|
||||
// MysqlNativePassword is generated by password hashing methods in MySQL.
|
||||
// These changes are illustrated by changes in the result from the PASSWORD() function
|
||||
// that computes password hash values and in the structure of the user table where passwords are stored.
|
||||
// mysql> SELECT PASSWORD('mypass');
|
||||
// +-------------------------------------------+
|
||||
// | PASSWORD('mypass') |
|
||||
// +-------------------------------------------+
|
||||
// | *6C8989366EAF75BB670AD8EA7A7FC1176A95CEF4 |
|
||||
// +-------------------------------------------+
|
||||
// MysqlNativePassword's format looks like "*6C8989366EAF75BB670AD8EA7A7FC1176A95CEF4", it store a hashing value.
|
||||
// Use MysqlNativePassword in auth config, maybe more secure. After all, it is cryptographic storage.
|
||||
MysqlNativePassword string
|
||||
Password string
|
||||
UserData string
|
||||
SourceHost string
|
||||
Groups []string
|
||||
}
|
||||
|
||||
// AuthMethod is part of the AuthServer interface.
|
||||
func (a *AuthServerStatic) AuthMethod(user string) (string, error) {
|
||||
return a.Method, nil
|
||||
}
|
||||
|
||||
// Salt is part of the AuthServer interface.
|
||||
func (a *AuthServerStatic) Salt() ([]byte, error) {
|
||||
return NewSalt()
|
||||
}
|
||||
|
||||
// ValidateHash is part of the AuthServer interface.
|
||||
func (a *AuthServerStatic) ValidateHash(salt []byte, user string, authResponse []byte, remoteAddr net.Addr) (Getter, error) {
|
||||
a.mu.Lock()
|
||||
entries, ok := a.Entries[user]
|
||||
a.mu.Unlock()
|
||||
|
||||
if !ok {
|
||||
return &StaticUserData{}, NewSQLError(ERAccessDeniedError, SSAccessDeniedError, "Access denied for user '%v'", user)
|
||||
}
|
||||
|
||||
for _, entry := range entries {
|
||||
if entry.MysqlNativePassword != "" {
|
||||
isPass := isPassScrambleMysqlNativePassword(authResponse, salt, entry.MysqlNativePassword)
|
||||
if matchSourceHost(remoteAddr, entry.SourceHost) && isPass {
|
||||
return &StaticUserData{entry.UserData, entry.Groups}, nil
|
||||
}
|
||||
} else {
|
||||
computedAuthResponse := ScramblePassword(salt, []byte(entry.Password))
|
||||
// Validate the password.
|
||||
if matchSourceHost(remoteAddr, entry.SourceHost) && bytes.Equal(authResponse, computedAuthResponse) {
|
||||
return &StaticUserData{entry.UserData, entry.Groups}, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
return &StaticUserData{}, NewSQLError(ERAccessDeniedError, SSAccessDeniedError, "Access denied for user '%v'", user)
|
||||
}
|
||||
|
||||
// Negotiate is part of the AuthServer interface.
|
||||
// It will be called if Method is anything else than MysqlNativePassword.
|
||||
// We only recognize MysqlClearPassword and MysqlDialog here.
|
||||
func (a *AuthServerStatic) Negotiate(c *Conn, user string, remoteAddr net.Addr) (Getter, error) {
|
||||
// Finish the negotiation.
|
||||
password, err := AuthServerNegotiateClearOrDialog(c, a.Method)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
a.mu.Lock()
|
||||
entries, ok := a.Entries[user]
|
||||
a.mu.Unlock()
|
||||
|
||||
if !ok {
|
||||
return &StaticUserData{}, NewSQLError(ERAccessDeniedError, SSAccessDeniedError, "Access denied for user '%v'", user)
|
||||
}
|
||||
for _, entry := range entries {
|
||||
// Validate the password.
|
||||
if matchSourceHost(remoteAddr, entry.SourceHost) && entry.Password == password {
|
||||
return &StaticUserData{entry.UserData, entry.Groups}, nil
|
||||
}
|
||||
}
|
||||
return &StaticUserData{}, NewSQLError(ERAccessDeniedError, SSAccessDeniedError, "Access denied for user '%v'", user)
|
||||
}
|
||||
|
||||
func matchSourceHost(remoteAddr net.Addr, targetSourceHost string) bool {
|
||||
// Legacy support, there was not matcher defined default to true
|
||||
if targetSourceHost == "" {
|
||||
return true
|
||||
}
|
||||
switch remoteAddr.(type) {
|
||||
case *net.UnixAddr:
|
||||
if targetSourceHost == localhostName {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// StaticUserData holds the username and groups
|
||||
type StaticUserData struct {
|
||||
username string
|
||||
groups []string
|
||||
}
|
||||
|
||||
// Get returns the wrapped username and groups
|
||||
func (sud *StaticUserData) Get() *querypb.VTGateCallerID {
|
||||
return &querypb.VTGateCallerID{Username: sud.username, Groups: sud.groups}
|
||||
}
|
||||
Reference in New Issue
Block a user