NAS: General request and logging improvements

This commit is contained in:
mkwcat
2024-02-04 21:58:07 -05:00
parent acd6d13671
commit 241ae4894b
4 changed files with 170 additions and 63 deletions

View File

@@ -29,6 +29,7 @@ type Config struct {
KeyPathDS string `xml:"keyPathDS"`
APISecret string `xml:"apiSecret"`
AllowDefaultDolphinKeys bool `xml:"allowDefaultDolphinKeys"`
ServerName string `xml:"serverName,omitempty"`
}
func GetConfig() Config {
@@ -39,6 +40,7 @@ func GetConfig() Config {
var config Config
config.AllowDefaultDolphinKeys = true
config.ServerName = "WiiLink"
err = xml.Unmarshal(data, &config)
if err != nil {
@@ -65,7 +67,7 @@ func GetConfig() Config {
enable := true
config.EnableHTTPSExploitWii = &enable
}
if config.EnableHTTPSExploitDS == nil {
enable := true
config.EnableHTTPSExploitDS = &enable

40
gamestats/main.go Normal file
View File

@@ -0,0 +1,40 @@
package gamestats
import (
"context"
"fmt"
"net/http"
"wwfc/common"
"wwfc/logging"
"github.com/jackc/pgx/v4/pgxpool"
"github.com/logrusorgru/aurora/v3"
)
var (
ctx = context.Background()
pool *pgxpool.Pool
)
func StartServer() {
// Get config
config := common.GetConfig()
common.ReadGameList()
// Start SQL
dbString := fmt.Sprintf("postgres://%s:%s@%s/%s", config.Username, config.Password, config.DatabaseAddress, config.DatabaseName)
dbConf, err := pgxpool.ParseConfig(dbString)
if err != nil {
panic(err)
}
pool, err = pgxpool.ConnectConfig(ctx, dbConf)
if err != nil {
panic(err)
}
}
func HandleRequest(w http.ResponseWriter, r *http.Request) {
logging.Info("GSTATS", aurora.Yellow(r.Method), aurora.Cyan(r.URL), "via", aurora.Cyan(r.Host), "from", aurora.BrightCyan(r.RemoteAddr))
}

View File

@@ -20,6 +20,7 @@ import (
"net"
"os"
"strings"
"time"
"wwfc/common"
"wwfc/logging"
@@ -65,6 +66,15 @@ func startHTTPSProxy(config common.Config) {
panic(err)
}
setupRealTLS(privKeyPath, certsPath)
// Reread the private key and certs on a regular interval
go func() {
for {
time.Sleep(24 * time.Hour)
setupRealTLS(privKeyPath, certsPath)
}
}()
if !(exploitWii || exploitDS) {
// Only handle real TLS requests
for {
@@ -204,7 +214,7 @@ func startHTTPSProxy(config common.Config) {
}...)
serverCertsRecordDS = append(serverCertsRecordDS, certDS...)
serverCertsRecordDS = append(serverCertsRecordDS, []byte{
byte(wiiCertLenDS >> 16),
byte(wiiCertLenDS >> 8),
@@ -224,7 +234,7 @@ func startHTTPSProxy(config common.Config) {
panic(err)
}
logging.Info("NAS-TLS", "Receiving HTTPS request from", aurora.BrightCyan(conn.RemoteAddr()))
// logging.Info("NAS-TLS", "Receiving HTTPS request from", aurora.BrightCyan(conn.RemoteAddr()))
moduleName := "NAS-TLS:" + conn.RemoteAddr().String()
go handleTLS(moduleName, conn, nasAddr, privKeyPath, certsPath, serverCertsRecordWii, rsaKeyWii, serverCertsRecordDS, rsaKeyDS)
@@ -262,10 +272,10 @@ func handleTLS(moduleName string, rawConn net.Conn, nasAddr string, privKeyPath
0x00, 0x35, 0x00, 0x00, 0x2F, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x09, 0x00,
0x00, 0x05, 0x00, 0x00, 0x04,
}[index] {
break;
break
}
}
if (index == 0x1D) {
if index == 0x1D {
macFn, cipher, clientCipher := handleWiiTLSHandshake(moduleName, conn, serverCertsRecordWii, rsaKeyWii)
proxyConsoleTLS(moduleName, conn, nasAddr, VersionTLS10, macFn, cipher, clientCipher)
return
@@ -285,17 +295,17 @@ func handleTLS(moduleName string, rawConn net.Conn, nasAddr string, privKeyPath
if helloBytes[index] != []byte{
0x16, 0x03, 0x00, 0x00, 0x2F, 0x01, 0x00, 0x00, 0x2B, 0x03, 0x00,
}[index] {
break;
break
}
}
if (index == 0x0B) {
if index == 0x0B {
macFn, cipher, clientCipher := handleDSSSLHandshake(moduleName, conn, serverCertsRecordDS, rsaKeyDS)
proxyConsoleTLS(moduleName, conn, nasAddr, VersionSSL30, macFn, cipher, clientCipher)
return
}
}
logging.Info(moduleName, "Forwarding client hello:", aurora.Cyan(fmt.Sprintf("% X ", helloBytes)))
// logging.Info(moduleName, "Forwarding client hello:", aurora.Cyan(fmt.Sprintf("% X ", helloBytes)))
handleRealTLS(moduleName, conn, nasAddr, privKeyPath, certsPath)
}
@@ -486,7 +496,7 @@ func handleDSSSLHandshake(moduleName string, conn bufferedConn, serverCertsRecor
finishHash := newFinishedHash(VersionSSL30)
finishHash.Write(clientHello[0x5:0x34])
clientRandom := clientHello[0x0b:0x0b+0x20]
clientRandom := clientHello[0x0b : 0x0b+0x20]
serverHello := []byte{0x16, 0x03, 0x00, 0x00, 0x2A, 0x02, 0x00, 0x00, 0x26, 0x03, 0x00}
@@ -715,7 +725,7 @@ func proxyConsoleTLS(moduleName string, conn bufferedConn, nasAddr string, versi
return
}
if (buf[1] != 0x03 || (version == VersionTLS10 && buf[2] != 0x01) || (version == VersionSSL30 && buf[2] != 0x00)) {
if buf[1] != 0x03 || (version == VersionTLS10 && buf[2] != 0x01) || (version == VersionSSL30 && buf[2] != 0x00) {
logging.Error(moduleName, "Invalid TLS version")
return
}
@@ -758,6 +768,36 @@ func proxyConsoleTLS(moduleName string, conn bufferedConn, nasAddr string, versi
}
}
var realTLSConfig *tls.Config
func setupRealTLS(privKeyPath string, certsPath string) {
// Read server key and certs
serverKey, err := os.ReadFile(privKeyPath)
if err != nil {
logging.Error("NAS-TLS", "Failed to read server key:", err)
return
}
serverCerts, err := os.ReadFile(certsPath)
if err != nil {
logging.Error("NAS-TLS", "Failed to read server certs:", err)
return
}
cert, err := tls.X509KeyPair(serverCerts, serverKey)
if err != nil {
logging.Error("NAS-TLS", "Failed to parse server certs:", err)
return
}
config := tls.Config{
Certificates: []tls.Certificate{cert},
}
realTLSConfig = &config
}
// handleRealTLS handles the TLS request legitimately using crypto/tls
func handleRealTLS(moduleName string, conn net.Conn, nasAddr string, privKeyPath string, certsPath string) {
// Recover from panics
@@ -767,30 +807,13 @@ func handleRealTLS(moduleName string, conn net.Conn, nasAddr string, privKeyPath
}
}()
// Read server key and certs
// TODO: Cache this
serverKey, err := os.ReadFile(privKeyPath)
if err != nil {
panic(err)
if realTLSConfig == nil {
return
}
serverCerts, err := os.ReadFile(certsPath)
if err != nil {
panic(err)
}
tlsConn := tls.Server(conn, realTLSConfig)
cert, err := tls.X509KeyPair(serverCerts, serverKey)
if err != nil {
panic(err)
}
config := tls.Config{
Certificates: []tls.Certificate{cert},
}
tlsConn := tls.Server(conn, &config)
err = tlsConn.Handshake()
err := tlsConn.Handshake()
if err != nil {
return
}
@@ -959,7 +982,7 @@ func keysFromMasterSecret(version uint16, masterSecret, clientRandom, serverRand
if version == VersionSSL30 {
prf = prf30
}
seed := make([]byte, 0, len(serverRandom)+len(clientRandom))
seed = append(seed, serverRandom...)
seed = append(seed, clientRandom...)
@@ -1104,7 +1127,7 @@ func macMD5(version uint16, key []byte) macFunction {
// tls10MAC implements the TLS 1.0 MAC function. RFC 2246, Section 6.2.3.
type tls10MAC struct {
h hash.Hash
h hash.Hash
}
func (s tls10MAC) MAC(out, seq, header, data, extra []byte) []byte {
@@ -1151,4 +1174,3 @@ func (s ssl30MAC) MAC(out, seq, header, data []byte, extra []byte) []byte {
s.h.Write(out)
return s.h.Sum(out[:0])
}

View File

@@ -9,6 +9,7 @@ import (
"strings"
"wwfc/api"
"wwfc/common"
"wwfc/gamestats"
"wwfc/logging"
"wwfc/nhttp"
"wwfc/sake"
@@ -20,6 +21,8 @@ import (
var (
ctx = context.Background()
pool *pgxpool.Pool
serverName string
)
func StartServer() {
@@ -38,6 +41,8 @@ func StartServer() {
panic(err)
}
serverName = config.ServerName
address := *config.NASAddress + ":" + config.NASPort
if config.EnableHTTPS {
@@ -49,6 +54,7 @@ func StartServer() {
}
var regexSakeHost = regexp.MustCompile(`^([a-z\-]+\.)?sake\.gs\.`)
var regexGamestatsHost = regexp.MustCompile(`^([a-z\-]+\.)?gamestats2?\.gs\.`)
var regexStage1URL = regexp.MustCompile(`^/w([0-9])$`)
func handleRequest(w http.ResponseWriter, r *http.Request) {
@@ -59,6 +65,13 @@ func handleRequest(w http.ResponseWriter, r *http.Request) {
return
}
// Check for *.gamestats(2).gs.* or gamestats(2).gs.*
if regexGamestatsHost.MatchString(r.Host) {
// Redirect to the gamestats server
gamestats.HandleRequest(w, r)
return
}
moduleName := "NAS:" + r.RemoteAddr
// Handle conntest server
@@ -67,6 +80,37 @@ func handleRequest(w http.ResponseWriter, r *http.Request) {
return
}
// Handle DWC auth requests
if r.URL.String() == "/ac" || r.URL.String() == "/pr" || r.URL.String() == "/download" {
handleAuthRequest(moduleName, w, r)
return
}
// Handle /nastest.jsp
if r.URL.Path == "/nastest.jsp" {
handleNASTest(w)
return
}
// Check for /payload
if strings.HasPrefix(r.URL.String(), "/payload") {
logging.Info("NAS", aurora.Yellow(r.Method), aurora.Cyan(r.URL), "via", aurora.Cyan(r.Host), "from", aurora.BrightCyan(r.RemoteAddr))
handlePayloadRequest(moduleName, w, r)
return
}
// Stage 1
if match := regexStage1URL.FindStringSubmatch(r.URL.String()); match != nil {
val, err := strconv.Atoi(match[1])
if err != nil {
panic(err)
}
logging.Info("NAS", "Get stage 1:", aurora.Yellow(r.Method), aurora.Cyan(r.URL), "via", aurora.Cyan(r.Host), "from", aurora.BrightCyan(r.RemoteAddr))
downloadStage1(w, val)
return
}
// Check for /api/groups
if r.URL.Path == "/api/groups" {
api.HandleGroups(w, r)
@@ -97,43 +141,42 @@ func handleRequest(w http.ResponseWriter, r *http.Request) {
return
}
if r.URL.String() == "/ac" || r.URL.String() == "/pr" || r.URL.String() == "/download" {
handleAuthRequest(moduleName, w, r)
return
}
// Check for /payload
if strings.HasPrefix(r.URL.String(), "/payload") {
handlePayloadRequest(moduleName, w, r)
return
}
// Stage 1
if match := regexStage1URL.FindStringSubmatch(r.URL.String()); match != nil {
val, err := strconv.Atoi(match[1])
if err != nil {
panic(err)
}
downloadStage1(w, val)
return
}
logging.Info("NAS", aurora.Yellow(r.Method), aurora.Cyan(r.URL), "via", aurora.Cyan(r.Host), "from", aurora.BrightCyan(r.RemoteAddr))
replyHTTPError(w, 404, "404 Not Found")
}
func replyHTTPError(w http.ResponseWriter, errorCode int, errorString string) {
response := "<html>\n"
response += "<head><title>" + errorString + "</title></head>\n"
response += "<body>\n"
response += "<center><h1>" + errorString + "</h1></center>\n"
response += "<hr><center>WiiLink</center>\n"
response += "</body>\n"
response += "</html>\n"
response := "<html>\n" +
"<head><title>" + errorString + "</title></head>\n" +
"<body>\n" +
"<center><h1>" + errorString + "</h1></center>\n" +
"<hr><center>" + serverName + "</center>\n" +
"</body>\n" +
"</html>\n"
w.Header().Set("Content-Type", "text/html")
w.Header().Set("Content-Length", strconv.Itoa(len(response)))
w.Header().Set("Connection", "close")
w.Header().Set("Server", "Nintendo")
w.WriteHeader(errorCode)
w.Write([]byte(response))
}
func handleNASTest(w http.ResponseWriter) {
response := "" +
"<html>\n" +
"<body>\n" +
"</br>AuthServer is up</br> \n" +
"\n" +
"</body>\n" +
"</html>\n"
w.Header().Set("Content-Type", "text/html;charset=ISO-8859-1")
w.Header().Set("Content-Length", strconv.Itoa(len(response)))
w.Header().Set("Connection", "close")
w.Header().Set("NODE", "authserver-service.authserver.svc.cluster.local")
w.Header().Set("Server", "Nintendo")
w.WriteHeader(200)
w.Write([]byte(response))
}