Skip to content

Commit 92d7fa6

Browse files
committed
Initial commit.
0 parents  commit 92d7fa6

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

63 files changed

+5272
-0
lines changed

.gitignore

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
# Binaries for programs and plugins
2+
*.exe
3+
*.exe~
4+
*.dll
5+
*.so
6+
*.dylib
7+
8+
.vscode/
9+
/bin
10+
.token
11+
.token-mailsend
12+
.token-azure
13+
14+
./ropci
15+
ropci
16+
ropci.exe
17+
ropci-mac
18+
.ropci.yaml
19+
users.list
20+
passwords.list
21+
22+
# Test binary, built with `go test -c`
23+
*.test
24+
25+
# Output of the go coverage tool, specifically when used with LiteIDE
26+
*.out
27+
28+
# Dependency directories (remove the comment below to include it)
29+
# vendor/

LICENSE

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
The MIT License (MIT)
2+
3+
Copyright © 2022 The ropci authors.
4+
5+
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:
6+
7+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
8+
9+
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.

README.md

Lines changed: 586 additions & 0 deletions
Large diffs are not rendered by default.

build.sh

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
#!/bin/sh
2+
3+
echo "Building"
4+
5+
6+
ver=$(git describe --tags)
7+
echo "Latest tag/version: $ver"
8+
9+
10+
echo "Preparing bin folder"
11+
rm -r ./bin
12+
13+
echo "Creating bin folders for various platforms"
14+
15+
mkdir -p ./bin/windows
16+
mkdir -p ./bin/linux
17+
mkdir -p ./bin/darwin
18+
19+
20+
echo "Building things"
21+
22+
GOOS=linux GOARCH=amd64 go build -ldflags "-s -w -X 'ropci/cmd.VersionInfo=$(git rev-parse HEAD)'" -o bin/linux/ropci main.go
23+
GOOS=windows GOARCH=amd64 go build -ldflags "-s -w -X 'ropci/cmd.VersionInfo=$(git rev-parse HEAD)'" -o bin/windows/ropci.exe main.go
24+
GOOS=darwin GOARCH=amd64 go build -ldflags "-s -w -X 'ropci/cmd.VersionInfo=$(git rev-parse HEAD)'" -o bin/darwin/ropci main.go
25+
26+
echo "Copying templates"
27+
28+
cp -r ./templates ./bin/windows
29+
cp -r ./templates ./bin/linux
30+
cp -r ./templates ./bin/darwin
31+
32+
echo "Zipping packages"
33+
34+
cd bin
35+
cd windows && zip ../ropci-windows-$ver.zip -r * && cd ..
36+
cd darwin && zip ../ropci-darwin-$ver.zip -r * && cd ..
37+
cd linux && zip ../ropci-linux-$ver.zip -r * && cd ..
38+
cd ..
39+
pwd
40+
echo "Done"
41+

clientids

Lines changed: 500 additions & 0 deletions
Large diffs are not rendered by default.

cmd/apps.go

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
/*
2+
Copyright © 2022 WUNDERWUZZI23
3+
*/
4+
package cmd
5+
6+
import (
7+
"ropci/utils"
8+
9+
"github.com/spf13/cobra"
10+
)
11+
12+
var appsSelectFields []string
13+
14+
// appsCmd represents the apps command
15+
var appsCmd = &cobra.Command{
16+
Use: "apps",
17+
Short: "List all the apps/clientids (servicePrincipals) available in the tenant",
18+
Long: `This command can be used to retrieve clientids for testing to check if one can perform ROPC grants on them.`,
19+
Run: func(cmd *cobra.Command, args []string) {
20+
21+
processViper()
22+
23+
utils.DoRequest(mainClient,
24+
rootGraphUri,
25+
"", //api-version not needed for Graph API
26+
"servicePrincipals",
27+
rootOutputFormat,
28+
rootOutputFilename,
29+
appsSelectFields,
30+
"", //search
31+
rootShowAll,
32+
callBody)
33+
},
34+
}
35+
36+
// type appsCmdFlags struct {
37+
// outputFilename string
38+
// selectFields []string
39+
// }
40+
41+
func init() {
42+
rootCmd.AddCommand(appsCmd)
43+
44+
appsCmd.Flags().StringVarP(&rootOutputFilename, "output", "o", "", "writing results to this json file")
45+
appsCmd.Flags().StringArrayVarP(&appsSelectFields, "fields", "f", []string{"displayName", "appId", "publisherName"}, "fields to select")
46+
}

cmd/auth.go

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
/*
2+
Copyright © 2022 wunderwuzzi23
3+
*/
4+
package cmd
5+
6+
import (
7+
"ropci/models"
8+
"sync"
9+
10+
"github.com/spf13/cobra"
11+
"github.com/spf13/pflag"
12+
"github.com/spf13/viper"
13+
)
14+
15+
var (
16+
authTenant string
17+
authClientID string
18+
authClientSecret string
19+
authUsername string
20+
authPassword string
21+
authScopes []string
22+
authDisplayName string
23+
authEnterPassword bool
24+
)
25+
26+
// authCmd represents the auth command
27+
var authCmd = &cobra.Command{
28+
Use: "auth",
29+
Short: "Authenticate to AAD using ROPC",
30+
Long: `Provide username, password and clientid.`,
31+
Run: func(cmd *cobra.Command, args []string) {
32+
cmd.Help()
33+
},
34+
}
35+
36+
func init() {
37+
rootCmd.AddCommand(authCmd)
38+
39+
authCmd.PersistentFlags().StringP("tenant", "t", "", "AAD Tenant name or ID")
40+
authCmd.PersistentFlags().StringP("username", "u", "", "Username for tenant")
41+
authCmd.PersistentFlags().StringP("password", "p", "", "Password for user")
42+
authCmd.PersistentFlags().StringP("clientid", "c", "d3590ed6-52b3-4102-aeff-aad2292ab01c", "ClientID")
43+
authCmd.PersistentFlags().StringP("clientsecret", "s", "", "optional (not needed for basic tests)")
44+
authCmd.PersistentFlags().StringSliceP("scope", "S", []string{"openid", "offline_access"}, "Requested scopes")
45+
authCmd.PersistentFlags().BoolP("enter-password", "P", false, "Prompt for password")
46+
47+
//authCmd.MarkPersistentFlagRequired("tenant")
48+
viper.BindPFlags(authCmd.PersistentFlags())
49+
50+
authCmd.Flags().VisitAll(func(flag *pflag.Flag) {
51+
if viper.IsSet(flag.Name) && viper.GetString(flag.Name) != "" {
52+
authCmd.PersistentFlags().Set(flag.Name, viper.GetString(flag.Name))
53+
authCmd.PersistentFlags().SetAnnotation(flag.Name, cobra.BashCompOneRequiredFlag, []string{"false"})
54+
}
55+
})
56+
57+
}
58+
59+
type authLogonResult struct {
60+
wg *sync.WaitGroup
61+
Token *models.Token
62+
Conf *models.OAuth2Config
63+
}

cmd/authBulk.go

Lines changed: 169 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,169 @@
1+
/*
2+
Copyright © 2022 wunderwuzzi23
3+
*/
4+
package cmd
5+
6+
import (
7+
"encoding/csv"
8+
"encoding/json"
9+
"fmt"
10+
"os"
11+
"ropci/models"
12+
"ropci/utils"
13+
"strings"
14+
15+
"github.com/olekukonko/tablewriter"
16+
"github.com/spf13/cobra"
17+
)
18+
19+
var (
20+
bulkInputfile string
21+
bulkOutputfile string
22+
)
23+
24+
// authBulkCmd represents the bulk command
25+
var authBulkCmd = &cobra.Command{
26+
Use: "bulk",
27+
Short: "Bulk validation of access to clientids via ROPC",
28+
Long: `Allows to highlight OAuth apps that might allow elevation or MFA bypass opportunities.`,
29+
Run: func(cmd *cobra.Command, args []string) {
30+
31+
processViper()
32+
33+
// inputfile = viper.GetString("inputfile")
34+
// outputfile = viper.GetString("outputfile")
35+
36+
fmt.Printf("ClientIDs from CSV file %s.\n", bulkInputfile)
37+
fmt.Printf("Results will be written to %s.\n\n", bulkOutputfile)
38+
39+
validateClientIDs(bulkInputfile, bulkOutputfile)
40+
},
41+
}
42+
43+
func init() {
44+
authCmd.AddCommand(authBulkCmd)
45+
46+
authBulkCmd.Flags().StringVarP(&bulkInputfile, "inputfile", "i", "clients.csv", "CSV file with Displayname,ClientID, ClientSecret(optional)")
47+
authBulkCmd.Flags().StringVarP(&bulkOutputfile, "outputfile", "o", "results.json", "File with the authentication results)")
48+
49+
authBulkCmd.MarkFlagRequired("inputfile")
50+
authBulkCmd.MarkFlagRequired("outputfile")
51+
}
52+
53+
func validateClientIDs(clientidsCSVFile string, outputfile string) {
54+
55+
//Create Result file
56+
outfile, err := os.OpenFile(outputfile, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0640)
57+
if err != nil {
58+
fmt.Println(err)
59+
panic(err)
60+
}
61+
defer outfile.Close()
62+
63+
tokch := make(chan authLogonResult, 20) // create a channel
64+
65+
//simple wait group
66+
count := 0
67+
68+
file, err := os.Open(clientidsCSVFile)
69+
if err != nil {
70+
fmt.Println("*** Error opening file", err)
71+
}
72+
defer file.Close()
73+
74+
csvLines, err := csv.NewReader(file).ReadAll()
75+
if err != nil {
76+
fmt.Println(err)
77+
}
78+
for _, line := range csvLines {
79+
80+
// for _, line := range utils.ReadFileAsStringArray(clientidsCSVFile) {
81+
//comp := strings.Split(line, ",")
82+
if len(line) < 2 {
83+
fmt.Println("*** Error: Incorrect csv format. Need DisplayName,ClientID.")
84+
return
85+
}
86+
87+
authDisplayName := line[0]
88+
authClientID := line[1]
89+
authClientSecret := ""
90+
// if len(line) > 2 { //secret is most likely not included (also not needed)
91+
// authClientSecret = line[2]
92+
// }
93+
94+
conf := &models.OAuth2Config{
95+
Username: authUsername,
96+
Password: authPassword,
97+
ClientID: authClientID,
98+
ClientSecret: authClientSecret,
99+
Scopes: authScopes,
100+
TokenEndpoint: utils.GetAzureTokenEndpoint(authTenant),
101+
}
102+
103+
//go ropcAuthenticate(tokch, conf, "")
104+
go logon(tokch, conf, authDisplayName)
105+
106+
//go ropcAuthenticate(tokch, conf, authDisplayName)
107+
//go logon(tokch, conf, authDisplayName)
108+
109+
count++
110+
111+
if count%20 == 0 {
112+
fmt.Printf("\033[2K\rIssuing Requests...~%d", count)
113+
}
114+
}
115+
116+
table := tablewriter.NewWriter(os.Stdout)
117+
table.SetAutoWrapText(true)
118+
table.SetAutoFormatHeaders(false)
119+
table.SetHeader([]string{"displayName", "appId", "result", "scope"})
120+
121+
fmt.Println("\nWaiting for results...")
122+
123+
//collect results
124+
for i := 0; i < count; i++ {
125+
result := <-tokch
126+
t := result.Token
127+
128+
//Authenticate
129+
//t, err := ropcAuthenticate(conf, displayName)
130+
if t.Error != "" {
131+
132+
table.Append([]string{t.DisplayName, t.ClientID, "error", ""})
133+
//fmt.Printf("%s, %s, %s\n", t.DisplayName, t.ClientID, "Error")
134+
//t.Error = err.Error()
135+
136+
line, err := json.MarshalIndent(t, "", " ")
137+
if err != nil {
138+
fmt.Println("*** Error: Marshal ", err)
139+
}
140+
141+
c, err := outfile.WriteString(string(line))
142+
if err != nil {
143+
fmt.Printf("*** Error: outfile %v,%v\n\n", c, err)
144+
}
145+
146+
continue
147+
}
148+
149+
s := strings.Replace(t.Scope, "00000003-0000-0000-c000-000000000000/", "", -1)
150+
// s = strings.Replace(s, " ", "\n", -1)
151+
152+
if utils.Verbose {
153+
table.Append([]string{t.DisplayName, t.ClientID, "success", s, t.AccessToken})
154+
} else {
155+
table.Append([]string{t.DisplayName, t.ClientID, "success", s})
156+
}
157+
158+
line, _ := json.Marshal(t)
159+
outfile.WriteString(string(line))
160+
}
161+
162+
table.Render()
163+
164+
fmt.Println("\nDone. ")
165+
fmt.Printf(`You could now run the following command to analyze valid tokens and there scopes:
166+
$ cat %s | jq -r 'select (.access_token!="") | [.display_name,.scope] | @csv'`, outputfile)
167+
fmt.Println("\nHappy Hacking.")
168+
169+
}

0 commit comments

Comments
 (0)