Skip to content

Instantly share code, notes, and snippets.

@ShaunLawrie
Last active October 6, 2022 09:13
Show Gist options
  • Save ShaunLawrie/de2815e17597ed27a2a93552e1f2cbf6 to your computer and use it in GitHub Desktop.
Save ShaunLawrie/de2815e17597ed27a2a93552e1f2cbf6 to your computer and use it in GitHub Desktop.
Quick script for extracting regex patterns from github codesearch
#requires -Version 7
function Invoke-GithubCodeSearchLogin {
param (
[Parameter(Mandatory)]
[string] $Username,
[Parameter(Mandatory)]
[securestring] $Password
)
Write-Verbose "This requires cookies across multiple domains so we're using a session like a web browser to keep state"
$session = [Microsoft.PowerShell.Commands.WebRequestSession]::new()
$response = Invoke-WebRequest -UseBasicParsing -Uri "https://cs.github.com/auth/login?redirect_url=%2F" -WebSession $session
Write-Verbose "Extract all the oauth state from the initial login page"
$authenticityToken = ($response.RawContent | Select-String 'authenticity_token" value="([^"]+)').Matches.Groups[1].Value
$returnTo = ($response.RawContent | Select-String 'return_to" value="([^"]+)').Matches.Groups[1].Value
$timestamp = ($response.RawContent | Select-String 'timestamp" value="([^"]+)').Matches.Groups[1].Value
$timestampSecret = ($response.RawContent | Select-String 'timestamp_secret" value="([^"]+)').Matches.Groups[1].Value
$requiredField = ($response.RawContent | Select-String 'required_field_([^"]+)').Matches.Groups[1].Value
Write-Verbose "Big login form let's go"
$sessionResponse = Invoke-WebRequest -UseBasicParsing -Uri "https://github.com/session" -WebSession $session -Method "POST" -Body @{
"commit" = "Sign in"
"authenticity_token" = $authenticityToken
"login" = $Username
"password" = ($Password | ConvertFrom-SecureString -AsPlainText)
"webauthn-support" = "unsupported"
"webauthn-iuvpaa-support" = "unsupported"
"return_to" = $returnTo
"allow_signup" = ""
"client_id" = ""
"integration" = ""
"required_field_$requiredField" = ""
"timestamp" = $timestamp
"timestamp_secret" = $timestampSecret
}
Write-Verbose "Handle MFA for the basic MFA scenarios"
$redirectUrl = Get-GithubMfaRedirectUrl -Session $session -SessionResponse $sessionResponse
Write-Verbose "Complete login"
Invoke-WebRequest -UseBasicParsing -Uri $redirectUrl -WebSession $session -SkipHttpErrorCheck -ErrorAction "SilentlyContinue" | Out-Null
Write-Host "Logged in"
return $session
}
function Get-GithubMfaRedirectUrl {
param (
[object] $Session,
[object] $SessionResponse
)
$sessionResponseContent = $SessionResponse.RawContent
if($sessionResponseContent.Contains("GitHub Mobile")) {
$mfaAuthenticityToken = ($sessionResponseContent | Select-String 'authenticity_token" value="([^"]+)').Matches.Groups[1].Value
$mfaCsrfToken = ($sessionResponseContent | Select-String 'value="(.+?)" data-csrf=').Matches.Groups[1].Value
$code = ($sessionResponseContent | Select-String '(?s)githubMobileChallengeValue.*?([0-9]+)').Matches.Groups[1].Value
if(!$code) {
Write-Error "Unable to extract the MFA prompt number from the page, try again"
exit 1
}
Write-Host "Enter the code '$code' on your GitHub mobile app for MFA authentication"
$timeout = (Get-Date).AddSeconds(60)
$headers = @{
"accept" = "application/json"
"scoped-csrf-token" = $mfaCsrfToken
"x-requested-with" = "XMLHttpRequest"
"accept-encoding" = "gzip, deflate, br"
"accept-language" = "en-US,en;q=0.9"
"origin" = "https://github.com"
"referer" = "https://github.com/sessions/two-factor/mobile?auto=true"
}
while($true) {
if((Get-Date) -gt $timeout) {
Write-Error "Timed out waiting for the mobile app to report MFA status"
exit 2
}
try {
$mobileResponse = Invoke-RestMethod -UseBasicParsing -Uri "https://github.com/sessions/two-factor/mobile_poll" -WebSession $Session -Headers $headers -Method "POST" -Body @{
"authenticity_token" = $mfaAuthenticityToken
}
if($mobileResponse.status -eq "STATUS_APPROVED") {
break
}
Write-Verbose "Mobile prompt status is '$($mobileResponse.status)'"
} catch {
Write-Warning "Failed to check mobile MFA status: $_"
}
Start-Sleep -Seconds 1
}
$mfaResponse = Invoke-WebRequest "https://github.com/sessions/two-factor/mobile" -WebSession $Session -Headers @{ "accept" = "text/html" } -Body @{
"auto" = "true"
"redirect" = "true"
}
$redirectResponse = $mfaResponse.RawContent
} elseif ($sessionResponseContent.Contains("Two-factor")) {
$mfaAuthenticityToken = ($sessionResponseContent | Select-String 'authenticity_token" value="([^"]+)').Matches.Groups[1].Value
$mfaCode = Read-Host "Enter your TOTP MFA token"
$mfaResponse = Invoke-WebRequest -UseBasicParsing -Uri "https://github.com/sessions/two-factor" -WebSession $Session -Method "POST" -Body @{
"authenticity_token" = $mfaAuthenticityToken
"otp" = $mfaCode
}
$redirectResponse = $mfaResponse.RawContent
} else {
$redirectResponse = $sessionResponseContent
}
return ($redirectResponse | Select-String 'redirect" href="([^"]+)').Matches.Groups[1].Value -replace '&', '&'
}
function Get-GithubCodeSearch {
[CmdletBinding()]
param (
[Parameter(Mandatory)]
[Microsoft.PowerShell.Commands.WebRequestSession] $Session,
[string] $SearchRegex,
[switch] $Pretty
)
if(!$SearchRegex) {
$SearchRegex = Read-Host "Enter a search term for GitHub CodeSearch"
}
$RawSearch = $SearchRegex
if($RawSearch.StartsWith("/") -and $RawSearch.EndsWith("/")) {
$SearchRegex = $RawSearch -replace '^\/', '' -replace '\/$', ''
} else {
$RawSearch = "/$RawSearch/"
}
if($Pretty) {
Write-Host -ForegroundColor "Green" -NoNewline "Searching for regex '"
Write-host -NoNewline "$RawSearch"
Write-Host -ForegroundColor "Green" "'`n"
}
$searchResponse = Invoke-RestMethod -UseBasicParsing -Uri "https://cs.github.com/api/search" -WebSession $Session -Body @{ q = $RawSearch }
for($p = 1; $p -le $searchResponse.total_pages; $p++) {
foreach($result in $searchResponse.results) {
$url = "https://github.com/$($result.repo_name)/tree/$($result.ref_name -replace 'refs/heads/', '')/$($result.path)"
if($Pretty) {
Write-Host -ForegroundColor DarkGreen "Location '$url'"
}
foreach($snippet in $result.snippets) {
$lines = $snippet.lines -join "`n"
try {
$marks = ($lines | Select-String -AllMatches $SearchRegex).Matches | Foreach-Object { $_.Value }
Write-Output ($marks -join "`n")
} catch {
Write-Warning $lines
}
}
}
$searchResponse = Invoke-RestMethod -UseBasicParsing -Uri "https://cs.github.com/api/search" -WebSession $Session -Body @{ q = $RawSearch; p = ($p + 1); page_token = $searchResponse.page_token }
}
}
<#
EXAMPLE
Import-Module .\GitHubCodeSearch.psm1
$session = Invoke-GithubCodeSearchLogin
Get-GithubCodeSearch -Session $session -SearchRegex "https:\/\/example.+"
# To see the repos where the patterns are found use -Pretty
Get-GithubCodeSearch -Session $session -SearchRegex "firstname.+lastname" -Pretty
This script is super hacky I just wanted to find some stuff in cs.github.com with regex, 90% of it is dealing with the github login dance with MFA
#>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment