mirror of
https://github.com/fleetdm/fleet
synced 2026-04-21 13:37:30 +00:00
remove old Windows MDM PoC tool (#39473)
This PR cleans up an old tool/windows-mdm-poc, that we no longer use or rely on. It is also an effort to minimze inline dependencies when unused.
This commit is contained in:
parent
aab959a7c7
commit
bce4c4afae
37 changed files with 4 additions and 2613 deletions
|
|
@ -33,6 +33,8 @@
|
|||
|
||||
- CSPs: https://learn.microsoft.com/en-us/windows/client-management/mdm/policy-configuration-service-provider
|
||||
|
||||
- Initial PoC PR's: [MDM Server](https://github.com/fleetdm/fleet/pull/9178) [Programmatic Enrollment](https://github.com/fleetdm/fleet/pull/9500)
|
||||
|
||||
### Android
|
||||
|
||||
See the [Android MDM documentation](./android-mdm.md)
|
||||
|
|
|
|||
|
|
@ -42,16 +42,14 @@ import (
|
|||
// The certificates generated by a Windows device during MDM enrollment were not being parsed correctly
|
||||
// by the standard x509 package. To work around this issue, we used a modified version of the isPrintable
|
||||
// function from the ASN.1 package that allows invalid characters.
|
||||
// You can find the implementation of isPrintable here:
|
||||
// You can find the original implementation of isPrintable here:
|
||||
// https://github.com/golang/go/blob/e126572f8a91d42b86242012012d0cad4507dca8/src/encoding/asn1/asn1.go#L433
|
||||
// The modification to the standard library requires applying the following patch to the x509 package:
|
||||
// https://github.com/fleetdm/fleet/blob/main/tools/mdm/windows/poc-mdm-server/patch/patch.go
|
||||
// Since this solution is not ideal and does not scale, we have wrapped a custom version of
|
||||
// ParseCertificateRequest with the necessary changes in ParseCertificateRequestFromWindowsDevice().
|
||||
// The invalid characters are: '!' and 0x00.
|
||||
// Here's an example of a certificate with invalid characters in the CommonName field:
|
||||
// Common Name: F717C0F0-5F68-4AC3-A341-01B254!4219DFB0A902F747A9C4FD43C8CE36CE
|
||||
// The new characters have been added to the isPrintable() function below.
|
||||
// The patched isPrintable method that allows these new characters, can be found below in this file.
|
||||
func ParseCertificateRequestFromWindowsDevice(asn1Data []byte) (*x509.CertificateRequest, error) {
|
||||
var csr certificateRequest
|
||||
|
||||
|
|
|
|||
1
third_party/vuln-check/README.md
vendored
1
third_party/vuln-check/README.md
vendored
|
|
@ -34,7 +34,6 @@ This directory solves that problem by creating "dummy" manifest files that list
|
|||
| josharian/impl | server/mock/mockimpl/ | v1.4.0 |
|
||||
| mitchellh/gon | orbit/pkg/packaging/macos_notarize.go | v0.2.3 |
|
||||
| sassoftware/relic | pkg/file/xar.go | v7.2.1+incompatible |
|
||||
| oscartbeaumont/windows_mdm | tools/mdm/windows/poc-mdm-server/ | v0.0.0-20210615145659-e52e28e50db7 |
|
||||
|
||||
### npm dependencies (package.json)
|
||||
|
||||
|
|
|
|||
4
third_party/vuln-check/go.mod
vendored
4
third_party/vuln-check/go.mod
vendored
|
|
@ -49,8 +49,4 @@ require (
|
|||
// relic - XAR file parsing (pkg/file/xar.go)
|
||||
// Copied: April 2023
|
||||
github.com/sassoftware/relic v7.2.1+incompatible
|
||||
|
||||
// poc-mdm-server - Windows MDM demo (tools/mdm/windows/poc-mdm-server/)
|
||||
// Forked from oscartbeaumont/windows_mdm
|
||||
github.com/oscartbeaumont/windows_mdm v0.0.0-20210615145659-e52e28e50db7
|
||||
)
|
||||
|
|
|
|||
|
|
@ -262,7 +262,6 @@ go run ./tools/run-scripts -scripts-disabled -content 'echo "Test"'
|
|||
| `mdm/migration/micromdm/` | MicroMDM migration tools | See [mdm/migration/micromdm/README.md](mdm/migration/micromdm/README.md) |
|
||||
| `mdm/migration/simplemdm/` | SimpleMDM migration tools | `go run ./tools/mdm/migration/simplemdm` |
|
||||
| `mdm/windows/bitlocker/` | BitLocker key management | Go utilities for BitLocker |
|
||||
| `mdm/windows/poc-mdm-server/` | PoC Windows MDM server | See [mdm/windows/poc-mdm-server/README.md](mdm/windows/poc-mdm-server/README.md) |
|
||||
| `mdm/windows/programmatic-enrollment/` | Windows MDM enrollment | `go run ./tools/mdm/windows/programmatic-enrollment` |
|
||||
| `windows-mdm-enroll/` | Windows MDM enrollment | Enrollment utilities for Windows |
|
||||
| **Other Utilities** | | |
|
||||
|
|
|
|||
18
tools/mdm/windows/poc-mdm-server/.gitignore
vendored
18
tools/mdm/windows/poc-mdm-server/.gitignore
vendored
|
|
@ -1,18 +0,0 @@
|
|||
# Binaries for programs and plugins
|
||||
*.exe
|
||||
*.exe~
|
||||
*.dll
|
||||
*.so
|
||||
*.dylib
|
||||
|
||||
# Test binary, build with `go test -c`
|
||||
*.test
|
||||
|
||||
# Output of the go coverage tool, specifically when used with LiteIDE
|
||||
*.out
|
||||
|
||||
# Mac System Files
|
||||
.DS_Store
|
||||
|
||||
# Ignore The Folder With My HTTPS Certifciates
|
||||
certs/
|
||||
|
|
@ -1,21 +0,0 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) 2021 Oscar Beaumont
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
File diff suppressed because one or more lines are too long
Binary file not shown.
|
|
@ -1,10 +0,0 @@
|
|||
module github.com/oscartbeaumont/windows_mdm
|
||||
|
||||
go 1.12
|
||||
|
||||
require (
|
||||
github.com/ernesto-jimenez/httplogger v0.0.0-20220128121225-117514c3f345
|
||||
github.com/go-xmlfmt/xmlfmt v1.1.2
|
||||
github.com/gorilla/handlers v1.4.2
|
||||
github.com/gorilla/mux v1.7.3
|
||||
)
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
github.com/ernesto-jimenez/httplogger v0.0.0-20220128121225-117514c3f345 h1:AZLrCR38RDhsyCQakz1UxCx72As18Ai5mObrKvT8DK8=
|
||||
github.com/ernesto-jimenez/httplogger v0.0.0-20220128121225-117514c3f345/go.mod h1:pw+gaKQ52Cl/SrERU62yQAiWauPpLgKpuR1hkxwL4tM=
|
||||
github.com/go-xmlfmt/xmlfmt v1.1.2 h1:Nea7b4icn8s57fTx1M5AI4qQT5HEM3rVUO8MuE6g80U=
|
||||
github.com/go-xmlfmt/xmlfmt v1.1.2/go.mod h1:aUCEOzzezBEjDBbFBoSiya/gduyIiWYRP6CnSFIV8AM=
|
||||
github.com/gorilla/handlers v1.4.2 h1:0QniY0USkHQ1RGCLfKxeNHK9bkDHGRYGNDFBCS+YARg=
|
||||
github.com/gorilla/handlers v1.4.2/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ=
|
||||
github.com/gorilla/mux v1.7.3 h1:gnP5JzjVOuiZD07fKKToCAOjS0yOpj/qPETTXCCS6hw=
|
||||
github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
|
||||
Binary file not shown.
Binary file not shown.
|
|
@ -1,180 +0,0 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"flag"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"net/http/httputil"
|
||||
"os"
|
||||
|
||||
"github.com/go-xmlfmt/xmlfmt"
|
||||
"github.com/gorilla/mux"
|
||||
)
|
||||
|
||||
// Code forked from https://github.com/oscartbeaumont/windows_mdm
|
||||
// Global config, populated via Command line flags
|
||||
var (
|
||||
domain string
|
||||
deepLinkUserEmail string
|
||||
authPolicy string
|
||||
profileDir string
|
||||
staticDir string
|
||||
verbose bool
|
||||
)
|
||||
|
||||
func main() {
|
||||
fmt.Println("Starting Windows MDM Demo Server")
|
||||
|
||||
// Parse CMD flags. This populates the varibles defined above
|
||||
flag.StringVar(&domain, "domain", "mdmwindows.com", "Your servers primary domain")
|
||||
flag.StringVar(&deepLinkUserEmail, "dl-user-email", "demo@mdmwindows.com", "An email of the enrolling user when using the Deeplink ('/deeplink')")
|
||||
flag.StringVar(&authPolicy, "auth-policy", "OnPremise", "An email of the enrolling user when using the Deeplink ('/deeplink')")
|
||||
flag.StringVar(&profileDir, "mdm-profile-dir", "./profile", "The MDM policy directory contains the SyncML MDM profile commmands to enforce to enrolled devices")
|
||||
flag.StringVar(&staticDir, "static-dir", "./static", "The directory to serve static files")
|
||||
flag.BoolVar(&verbose, "verbose", false, "HTTP traffic dump")
|
||||
flag.Parse()
|
||||
|
||||
// Verify authPolicy is valid
|
||||
if authPolicy != "Federated" && authPolicy != "OnPremise" {
|
||||
panic("unsupported authpolicy")
|
||||
}
|
||||
|
||||
// Checking if profile directory exists
|
||||
_, err := os.Stat(profileDir)
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
panic("profile directory does not exists")
|
||||
} else {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
// Checking if static directory exists
|
||||
_, err = os.Stat(staticDir)
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
panic("static directory does not exists")
|
||||
} else {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
// Create HTTP request router
|
||||
r := mux.NewRouter()
|
||||
|
||||
// MS-MDE and MS-MDM endpoints
|
||||
r.Path("/EnrollmentServer/Discovery.svc").Methods("GET", "POST").HandlerFunc(DiscoveryHandler)
|
||||
r.Path("/EnrollmentServer/Policy.svc").Methods("POST").HandlerFunc(PolicyHandler)
|
||||
r.Path("/EnrollmentServer/Enrollment.svc").Methods("POST").HandlerFunc(EnrollHandler)
|
||||
r.Path("/ManagementServer/MDM.svc").Methods("POST").HandlerFunc(ManageHandler)
|
||||
|
||||
// Static root endpoint
|
||||
r.Path("/").Methods("GET").HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", "text/html; charset=UTF-8")
|
||||
w.Write([]byte(`<center><h1>FleetDM Windows MDM Demo Server<br></h1>.<center>`))
|
||||
w.Write([]byte(`<br><center><img src="https://fleetdm.com/images/press-kit/fleet-logo-dark-rgb.png"></center>`))
|
||||
})
|
||||
|
||||
// Static file serve
|
||||
fileServer := http.FileServer(http.Dir(staticDir))
|
||||
r.PathPrefix("/").Handler(http.StripPrefix("/static", fileServer))
|
||||
|
||||
// Start HTTPS Server
|
||||
fmt.Println("HTTPS server listening on port 443")
|
||||
err = http.ListenAndServeTLS(":443", "./certs/dev_cert_mdmwindows_com_cert.pem", "./certs/dev_cert_mdmwindows_com.key", globalHandler(r))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
// drainBody reads all of bytes to memory and then returns two equivalent
|
||||
// ReadClosers yielding the same bytes.
|
||||
//
|
||||
// It returns an error if the initial slurp of all bytes fails. It does not attempt
|
||||
// to make the returned ReadClosers have identical error-matching behavior.
|
||||
func drainBody(b io.ReadCloser) (r1, r2 io.ReadCloser, body []byte, err error) {
|
||||
if b == nil || b == http.NoBody {
|
||||
// No copying needed. Preserve the magic sentinel meaning of NoBody.
|
||||
return http.NoBody, http.NoBody, nil, nil
|
||||
}
|
||||
var buf bytes.Buffer
|
||||
if _, err = buf.ReadFrom(b); err != nil {
|
||||
return nil, b, nil, err
|
||||
}
|
||||
if err = b.Close(); err != nil {
|
||||
return nil, b, nil, err
|
||||
}
|
||||
return io.NopCloser(&buf), io.NopCloser(bytes.NewReader(buf.Bytes())), buf.Bytes(), nil
|
||||
}
|
||||
|
||||
// global HTTP handler to log input and output https traffic
|
||||
func globalHandler(h http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
if verbose {
|
||||
// grabbing Input Header and Body
|
||||
reqHeader, err := httputil.DumpRequest(r, false)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
var bodyBytes []byte
|
||||
reqBodySave := r.Body
|
||||
if r.Body != nil {
|
||||
reqBodySave, r.Body, bodyBytes, err = drainBody(r.Body)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
r.Body = reqBodySave
|
||||
|
||||
var beautifiedReqBody string
|
||||
if len(bodyBytes) > 0 {
|
||||
beautifiedReqBody = xmlfmt.FormatXML(string(bodyBytes), " ", " ")
|
||||
}
|
||||
|
||||
fmt.Printf("\n\n============================= Input Request =============================\n")
|
||||
fmt.Println("----------- Input Header -----------\n", string(reqHeader))
|
||||
if len(beautifiedReqBody) > 0 {
|
||||
fmt.Println("----------- Input Body -----------\n", string(beautifiedReqBody))
|
||||
} else {
|
||||
fmt.Printf("----------- Empty Input Body -----------\n")
|
||||
}
|
||||
fmt.Printf("=========================================================================\n\n\n")
|
||||
}
|
||||
|
||||
rec := httptest.NewRecorder()
|
||||
h.ServeHTTP(rec, r)
|
||||
|
||||
if verbose {
|
||||
// grabbing Output Header and Body
|
||||
var beautifiedResponseBody string
|
||||
responseBody := rec.Body.Bytes()
|
||||
if len(responseBody) > 0 {
|
||||
beautifiedResponseBody = xmlfmt.FormatXML(string(responseBody), " ", " ")
|
||||
}
|
||||
|
||||
responseHeader, err := httputil.DumpResponse(rec.Result(), false)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
fmt.Printf("\n\n============================= Output Response =============================\n")
|
||||
fmt.Println("----------- Response Header -----------\n", string(responseHeader))
|
||||
if len(beautifiedResponseBody) > 0 {
|
||||
fmt.Println("----------- Response Body -----------\n", string(beautifiedResponseBody))
|
||||
} else {
|
||||
fmt.Printf("----------- Empty Response Body -----------\n")
|
||||
}
|
||||
fmt.Printf("=========================================================================\n\n\n")
|
||||
}
|
||||
|
||||
// we copy the captured response headers to our new response
|
||||
for k, v := range rec.Header() {
|
||||
w.Header()[k] = v
|
||||
}
|
||||
w.Write(rec.Body.Bytes())
|
||||
})
|
||||
}
|
||||
|
|
@ -1,65 +0,0 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// DiscoveryHandler is the HTTP handler assosiated with the enrollment protocol's discovery endpoint.
|
||||
func DiscoveryHandler(w http.ResponseWriter, r *http.Request) {
|
||||
// Return HTTP Status 200 Ok when a HTTP GET request is received.
|
||||
if r.Method == http.MethodGet {
|
||||
w.WriteHeader(http.StatusOK)
|
||||
return
|
||||
}
|
||||
|
||||
// Read The HTTP Request body
|
||||
bodyRaw, err := ioutil.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
body := string(bodyRaw)
|
||||
|
||||
// Retrieve the MessageID From The Body For The Response
|
||||
messageID := strings.Replace(strings.Replace(regexp.MustCompile(`<a:MessageID>[\s\S]*?<\/a:MessageID>`).FindStringSubmatch(body)[0], "<a:MessageID>", "", -1), "</a:MessageID>", "", -1)
|
||||
|
||||
var extraParams = ""
|
||||
if authPolicy == "Federated" {
|
||||
extraParams += "<AuthenticationServiceUrl>https://" + domain + "/EnrollmentServer/Auth</AuthenticationServiceUrl>"
|
||||
}
|
||||
|
||||
// Create response payload
|
||||
response := []byte(`
|
||||
<s:Envelope
|
||||
xmlns:s="http://www.w3.org/2003/05/soap-envelope"
|
||||
xmlns:a="http://www.w3.org/2005/08/addressing">
|
||||
<s:Header>
|
||||
<a:Action s:mustUnderstand="1">http://schemas.microsoft.com/windows/management/2012/01/enrollment/IDiscoveryService/DiscoverResponse</a:Action>
|
||||
<ActivityId CorrelationId="8c6060c4-3d78-4d73-ae17-e8bce88426ee"
|
||||
xmlns="http://schemas.microsoft.com/2004/09/ServiceModel/Diagnostics">8c6060c4-3d78-4d73-ae17-e8bce88426ee
|
||||
</ActivityId>
|
||||
<a:RelatesTo>` + messageID + `</a:RelatesTo>
|
||||
</s:Header>
|
||||
<s:Body>
|
||||
<DiscoverResponse
|
||||
xmlns="http://schemas.microsoft.com/windows/management/2012/01/enrollment">
|
||||
<DiscoverResult>
|
||||
<AuthPolicy>` + authPolicy + `</AuthPolicy>
|
||||
<EnrollmentVersion>4.0</EnrollmentVersion>
|
||||
<EnrollmentPolicyServiceUrl>https://` + domain + `/EnrollmentServer/Policy.svc</EnrollmentPolicyServiceUrl>
|
||||
<EnrollmentServiceUrl>https://` + domain + `/EnrollmentServer/Enrollment.svc</EnrollmentServiceUrl>
|
||||
` + extraParams + `
|
||||
|
||||
</DiscoverResult>
|
||||
</DiscoverResponse>
|
||||
</s:Body>
|
||||
</s:Envelope>`)
|
||||
|
||||
// Return response body
|
||||
w.Header().Set("Content-Type", "application/soap+xml; charset=utf-8")
|
||||
w.Header().Set("Content-Length", strconv.Itoa(len(response)))
|
||||
w.Write(response)
|
||||
}
|
||||
|
|
@ -1,237 +0,0 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"crypto/sha1"
|
||||
"crypto/x509"
|
||||
"crypto/x509/pkix"
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"math/big"
|
||||
mathrand "math/rand"
|
||||
"net/http"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// EnrollHandler is the HTTP handler assosiated with the enrollment protocol's enrollment endpoint.
|
||||
func EnrollHandler(w http.ResponseWriter, r *http.Request) {
|
||||
// Read The HTTP Request body
|
||||
bodyRaw, err := ioutil.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
body := string(bodyRaw)
|
||||
|
||||
// Retrieve the MessageID From The Body For The Response
|
||||
messageID := strings.Replace(strings.Replace(regexp.MustCompile(`<a:MessageID>[\s\S]*?<\/a:MessageID>`).FindStringSubmatch(body)[0], "<a:MessageID>", "", -1), "</a:MessageID>", "", -1)
|
||||
|
||||
// Retrieve the BinarySecurityToken (which contains a Certificate Signing Request) From The Body For The Response
|
||||
binarySecurityToken := strings.Replace(strings.Replace(regexp.MustCompile(`<wsse:BinarySecurityToken ValueType="http:\/\/schemas.microsoft.com\/windows\/pki\/2009\/01\/enrollment#PKCS10" EncodingType="http:\/\/docs\.oasis-open\.org\/wss\/2004\/01\/oasis-200401-wss-wssecurity-secext-1\.0\.xsd#base64binary">[\s\S]*?<\/wsse:BinarySecurityToken>`).FindStringSubmatch(body)[0], `<wsse:BinarySecurityToken ValueType="http://schemas.microsoft.com/windows/pki/2009/01/enrollment#PKCS10" EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd#base64binary">`, "", -1), "</wsse:BinarySecurityToken>", "", -1)
|
||||
|
||||
// Retrieve the DeviceID From The Body For The Response
|
||||
deviceID := strings.Replace(strings.Replace(regexp.MustCompile(`<ac:ContextItem Name="DeviceID"><ac:Value>[\s\S]*?<\/ac:Value><\/ac:ContextItem>`).FindStringSubmatch(body)[0], `<ac:ContextItem Name="DeviceID"><ac:Value>`, "", -1), "</ac:Value></ac:ContextItem>", "", -1)
|
||||
|
||||
// Retrieve the EnrollmentType From The Body For The Response
|
||||
enrollmentType := strings.Replace(strings.Replace(regexp.MustCompile(`<ac:ContextItem Name="EnrollmentType"><ac:Value>[\s\S]*?<\/ac:Value><\/ac:ContextItem>`).FindStringSubmatch(body)[0], `<ac:ContextItem Name="EnrollmentType"><ac:Value>`, "", -1), "</ac:Value></ac:ContextItem>", "", -1)
|
||||
|
||||
/* Sign binary security token */
|
||||
// Load raw Root CA
|
||||
rootCertificateDer, err := ioutil.ReadFile("./identity/identity.crt")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
rootPrivateKeyDer, err := ioutil.ReadFile("./identity/identity.key")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// Convert the raw Root CA cert & key to parsed version
|
||||
rootCert, err := x509.ParseCertificate(rootCertificateDer)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
rootPrivateKey, err := x509.ParsePKCS1PrivateKey(rootPrivateKeyDer)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// Decode Base64
|
||||
csrRaw, err := base64.StdEncoding.DecodeString(binarySecurityToken)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// Decode and verify CSR
|
||||
csr, err := x509.ParseCertificateRequest(csrRaw)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if err = csr.CheckSignature(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// Create client identity certificate
|
||||
NotBefore1 := time.Now().Add(time.Duration(mathrand.Int31n(120)) * -time.Minute) // This randomises the creation time a bit for added security (Recommended by x509 signing article not the MDM spec)
|
||||
clientCertificate := &x509.Certificate{
|
||||
Signature: csr.Signature,
|
||||
SignatureAlgorithm: csr.SignatureAlgorithm,
|
||||
PublicKeyAlgorithm: csr.PublicKeyAlgorithm,
|
||||
PublicKey: csr.PublicKey,
|
||||
SerialNumber: big.NewInt(2),
|
||||
Issuer: rootCert.Issuer,
|
||||
Subject: pkix.Name{
|
||||
CommonName: deviceID,
|
||||
}, // The Subject is not used from the CSR because the characters in it are causing issues.
|
||||
NotBefore: NotBefore1,
|
||||
NotAfter: NotBefore1.Add(365 * 24 * time.Hour),
|
||||
KeyUsage: x509.KeyUsageDigitalSignature,
|
||||
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
|
||||
}
|
||||
|
||||
// Sign certificate with the identity
|
||||
clientCRTRaw, err := x509.CreateCertificate(rand.Reader, clientCertificate, rootCert, csr.PublicKey, rootPrivateKey)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// Note: SHA-1 Hash OID is deprecated
|
||||
|
||||
// Fingerprint (SHA-1 hash) of client certificate
|
||||
h := sha1.New()
|
||||
h.Write(clientCRTRaw)
|
||||
signedClientCertFingerprint := strings.ToUpper(fmt.Sprintf("%x", h.Sum(nil))) // TODO: Cleanup -> This line is probally messer than it needs to be
|
||||
|
||||
// Fingerprint (SHA-1 hash) of client certificate
|
||||
h2 := sha1.New()
|
||||
h2.Write(rootCertificateDer)
|
||||
identityCertFingerprint := strings.ToUpper(fmt.Sprintf("%x", h2.Sum(nil))) // TODO: Cleanup -> This line is probally messer than it needs to be
|
||||
|
||||
// Determain Certstore
|
||||
certStore := "User"
|
||||
if enrollmentType == "Device" {
|
||||
certStore = "System"
|
||||
}
|
||||
|
||||
// End Sign binary security token
|
||||
|
||||
// Generate WAP provisioning profile for inside the payload
|
||||
wapProvisionProfile := `
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<wap-provisioningdoc version="1.1">
|
||||
<characteristic type="CertificateStore">
|
||||
<characteristic type="Root">
|
||||
<characteristic type="System">
|
||||
<characteristic type="` + identityCertFingerprint /* Root CA Certificate Fingureprint (SHA-1 hash of Der) */ + `">
|
||||
<parm name="EncodedCertificate" value="` + base64.StdEncoding.EncodeToString(rootCertificateDer) /* Base64 encoded root CA certificate */ + `" />
|
||||
</characteristic>
|
||||
</characteristic>
|
||||
</characteristic>
|
||||
<characteristic type="My">
|
||||
<characteristic type="` + certStore + `">
|
||||
<characteristic type="` + signedClientCertFingerprint /* Signed Client Certificate (From the BinarySecurityToken) Fingureprint (SHA-1 hash of Der) */ + `">
|
||||
<parm name="EncodedCertificate" value="` + base64.StdEncoding.EncodeToString(clientCRTRaw) /* Base64 encoded signed certificate */ + `" />
|
||||
</characteristic>
|
||||
<characteristic type="PrivateKeyContainer" />
|
||||
</characteristic>
|
||||
<characteristic type="WSTEP">
|
||||
<characteristic type="Renew">
|
||||
<parm name="ROBOSupport" value="true" datatype="boolean"/>
|
||||
<parm name="RenewPeriod" value="60" datatype="integer"/>
|
||||
<parm name="RetryInterval" value="4" datatype="integer"/>
|
||||
</characteristic>
|
||||
</characteristic>
|
||||
</characteristic>
|
||||
</characteristic>
|
||||
<characteristic type="APPLICATION">
|
||||
<parm name="APPID" value="w7" />
|
||||
<parm name="PROVIDER-ID" value="DEMO MDM" />
|
||||
<parm name="NAME" value="FleetDM Demo Server - Windows" />
|
||||
<parm name="ADDR" value="https://` + domain + `/ManagementServer/MDM.svc" />
|
||||
<parm name="ServerList" value="https://` + domain + `/ManagementServer/ServerList.svc" />
|
||||
<parm name="ROLE" value="4294967295" />
|
||||
<parm name="BACKCOMPATRETRYDISABLED" />
|
||||
<parm name="CONNRETRYFREQ" value="6" />
|
||||
<parm name="INITIALBACKOFFTIME" value="30000" />
|
||||
<parm name="MAXBACKOFFTIME" value="120000" />
|
||||
<parm name="DEFAULTENCODING" value="application/vnd.syncml.dm+xml" />
|
||||
<characteristic type="APPAUTH">
|
||||
<parm name="AAUTHLEVEL" value="CLIENT" />
|
||||
<parm name="AAUTHTYPE" value="DIGEST" />
|
||||
<parm name="AAUTHSECRET" value="dummy" />
|
||||
<parm name="AAUTHDATA" value="nonce" />
|
||||
</characteristic>
|
||||
<characteristic type="APPAUTH">
|
||||
<parm name="AAUTHLEVEL" value="APPSRV" />
|
||||
<parm name="AAUTHTYPE" value="DIGEST" />
|
||||
<parm name="AAUTHNAME" value="dummy" />
|
||||
<parm name="AAUTHSECRET" value="dummy" />
|
||||
<parm name="AAUTHDATA" value="nonce" />
|
||||
</characteristic>
|
||||
</characteristic>
|
||||
<characteristic type="DMClient">
|
||||
<characteristic type="Provider">
|
||||
<characteristic type="DEMO MDM">
|
||||
<characteristic type="Poll">
|
||||
<parm name="NumberOfFirstRetries" value="8" datatype="integer" />
|
||||
<parm name="IntervalForFirstSetOfRetries" value="15" datatype="integer" />
|
||||
<parm name="NumberOfSecondRetries" value="5" datatype="integer" />
|
||||
<parm name="IntervalForSecondSetOfRetries" value="3" datatype="integer" />
|
||||
<parm name="NumberOfRemainingScheduledRetries" value="0" datatype="integer" />
|
||||
<parm name="IntervalForRemainingScheduledRetries" value="1560" datatype="integer" />
|
||||
<parm name="PollOnLogin" value="true" datatype="boolean" />
|
||||
</characteristic>
|
||||
</characteristic>
|
||||
</characteristic>
|
||||
</characteristic>
|
||||
</wap-provisioningdoc>`
|
||||
|
||||
wapProvisionProfileRaw := []byte(strings.ReplaceAll(strings.ReplaceAll(wapProvisionProfile, "\n", ""), "\t", ""))
|
||||
|
||||
// Create response payload
|
||||
response := []byte(`
|
||||
<s:Envelope
|
||||
xmlns:s="http://www.w3.org/2003/05/soap-envelope"
|
||||
xmlns:a="http://www.w3.org/2005/08/addressing"
|
||||
xmlns:u="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
|
||||
<s:Header>
|
||||
<a:Action s:mustUnderstand="1">http://schemas.microsoft.com/windows/pki/2009/01/enrollment/RSTRC/wstep</a:Action>
|
||||
<a:RelatesTo>` + messageID + `</a:RelatesTo>
|
||||
<o:Security
|
||||
xmlns:o="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" s:mustUnderstand="1">
|
||||
<u:Timestamp u:Id="_0">
|
||||
<u:Created>2018-11-30T00:32:59.420Z</u:Created>
|
||||
<u:Expires>2018-12-30T00:37:59.420Z</u:Expires>
|
||||
</u:Timestamp>
|
||||
</o:Security>
|
||||
</s:Header>
|
||||
<s:Body>
|
||||
<RequestSecurityTokenResponseCollection
|
||||
xmlns="http://docs.oasis-open.org/ws-sx/ws-trust/200512">
|
||||
<RequestSecurityTokenResponse>
|
||||
<TokenType>http://schemas.microsoft.com/5.0.0.0/ConfigurationManager/Enrollment/DeviceEnrollmentToken</TokenType>
|
||||
<DispositionMessage
|
||||
xmlns="http://schemas.microsoft.com/windows/pki/2009/01/enrollment">
|
||||
</DispositionMessage>
|
||||
<RequestedSecurityToken>
|
||||
<BinarySecurityToken
|
||||
xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" ValueType="http://schemas.microsoft.com/5.0.0.0/ConfigurationManager/Enrollment/DeviceEnrollmentProvisionDoc" EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd#base64binary">` + base64.StdEncoding.EncodeToString(wapProvisionProfileRaw) + `
|
||||
</BinarySecurityToken>
|
||||
</RequestedSecurityToken>
|
||||
<RequestID
|
||||
xmlns="http://schemas.microsoft.com/windows/pki/2009/01/enrollment">0
|
||||
</RequestID>
|
||||
</RequestSecurityTokenResponse>
|
||||
</RequestSecurityTokenResponseCollection>
|
||||
</s:Body>
|
||||
</s:Envelope>`)
|
||||
|
||||
// Return response body
|
||||
w.Header().Set("Content-Type", "application/soap+xml; charset=utf-8")
|
||||
w.Header().Set("Content-Length", strconv.Itoa(len(response)))
|
||||
w.Write(response)
|
||||
}
|
||||
|
|
@ -1,94 +0,0 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// PolicyHandler is the HTTP handler assosiated with the enrollment protocol's policy endpoint.
|
||||
func PolicyHandler(w http.ResponseWriter, r *http.Request) {
|
||||
// Read The HTTP Request body
|
||||
bodyRaw, err := ioutil.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
body := string(bodyRaw)
|
||||
|
||||
// Retrieve the MessageID From The Body For The Response
|
||||
messageID := strings.Replace(strings.Replace(regexp.MustCompile(`<a:MessageID>[\s\S]*?<\/a:MessageID>`).FindStringSubmatch(body)[0], "<a:MessageID>", "", -1), "</a:MessageID>", "", -1)
|
||||
|
||||
response := []byte(`
|
||||
<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:a="http://www.w3.org/2005/08/addressing" xmlns:u="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
|
||||
<s:Header>
|
||||
<a:Action s:mustUnderstand="1">http://schemas.microsoft.com/windows/pki/2009/01/enrollmentpolicy/IPolicy/GetPoliciesResponse</a:Action>
|
||||
<a:RelatesTo>` + messageID + `</a:RelatesTo>
|
||||
</s:Header>
|
||||
<s:Body
|
||||
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<GetPoliciesResponse xmlns="http://schemas.microsoft.com/windows/pki/2009/01/enrollmentpolicy">
|
||||
<response>
|
||||
<policyID />
|
||||
<policyFriendlyName xsi:nil="true" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"/>
|
||||
<nextUpdateHours xsi:nil="true" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"/>
|
||||
<policiesNotChanged xsi:nil="true" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"/>
|
||||
<policies>
|
||||
<policy>
|
||||
<policyOIDReference>0</policyOIDReference>
|
||||
<cAs xsi:nil="true" />
|
||||
<attributes>
|
||||
<commonName>CEPUnitTest</commonName>
|
||||
<policySchema>3</policySchema>
|
||||
<certificateValidity>
|
||||
<validityPeriodSeconds>1209600</validityPeriodSeconds>
|
||||
<renewalPeriodSeconds>172800</renewalPeriodSeconds>
|
||||
</certificateValidity>
|
||||
<permission>
|
||||
<enroll>true</enroll>
|
||||
<autoEnroll>false</autoEnroll>
|
||||
</permission>
|
||||
<privateKeyAttributes>
|
||||
<minimalKeyLength>2048</minimalKeyLength>
|
||||
<keySpec xsi:nil="true" />
|
||||
<keyUsageProperty xsi:nil="true" />
|
||||
<permissions xsi:nil="true" />
|
||||
<algorithmOIDReference xsi:nil="true" />
|
||||
<cryptoProviders xsi:nil="true" />
|
||||
</privateKeyAttributes>
|
||||
<revision>
|
||||
<majorRevision>101</majorRevision>
|
||||
<minorRevision>0</minorRevision>
|
||||
</revision>
|
||||
<supersededPolicies xsi:nil="true" />
|
||||
<privateKeyFlags xsi:nil="true" />
|
||||
<subjectNameFlags xsi:nil="true" />
|
||||
<enrollmentFlags xsi:nil="true" />
|
||||
<generalFlags xsi:nil="true" />
|
||||
<hashAlgorithmOIDReference>0</hashAlgorithmOIDReference>
|
||||
<rARequirements xsi:nil="true" />
|
||||
<keyArchivalAttributes xsi:nil="true" />
|
||||
<extensions xsi:nil="true" />
|
||||
</attributes>
|
||||
</policy>
|
||||
</policies>
|
||||
</response>
|
||||
<oIDs>
|
||||
<oID>
|
||||
<value>1.3.14.3.2.29</value>
|
||||
<group>1</group>
|
||||
<oIDReferenceID>0</oIDReferenceID>
|
||||
<defaultName> szOID_NIST_sha256</defaultName>
|
||||
</oID>
|
||||
</oIDs>
|
||||
</GetPoliciesResponse>
|
||||
</s:Body>
|
||||
</s:Envelope>`)
|
||||
|
||||
// Return response body
|
||||
w.Header().Set("Content-Type", "application/soap+xml; charset=utf-8")
|
||||
w.Header().Set("Content-Length", strconv.Itoa(len(response)))
|
||||
w.Write(response)
|
||||
}
|
||||
|
|
@ -1,311 +0,0 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"encoding/xml"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// SyncML XML Parsing Types - This needs to be improved
|
||||
type SyncMLHeader struct {
|
||||
DTD string `xml:"VerDTD"`
|
||||
Version string `xml:"VerProto"`
|
||||
SessionID int `xml:"SessionID"`
|
||||
MsgID int `xml:"MsgID"`
|
||||
Target string `xml:"Target>LocURI"`
|
||||
Source string `xml:"Source>LocURI"`
|
||||
MaxMsgSize int `xml:"Meta>A:MaxMsgSize"`
|
||||
}
|
||||
|
||||
type SyncMLCommandMeta struct {
|
||||
XMLinfo string `xml:"xmlns,attr"`
|
||||
Type string `xml:"Type"`
|
||||
}
|
||||
|
||||
type SyncMLCommandItem struct {
|
||||
Meta SyncMLCommandMeta `xml:"Meta"`
|
||||
Source string `xml:"Source>LocURI"`
|
||||
Data string `xml:"Data"`
|
||||
}
|
||||
|
||||
type SyncMLCommand struct {
|
||||
XMLName xml.Name
|
||||
CmdID int `xml:",omitempty"`
|
||||
MsgRef string `xml:",omitempty"`
|
||||
CmdRef string `xml:",omitempty"`
|
||||
Cmd string `xml:",omitempty"`
|
||||
Target string `xml:"Target>LocURI"`
|
||||
Source string `xml:"Source>LocURI"`
|
||||
Data string `xml:",omitempty"`
|
||||
Item []SyncMLCommandItem `xml:",any"`
|
||||
}
|
||||
|
||||
type SyncMLBody struct {
|
||||
Item []SyncMLCommand `xml:",any"`
|
||||
}
|
||||
|
||||
type SyncMLMessage struct {
|
||||
XMLinfo string `xml:"xmlns,attr"`
|
||||
Header SyncMLHeader `xml:"SyncHdr"`
|
||||
Body SyncMLBody `xml:"SyncBody"`
|
||||
}
|
||||
|
||||
// Returns the MDM configuration profile SyncML content from profile dir
|
||||
func getConfigurationProfiles(cmdIDstart int) string {
|
||||
|
||||
files, err := ioutil.ReadDir(profileDir)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
var syncmlCommands string
|
||||
var tokenCmdID string = "xxcmdidxx"
|
||||
|
||||
for _, file := range files {
|
||||
fileContent, err := os.ReadFile(profileDir + "/" + file.Name())
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
fileContentStr := string(fileContent)
|
||||
nrTokenOcurrences := strings.Count(fileContentStr, tokenCmdID)
|
||||
for i := 0; i < nrTokenOcurrences; i++ {
|
||||
cmdIDstart++
|
||||
|
||||
fmt.Printf("\n--------- Command Request %d ---------\n", cmdIDstart)
|
||||
fmt.Printf("Command payload retrieved from file %s\n", file.Name())
|
||||
|
||||
fileContentStr = strings.Replace(fileContentStr, tokenCmdID, strconv.Itoa(cmdIDstart), 1)
|
||||
}
|
||||
|
||||
if len(fileContentStr) > 0 {
|
||||
syncmlCommands += fileContentStr
|
||||
syncmlCommands += "\n"
|
||||
}
|
||||
}
|
||||
|
||||
//input sanitization
|
||||
sanitizedSyncmlOutput := strings.ReplaceAll(syncmlCommands, "\r\n", "\n")
|
||||
if len(sanitizedSyncmlOutput) > 0 {
|
||||
fmt.Print("\n")
|
||||
}
|
||||
return sanitizedSyncmlOutput
|
||||
}
|
||||
|
||||
// Alert Command IDs
|
||||
const DeviceUnenrollmentID = "1226"
|
||||
const HostInitMessageID = "1201"
|
||||
|
||||
// Checks if body contains a DM device unrollment SyncML message
|
||||
func isDeviceUnenrollmentMessage(body SyncMLBody) bool {
|
||||
for _, element := range body.Item {
|
||||
if element.Data == DeviceUnenrollmentID {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// Checks if body contains a DM session initialization SyncML message sent by device
|
||||
func isSessionInitializationMessage(body SyncMLBody) bool {
|
||||
isUnenrollMessage := isDeviceUnenrollmentMessage(body)
|
||||
|
||||
for _, element := range body.Item {
|
||||
if element.Data == HostInitMessageID && !isUnenrollMessage {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// Get IP address from HTTP Request
|
||||
func getIP(r *http.Request) (string, error) {
|
||||
|
||||
//Get IP from the X-REAL-IP header
|
||||
ip := r.Header.Get("X-REAL-IP")
|
||||
netIP := net.ParseIP(ip)
|
||||
if netIP != nil {
|
||||
return ip, nil
|
||||
}
|
||||
|
||||
//Get IP from X-FORWARDED-FOR header
|
||||
ips := r.Header.Get("X-FORWARDED-FOR")
|
||||
splitIps := strings.Split(ips, ",")
|
||||
for _, ip := range splitIps {
|
||||
netIP := net.ParseIP(ip)
|
||||
if netIP != nil {
|
||||
return ip, nil
|
||||
}
|
||||
}
|
||||
|
||||
//Get IP from RemoteAddr
|
||||
ip, _, err := net.SplitHostPort(r.RemoteAddr)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
netIP = net.ParseIP(ip)
|
||||
if netIP != nil {
|
||||
return ip, nil
|
||||
}
|
||||
return "", fmt.Errorf("no valid ip found")
|
||||
}
|
||||
|
||||
// ManageHandler is the HTTP handler assosiated with the mdm management service. This is what constantly pushes configuration profiles to the device.
|
||||
func ManageHandler(w http.ResponseWriter, r *http.Request) {
|
||||
// Read The HTTP Request body
|
||||
bodyRaw, err := ioutil.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
var responseRaw []byte
|
||||
var response string
|
||||
var message SyncMLMessage
|
||||
|
||||
//Parsing input SyncML message
|
||||
if err := xml.Unmarshal(bodyRaw, &message); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// Cmd ID variable with getNextCmdID() increment statement hack
|
||||
CmdID := 0
|
||||
getNextCmdID := func(i *int) string { *i++; return strconv.Itoa(*i) }
|
||||
|
||||
// Retrieve the MessageID From The Body For The Response
|
||||
DeviceID := message.Header.Source
|
||||
|
||||
// Retrieve the SessionID From The Body For The Response
|
||||
SessionID := message.Header.SessionID
|
||||
|
||||
// Retrieve the MsgID From The Body For The Response
|
||||
MsgID := message.Header.MsgID
|
||||
|
||||
//Only handle DM session initialization SyncML message sent by device
|
||||
|
||||
// Retrieve the IP Address from calling device
|
||||
ipAddressBytes, err := getIP(r)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
//Checking the SyncML message types
|
||||
if isSessionInitializationMessage(message.Body) {
|
||||
|
||||
fmt.Printf("\n========= New OMA-DM session from Windows Host %s (%s) =========\n", string(ipAddressBytes), r.UserAgent())
|
||||
|
||||
// Create response payload - MDM syncml configuration profiles commands will be enforced here
|
||||
response = `
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<SyncML xmlns="SYNCML:SYNCML1.2">
|
||||
<SyncHdr>
|
||||
<VerDTD>1.2</VerDTD>
|
||||
<VerProto>DM/1.2</VerProto>
|
||||
<SessionID>` + strconv.Itoa(SessionID) + `</SessionID>
|
||||
<MsgID>` + strconv.Itoa(MsgID) + `</MsgID>
|
||||
<Target>
|
||||
<LocURI>` + DeviceID + `</LocURI>
|
||||
</Target>
|
||||
<Source>
|
||||
<LocURI>https://` + domain + `/ManagementServer/MDM.svc</LocURI>
|
||||
</Source>
|
||||
</SyncHdr>
|
||||
<SyncBody>
|
||||
<Status>
|
||||
<CmdID>` + getNextCmdID(&CmdID) + `</CmdID>
|
||||
<MsgRef>` + strconv.Itoa(MsgID) + `</MsgRef>
|
||||
<CmdRef>0</CmdRef>
|
||||
<Cmd>SyncHdr</Cmd>
|
||||
<Data>200</Data>
|
||||
</Status>
|
||||
<Status>
|
||||
<CmdID>` + getNextCmdID(&CmdID) + `</CmdID>
|
||||
<MsgRef>` + strconv.Itoa(MsgID) + `</MsgRef>
|
||||
<CmdRef>2</CmdRef>
|
||||
<Cmd>Alert</Cmd>
|
||||
<Data>200</Data>
|
||||
</Status>
|
||||
<Status>
|
||||
<CmdID>` + getNextCmdID(&CmdID) + `</CmdID>
|
||||
<MsgRef>` + strconv.Itoa(MsgID) + `</MsgRef>
|
||||
<CmdRef>3</CmdRef>
|
||||
<Cmd>Alert</Cmd>
|
||||
<Data>200</Data>
|
||||
</Status>
|
||||
<Status>
|
||||
<CmdID>` + getNextCmdID(&CmdID) + `</CmdID>
|
||||
<MsgRef>` + strconv.Itoa(MsgID) + `</MsgRef>
|
||||
<CmdRef>4</CmdRef>
|
||||
<Cmd>Replace</Cmd>
|
||||
<Data>200</Data>
|
||||
</Status>
|
||||
` + getConfigurationProfiles(CmdID) + `
|
||||
<Final />
|
||||
</SyncBody>
|
||||
</SyncML>`
|
||||
|
||||
// Return response
|
||||
responseRaw = []byte(strings.ReplaceAll(strings.ReplaceAll(response, "\n", ""), "\t", ""))
|
||||
w.Header().Set("Content-Type", "application/vnd.syncml.dm+xml")
|
||||
w.Header().Set("Content-Length", strconv.Itoa(len(response)))
|
||||
w.Write(responseRaw)
|
||||
} else {
|
||||
|
||||
//Log if this is a device unrollment message
|
||||
if isDeviceUnenrollmentMessage(message.Body) {
|
||||
fmt.Printf("\nWindows Device at %s was removed from MDM!\n\n", string(ipAddressBytes))
|
||||
}
|
||||
|
||||
//Acknowledge the HTTP request sent by device
|
||||
response = `
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<SyncML xmlns="SYNCML:SYNCML1.2">
|
||||
<SyncHdr>
|
||||
<VerDTD>1.2</VerDTD>
|
||||
<VerProto>DM/1.2</VerProto>
|
||||
<SessionID>` + strconv.Itoa(SessionID) + `</SessionID>
|
||||
<MsgID>` + strconv.Itoa(MsgID) + `</MsgID>
|
||||
<Target>
|
||||
<LocURI>` + DeviceID + `</LocURI>
|
||||
</Target>
|
||||
<Source>
|
||||
<LocURI>https://` + domain + `/ManagementServer/MDM.svc</LocURI>
|
||||
</Source>
|
||||
</SyncHdr>
|
||||
<SyncBody>
|
||||
<Status>
|
||||
<CmdID>` + getNextCmdID(&CmdID) + `</CmdID>
|
||||
<MsgRef>` + strconv.Itoa(MsgID) + `</MsgRef>
|
||||
<CmdRef>0</CmdRef>
|
||||
<Cmd>SyncHdr</Cmd>
|
||||
<Data>200</Data>
|
||||
</Status>
|
||||
<Final />
|
||||
</SyncBody>
|
||||
</SyncML>`
|
||||
|
||||
// Dump Response Payload
|
||||
for _, element := range message.Body.Item {
|
||||
if element.XMLName.Local != "Final" && element.Cmd != "SyncHdr" {
|
||||
commandStr, _ := xml.MarshalIndent(element, "", " ")
|
||||
if element.XMLName.Local == "Status" {
|
||||
fmt.Printf("\n--------- Command Response %s - Return Code: %s ---------\n", element.CmdRef, element.Data)
|
||||
} else {
|
||||
fmt.Printf("%s\n", commandStr)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Return response body
|
||||
responseRaw = []byte(strings.ReplaceAll(strings.ReplaceAll(response, "\n", ""), "\t", ""))
|
||||
w.Header().Set("Content-Type", "application/vnd.syncml.dm+xml")
|
||||
w.Header().Set("Content-Length", strconv.Itoa(len(response)))
|
||||
w.Write(responseRaw)
|
||||
}
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
|
|
@ -1,62 +0,0 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"os"
|
||||
"path"
|
||||
)
|
||||
|
||||
var (
|
||||
sourceFilePath = path.Join(os.Getenv("GOROOT"), "src", "encoding", "asn1", "asn1.go")
|
||||
patchedFilePath = path.Join(os.Getenv("GOROOT"), "src", "encoding", "asn1", "asn1-patched.go")
|
||||
)
|
||||
|
||||
func main() {
|
||||
// Check for the GOROOT env varible. Should be set by Go automatically
|
||||
if os.Getenv("GOROOT") == "" {
|
||||
panic("Plese set your GOROOT path")
|
||||
}
|
||||
|
||||
// Load The file and create a scanner
|
||||
file, err := os.Open(sourceFilePath)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
scanner := bufio.NewScanner(file)
|
||||
|
||||
// Open Output File
|
||||
out, err2 := os.Create(patchedFilePath)
|
||||
if err2 != nil {
|
||||
panic(err2)
|
||||
}
|
||||
|
||||
// Loop of each line of the file checking it
|
||||
for scanner.Scan() {
|
||||
out.Write(scanner.Bytes())
|
||||
out.Write([]byte("\n"))
|
||||
|
||||
if scanner.Text() == " b == '?' ||" {
|
||||
scanner.Scan()
|
||||
if scanner.Text() != " b == '!' || // Windows MDM Certificate Parsing Patch" {
|
||||
out.Write([]byte(" b == '!' || // Windows MDM Certificate Parsing Patch\n"))
|
||||
out.Write([]byte(" b == 0 || // Windows MDM Certificate Parsing Patch\n"))
|
||||
}
|
||||
|
||||
out.Write(scanner.Bytes())
|
||||
out.Write([]byte("\n"))
|
||||
}
|
||||
}
|
||||
|
||||
// Close writters
|
||||
file.Close()
|
||||
out.Close()
|
||||
|
||||
// Replace the main file with the patched one
|
||||
if err := os.Rename(patchedFilePath, sourceFilePath); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// Success
|
||||
fmt.Println("Patch Applied To Your Go Sources! Please be carefull with the certs you are loading as they could cause undesired outcomes in the future.")
|
||||
}
|
||||
|
|
@ -1,13 +0,0 @@
|
|||
<Replace>
|
||||
<CmdID>xxcmdidxx</CmdID>
|
||||
<Item>
|
||||
<Target>
|
||||
<LocURI>./Vendor/MSFT/Personalization/DesktopImageUrl</LocURI>
|
||||
</Target>
|
||||
<Meta>
|
||||
<Format xmlns="syncml:metinf">chr</Format>
|
||||
<Type>text/plain</Type>
|
||||
</Meta>
|
||||
<Data>https://fleetdm.com/images/articles/fleet-4.24.0-cover-1600x900@2x.jpg</Data>
|
||||
</Item>
|
||||
</Replace>
|
||||
|
|
@ -1,24 +0,0 @@
|
|||
<Atomic>
|
||||
<CmdID>7</CmdID>
|
||||
<Add>
|
||||
<CmdID>5</CmdID>
|
||||
<Item>
|
||||
<Target>
|
||||
<LocURI>./Device/Vendor/MSFT/EnterpriseDesktopAppManagement/MSI/%7B90413BF7-7D99-482E-A7FB-C6616CC871FC%7D/DownloadInstall</LocURI>
|
||||
</Target>
|
||||
</Item>
|
||||
</Add>
|
||||
<Exec>
|
||||
<CmdID>6</CmdID>
|
||||
<Item>
|
||||
<Target>
|
||||
<LocURI>./Device/Vendor/MSFT/EnterpriseDesktopAppManagement/MSI/%7B90413BF7-7D99-482E-A7FB-C6616CC871FC%7D/DownloadInstall</LocURI>
|
||||
</Target>
|
||||
<Meta>
|
||||
<A:Format>xml</A:Format>
|
||||
<A:Type>text/plain</A:Type>
|
||||
</Meta>
|
||||
<Data><MsiInstallJob id="{90413BF7-7D99-482E-A7FB-C6616CC871FC}"><Product Version="1.4.0"><Download><ContentURLList><ContentURL>https://mdmwindows.com/static/fleet-osquery.msi</ContentURL></ContentURLList></Download><Validation><FileHash>3B9FD63248465A51500D41DECC794D1149506EB48EEF9D7A733516B482D16ABB</FileHash></Validation><Enforcement><CommandLine>/quiet</CommandLine><RetryCount>5</RetryCount><RetryInterval>3</RetryInterval></Enforcement></Product></MsiInstallJob></Data>
|
||||
</Item>
|
||||
</Exec>
|
||||
</Atomic>
|
||||
|
|
@ -1,13 +0,0 @@
|
|||
<Add>
|
||||
<CmdID>xxcmdidxx</CmdID>
|
||||
<Item>
|
||||
<Target>
|
||||
<LocURI>./Device/Vendor/MSFT/Policy/Config/Settings/AllowDateTime</LocURI>
|
||||
</Target>
|
||||
<Meta>
|
||||
<A:Format>int</A:Format>
|
||||
<A:Type>text/plain</A:Type>
|
||||
</Meta>
|
||||
<Data>0</Data>
|
||||
</Item>
|
||||
</Add>
|
||||
|
|
@ -1,13 +0,0 @@
|
|||
<Add>
|
||||
<CmdID>xxcmdidxx</CmdID>
|
||||
<Item>
|
||||
<Target>
|
||||
<LocURI>./Device/Vendor/MSFT/Policy/Config/Defender/AllowRealtimeMonitoring</LocURI>
|
||||
</Target>
|
||||
<Meta>
|
||||
<A:Format>int</A:Format>
|
||||
<A:Type>text/plain</A:Type>
|
||||
</Meta>
|
||||
<Data>0</Data>
|
||||
</Item>
|
||||
</Add>
|
||||
|
|
@ -1,13 +0,0 @@
|
|||
<Add>
|
||||
<CmdID>xxcmdidxx</CmdID>
|
||||
<Item>
|
||||
<Target>
|
||||
<LocURI>./Vendor/MSFT/Firewall/MdmStore/PrivateProfile/EnableFirewall</LocURI>
|
||||
</Target>
|
||||
<Meta>
|
||||
<A:Format>bool</A:Format>
|
||||
<A:Type>text/plain</A:Type>
|
||||
</Meta>
|
||||
<Data>false</Data>
|
||||
</Item>
|
||||
</Add>
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
<Get>
|
||||
<CmdID>xxcmdidxx</CmdID>
|
||||
<Item>
|
||||
<Target>
|
||||
<LocURI>./Vendor/MSFT/CertificateStore/Root/System?list=StructData</LocURI>
|
||||
</Target>
|
||||
</Item>
|
||||
</Get>
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
<Get>
|
||||
<CmdID>xxcmdidxx</CmdID>
|
||||
<Item>
|
||||
<Target>
|
||||
<LocURI>./Device/Vendor/MSFT/DeviceManageability/Capabilities/CSPVersions</LocURI>
|
||||
</Target>
|
||||
</Item>
|
||||
</Get>
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
<Get>
|
||||
<CmdID>xxcmdidxx</CmdID>
|
||||
<Item>
|
||||
<Target>
|
||||
<LocURI>./DevDetail/Ext/Microsoft/DeviceName</LocURI>
|
||||
</Target>
|
||||
</Item>
|
||||
</Get>
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
<Get>
|
||||
<CmdID>xxcmdidxx</CmdID>
|
||||
<Item>
|
||||
<Target>
|
||||
<LocURI>./DevDetail/HwV</LocURI>
|
||||
</Target>
|
||||
</Item>
|
||||
</Get>
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
<Get>
|
||||
<CmdID>xxcmdidxx</CmdID>
|
||||
<Item>
|
||||
<Target>
|
||||
<LocURI>./DevDetail/Ext/Microsoft/LocalTime</LocURI>
|
||||
</Target>
|
||||
</Item>
|
||||
</Get>
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
<Get>
|
||||
<CmdID>xxcmdidxx</CmdID>
|
||||
<Item>
|
||||
<Target>
|
||||
<LocURI>./DevDetail/Ext/Microsoft/OSPlatform</LocURI>
|
||||
</Target>
|
||||
</Item>
|
||||
</Get>
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
<Get>
|
||||
<CmdID>xxcmdidxx</CmdID>
|
||||
<Item>
|
||||
<Target>
|
||||
<LocURI>./DevDetail/SwV</LocURI>
|
||||
</Target>
|
||||
</Item>
|
||||
</Get>
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
<Get>
|
||||
<CmdID>xxcmdidxx</CmdID>
|
||||
<Item>
|
||||
<Target>
|
||||
<LocURI>./DevDetail/Ext/Microsoft/TotalStorage</LocURI>
|
||||
</Target>
|
||||
</Item>
|
||||
</Get>
|
||||
|
|
@ -1,38 +0,0 @@
|
|||
<Add>
|
||||
<CmdID>xxcmdidxx</CmdID>
|
||||
<Item>
|
||||
<Target>
|
||||
<LocURI>./Device/Vendor/MSFT/EnterpriseDesktopAppManagement/MSI/%7B90413bf7-7d99-482e-a7fb-c6616cc871fc%7D/DownloadInstall</LocURI>
|
||||
</Target>
|
||||
</Item>
|
||||
</Add>
|
||||
<Exec>
|
||||
<CmdID>xxcmdidxx</CmdID>
|
||||
<Item>
|
||||
<Target>
|
||||
<LocURI>./Device/Vendor/MSFT/EnterpriseDesktopAppManagement/MSI/%7B90413bf7-7d99-482e-a7fb-c6616cc871fc%7D/DownloadInstall</LocURI>
|
||||
</Target>
|
||||
<Data><MsiInstallJob id="{90413bf7-7d99-482e-a7fb-c6616cc871fc}">
|
||||
<Product Version="1.0.0.0">
|
||||
<Download>
|
||||
<ContentURLList>
|
||||
<ContentURL>https://mdmwindows.com/static/fleet-osquery.msi</ContentURL>
|
||||
</ContentURLList>
|
||||
</Download>
|
||||
<Validation>
|
||||
<FileHash>3B9FD63248465A51500D41DECC794D1149506EB48EEF9D7A733516B482D16ABB</FileHash>
|
||||
</Validation>
|
||||
<Enforcement>
|
||||
<CommandLine>/quiet</CommandLine>
|
||||
<TimeOut>10</TimeOut>
|
||||
<RetryCount>1</RetryCount>
|
||||
<RetryInterval>5</RetryInterval>
|
||||
</Enforcement>
|
||||
</Product>
|
||||
</MsiInstallJob></Data>
|
||||
<Meta>
|
||||
<Type xmlns="syncml:metinf">text/plain</Type>
|
||||
<Format xmlns="syncml:metinf">xml</Format>
|
||||
</Meta>
|
||||
</Item>
|
||||
</Exec>
|
||||
|
|
@ -1,13 +0,0 @@
|
|||
<Replace>
|
||||
<CmdID>xxcmdidxx</CmdID>
|
||||
<Item>
|
||||
<Target>
|
||||
<LocURI>./Vendor/MSFT/Personalization/DesktopImageUrl</LocURI>
|
||||
</Target>
|
||||
<Meta>
|
||||
<Format xmlns="syncml:metinf">chr</Format>
|
||||
<Type>text/plain</Type>
|
||||
</Meta>
|
||||
<Data>https://fleetdm.com/images/articles/fleet-4.24.0-cover-1600x900@2x.jpg</Data>
|
||||
</Item>
|
||||
</Replace>
|
||||
|
|
@ -1,13 +0,0 @@
|
|||
<Replace>
|
||||
<CmdID>xxcmdidxx</CmdID>
|
||||
<Item>
|
||||
<Target>
|
||||
<LocURI>./Vendor/MSFT/Personalization/LockScreenImageUrl</LocURI>
|
||||
</Target>
|
||||
<Meta>
|
||||
<Format xmlns="syncml:metinf">chr</Format>
|
||||
<Type>text/plain</Type>
|
||||
</Meta>
|
||||
<Data>https://fleetdm.com/images/articles/fleet-4.24.0-cover-1600x900@2x.jpg</Data>
|
||||
</Item>
|
||||
</Replace>
|
||||
|
|
@ -1 +0,0 @@
|
|||
world
|
||||
Loading…
Reference in a new issue