AnalysisType: rule
Filename: push_security_authorized_idp_login.py
RuleID: "Push.Security.Authorized.IdP.Login"
DisplayName: "Push Security Authorized IdP Login"
Enabled: false
CreateAlert: false
LogTypes:
- PushSecurity.Activity
Tags:
- Configuration Required
Severity: Info
Description: Login to application with unauthorized identity provider which could indicate a SAMLjacking attack.
DedupPeriodMinutes: 60
Threshold: 1
Reference: https://github.com/pushsecurity/saas-attacks/blob/main/techniques/samljacking/description.md
InlineFilters:
- All: []
Tests:
- Name: Google Workspace Password Login
ExpectedResult: false
Log:
id: d240e3f2-3cd6-425f-a835-dad0ff237d09
new:
accountId: a93b45a7-fdce-489e-b76d-2bd6862a62ba
appId: 8348ca36-d254-4e1b-8f31-6837d82fc5cb
appType: GOOGLE_WORKSPACE
browser: EDGE
email: jet.black@issp.com
employeeId: ca6cf7ce-90e6-4eb5-a262-7899bc48c39c
identityProvider: GOOGLE_WORKSPACE
leakedPassword: false
loginTimestamp: 1.707773386e+09
loginType: PASSWORD_LOGIN
os: WINDOWS
passwordId: 6ae9f0b2-9300-43f0-b210-c0d3c16640f8
passwordManuallyTyped: false
sourceIpAddress: 35.90.103.134
userAgent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36 Edg/123.0.2420.81
weakPassword: false
weakPasswordReasons: null
object: LOGIN
timestamp: 1.707774319e+09
version: "1"
- Name: Microsoft 365 OIDC Login
ExpectedResult: false
Log:
id: d240e3f2-3cd6-425f-a835-dad0ff237d09
new:
accountId: a93b45a7-fdce-489e-b76d-2bd6862a62ba
appId: 8348ca36-d254-4e1b-8f31-6837d82fc5cb
appType: DROPBOX
browser: EDGE
email: jet.black@issp.com
employeeId: ca6cf7ce-90e6-4eb5-a262-7899bc48c39c
identityProvider: MICROSOFT_365
leakedPassword: false
loginTimestamp: 1.707773386e+09
loginType: OIDC_LOGIN
os: WINDOWS
passwordId: 6ae9f0b2-9300-43f0-b210-c0d3c16640f8
passwordManuallyTyped: false
sourceIpAddress: 35.90.103.134
userAgent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36 Edg/123.0.2420.81
weakPassword: false
weakPasswordReasons: null
object: LOGIN
timestamp: 1.707774319e+09
version: "1"
- Name: Okta Login
ExpectedResult: true
Log:
id: d240e3f2-3cd6-425f-a835-dad0ff237d09
new:
accountId: a93b45a7-fdce-489e-b76d-2bd6862a62ba
appId: 8348ca36-d254-4e1b-8f31-6837d82fc5cb
appType: Dropbox
browser: EDGE
email: jet.black@issp.com
employeeId: ca6cf7ce-90e6-4eb5-a262-7899bc48c39c
identityProvider: OKTA
leakedPassword: false
loginTimestamp: 1.707773386e+09
loginType: PASSWORD_LOGIN
os: WINDOWS
passwordId: 6ae9f0b2-9300-43f0-b210-c0d3c16640f8
passwordManuallyTyped: false
sourceIpAddress: 35.90.103.134
userAgent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36 Edg/123.0.2420.81
weakPassword: false
weakPasswordReasons: null
object: LOGIN
timestamp: 1.707774319e+09
version: "1"
- Name: Password Login
ExpectedResult: false
Log:
id: d240e3f2-3cd6-425f-a835-dad0ff237d09
new:
accountId: a93b45a7-fdce-489e-b76d-2bd6862a62ba
appId: 8348ca36-d254-4e1b-8f31-6837d82fc5cb
appType: DROPBOX
browser: EDGE
email: jet.black@issp.com
employeeId: ca6cf7ce-90e6-4eb5-a262-7899bc48c39c
identityProvider: null
leakedPassword: false
loginTimestamp: 1.707773386e+09
loginType: PASSWORD_LOGIN
os: WINDOWS
passwordId: 6ae9f0b2-9300-43f0-b210-c0d3c16640f8
passwordManuallyTyped: false
sourceIpAddress: 35.90.103.134
userAgent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36 Edg/123.0.2420.81
weakPassword: false
weakPasswordReasons: null
object: LOGIN
timestamp: 1.707774319e+09
version: "1"
# ------ paired body: push_security_authorized_idp_login.py ------
# Configure allowed identity provider logins to SaaS apps
allowed_idps = {
# "GOOGLE_WORKSPACE": {"OIDC_LOGIN", "SAML_LOGIN"},
"OKTA": {"PASSWORD_LOGIN"},
}
def rule(event):
if event.get("object") != "LOGIN":
return False
identity_provider = event.deep_get("new", "identityProvider")
login_type = event.deep_get("new", "loginType")
if identity_provider in allowed_idps and login_type in allowed_idps[identity_provider]:
return True
return False
def title(event):
identity_provider = event.deep_get("new", "identityProvider", default="Null identityProvider")
login_type = event.deep_get("new", "loginType", default="Null loginType")
app_type = event.deep_get("new", "appType", default="Null appType")
new_email = event.deep_get("new", "email")
return f"Authorized identity provider in use. User: {new_email} \
used {identity_provider} {login_type} on {app_type}"