Full Code of h4wkst3r/SCMKit for AI

main 138a811b6512 cached
61 files
407.0 KB
75.7k tokens
137 symbols
1 requests
Download .txt
Showing preview only (428K chars total). Download the full file or copy to clipboard to get everything.
Repository: h4wkst3r/SCMKit
Branch: main
Commit: 138a811b6512
Files: 61
Total size: 407.0 KB

Directory structure:
gitextract_g9j8xacg/

├── .gitignore
├── Detections/
│   ├── SCMKit.rules
│   └── SCMKit.yar
├── LICENSE
├── README.md
├── SCMKit/
│   ├── App.config
│   ├── FodyWeavers.xml
│   ├── Properties/
│   │   └── AssemblyInfo.cs
│   ├── SCMKit.cs
│   ├── SCMKit.csproj
│   ├── library/
│   │   ├── BitbucketUtils.cs
│   │   ├── GitHubUtils.cs
│   │   ├── GitLabUtils.cs
│   │   ├── Utils.cs
│   │   └── WebUtils.cs
│   ├── modules/
│   │   ├── bitbucket/
│   │   │   ├── AddAdmin.cs
│   │   │   ├── CodeSearch.cs
│   │   │   ├── CreatePAT.cs
│   │   │   ├── CreateSSHKey.cs
│   │   │   ├── FileSearch.cs
│   │   │   ├── ListPAT.cs
│   │   │   ├── ListSSHKeys.cs
│   │   │   ├── RemoveAdmin.cs
│   │   │   ├── RemovePAT.cs
│   │   │   ├── RemoveSSHKey.cs
│   │   │   ├── RepoList.cs
│   │   │   └── RepoSearch.cs
│   │   ├── github/
│   │   │   ├── AddAdmin.cs
│   │   │   ├── AdminStats.cs
│   │   │   ├── BranchProtection.cs
│   │   │   ├── CodeSearch.cs
│   │   │   ├── CreatePAT.cs
│   │   │   ├── CreateSSHKey.cs
│   │   │   ├── FileSearch.cs
│   │   │   ├── GistList.cs
│   │   │   ├── ListPAT.cs
│   │   │   ├── ListSSHKeys.cs
│   │   │   ├── OrgList.cs
│   │   │   ├── Privs.cs
│   │   │   ├── RemoveAdmin.cs
│   │   │   ├── RemovePAT.cs
│   │   │   ├── RemoveSSHKey.cs
│   │   │   ├── RepoList.cs
│   │   │   └── RepoSearch.cs
│   │   └── gitlab/
│   │       ├── AddAdmin.cs
│   │       ├── CodeSearch.cs
│   │       ├── CreatePAT.cs
│   │       ├── CreateSSHKey.cs
│   │       ├── FileSearch.cs
│   │       ├── ListPAT.cs
│   │       ├── ListSSHKeys.cs
│   │       ├── Privs.cs
│   │       ├── RemoveAdmin.cs
│   │       ├── RemovePAT.cs
│   │       ├── RemoveSSHKey.cs
│   │       ├── RepoList.cs
│   │       ├── RepoSearch.cs
│   │       ├── RunnerList.cs
│   │       └── SnippetList.cs
│   └── packages.config
└── SCMKit.sln

================================================
FILE CONTENTS
================================================

================================================
FILE: .gitignore
================================================
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
##
## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore

*.exe

# User-specific files
*.rsuser
*.suo
*.user
*.userosscache
*.sln.docstates

# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs

# Mono auto generated files
mono_crash.*

# Build results
[Dd]ebug/
[Dd]ebugPublic/
[Rr]elease/
[Rr]eleases/
x64/
x86/
[Ww][Ii][Nn]32/
[Aa][Rr][Mm]/
[Aa][Rr][Mm]64/
bld/
[Bb]in/
[Oo]bj/
[Ll]og/
[Ll]ogs/

# Visual Studio 2015/2017 cache/options directory
.vs/
# Uncomment if you have tasks that create the project's static files in wwwroot
#wwwroot/

# Visual Studio 2017 auto generated files
Generated\ Files/

# MSTest test Results
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*

# NUnit
*.VisualState.xml
TestResult.xml
nunit-*.xml

# Build Results of an ATL Project
[Dd]ebugPS/
[Rr]eleasePS/
dlldata.c

# Benchmark Results
BenchmarkDotNet.Artifacts/

# .NET Core
project.lock.json
project.fragment.lock.json
artifacts/

# ASP.NET Scaffolding
ScaffoldingReadMe.txt

# StyleCop
StyleCopReport.xml

# Files built by Visual Studio
*_i.c
*_p.c
*_h.h
*.ilk
*.meta
*.obj
*.iobj
*.pch
*.pdb
*.ipdb
*.pgc
*.pgd
*.rsp
*.sbr
*.tlb
*.tli
*.tlh
*.tmp
*.tmp_proj
*_wpftmp.csproj
*.log
*.tlog
*.vspscc
*.vssscc
.builds
*.pidb
*.svclog
*.scc

# Chutzpah Test files
_Chutzpah*

# Visual C++ cache files
ipch/
*.aps
*.ncb
*.opendb
*.opensdf
*.sdf
*.cachefile
*.VC.db
*.VC.VC.opendb

# Visual Studio profiler
*.psess
*.vsp
*.vspx
*.sap

# Visual Studio Trace Files
*.e2e

# TFS 2012 Local Workspace
$tf/

# Guidance Automation Toolkit
*.gpState

# ReSharper is a .NET coding add-in
_ReSharper*/
*.[Rr]e[Ss]harper
*.DotSettings.user

# TeamCity is a build add-in
_TeamCity*

# DotCover is a Code Coverage Tool
*.dotCover

# AxoCover is a Code Coverage Tool
.axoCover/*
!.axoCover/settings.json

# Coverlet is a free, cross platform Code Coverage Tool
coverage*.json
coverage*.xml
coverage*.info

# Visual Studio code coverage results
*.coverage
*.coveragexml

# NCrunch
_NCrunch_*
.*crunch*.local.xml
nCrunchTemp_*

# MightyMoose
*.mm.*
AutoTest.Net/

# Web workbench (sass)
.sass-cache/

# Installshield output folder
[Ee]xpress/

# DocProject is a documentation generator add-in
DocProject/buildhelp/
DocProject/Help/*.HxT
DocProject/Help/*.HxC
DocProject/Help/*.hhc
DocProject/Help/*.hhk
DocProject/Help/*.hhp
DocProject/Help/Html2
DocProject/Help/html

# Click-Once directory
publish/

# Publish Web Output
*.[Pp]ublish.xml
*.azurePubxml
# Note: Comment the next line if you want to checkin your web deploy settings,
# but database connection strings (with potential passwords) will be unencrypted
*.pubxml
*.publishproj

# Microsoft Azure Web App publish settings. Comment the next line if you want to
# checkin your Azure Web App publish settings, but sensitive information contained
# in these scripts will be unencrypted
PublishScripts/

# NuGet Packages
*.nupkg
# NuGet Symbol Packages
*.snupkg
# The packages folder can be ignored because of Package Restore
[Pp]ackages/*
# except build/, which is used as an MSBuild target.
![Pp]ackages/build/
# Uncomment if necessary however generally it will be regenerated when needed
#!**/[Pp]ackages/repositories.config
# NuGet v3's project.json files produces more ignorable files
*.nuget.props
*.nuget.targets

# Nuget personal access tokens and Credentials
nuget.config

# Microsoft Azure Build Output
csx/
*.build.csdef

# Microsoft Azure Emulator
ecf/
rcf/

# Windows Store app package directories and files
AppPackages/
BundleArtifacts/
Package.StoreAssociation.xml
_pkginfo.txt
*.appx
*.appxbundle
*.appxupload

# Visual Studio cache files
# files ending in .cache can be ignored
*.[Cc]ache
# but keep track of directories ending in .cache
!?*.[Cc]ache/

# Others
ClientBin/
~$*
*~
*.dbmdl
*.dbproj.schemaview
*.jfm
*.pfx
*.publishsettings
orleans.codegen.cs

# Including strong name files can present a security risk
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
#*.snk

# Since there are multiple workflows, uncomment next line to ignore bower_components
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
#bower_components/

# RIA/Silverlight projects
Generated_Code/

# Backup & report files from converting an old project file
# to a newer Visual Studio version. Backup files are not needed,
# because we have git ;-)
_UpgradeReport_Files/
Backup*/
UpgradeLog*.XML
UpgradeLog*.htm
ServiceFabricBackup/
*.rptproj.bak

# SQL Server files
*.mdf
*.ldf
*.ndf

# Business Intelligence projects
*.rdl.data
*.bim.layout
*.bim_*.settings
*.rptproj.rsuser
*- [Bb]ackup.rdl
*- [Bb]ackup ([0-9]).rdl
*- [Bb]ackup ([0-9][0-9]).rdl

# Microsoft Fakes
FakesAssemblies/

# GhostDoc plugin setting file
*.GhostDoc.xml

# Node.js Tools for Visual Studio
.ntvs_analysis.dat
node_modules/

# Visual Studio 6 build log
*.plg

# Visual Studio 6 workspace options file
*.opt

# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
*.vbw

# Visual Studio LightSwitch build output
**/*.HTMLClient/GeneratedArtifacts
**/*.DesktopClient/GeneratedArtifacts
**/*.DesktopClient/ModelManifest.xml
**/*.Server/GeneratedArtifacts
**/*.Server/ModelManifest.xml
_Pvt_Extensions

# Paket dependency manager
.paket/paket.exe
paket-files/

# FAKE - F# Make
.fake/

# CodeRush personal settings
.cr/personal

# Python Tools for Visual Studio (PTVS)
__pycache__/
*.pyc

# Cake - Uncomment if you are using it
# tools/**
# !tools/packages.config

# Tabs Studio
*.tss

# Telerik's JustMock configuration file
*.jmconfig

# BizTalk build output
*.btp.cs
*.btm.cs
*.odx.cs
*.xsd.cs

# OpenCover UI analysis results
OpenCover/

# Azure Stream Analytics local run output
ASALocalRun/

# MSBuild Binary and Structured Log
*.binlog

# NVidia Nsight GPU debugger configuration file
*.nvuser

# MFractors (Xamarin productivity tool) working folder
.mfractor/

# Local History for Visual Studio
.localhistory/

# BeatPulse healthcheck temp database
healthchecksdb

# Backup folder for Package Reference Convert tool in Visual Studio 2017
MigrationBackup/

# Ionide (cross platform F# VS Code tools) working folder
.ionide/

# Fody - auto-generated XML schema
FodyWeavers.xsd

# VS Code files for those working on multiple tools
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
*.code-workspace

# Local History for Visual Studio Code
.history/

# Windows Installer files from build outputs
*.cab
*.msi
*.msix
*.msm
*.msp

# JetBrains Rider
.idea/
*.sln.iml

================================================
FILE: Detections/SCMKit.rules
================================================
alert tcp $HOME_NET any -> any $HTTP_PORTS (flow:established,to_server; content:"SCMKIT-5dc493ada400c79dd318abbe770dac7c"; http_header; fast_pattern:only; pcre:"/^User\x2dAgent\x3a\x20SCMKit/Hm"; metadata:service http; msg:"Known malicious user-agent string SCMKit tool"; id:5493400793187707; rev:1; )


================================================
FILE: Detections/SCMKit.yar
================================================
rule SCMKit_Signatures
{
    meta:
        description = "Static signatures for the SCMKit tool."
        md5 = "9b4b2a06aa840afcbbfe2d412f99b4a8"
        rev = 1
        author = "Brett Hawkins"
    strings:
        $typelibguid = "266c644a-69b1-426b-a47c-1cf32b211f80" ascii nocase wide
        $gitlabModules = "SCMKit.modules.gitlab" ascii nocase wide
        $githubModules = "SCMKit.modules.github" ascii nocase wide
        $bitbucketModules = "SCMKit.modules.bitbucket" ascii nocase wide
    condition:
        uint16(0) == 0x5A4D and $typelibguid and $gitlabModules and $githubModules and $bitbucketModules
}


================================================
FILE: LICENSE
================================================
                                 Apache License
                           Version 2.0, January 2004
                        http://www.apache.org/licenses/

   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION

   1. Definitions.

      "License" shall mean the terms and conditions for use, reproduction,
      and distribution as defined by Sections 1 through 9 of this document.

      "Licensor" shall mean the copyright owner or entity authorized by
      the copyright owner that is granting the License.

      "Legal Entity" shall mean the union of the acting entity and all
      other entities that control, are controlled by, or are under common
      control with that entity. For the purposes of this definition,
      "control" means (i) the power, direct or indirect, to cause the
      direction or management of such entity, whether by contract or
      otherwise, or (ii) ownership of fifty percent (50%) or more of the
      outstanding shares, or (iii) beneficial ownership of such entity.

      "You" (or "Your") shall mean an individual or Legal Entity
      exercising permissions granted by this License.

      "Source" form shall mean the preferred form for making modifications,
      including but not limited to software source code, documentation
      source, and configuration files.

      "Object" form shall mean any form resulting from mechanical
      transformation or translation of a Source form, including but
      not limited to compiled object code, generated documentation,
      and conversions to other media types.

      "Work" shall mean the work of authorship, whether in Source or
      Object form, made available under the License, as indicated by a
      copyright notice that is included in or attached to the work
      (an example is provided in the Appendix below).

      "Derivative Works" shall mean any work, whether in Source or Object
      form, that is based on (or derived from) the Work and for which the
      editorial revisions, annotations, elaborations, or other modifications
      represent, as a whole, an original work of authorship. For the purposes
      of this License, Derivative Works shall not include works that remain
      separable from, or merely link (or bind by name) to the interfaces of,
      the Work and Derivative Works thereof.

      "Contribution" shall mean any work of authorship, including
      the original version of the Work and any modifications or additions
      to that Work or Derivative Works thereof, that is intentionally
      submitted to Licensor for inclusion in the Work by the copyright owner
      or by an individual or Legal Entity authorized to submit on behalf of
      the copyright owner. For the purposes of this definition, "submitted"
      means any form of electronic, verbal, or written communication sent
      to the Licensor or its representatives, including but not limited to
      communication on electronic mailing lists, source code control systems,
      and issue tracking systems that are managed by, or on behalf of, the
      Licensor for the purpose of discussing and improving the Work, but
      excluding communication that is conspicuously marked or otherwise
      designated in writing by the copyright owner as "Not a Contribution."

      "Contributor" shall mean Licensor and any individual or Legal Entity
      on behalf of whom a Contribution has been received by Licensor and
      subsequently incorporated within the Work.

   2. Grant of Copyright License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      copyright license to reproduce, prepare Derivative Works of,
      publicly display, publicly perform, sublicense, and distribute the
      Work and such Derivative Works in Source or Object form.

   3. Grant of Patent License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      (except as stated in this section) patent license to make, have made,
      use, offer to sell, sell, import, and otherwise transfer the Work,
      where such license applies only to those patent claims licensable
      by such Contributor that are necessarily infringed by their
      Contribution(s) alone or by combination of their Contribution(s)
      with the Work to which such Contribution(s) was submitted. If You
      institute patent litigation against any entity (including a
      cross-claim or counterclaim in a lawsuit) alleging that the Work
      or a Contribution incorporated within the Work constitutes direct
      or contributory patent infringement, then any patent licenses
      granted to You under this License for that Work shall terminate
      as of the date such litigation is filed.

   4. Redistribution. You may reproduce and distribute copies of the
      Work or Derivative Works thereof in any medium, with or without
      modifications, and in Source or Object form, provided that You
      meet the following conditions:

      (a) You must give any other recipients of the Work or
          Derivative Works a copy of this License; and

      (b) You must cause any modified files to carry prominent notices
          stating that You changed the files; and

      (c) You must retain, in the Source form of any Derivative Works
          that You distribute, all copyright, patent, trademark, and
          attribution notices from the Source form of the Work,
          excluding those notices that do not pertain to any part of
          the Derivative Works; and

      (d) If the Work includes a "NOTICE" text file as part of its
          distribution, then any Derivative Works that You distribute must
          include a readable copy of the attribution notices contained
          within such NOTICE file, excluding those notices that do not
          pertain to any part of the Derivative Works, in at least one
          of the following places: within a NOTICE text file distributed
          as part of the Derivative Works; within the Source form or
          documentation, if provided along with the Derivative Works; or,
          within a display generated by the Derivative Works, if and
          wherever such third-party notices normally appear. The contents
          of the NOTICE file are for informational purposes only and
          do not modify the License. You may add Your own attribution
          notices within Derivative Works that You distribute, alongside
          or as an addendum to the NOTICE text from the Work, provided
          that such additional attribution notices cannot be construed
          as modifying the License.

      You may add Your own copyright statement to Your modifications and
      may provide additional or different license terms and conditions
      for use, reproduction, or distribution of Your modifications, or
      for any such Derivative Works as a whole, provided Your use,
      reproduction, and distribution of the Work otherwise complies with
      the conditions stated in this License.

   5. Submission of Contributions. Unless You explicitly state otherwise,
      any Contribution intentionally submitted for inclusion in the Work
      by You to the Licensor shall be under the terms and conditions of
      this License, without any additional terms or conditions.
      Notwithstanding the above, nothing herein shall supersede or modify
      the terms of any separate license agreement you may have executed
      with Licensor regarding such Contributions.

   6. Trademarks. This License does not grant permission to use the trade
      names, trademarks, service marks, or product names of the Licensor,
      except as required for reasonable and customary use in describing the
      origin of the Work and reproducing the content of the NOTICE file.

   7. Disclaimer of Warranty. Unless required by applicable law or
      agreed to in writing, Licensor provides the Work (and each
      Contributor provides its Contributions) on an "AS IS" BASIS,
      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
      implied, including, without limitation, any warranties or conditions
      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
      PARTICULAR PURPOSE. You are solely responsible for determining the
      appropriateness of using or redistributing the Work and assume any
      risks associated with Your exercise of permissions under this License.

   8. Limitation of Liability. In no event and under no legal theory,
      whether in tort (including negligence), contract, or otherwise,
      unless required by applicable law (such as deliberate and grossly
      negligent acts) or agreed to in writing, shall any Contributor be
      liable to You for damages, including any direct, indirect, special,
      incidental, or consequential damages of any character arising as a
      result of this License or out of the use or inability to use the
      Work (including but not limited to damages for loss of goodwill,
      work stoppage, computer failure or malfunction, or any and all
      other commercial damages or losses), even if such Contributor
      has been advised of the possibility of such damages.

   9. Accepting Warranty or Additional Liability. While redistributing
      the Work or Derivative Works thereof, You may choose to offer,
      and charge a fee for, acceptance of support, warranty, indemnity,
      or other liability obligations and/or rights consistent with this
      License. However, in accepting such obligations, You may act only
      on Your own behalf and on Your sole responsibility, not on behalf
      of any other Contributor, and only if You agree to indemnify,
      defend, and hold each Contributor harmless for any liability
      incurred by, or claims asserted against, such Contributor by reason
      of your accepting any such warranty or additional liability.

   END OF TERMS AND CONDITIONS

   APPENDIX: How to apply the Apache License to your work.

      To apply the Apache License to your work, attach the following
      boilerplate notice, with the fields enclosed by brackets "[]"
      replaced with your own identifying information. (Don't include
      the brackets!)  The text should be enclosed in the appropriate
      comment syntax for the file format. We also recommend that a
      file or class name and description of purpose be included on the
      same "printed page" as the copyright notice for easier
      identification within third-party archives.

   Copyright 2022 Brett Hawkins

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.


================================================
FILE: README.md
================================================
# SCMKit

## Description
**S**ource **C**ode **M**anagement Attack Tool**kit** - SCMKit is a toolkit that can be used to attack SCM systems. SCMKit allows the user to specify the SCM system and attack module to use, along with specifying valid credentials (username/password or API key) to the respective SCM system. Currently, the SCM systems that SCMKit supports are GitHub Enterprise, GitLab Enterprise and Bitbucket Server. The attack modules supported include reconnaissance, privilege escalation and persistence. SCMKit was built in a modular approach, so that new modules and SCM systems can be added in the future by the information security community.

## Release
* Version 1.2 of SCMKit can be found in Releases

## Table of Contents

- [SCMKit](#scmkit)
- [Table of Contents](#table-of-contents)
- [Installation/Building](#installationbuilding)
  - [Libraries Used](#libraries-used)
  - [Pre-Compiled](#pre-compiled)
  - [Building Yourself](#building-yourself)
- [Usage](#usage)
  - [Arguments/Options](#argumentsoptions)
  - [Systems](#systems--s--system)
  - [Modules](#modules--m--module)
  - [Module Details Table](#Module-Details-Table)
- [Examples](#examples)
  - [List Repos](#List-repos)
  - [Search Repos](#Search-repos)
  - [Search Code](#Search-code)
  - [Search Files](#Search-files)
  - [List Snippets](#List-snippets)
  - [List Runners](#List-runners)
  - [List Gists](#List-gists)
  - [List Orgs](#List-orgs)
  - [Get Privileges of API Key](#Get-privileges-of-api-token)
  - [Add Admin](#Add-admin)
  - [Remove Admin](#Remove-admin)
  - [Create Access Token](#Create-access-token)
  - [List Access Tokens](#List-access-tokens)
  - [Remove Access Token](#Remove-access-token)
  - [Create SSH Key](#Create-ssh-key)
  - [List SSH Keys](#List-ssh-keys)
  - [Remove SSH Key](#Remove-ssh-key)
  - [List Admin Stats](#list-admin-stats)
  - [List Branch Protection](#list-branch-protection)
- [Detection](#detection)
- [References](#references)


## Installation/Building

### Libraries Used
The below 3rd party libraries are used in this project.

| Library | URL | License |
| ------------- | ------------- | ------------- |
| Octokit  | [https://github.com/octokit/octokit.net](https://github.com/octokit/octokit.net) | MIT License  |
| Fody  | [https://github.com/Fody/Fody](https://github.com/Fody/Fody) | MIT License  |
| GitLabApiClient  | [https://github.com/nmklotas/GitLabApiClient](https://github.com/nmklotas/GitLabApiClient) | MIT License  |
| Newtonsoft.Json  | [https://github.com/JamesNK/Newtonsoft.Json](https://github.com/JamesNK/Newtonsoft.Json) | MIT License  |

### Pre-Compiled 

* Use the pre-compiled binary in Releases

### Building Yourself

Take the below steps to setup Visual Studio in order to compile the project yourself. This requires a .NET library that can be installed from the NuGet package manager.


* Load the Visual Studio project up and go to "Tools" --> "NuGet Package Manager" --> "Package Manager Settings"
* Go to "NuGet Package Manager" --> "Package Sources"
* Add a package source with the URL `https://api.nuget.org/v3/index.json`
* Install the below NuGet packages
  * `Install-Package Costura.Fody -Version 3.3.3`
  * `Install-Package Octokit`
  * `Install-Package GitLabApiClient`
  * `Install-Package Newtonsoft.Json`
* You can now build the project yourself!

## Usage

### Arguments/Options

* <b>-c, -credential </b> - credential for authentication (username:password or apiKey)
* <b>-s, -system </b> - system to attack (github,gitlab,bitbucket)
* <b>-u, -url </b> - URL for GitHub Enterprise, GitLab Enterprise or Bitbucket Server
* <b>-m, -module </b> - module to run
* <b>-o, -option </b> - options (when applicable)

### Systems (-s, -system)
* <b>github:</b> GitHub Enterprise
* <b>gitlab:</b> GitLab Enterprise
* <b>bitbucket:</b> Bitbucket Server

### Modules (-m, -module)
* <b>listrepo:</b> list all repos the current user can see
* <b>searchrepo:</b> search for a given repo
* <b>searchcode:</b> search for code containing keyword search term
* <b>searchfile:</b> search for filename containing keyword search term
* <b>listsnippet:</b> list all snippets of current user
* <b>listrunner:</b> list all GitLab runners available to current user
* <b>listgist:</b> list all gists of current user
* <b>listorg:</b> list all orgs current user belongs to
* <b>privs:</b> get privs of current API token
* <b>addadmin:</b> promote given user to admin role
* <b>removeadmin:</b> demote given user from admin role
* <b>createpat:</b> create personal access token for target user
* <b>listpat:</b> list personal access tokens for a target user
* <b>removepat:</b> remove personal access token for a target user
* <b>createsshkey:</b> create SSH key for current user
* <b>listsshkey:</b> list SSH keys for current user
* <b>removesshkey:</b> remove SSH key for current user
* <b>adminstats:</b> get admin stats (users, repos, orgs, gists)
* <b>protection:</b> get branch protection settings



### Module Details Table
The below table shows where each module is supported

Attack Scenario | Module  | Requires Admin? | GitHub Enterprise | GitLab Enterprise | Bitbucket Server
:---: |:---: | :---: | :---: | :---: | :---:
Reconnaissance | `listrepo` |  No | X | X | X
Reconnaissance |`searchrepo` |  No | X | X | X
Reconnaissance |`searchcode` |  No | X | X | X
Reconnaissance |`searchfile` |  No | X | X | X
Reconnaissance |`listsnippet` |  No |  | X | 
Reconnaissance |`listrunner` |  No |  | X | 
Reconnaissance |`listgist` |  No | X |  | 
Reconnaissance |`listorg` |  No | X |  | 
Reconnaissance |`privs` |  No | X | X | 
Reconnaissance |`protection` |  No | X |  | 
Persistence | `listsshkey` |  No | X | X | X
Persistence | `removesshkey` |  No | X | X | X
Persistence | `createsshkey` |  No | X | X | X
Persistence | `listpat` |  No |  | X | X
Persistence | `removepat` |  No |  | X | X
Persistence | `createpat` |  Yes (GitLab Enterprise only) |  | X | X
Privilege Escalation | `addadmin` |  Yes | X | X | X
Privilege Escalation | `removeadmin` |  Yes | X | X | X
Reconnaissance | `adminstats` |  Yes | X |  |


## Examples

### List Repos

#### Use Case

> *Discover repositories being used in a particular SCM system*

#### Syntax

Provide the `listrepo` module, along with any relevant authentication information and URL. This will output the repository name and URL.

##### GitHub Enterprise

This will list all repositories that a user can see.

`SCMKit.exe -s github -m listrepo -c userName:password -u https://github.something.local`

`SCMKit.exe -s github -m listrepo -c apiKey -u https://github.something.local`

##### GitLab Enterprise

This will list all repositories that a user can see.

`SCMKit.exe -s gitlab -m listrepo -c userName:password -u https://gitlab.something.local`

`SCMKit.exe -s gitlab -m listrepo -c apiKey -u https://gitlab.something.local`

##### Bitbucket Server

This will list all repositories that a user can see.

`SCMKit.exe -s bitbucket -m listrepo -c userName:password -u https://bitbucket.something.local`

`SCMKit.exe -s bitbucket -m listrepo -c apiKey -u https://bitbucket.something.local`

#### Example Output

```

C:\>SCMKit.exe -s gitlab -m listrepo -c username:password -u https://gitlab.hogwarts.local

==================================================
Module:         listrepo
System:         gitlab
Auth Type:      Username/Password
Options:
Target URL:     https://gitlab.hogwarts.local

Timestamp:      1/14/2022 8:30:47 PM
==================================================

                                    Name | Visibility |                                                URL
----------------------------------------------------------------------------------------------------------
                            MaraudersMap |    Private | https://gitlab.hogwarts.local/hpotter/maraudersmap
                            testingStuff |   Internal | https://gitlab.hogwarts.local/adumbledore/testingstuff
                               Spellbook |   Internal |    https://gitlab.hogwarts.local/hpotter/spellbook
       findShortestPathToGryffindorSword |   Internal | https://gitlab.hogwarts.local/hpotter/findShortestPathToGryffindorSword
                                  charms |     Public |      https://gitlab.hogwarts.local/hgranger/charms
                           Secret-Spells |   Internal | https://gitlab.hogwarts.local/adumbledore/secret-spells
                              Monitoring |   Internal | https://gitlab.hogwarts.local/gitlab-instance-10590c85/Monitoring
```

### Search Repos

#### Use Case

> *Search for repositories by repository name in a particular SCM system*

#### Syntax

Provide the `searchrepo` module and your search criteria in the `-o` command-line switch, along with any relevant authentication information and URL. This will output the matching repository name and URL.

##### GitHub Enterprise

The GitHub repo search is a "contains" search where the string you enter it will search for repos with names that contain your search term.

`SCMKit.exe -s github -m searchrepo -c userName:password -u https://github.something.local -o "some search term"`

`SCMKit.exe -s github -m searchrepo -c apikey -u https://github.something.local -o "some search term"`

##### GitLab Enterprise

The GitLab repo search is a "contains" search where the string you enter it will search for repos with names that contain your search term.

`SCMKit.exe -s gitlab -m searchrepo -c userName:password -u https://gitlab.something.local -o "some search term"`

`SCMKit.exe -s gitlab -m searchrepo -c apikey -u https://gitlab.something.local -o "some search term"`

##### Bitbucket Server

The Bitbucket repo search is a "starts with" search where the string you enter it will search for repos with names that start with your search term.

`SCMKit.exe -s bitbucket -m searchrepo -c userName:password -u https://bitbucket.something.local -o "some search term"`

`SCMKit.exe -s bitbucket -m searchrepo -c apikey -u https://bitbucket.something.local -o "some search term"`

#### Example Output

```

C:\>SCMKit.exe -s gitlab -m searchrepo -c apiKey -u https://gitlab.hogwarts.local -o "spell"

==================================================
Module:         searchrepo
System:         gitlab
Auth Type:      API Key
Options:        spell
Target URL:     https://gitlab.hogwarts.local

Timestamp:      1/14/2022 8:32:30 PM
==================================================

                                    Name | Visibility |                                                URL
----------------------------------------------------------------------------------------------------------
                               Spellbook |   Internal |    https://gitlab.hogwarts.local/hpotter/spellbook
                           Secret-Spells |   Internal | https://gitlab.hogwarts.local/adumbledore/secret-spells
```

### Search Code

#### Use Case

> *Search for code containing a given keyword in a particular SCM system*

#### Syntax

Provide the `searchcode` module and your search criteria in the `-o` command-line switch, along with any relevant authentication information and URL. This will output the URL to the matching code file, along with the line in the code that matched.

##### GitHub Enterprise

The GitHub code search is a "contains" search where the string you enter it will search for code that contains your search term in any line.

`SCMKit.exe -s github -m searchcode -c userName:password -u https://github.something.local -o "some search term"`

`SCMKit.exe -s github -m searchcode -c apikey -u https://github.something.local -o "some search term"`

##### GitLab Enterprise

The GitLab code search is a "contains" search where the string you enter it will search for code that contains your search term in any line.

`SCMKit.exe -s gitlab -m searchcode -c userName:password -u https://gitlab.something.local -o "some search term"`

`SCMKit.exe -s gitlab -m searchcode -c apikey -u https://gitlab.something.local -o "some search term"`

##### Bitbucket Server

The Bitbucket code search is a "contains" search where the string you enter it will search for code that contains your search term in any line.

`SCMKit.exe -s bitbucket -m searchcode -c userName:password -u https://bitbucket.something.local -o "some search term"`

`SCMKit.exe -s bitbucket -m searchcode -c apikey -u https://bitbucket.something.local -o "some search term"`

#### Example Output

```

C:\>SCMKit.exe -s gitlab -m searchcode -c username:password -u https://gitlab.hogwarts.local -o "api_key"

==================================================
Module:         searchcode
System:         gitlab
Auth Type:      Username/Password
Options:        api_key
Target URL:     https://gitlab.hogwarts.local

Timestamp:      1/14/2022 8:34:14 PM
==================================================


[>] URL: https://gitlab.hogwarts.local/adumbledore/secret-spells/stuff.txt
    |_ API_KEY=abc123

Total number of items matching code search: 1

```

### Search Files

#### Use Case

> *Search for files in repositories containing a given keyword in the file name in a particular SCM system*

#### Syntax

Provide the `searchfile` module and your search criteria in the `-o` command-line switch, along with any relevant authentication information and URL. This will output the URL to the matching file in its respective repository.

##### GitHub Enterprise

The GitLab file search is a "contains" search where the string you enter it will search for files that contains your search term in the file name.

`SCMKit.exe -s github -m searchfile -c userName:password -u https://github.something.local -o "some search term"`

`SCMKit.exe -s github -m searchfile -c apikey -u https://github.something.local -o "some search term"`

##### GitLab Enterprise

The GitLab file search is a "contains" search where the string you enter it will search for files that contains your search term in the file name.

`SCMKit.exe -s gitlab -m searchfile -c userName:password -u https://gitlab.something.local -o "some search term"`

`SCMKit.exe -s gitlab -m searchfile -c apikey -u https://gitlab.something.local -o "some search term"`

##### Bitbucket Server

The Bitbucket file search is a "contains" search where the string you enter it will search for files that contains your search term in the file name.

`SCMKit.exe -s bitbucket -m searchfile -c userName:password -u https://bitbucket.something.local -o "some search term"`

`SCMKit.exe -s bitbucket -m searchfile -c apikey -u https://bitbucket.something.local -o "some search term"`

#### Example Output

```

C:\source\SCMKit\SCMKit\bin\Release>SCMKit.exe -s bitbucket -m searchfile -c apikey -u http://bitbucket.hogwarts.local:7990 -o jenkinsfile

==================================================
Module:         searchfile
System:         bitbucket
Auth Type:      API Key
Options:        jenkinsfile
Target URL:     http://bitbucket.hogwarts.local:7990

Timestamp:      1/14/2022 10:17:59 PM
==================================================


[>] REPO: http://bitbucket.hogwarts.local:7990/scm/~HPOTTER/hpotter
    [>] FILE: Jenkinsfile

[>] REPO: http://bitbucket.hogwarts.local:7990/scm/STUD/cred-decryption
    [>] FILE: subDir/Jenkinsfile

Total matching results: 2

```

### List Snippets

#### Use Case

> *List snippets owned by the current user in GitLab*

#### Syntax

Provide the `listsnippet` module, along with any relevant authentication information and URL.

##### GitLab Enterprise

`SCMKit.exe -s gitlab -m listsnippet -c userName:password -u https://gitlab.something.local`

`SCMKit.exe -s gitlab -m listsnippet -c apikey -u https://gitlab.something.local`

#### Example Output

```

C:\>SCMKit.exe -s gitlab -m listsnippet -c username:password -u https://gitlab.hogwarts.local

==================================================
Module:         listsnippet
System:         gitlab
Auth Type:      Username/Password
Options:
Target URL:     https://gitlab.hogwarts.local

Timestamp:      1/14/2022 9:17:36 PM
==================================================

               Title |                                                                Raw URL
---------------------------------------------------------------------------------------------
        spell-script |                         https://gitlab.hogwarts.local/-/snippets/2/raw
```

### List Runners

#### Use Case

> *List all GitLab runners available to the current user in GitLab*

#### Syntax

Provide the `listrunner` module, along with any relevant authentication information and URL. If the user is an administrator, you will be able to list all runners within the GitLab Enterprise instance, which includes shared and group runners. 

##### GitLab Enterprise

`SCMKit.exe -s gitlab -m listrunner -c userName:password -u https://gitlab.something.local`

`SCMKit.exe -s gitlab -m listrunner -c apikey -u https://gitlab.something.local`

#### Example Output

```

C:\>SCMKit.exe -s gitlab -m listrunner -c username:password -u https://gitlab.hogwarts.local

==================================================
Module:         listrunner
System:         gitlab
Auth Type:      Username/Password
Options:
Target URL:     https://gitlab.hogwarts.local

Timestamp:      1/25/2022 11:40:08 AM
==================================================

   ID |                 Name |                                      Repo Assigned
---------------------------------------------------------------------------------
    2 |        gitlab-runner | https://gitlab.hogwarts.local/hpotter/spellbook.git
    3 |        gitlab-runner | https://gitlab.hogwarts.local/hpotter/maraudersmap.git
    
```


### List Gists

#### Use Case

> *List gists owned by the current user in GitHub*

#### Syntax

Provide the `listgist` module, along with any relevant authentication information and URL.

##### GitHub Enterprise

`SCMKit.exe -s github -m listgist -c userName:password -u https://github.something.local`

`SCMKit.exe -s github -m listgist -c apikey -u https://github.something.local`

#### Example Output

```

C:\>SCMKit.exe -s github -m listgist -c username:password -u https://github-enterprise.hogwarts.local

==================================================
Module:         listgist
System:         github
Auth Type:      Username/Password
Options:
Target URL:     https://github-enterprise.hogwarts.local

Timestamp:      1/14/2022 9:43:23 PM
==================================================

                             Description | Visibility |                                                URL
----------------------------------------------------------------------------------------------------------
            Shell Script to Decode Spell |     public | https://github-enterprise.hogwarts.local/gist/c11c6bb3f47fe67183d5bc9f048412a1
            
```

### List Orgs

#### Use Case

> *List all organizations the current user belongs to in GitHub*

#### Syntax

Provide the `listorg` module, along with any relevant authentication information and URL.

##### GitHub Enterprise

`SCMKit.exe -s github -m listorg -c userName:password -u https://github.something.local`

`SCMKit.exe -s github -m listorg -c apiKey -u https://github.something.local`

#### Example Output

```

C:\>SCMKit.exe -s github -m listorg -c username:password -u https://github-enterprise.hogwarts.local

==================================================
Module:         listorg
System:         github
Auth Type:      Username/Password
Options:
Target URL:     https://github-enterprise.hogwarts.local

Timestamp:      1/14/2022 9:44:48 PM
==================================================

                          Name |                                                URL
-----------------------------------------------------------------------------------
                      Hogwarts | https://github-enterprise.hogwarts.local/api/v3/orgs/Hogwarts/repos
                      
```

### Get Privileges of API Token

#### Use Case

> *Get the assigned privileges to an access token being used in a particular SCM system*

#### Syntax

Provide the `privs` module, along with an API key and URL.

##### GitHub Enterprise

`SCMKit.exe -s github -m privs -c apiKey -u https://github.something.local`

##### GitLab Enterprise

`SCMKit.exe -s gitlab -m privs -c apiKey -u https://gitlab.something.local`

#### Example Output

```

C:\>SCMKit.exe -s gitlab -m privs -c apikey -u https://gitlab.hogwarts.local

==================================================
Module:         privs
System:         gitlab
Auth Type:      API Key
Options:
Target URL:     https://gitlab.hogwarts.local

Timestamp:      1/14/2022 9:18:27 PM
==================================================

          Token Name |    Active? |            Privilege |                                                            Description
---------------------------------------------------------------------------------------------------------------------------------
  hgranger-api-token |       True |                  api | Read-write for the complete API, including all groups and projects, the Container Registry, and the Package Registry.
  hgranger-api-token |       True |            read_user | Read-only for endpoints under /users. Essentially, access to any of the GET requests in the Users API.
  hgranger-api-token |       True |             read_api | Read-only for the complete API, including all groups and projects, the Container Registry, and the Package Registry.
  hgranger-api-token |       True |      read_repository |                      Read-only (pull) for the repository through git clone.
  hgranger-api-token |       True |     write_repository | Read-write (pull, push) for the repository through git clone. Required for accessing Git repositories over HTTP when 2FA is enabled.
  
```

### Add Admin

#### Use Case

> *Promote a normal user to an administrative role in a particular SCM system*

#### Syntax

Provide the `addadmin` module, along with any relevant authentication information and URL. Additionally, provide the target user you would like to add an administrative role to.

##### GitHub Enterprise

`SCMKit.exe -s github -m addadmin -c userName:password -u https://github.something.local -o targetUserName`

`SCMKit.exe -s github -m addadmin -c apikey -u https://github.something.local -o targetUserName`

##### GitLab Enterprise

`SCMKit.exe -s gitlab -m addadmin -c userName:password -u https://gitlab.something.local -o targetUserName`

`SCMKit.exe -s gitlab -m addadmin -c apikey -u https://gitlab.something.local -o targetUserName`

##### Bitbucket Server

Only username/password auth is supported to perform actions not related to repos or projects in Bitbucket.

`SCMKit.exe -s bitbucket -m addadmin -c userName:password -u https://bitbucket.something.local -o targetUserName`

#### Example Output

```

C:\>SCMKit.exe -s gitlab -m addadmin -c apikey -u https://gitlab.hogwarts.local -o hgranger

==================================================
Module:         addadmin
System:         gitlab
Auth Type:      API Key
Options:        hgranger
Target URL:     https://gitlab.hogwarts.local

Timestamp:      1/14/2022 9:19:32 PM
==================================================


[+] SUCCESS: The hgranger user was successfully added to the admin role.

```

### Remove Admin

#### Use Case

> *Demote an administrative user to a normal user role in a particular SCM system*

#### Syntax

Provide the `removeadmin` module, along with any relevant authentication information and URL. Additionally, provide the target user you would like to remove an administrative role from.

##### GitHub Enterprise

`SCMKit.exe -s github -m removeadmin -c userName:password -u https://github.something.local -o targetUserName`

`SCMKit.exe -s github -m removeadmin -c apikey -u https://github.something.local -o targetUserName`

##### GitLab Enterprise

`SCMKit.exe -s gitlab -m removeadmin -c userName:password -u https://gitlab.something.local -o targetUserName`

`SCMKit.exe -s gitlab -m removeadmin -c apikey -u https://gitlab.something.local -o targetUserName`

##### Bitbucket Server

Only username/password auth is supported to perform actions not related to repos or projects in Bitbucket.

`SCMKit.exe -s bitbucket -m removeadmin -c userName:password -u https://bitbucket.something.local -o targetUserName`

#### Example Output

```

C:\>SCMKit.exe -s gitlab -m removeadmin -c username:password -u https://gitlab.hogwarts.local -o hgranger

==================================================
Module:         removeadmin
System:         gitlab
Auth Type:      Username/Password
Options:        hgranger
Target URL:     https://gitlab.hogwarts.local

Timestamp:      1/14/2022 9:20:12 PM
==================================================


[+] SUCCESS: The hgranger user was successfully removed from the admin role.

```

### Create Access Token

#### Use Case

> *Create an access token to be used in a particular SCM system*

#### Syntax

Provide the `createpat` module, along with any relevant authentication information and URL. Additionally, provide the target user you would like to create an access token for.

##### GitLab Enterprise

This can only be performed as an administrator. You will provide the username that you would like to create a PAT for.

`SCMKit.exe -s gitlab -m createpat -c userName:password -u https://gitlab.something.local -o targetUserName`

`SCMKit.exe -s gitlab -m createpat -c apikey -u https://gitlab.something.local -o targetUserName`

##### Bitbucket Server

Creates PAT for the current user authenticating as. In Bitbucket you cannot create a PAT for another user, even as an admin. Only username/password auth is supported to perform actions not related to repos or projects in Bitbucket. Take note of the PAT ID that is shown after being created. You will need this when you need to remove the PAT in the future.

`SCMKit.exe -s bitbucket -m createpat -c userName:password -u https://bitbucket.something.local `

#### Example Output

```

C:\>SCMKit.exe -s gitlab -m createpat -c username:password -u https://gitlab.hogwarts.local -o hgranger

==================================================
Module:         createpat
System:         gitlab
Auth Type:      Username/Password
Options:        hgranger
Target URL:     https://gitlab.hogwarts.local

Timestamp:      1/20/2022 1:51:23 PM
==================================================

   ID |         Name |                          Token
-----------------------------------------------------
   59 | SCMKIT-AaCND |           R3ySx_8HUn6UQ_6onETx

[+] SUCCESS: The hgranger user personal access token was successfully added.


```

### List Access Tokens

#### Use Case

> *List access tokens for a user on a particular SCM system*

#### Syntax

Provide the `listpat` module, along with any relevant authentication information and URL. 

##### GitLab Enterprise

Only requires admin if you want to list another user's PAT's. A regular user can list their own PAT's.

`SCMKit.exe -s gitlab -m listpat -c userName:password -u https://gitlab.something.local -o targetUser`

`SCMKit.exe -s gitlab -m listpat -c apikey -u https://gitlab.something.local -o targetUser`

##### Bitbucket Server

List access tokens for current user. Only username/password auth is supported to perform actions not related to repos or projects in Bitbucket.

`SCMKit.exe -s bitbucket -m listpat -c userName:password -u https://bitbucket.something.local`

List access tokens for another user (requires admin). Only username/password auth is supported to perform actions not related to repos or projects in Bitbucket.

`SCMKit.exe -s bitbucket -m listpat -c userName:password -u https://bitbucket.something.local -o targetUser`

#### Example Output

```

C:\>SCMKit.exe -s gitlab -m listpat -c username:password -u https://gitlab.hogwarts.local -o hgranger

==================================================
Module:         listpat
System:         gitlab
Auth Type:      Username/Password
Options:        hgranger
Target URL:     https://gitlab.hogwarts.local

Timestamp:      1/20/2022 1:54:41 PM
==================================================

   ID |                 Name |    Active? |                                             Scopes
----------------------------------------------------------------------------------------------
   59 |         SCMKIT-AaCND |       True |             api, read_repository, write_repository
    
```

### Remove Access Token

#### Use Case

> *Remove an access token for a user in a particular SCM system*

#### Syntax

Provide the `removepat` module, along with any relevant authentication information and URL. Additionally, provide the target user PAT ID you would like to remove an access token for.

##### GitLab Enterprise

Only requires admin if you want to remove another user's PAT. A regular user can remove their own PAT. You have to provide the PAT ID to remove. This ID was shown whenever you created the PAT and also when you listed the PAT.

`SCMKit.exe -s gitlab -m removepat -c userName:password -u https://gitlab.something.local -o patID`

`SCMKit.exe -s gitlab -m removepat -c apikey -u https://gitlab.something.local -o patID`

##### Bitbucket Server

Only username/password auth is supported to perform actions not related to repos or projects in Bitbucket. You have to provide the PAT ID to remove. This ID was shown whenever you created the PAT.

`SCMKit.exe -s bitbucket -m removepat -c userName:password -u https://bitbucket.something.local -o patID`

#### Example Output

```

C:\>SCMKit.exe -s gitlab -m removepat -c apikey -u https://gitlab.hogwarts.local -o 58

==================================================
Module:         removepat
System:         gitlab
Auth Type:      API Key
Options:        59
Target URL:     https://gitlab.hogwarts.local

Timestamp:      1/20/2022 1:56:47 PM
==================================================



[*] INFO: Revoking personal access token of ID: 59


[+] SUCCESS: The personal access token of ID 59 was successfully revoked.

```


### Create SSH Key

#### Use Case

> *Create an SSH key to be used in a particular SCM system*

#### Syntax

Provide the `createsshkey` module, along with any relevant authentication information and URL.

##### GitHub Enterprise

Creates SSH key for the current user authenticating as.

`SCMKit.exe -s github -m createsshkey -c userName:password -u https://github.something.local -o "ssh public key"`

`SCMKit.exe -s github -m createsshkey -c apiToken -u https://github.something.local -o "ssh public key"`

##### GitLab Enterprise

Creates SSH key for the current user authenticating as. Take note of the SSH key ID that is shown after being created. You will need this when you need to remove the SSH key in the future.

`SCMKit.exe -s gitlab -m createsshkey -c userName:password -u https://gitlab.something.local -o "ssh public key"`

`SCMKit.exe -s gitlab -m createsshkey -c apiToken -u https://gitlab.something.local -o "ssh public key"`


##### Bitbucket Server

Creates SSH key for the current user authenticating as. Only username/password auth is supported to perform actions not related to repos or projects in Bitbucket. Take note of the SSH key ID that is shown after being created. You will need this when you need to remove the SSH key in the future.

`SCMKit.exe -s bitbucket -m createsshkey -c userName:password -u https://bitbucket.something.local -o "ssh public key"`

#### Example Output

```

C:\>SCMKit.exe -s bitbucket -m createsshkey -c username:password -u https://bitbucket.hogwarts.local -o "ssh-rsa..."

==================================================
Module:         createsshkey
System:         bitbucket
Auth Type:      Username/Password
Options:        ssh-rsa ...
Target URL:     http://bitbucket.hogwarts.local:7990

Timestamp:      2/7/2022 1:02:31 PM
==================================================

  SSH Key ID
------------
          16

[+] SUCCESS: The hpotter user SSH key was successfully added.


```

### List SSH Keys

#### Use Case

> *List SSH keys for a user on a particular SCM system*

#### Syntax

Provide the `listsshkey` module, along with any relevant authentication information and URL. 

##### GitHub Enterprise

List SSH keys for current user. This will include SSH key ID's, which is needed when you would want to remove an SSH key.

`SCMKit.exe -s github -m listsshkey -c userName:password -u https://github.something.local`

`SCMKit.exe -s github -m listsshkey -c apiToken -u https://github.something.local`

##### GitLab Enterprise

List SSH keys for current user.

`SCMKit.exe -s gitlab -m listsshkey -c userName:password -u https://gitlab.something.local`

`SCMKit.exe -s gitlab -m listsshkey -c apiToken -u https://gitlab.something.local`


##### Bitbucket Server

List SSH keys for current user. Only username/password auth is supported to perform actions not related to repos or projects in Bitbucket.

`SCMKit.exe -s bitbucket -m listsshkey -c userName:password -u https://bitbucket.something.local`


#### Example Output

```

C:\>SCMKit.exe -s gitlab -m listsshkey -u http://gitlab.hogwarts.local -c apiToken

==================================================
Module:         listsshkey
System:         gitlab
Auth Type:      API Key
Options:
Target URL:     https://gitlab.hogwarts.local

Timestamp:      2/7/2022 4:09:40 PM
==================================================

  SSH Key ID |             SSH Key Value |                Title
---------------------------------------------------------------
           9 | .....p50edigBAF4lipVZkAM= |         SCMKIT-RLzie
          10 | .....vGJLPGHiTwIxW9i+xAs= |         SCMKIT-muFGU
    
```

### Remove SSH Key

#### Use Case

> *Remove an SSH key for a user in a particular SCM system*

#### Syntax

Provide the `removesshkey` module, along with any relevant authentication information and URL. Additionally, provide the target user SSH key ID to remove.

##### GitHub Enterprise

You have to provide the SSH key ID to remove. This ID was shown whenever you list SSH keys.

`SCMKit.exe -s github -m removesshkey -c userName:password -u https://github.something.local -o sshKeyID`

`SCMKit.exe -s github -m removesshkey -c apiToken -u https://github.something.local -o sshKeyID`

##### GitLab Enterprise

 You have to provide the SSH key ID to remove. This ID was shown whenever you created the SSH key and is also shown when listing SSH keys.

`SCMKit.exe -s gitlab -m removesshkey -c userName:password -u https://gitlab.something.local -o sshKeyID`

`SCMKit.exe -s gitlab -m removesshkey -c apiToken -u https://gitlab.something.local -o sshKeyID`

##### Bitbucket Server

Only username/password auth is supported to perform actions not related to repos or projects in Bitbucket. You have to provide the SSH key ID to remove. This ID was shown whenever you created the SSH key and is also shown when listing SSH keys.

`SCMKit.exe -s bitbucket -m removesshkey -c userName:password -u https://bitbucket.something.local -o sshKeyID`

#### Example Output

```

C:\>SCMKit.exe -s bitbucket -m removesshkey -u http://bitbucket.hogwarts.local:7990 -c username:password -o 16

==================================================
Module:         removesshkey
System:         bitbucket
Auth Type:      Username/Password
Options:        16
Target URL:     http://bitbucket.hogwarts.local:7990

Timestamp:      2/7/2022 1:48:03 PM
==================================================


[+] SUCCESS: The SSH key of ID 16 was successfully revoked.

```


### List Admin Stats

#### Use Case

> *List admin stats in GitHub Enterprise*

#### Syntax

Provide the `adminstats` module, along with any relevant authentication information and URL. Site admin access in GitHub Enterprise is required to use this module

##### GitHub Enterprise

`SCMKit.exe -s github -m adminstats -c userName:password -u https://github.something.local`

`SCMKit.exe -s github -m adminstats -c apikey -u https://github.something.local`

#### Example Output

```

C:\>SCMKit.exe -s github -m adminstats -c username:password -u https://github-enterprise.hogwarts.local

==================================================
Module:         adminstats
System:         github
Auth Type:      Username/Password
Options:
Target URL:     https://github-enterprise.hogwarts.local

Timestamp:      1/14/2022 9:45:50 PM
==================================================

     Admin Users |  Suspended Users |      Total Users
------------------------------------------------------
               1 |                0 |                5


     Total Repos |      Total Wikis
-----------------------------------
               4 |                0


      Total Orgs |   Total Team Members |      Total Teams
----------------------------------------------------------
               1 |                    0 |                0


   Private Gists |     Public Gists
-----------------------------------
               0 |                1
               
```

### List Branch Protection

#### Use Case

> *List branch protections in GitHub Enterprise*

#### Syntax

Provide the `protection` module, along with any relevant authentication information and URL. Optionally, supply a string in the options parameter to return matching results contained in repo names

##### GitHub Enterprise

`SCMKit.exe -s github -m protection -c userName:password -u https://github.something.local`

`SCMKit.exe -s github -m protection -c apikey -u https://github.something.local`

`SCMKit.exe -s github -m protection -c apikey -u https://github.something.local -o reponame`

#### Example Output

```
C:\>.\SCMKit.exe -u http://github.hogwarts.local -s github -c apiToken -m protection -o public-r

==================================================
Module:         protection
System:         github
Auth Type:      API Key
Options:        public-r
Target URL:     http://github.hogwarts.local

Timestamp:      8/29/2022 2:02:42 PM
==================================================

                     Repo |                    Branch |                                         Protection
----------------------------------------------------------------------------------------------------------
              public-repo |                       dev | Protected: True
                                                        Status checks must pass before merge:
                                                          Branch must be up-to-date before merge: True
                                                        Owner review required before merge: True
                                                        Approvals required before merge: 2
                                                        Protections apply to repo admins: True
              public-repo |                      main | Protected: False
```

## Detection

Below are static signatures for the specific usage of this tool in its default state:

* Project GUID - `{266C644A-69B1-426B-A47C-1CF32B211F80}`
  * See [SCMKit Yara Rule](Detections/SCMKit.yar) in this repo.
* User Agent String - `SCMKIT-5dc493ada400c79dd318abbe770dac7c`
  * See [SCMKit Snort Rule](Detections/SCMKit.rules) in this repo.
* Access Token & SSH Key Names - Access tokens and SSH keys that are created using the tool are prepended with `SCMKIT-` for the name.

For detection guidance of the techniques used by the tool, see the X-Force Red [blog post](https://securityintelligence.com/posts/abusing-source-code-management-systems).

## References
* Bitbucket API Documentation 
  * https://developer.atlassian.com/server/bitbucket/reference/rest-api/
* Octokit Documentation
  * https://octokitnet.readthedocs.io/en/latest/
  * https://github.com/octokit/octokit.net
* GitHub API Documentation
  * https://docs.github.com/en/rest/overview
* GitLab API Documentation
  * https://docs.gitlab.com/ee/api/api_resources.html
* GitLabApiClient Nuget Package Documentation
  * https://github.com/nmklotas/GitLabApiClient


================================================
FILE: SCMKit/App.config
================================================
<?xml version="1.0" encoding="utf-8"?>
<configuration>
    <startup> 
        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.8" />
    </startup>
  <runtime>
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
      <dependentAssembly>
        <assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral" />
        <bindingRedirect oldVersion="0.0.0.0-13.0.0.0" newVersion="13.0.0.0" />
      </dependentAssembly>
    </assemblyBinding>
  </runtime>
</configuration>

================================================
FILE: SCMKit/FodyWeavers.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd">
  <Costura />
</Weavers>

================================================
FILE: SCMKit/Properties/AssemblyInfo.cs
================================================
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;

// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("SCMKit")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("SCMKit")]
[assembly: AssemblyCopyright("Copyright © 2022")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]

// Setting ComVisible to false makes the types in this assembly not visible
// to COM components.  If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]

// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("266c644a-69b1-426b-a47c-1cf32b211f80")]

// Version information for an assembly consists of the following four values:
//
//      Major Version
//      Minor Version
//      Build Number
//      Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.2")]
[assembly: AssemblyFileVersion("1.2")]


================================================
FILE: SCMKit/SCMKit.cs
================================================
using System;
using System.Collections.Generic;
using System.Threading.Tasks;

namespace SCMKit
{
    class SCMKit
    {

        // variables to be used
        private static string module = "";
        private static string credential = "";
        private static string system = "";
        private static string url = "";
        private static string option = "";
        private static List<string> approvedModules = new List<string> { "listrepo", "repolist", "reposearch", "codesearch", "snippetlist", "gistlist", "orglist", "searchrepo", "searchcode", "searchfile", "listsnippet", "listgist", "listorg", "privs", "addadmin", "removeadmin", "createpat", "removepat", "listpat", "adminstats", "listrunner", "runnerlist", "createsshkey", "removesshkey", "listsshkey", "protection" };


        static async Task Main(string[] args)
        {

            try
            {

                Dictionary<string, string> argDict = library.Utils.ParseTheArguments(args); // dictionary to hold arguments

                // if no arguments given, display help and return
                if ((args.Length > 0 && argDict.Count == 0) || argDict.ContainsKey("h") || argDict.ContainsKey("help"))
                {
                    library.Utils.HelpMe();
                    return;
                }

                // if url is not set, display message and exit
                if ((!argDict.ContainsKey("u") && !argDict.ContainsKey("url")))
                {
                    Console.WriteLine("");
                    Console.WriteLine("[-] ERROR: Must supply a URL. See the README.");
                    return;
                }

                // if system is not set, display message and exit
                if ((!argDict.ContainsKey("s") && !argDict.ContainsKey("system")))
                {
                    Console.WriteLine("");
                    Console.WriteLine("[-] ERROR: Must supply a system. See the README.");
                    return;
                }

                // if both module and credential are not given, display message and exit
                if ((!argDict.ContainsKey("m") && !argDict.ContainsKey("module")) && (!argDict.ContainsKey("c") && !argDict.ContainsKey("credential")))
                {
                    Console.WriteLine("");
                    Console.WriteLine("[-] ERROR: Must supply both a module and credential. See the README.");
                    return;
                }

                // initialize variables

                // module
                if (argDict.ContainsKey("m") || argDict.ContainsKey("module"))
                {
                    if (argDict.ContainsKey("m"))
                    {
                        module = argDict["m"];
                    }
                    else
                    {
                        module = argDict["module"];
                    }
                }

                // options
                if (argDict.ContainsKey("o") || argDict.ContainsKey("options"))
                {
                    if (argDict.ContainsKey("o"))
                    {
                        option = argDict["o"];
                    }
                    else
                    {
                        option = argDict["options"];
                    }
                }


                // credential
                if (argDict.ContainsKey("c") || argDict.ContainsKey("credential"))
                {
                    if (argDict.ContainsKey("c"))
                    {
                        credential = argDict["c"];
                    }
                    else
                    {
                        credential = argDict["credential"];
                    }

                }


                // url
                if (argDict.ContainsKey("u") || argDict.ContainsKey("url"))
                {
                    if (argDict.ContainsKey("u"))
                    {
                        url = argDict["u"];
                    }
                    else
                    {
                        url = argDict["url"];
                    }

                }


                // system
                if (argDict.ContainsKey("s") || argDict.ContainsKey("system"))
                {
                    if (argDict.ContainsKey("s"))
                    {
                        system = argDict["s"];
                    }
                    else
                    {
                        system = argDict["system"];
                    }

                }

                // determine if invalid module was given
                if (!approvedModules.Contains(module.ToLower()))
                {
                    Console.WriteLine("");
                    Console.WriteLine("[-] ERROR: Invalid module given. Please see the README for approved modules.");
                    return;
                }


                // system is github
                if (system.ToLower().Equals("github"))
                {

                    // get to the appropriate module that user specified
                    switch (module.ToLower())
                    {
                        case "listrepo":
                            await modules.github.RepoList.execute(credential, url, option, system);
                            break;
                        case "searchrepo":
                            await modules.github.RepoSearch.execute(credential, url, option, system);
                            break;
                        case "searchcode":
                            await modules.github.CodeSearch.execute(credential, url, option, system);
                            break;
                        case "searchfile":
                            await modules.github.FileSearch.execute(credential, url, option, system);
                            break;
                        case "listgist":
                            await modules.github.GistList.execute(credential, url, option, system);
                            break;
                        case "listorg":
                            await modules.github.OrgList.execute(credential, url, option, system);
                            break;
                        case "repolist":
                            await modules.github.RepoList.execute(credential, url, option, system);
                            break;
                        case "reposearch":
                            await modules.github.RepoSearch.execute(credential, url, option, system);
                            break;
                        case "codesearch":
                            await modules.github.CodeSearch.execute(credential, url, option, system);
                            break;
                        case "filesearch":
                            await modules.github.FileSearch.execute(credential, url, option, system);
                            break;
                        case "gistlist":
                            await modules.github.GistList.execute(credential, url, option, system);
                            break;
                        case "orglist":
                            await modules.github.OrgList.execute(credential, url, option, system);
                            break;
                        case "privs":
                            await modules.github.Privs.execute(credential, url, option, system);
                            break;
                        case "addadmin":
                            await modules.github.AddAdmin.execute(credential, url, option, system);
                            break;
                        case "removeadmin":
                            await modules.github.RemoveAdmin.execute(credential, url, option, system);
                            break;
                        case "adminstats":
                            await modules.github.AdminStats.execute(credential, url, option, system);
                            break;
                        case "createsshkey":
                            await modules.github.CreateSSHKey.execute(credential, url, option, system);
                            break;
                        case "listsshkey":
                            await modules.github.ListSSHKeys.execute(credential, url, option, system);
                            break;
                        case "removesshkey":
                            await modules.github.RemoveSSHKey.execute(credential, url, option, system);
                            break;
                        case "protection":
                            await modules.github.BranchProtection.execute(credential, url, option, system);
                            break;
                        default:
                            Console.WriteLine("");
                            Console.WriteLine("[-] ERROR: That module is not supported for " + system + ". Please see README");
                            Console.WriteLine("");
                            Environment.Exit(1);
                            break;
                    }

                }

                // system is gitlab
                else if (system.ToLower().Equals("gitlab"))
                {
                    // get to the appropriate module that user specified
                    switch (module.ToLower())
                    {
                        case "listrepo":
                            await modules.gitlab.RepoList.execute(credential, url, option, system);
                            break;
                        case "searchrepo":
                            await modules.gitlab.RepoSearch.execute(credential, url, option, system);
                            break;
                        case "searchcode":
                            await modules.gitlab.CodeSearch.execute(credential, url, option, system);
                            break;
                        case "searchfile":
                            await modules.gitlab.FileSearch.execute(credential, url, option, system);
                            break;
                        case "listsnippet":
                            await modules.gitlab.SnippetList.execute(credential, url, option, system);
                            break;
                        case "repolist":
                            await modules.gitlab.RepoList.execute(credential, url, option, system);
                            break;
                        case "reposearch":
                            await modules.gitlab.RepoSearch.execute(credential, url, option, system);
                            break;
                        case "codesearch":
                            await modules.gitlab.CodeSearch.execute(credential, url, option, system);
                            break;
                        case "filesearch":
                            await modules.gitlab.FileSearch.execute(credential, url, option, system);
                            break;
                        case "snippetlist":
                            await modules.gitlab.SnippetList.execute(credential, url, option, system);
                            break;
                        case "privs":
                            await modules.gitlab.Privs.execute(credential, url, option, system);
                            break;
                        case "createpat":
                            await modules.gitlab.CreatePAT.execute(credential, url, option, system);
                            break;
                        case "listpat":
                            await modules.gitlab.ListPAT.execute(credential, url, option, system);
                            break;
                        case "removepat":
                            await modules.gitlab.RemovePAT.execute(credential, url, option, system);
                            break;
                        case "addadmin":
                            await modules.gitlab.AddAdmin.execute(credential, url, option, system);
                            break;
                        case "removeadmin":
                            await modules.gitlab.RemoveAdmin.execute(credential, url, option, system);
                            break;
                        case "listrunner":
                            await modules.gitlab.RunnerList.execute(credential, url, option, system);
                            break;
                        case "runnerlist":
                            await modules.gitlab.RunnerList.execute(credential, url, option, system);
                            break;
                        case "createsshkey":
                            await modules.gitlab.CreateSSHKey.execute(credential, url, option, system);
                            break;
                        case "removesshkey":
                            await modules.gitlab.RemoveSSHKey.execute(credential, url, option, system);
                            break;
                        case "listsshkey":
                            await modules.gitlab.ListSSHKeys.execute(credential, url, option, system);
                            break;
                        default:
                            Console.WriteLine("");
                            Console.WriteLine("[-] ERROR: That module is not supported for " + system + ". Please see README");
                            Console.WriteLine("");
                            Environment.Exit(1);
                            break;
                    }
                }

                // system is bitbucket
                else if (system.ToLower().Equals("bitbucket"))
                {
                    // get to the appropriate module that user specified
                    switch (module.ToLower())
                    {
                        case "listrepo":
                            await modules.bitbucket.RepoList.execute(credential, url, option, system);
                            break;
                        case "searchrepo":
                            await modules.bitbucket.RepoSearch.execute(credential, url, option, system);
                            break;
                        case "searchcode":
                            await modules.bitbucket.CodeSearch.execute(credential, url, option, system);
                            break;
                        case "searchfile":
                            await modules.bitbucket.FileSearch.execute(credential, url, option, system);
                            break;
                        case "repolist":
                            await modules.bitbucket.RepoList.execute(credential, url, option, system);
                            break;
                        case "reposearch":
                            await modules.bitbucket.RepoSearch.execute(credential, url, option, system);
                            break;
                        case "codesearch":
                            await modules.bitbucket.CodeSearch.execute(credential, url, option, system);
                            break;
                        case "filesearch":
                            await modules.bitbucket.FileSearch.execute(credential, url, option, system);
                            break;
                        case "createpat":
                            await modules.bitbucket.CreatePAT.execute(credential, url, option, system);
                            break;
                        case "listpat":
                            await modules.bitbucket.ListPAT.execute(credential, url, option, system);
                            break;
                        case "removepat":
                            await modules.bitbucket.RemovePAT.execute(credential, url, option, system);
                            break;
                        case "addadmin":
                            await modules.bitbucket.AddAdmin.execute(credential, url, option, system);
                            break;
                        case "removeadmin":
                            await modules.bitbucket.RemoveAdmin.execute(credential, url, option, system);
                            break;
                        case "createsshkey":
                            await modules.bitbucket.CreateSSHKey.execute(credential, url, option, system);
                            break;
                        case "removesshkey":
                            await modules.bitbucket.RemoveSSHKey.execute(credential, url, option, system);
                            break;
                        case "listsshkey":
                            await modules.bitbucket.ListSSHKeys.execute(credential, url, option, system);
                            break;
                        default:
                            Console.WriteLine("");
                            Console.WriteLine("[-] ERROR: That module is not supported for " + system + ". Please see README");
                            Console.WriteLine("");
                            break;
                    }
                }

                // invalid system given
                else
                {
                    Console.WriteLine("");
                    Console.WriteLine("[-] ERROR: Invalid system given. Please see the README for approved modules.");
                    return;
                }

            } // end try

            catch (Exception ex)
            {
                Console.WriteLine("");
                Console.WriteLine("[-] ERROR : {0}", ex.Message);
            }


        } // end main

    } // end class

} // end namespace

================================================
FILE: SCMKit/SCMKit.csproj
================================================
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <Import Project="..\packages\Costura.Fody.3.3.3\build\Costura.Fody.props" Condition="Exists('..\packages\Costura.Fody.3.3.3\build\Costura.Fody.props')" />
  <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
  <PropertyGroup>
    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
    <ProjectGuid>{266C644A-69B1-426B-A47C-1CF32B211F80}</ProjectGuid>
    <OutputType>Exe</OutputType>
    <RootNamespace>SCMKit</RootNamespace>
    <AssemblyName>SCMKit</AssemblyName>
    <TargetFrameworkVersion>v4.8</TargetFrameworkVersion>
    <FileAlignment>512</FileAlignment>
    <AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
    <Deterministic>true</Deterministic>
    <NuGetPackageImportStamp>
    </NuGetPackageImportStamp>
    <PublishUrl>publish\</PublishUrl>
    <Install>true</Install>
    <InstallFrom>Disk</InstallFrom>
    <UpdateEnabled>false</UpdateEnabled>
    <UpdateMode>Foreground</UpdateMode>
    <UpdateInterval>7</UpdateInterval>
    <UpdateIntervalUnits>Days</UpdateIntervalUnits>
    <UpdatePeriodically>false</UpdatePeriodically>
    <UpdateRequired>false</UpdateRequired>
    <MapFileExtensions>true</MapFileExtensions>
    <ApplicationRevision>0</ApplicationRevision>
    <ApplicationVersion>1.0.0.%2a</ApplicationVersion>
    <IsWebBootstrapper>false</IsWebBootstrapper>
    <UseApplicationTrust>false</UseApplicationTrust>
    <BootstrapperEnabled>true</BootstrapperEnabled>
  </PropertyGroup>
  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
    <PlatformTarget>AnyCPU</PlatformTarget>
    <DebugSymbols>true</DebugSymbols>
    <DebugType>full</DebugType>
    <Optimize>false</Optimize>
    <OutputPath>bin\Debug\</OutputPath>
    <DefineConstants>DEBUG;TRACE</DefineConstants>
    <ErrorReport>prompt</ErrorReport>
    <WarningLevel>4</WarningLevel>
  </PropertyGroup>
  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
    <PlatformTarget>AnyCPU</PlatformTarget>
    <DebugType>none</DebugType>
    <Optimize>true</Optimize>
    <OutputPath>bin\Release\</OutputPath>
    <DefineConstants>TRACE</DefineConstants>
    <ErrorReport>prompt</ErrorReport>
    <WarningLevel>4</WarningLevel>
  </PropertyGroup>
  <ItemGroup>
    <Reference Include="Costura, Version=3.3.3.0, Culture=neutral, PublicKeyToken=9919ef960d84173d, processorArchitecture=MSIL">
      <HintPath>..\packages\Costura.Fody.3.3.3\lib\net40\Costura.dll</HintPath>
    </Reference>
    <Reference Include="GitLabApiClient, Version=1.8.0.0, Culture=neutral, processorArchitecture=MSIL">
      <HintPath>..\packages\GitLabApiClient.1.8.0\lib\net48\GitLabApiClient.dll</HintPath>
    </Reference>
    <Reference Include="Newtonsoft.Json, Version=13.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
      <HintPath>..\packages\Newtonsoft.Json.13.0.1\lib\net45\Newtonsoft.Json.dll</HintPath>
    </Reference>
    <Reference Include="Octokit, Version=2.0.1.0, Culture=neutral, processorArchitecture=MSIL">
      <HintPath>..\packages\Octokit.2.0.1\lib\netstandard2.0\Octokit.dll</HintPath>
    </Reference>
    <Reference Include="System" />
    <Reference Include="System.Core" />
    <Reference Include="System.Xml.Linq" />
    <Reference Include="System.Data.DataSetExtensions" />
    <Reference Include="Microsoft.CSharp" />
    <Reference Include="System.Data" />
    <Reference Include="System.Net.Http" />
    <Reference Include="System.Xml" />
  </ItemGroup>
  <ItemGroup>
    <Compile Include="library\BitbucketUtils.cs" />
    <Compile Include="library\GitHubUtils.cs" />
    <Compile Include="library\GitLabUtils.cs" />
    <Compile Include="library\Utils.cs" />
    <Compile Include="library\WebUtils.cs" />
    <Compile Include="modules\bitbucket\AddAdmin.cs" />
    <Compile Include="modules\bitbucket\CodeSearch.cs" />
    <Compile Include="modules\bitbucket\CreatePAT.cs" />
    <Compile Include="modules\bitbucket\CreateSSHKey.cs" />
    <Compile Include="modules\bitbucket\FileSearch.cs" />
    <Compile Include="modules\bitbucket\ListPAT.cs" />
    <Compile Include="modules\bitbucket\ListSSHKeys.cs" />
    <Compile Include="modules\bitbucket\RemoveAdmin.cs" />
    <Compile Include="modules\bitbucket\RemovePAT.cs" />
    <Compile Include="modules\bitbucket\RemoveSSHKey.cs" />
    <Compile Include="modules\bitbucket\RepoList.cs" />
    <Compile Include="modules\bitbucket\RepoSearch.cs" />
    <Compile Include="modules\github\AddAdmin.cs" />
    <Compile Include="modules\github\AdminStats.cs" />
    <Compile Include="modules\github\BranchProtection.cs" />
    <Compile Include="modules\github\CreateSSHKey.cs" />
    <Compile Include="modules\github\FileSearch.cs" />
    <Compile Include="modules\github\GistList.cs" />
    <Compile Include="modules\github\ListSSHKeys.cs" />
    <Compile Include="modules\github\OrgList.cs" />
    <Compile Include="modules\github\Privs.cs" />
    <Compile Include="modules\github\RemoveAdmin.cs" />
    <Compile Include="modules\github\RemoveSSHKey.cs" />
    <Compile Include="modules\github\RepoList.cs" />
    <Compile Include="modules\github\CodeSearch.cs" />
    <Compile Include="modules\github\RepoSearch.cs" />
    <Compile Include="modules\gitlab\AddAdmin.cs" />
    <Compile Include="modules\gitlab\CodeSearch.cs" />
    <Compile Include="modules\gitlab\CreatePAT.cs" />
    <Compile Include="modules\gitlab\CreateSSHKey.cs" />
    <Compile Include="modules\gitlab\FileSearch.cs" />
    <Compile Include="modules\gitlab\ListPAT.cs" />
    <Compile Include="modules\gitlab\ListSSHKeys.cs" />
    <Compile Include="modules\gitlab\Privs.cs" />
    <Compile Include="modules\gitlab\RemoveAdmin.cs" />
    <Compile Include="modules\gitlab\RemovePAT.cs" />
    <Compile Include="modules\gitlab\RemoveSSHKey.cs" />
    <Compile Include="modules\gitlab\RepoList.cs" />
    <Compile Include="modules\gitlab\RepoSearch.cs" />
    <Compile Include="modules\gitlab\RunnerList.cs" />
    <Compile Include="modules\gitlab\SnippetList.cs" />
    <Compile Include="SCMKit.cs" />
    <Compile Include="Properties\AssemblyInfo.cs" />
  </ItemGroup>
  <ItemGroup>
    <None Include="App.config" />
    <None Include="packages.config" />
  </ItemGroup>
  <ItemGroup />
  <ItemGroup>
    <BootstrapperPackage Include=".NETFramework,Version=v4.8">
      <Visible>False</Visible>
      <ProductName>Microsoft .NET Framework 4.8 %28x86 and x64%29</ProductName>
      <Install>true</Install>
    </BootstrapperPackage>
    <BootstrapperPackage Include="Microsoft.Net.Framework.3.5.SP1">
      <Visible>False</Visible>
      <ProductName>.NET Framework 3.5 SP1</ProductName>
      <Install>false</Install>
    </BootstrapperPackage>
  </ItemGroup>
  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
  <Import Project="..\packages\Fody.4.0.2\build\Fody.targets" Condition="Exists('..\packages\Fody.4.0.2\build\Fody.targets')" />
  <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
    <PropertyGroup>
      <ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them.  For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
    </PropertyGroup>
    <Error Condition="!Exists('..\packages\Fody.4.0.2\build\Fody.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Fody.4.0.2\build\Fody.targets'))" />
    <Error Condition="!Exists('..\packages\Costura.Fody.3.3.3\build\Costura.Fody.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Costura.Fody.3.3.3\build\Costura.Fody.props'))" />
  </Target>
</Project>

================================================
FILE: SCMKit/library/BitbucketUtils.cs
================================================
using System;
using System.IO;
using System.Net;
using System.Net.Security;
using System.Security.Cryptography.X509Certificates;
using System.Threading.Tasks;
using Newtonsoft.Json;

namespace SCMKit.library
{
    class BitbucketUtils
    {


        /**
        * authenticate to Bitbucket to get SESSION ID if not using API auth
        * 
        * */
        public static string GetSessionID(string credentials, string url)
        {
            try
            {
                ServicePointManager.ServerCertificateValidationCallback = delegate (object s, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) { return true; };

                string sessID = "";
                bool authValid = false;
                var webRequest = (HttpWebRequest)System.Net.WebRequest.Create(url + "/j_atl_security_check");

                if (webRequest != null)
                {
                    // set header values
                    webRequest.Method = "POST";
                    webRequest.ContentType = "application/x-www-form-urlencoded";
                    webRequest.UserAgent = "SCMKIT-5dc493ada400c79dd318abbe770dac7c";
                    webRequest.AllowAutoRedirect = false;
                    string[] theCreds = credentials.Split(':');


                    // set body and send request
                    using (var streamWriter = new StreamWriter(webRequest.GetRequestStream()))
                    {

                        string body = "j_username=" + theCreds[0] + "&j_password=" + theCreds[1] + "&_atl_remember_me=on&submit=Log+in";
                        streamWriter.Write(body);
                    }

                    // get the response and the Bitbucket session ID
                    var httpResponse = (HttpWebResponse)webRequest.GetResponse();
                    var streamReader = new StreamReader(httpResponse.GetResponseStream());
                    string result = streamReader.ReadToEnd();

                    for (int i = 0; i < httpResponse.Headers.Count; ++i)
                    {

                        string[] splitValues = httpResponse.Headers[i].Split(',');
                        foreach (string val in splitValues)
                        {

                            // this header is set only if auth request is valid
                            if (val.Contains("_atl_bitbucket_remember_me"))
                            {
                                authValid = true;
                            }

                            // get the bitbucket session ID
                            if (val.Contains("BITBUCKETSESSIONID=") && authValid)
                            {

                                string[] splitValsAgain = val.Split(';');
                                sessID = splitValsAgain[0];
                                sessID = sessID.Replace("BITBUCKETSESSIONID=", "");

                            }
                        }


                    }

                }

                // if auth was valid return the session ID
                if (authValid)
                {
                    return sessID;

                }

                // if auth wasn't valid, return error and exit
                else
                {
                    Console.WriteLine("");
                    Console.WriteLine("[-] ERROR: Could not authenticate to URL with credentials provided.");
                    Console.WriteLine("");
                    return null;
                }


            }

            catch (Exception ex)
            {
                Console.WriteLine("");
                Console.WriteLine("[-] ERROR: Could not authenticate to URL with credentials provided. Exception: " + ex.ToString());
                Console.WriteLine("");
                return null;
            }

        }



        /**
         * Get the full Bitbucket URL, based on project key and repo slug
         * 
         * */
        public static async Task<string> GetFullBitbucketRepoURLAsync(string credential, string sessID, string projKey, string repoSlug, string url)
        {
            string urlToReturn = "Unable to Determine";

            try
            {
                ServicePointManager.ServerCertificateValidationCallback = delegate (object s, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) { return true; };
                ServicePointManager.Expect100Continue = true;
                ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;


                // web request to get a repo details in Bitbucket via API
                var webRequest = (HttpWebRequest)System.Net.WebRequest.Create(url + "/rest/api/1.0/projects/" + projKey + "/repos/" + repoSlug + "");
                if (webRequest != null)
                {
                    // set header values
                    webRequest.Method = "GET";
                    webRequest.ContentType = "application/json";
                    webRequest.UserAgent = "SCMKIT-5dc493ada400c79dd318abbe770dac7c";

                    // if username/password auth was used, then pass the sessionID
                    if (credential.Contains(":"))
                    {
                        webRequest.Headers.Add("Cookie", "BITBUCKETSESSIONID= " + sessID);
                    }
                    // if user just specified http access token
                    else
                    {
                        webRequest.Headers.Add("Authorization", "Bearer " + credential);
                    }

                    // get web response
                    WebResponse myWebResponse = await webRequest.GetResponseAsync();
                    string content;
                    var reader = new StreamReader(myWebResponse.GetResponseStream());
                    content = reader.ReadToEnd();

                    // parse the JSON output and display results
                    JsonTextReader jsonResult = new JsonTextReader(new StringReader(content));

                    string propName = "";

                    // read the json results
                    while (jsonResult.Read())
                    {

                        switch (jsonResult.TokenType.ToString())
                        {
                            case "PropertyName":
                                propName = jsonResult.Value.ToString();
                                break;
                            case "String":

                                if (propName.ToLower().Equals("href") && jsonResult.Value.ToString().ToLower().Contains(repoSlug) && jsonResult.Value.ToString().EndsWith(".git") && jsonResult.Value.ToString().StartsWith("http"))
                                {
                                    urlToReturn = jsonResult.Value.ToString();
                                    urlToReturn = urlToReturn.Replace(".git", "");
                                }

                                break;
                            default:
                                break;

                        }

                    }

                }
            }

            catch (Exception ex)
            {
                return urlToReturn;
            }

            return urlToReturn;


        }


    }

}


================================================
FILE: SCMKit/library/GitHubUtils.cs
================================================
using System;
using System.IO;
using System.Net;
using System.Net.Security;
using System.Security.Cryptography.X509Certificates;
using System.Threading.Tasks;
using Octokit;

namespace SCMKit.library
{
    class GitHubUtils
    {

       /**
       * authenticate to GitHub
       * 
       * */
        public static dynamic AuthToGitHub(string credentials, string url)
        {
            try
            {
                ServicePointManager.ServerCertificateValidationCallback = delegate (object s, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) { return true; };

                GitHubClient client = null;
                Credentials auth = null;
                Uri uri = new Uri(url);

                client = new GitHubClient(new ProductHeaderValue("SCMKIT-5dc493ada400c79dd318abbe770dac7c"), uri);

                // if username/password auth being used
                if (credentials.Contains(":"))
                {
                    string[] theCreds = credentials.Split(':');
                    auth = new Credentials(theCreds[0], theCreds[1]);
                }

                // if token auth being used
                else
                {
                    auth = new Credentials(credentials);
                }

                client.Credentials = auth;

                return client;

            }

            catch (Exception ex)
            {
                Console.WriteLine("");
                Console.WriteLine("[-] ERROR: Could not authenticate to URL with credentials provided. Exception: " + ex.ToString());
                Console.WriteLine("");
                Environment.Exit(1);
                return null;
            }

        }

        public static async Task<string> callGitHubApiGet(string credential, string baseUrl, string path, string query)
        {
            string content = "";
            var webRequest = (HttpWebRequest)WebRequest.Create(baseUrl + path + query);
            // set header values
            webRequest.Method = "GET";
            webRequest.ContentType = "application/json";
            webRequest.UserAgent = "SCMKIT-5dc493ada400c79dd318abbe770dac7c";

            // if we need to pass the username/password
            if (credential.Contains(":"))
            {
                var base64EncodedAuthenticationString = Convert.ToBase64String(System.Text.Encoding.ASCII.GetBytes(credential));
                webRequest.Headers.Add("Authorization", "Basic " + base64EncodedAuthenticationString);
            }
            // if user just specified personal access token
            else
            {
                webRequest.Headers.Add("Authorization", "Bearer " + credential);
            }

            // get web response
            WebResponse response = await webRequest.GetResponseAsync();
            var reader = new StreamReader(response.GetResponseStream());
            content = reader.ReadToEnd();
            return content;
        }
    }
}


================================================
FILE: SCMKit/library/GitLabUtils.cs
================================================
using System;
using System.IO;
using System.Net;
using System.Net.Security;
using System.Security.Cryptography.X509Certificates;
using System.Threading.Tasks;
using GitLabApiClient;

namespace SCMKit.library
{
    class GitLabUtils
    {


       /**
       * Get the GitLab project visibilty based on project ID
       * 
       * */
        public static async Task<string> GetGitLabProjectVisibility(string credential, string accessToken, string projID, string url)
        {
            string visibility = "public";

            try
            {
                ServicePointManager.ServerCertificateValidationCallback = delegate (object s, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) { return true; };
                ServicePointManager.Expect100Continue = true;
                ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;


                // web request to get details of a project
                var webRequest = (HttpWebRequest)System.Net.WebRequest.Create(url + "/api/v4/projects/" + projID);
                if (webRequest != null)
                {
                    // set header values
                    webRequest.Method = "GET";
                    webRequest.ContentType = "application/json";
                    webRequest.UserAgent = "SCMKIT-5dc493ada400c79dd318abbe770dac7c";

                    // if we need to pass the token obtained from the username/password auth
                    if (credential.Contains(":"))
                    {
                        webRequest.Headers.Add("Authorization", "Bearer " + accessToken);
                    }
                    // if user just specified personal access token
                    else
                    {
                        webRequest.Headers.Add("PRIVATE-TOKEN", credential);
                    }

                    // get web response
                    WebResponse myWebResponse = await webRequest.GetResponseAsync();
                    string content;
                    var reader = new StreamReader(myWebResponse.GetResponseStream());
                    content = reader.ReadToEnd();

                    // parse response to get visibility
                    int startingIndex = content.IndexOf("\"visibility\":");
                    int endingIndex = content.IndexOf("\"owner\":{");
                    visibility = content.Substring(startingIndex + "\"visibility\":".Length, endingIndex - startingIndex - "\"visibility\":".Length);
                    visibility = visibility.Replace("\"", "");
                    visibility = visibility.Replace(",", "");


                }
            }

            catch (Exception ex)
            {
                return visibility;
            }

            return visibility;


        }


       /**
       * Authenticate to GitLab
       * 
       * */
        public static async Task<GitLabClient> AuthToGitLabAsync(string credentials, string url)
        {
            try
            {
                ServicePointManager.ServerCertificateValidationCallback = delegate (object s, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) { return true; };

                GitLabClient client = null;
                Uri uri = new Uri(url);

                // if username/password auth being used
                if (credentials.Contains(":"))
                {
                    string[] theCreds = credentials.Split(':');
                    client = new GitLabClient(uri.ToString());
                    await client.LoginAsync(theCreds[0], theCreds[1]);
                }

                // if token auth being used
                else
                {
                    client = new GitLabClient(uri.ToString(), credentials);
                }


                return client;

            }

            catch (Exception ex)
            {
                Console.WriteLine("");
                Console.WriteLine("[-] ERROR: Could not authenticate to URL with credentials provided. Exception: " + ex.ToString());
                Console.WriteLine("");
                return null;
            }

        }



        /**
        * get access token for GitLab based on username/password given
        * 
        * */
        public static string GetAccessToken(string credential, string url)
        {

            string accessToken = "";

            // get personal access tokens for user
            var webRequestOAuthToken = System.Net.WebRequest.Create(url + "/oauth/token");
            if (webRequestOAuthToken != null)
            {
                // set header values
                webRequestOAuthToken.Method = "POST";
                webRequestOAuthToken.ContentType = "application/json";


                // set body and sent request
                using (var streamWriter = new StreamWriter(webRequestOAuthToken.GetRequestStream()))
                {
                    string[] theCreds = credential.Split(':');
                    string json = "{\"grant_type\":\"password\",\"scope\":\"api\",\"username\":\"" + theCreds[0] + "\",\"password\":\"" + theCreds[1] + "\"}";

                    streamWriter.Write(json);
                }

                // get the response and the access token
                var httpResponse = (HttpWebResponse)webRequestOAuthToken.GetResponse();
                var streamReader = new StreamReader(httpResponse.GetResponseStream());
                string result = streamReader.ReadToEnd();
                int startIndex = result.IndexOf("\"access_token\":\"");
                int endIndex = result.IndexOf("\",\"token_type\":");
                accessToken = result.Substring(startIndex + "\"access_token\":\"".Length, endIndex - startIndex - "\", \"token_type\":".Length);

            }

            return accessToken;

        }


    }

}


================================================
FILE: SCMKit/library/Utils.cs
================================================
using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Security;
using System.Security.Cryptography.X509Certificates;
using System.Threading.Tasks;

namespace SCMKit.library
{
    class Utils
    {

        /**
        * Parse command line arguments
         * 
        * */
        public static Dictionary<string, string> ParseTheArguments(string[] args)
        {
            try
            {
                Dictionary<string, string> ret = new Dictionary<string, string>();
                if (args.Length % 2 == 0 && args.Length > 0)
                {
                    for (int i = 0; i < args.Length; i = i + 2)
                    {
                        ret.Add(args[i].Substring(1, args[i].Length - 1).ToLower(), args[i + 1]);

                    }
                }
                return ret;
            }
            catch (ArgumentException ex)
            {
                Console.WriteLine("");
                Console.WriteLine("[-] You specified duplicate switches. Check your command again. Exception: " + ex.ToString());
                return null;
            }

        } // end



        /**
        * print help
        * 
        * */
        public static void HelpMe()
        {
            Console.Write("\nPlease read the README page for proper usage of the tool.\n\n");


        } // end print help method



        /**
        * Generate module header
        * 
        * */
        public static string GenerateHeader(string module, string credential, string url, string options, string system)
        {
            string output = String.Empty;
            string delim = "==================================================";
            string authType = "";

            if (credential.Contains(":"))
            {
                authType = "Username/Password";
            }
            else
            {
                authType = "API Key";
            }

            output += "\n" + delim + "\n";
            output += "Module:\t\t" + module + "\n";
            output += "System:\t\t" + system + "\n";
            output += "Auth Type:\t" + authType + "\n";
            output += "Options:\t" + options + "\n";
            output += "Target URL:\t" + url + "\n\n";
            output += "Timestamp:\t" + DateTime.Now + "\n";
            output += delim + "\n";

            return output;
        }


        /**
         * Heartbeat request to indicate it is SCMKit being used for modules not using raw HTTP requests
         * 
         */
        public static async Task<WebResponse> HeartbeatRequest(string url)
        {



            ServicePointManager.ServerCertificateValidationCallback = delegate (object s, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) { return true; };
            ServicePointManager.Expect100Continue = true;
            ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;

            WebResponse myWebResponse = null;

            try
            {
                var webRequest = (HttpWebRequest)System.Net.WebRequest.Create(url);
                if (webRequest != null)
                {
                    // set header values
                    webRequest.Method = "GET";
                    webRequest.ContentType = "application/json";
                    webRequest.UserAgent = "SCMKIT-5dc493ada400c79dd318abbe770dac7c";

                    // get web response
                    myWebResponse = await webRequest.GetResponseAsync();


                }
            }

            catch (Exception ex)
            {
                Console.WriteLine("");
                Console.WriteLine("[-] ERROR: Could not perform heartbeat request. Exception: " + ex.ToString());
                Console.WriteLine("");
                Environment.Exit(1);
            }

            return myWebResponse;

        }


        /**
         * method to get all indexes where a value exists in a string
         * 
         * */
        public static int[] AllIndexesOf(string str, string substr, bool ignoreCase = false)
        {
            if (string.IsNullOrWhiteSpace(str) ||
                string.IsNullOrWhiteSpace(substr))
            {
                throw new ArgumentException("String or substring is not specified.");
            }

            var indexes = new List<int>();
            int index = 0;

            while ((index = str.IndexOf(substr, index, ignoreCase ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal)) != -1)
            {
                indexes.Add(index++);
            }

            return indexes.ToArray();
        }
       

    }

}


================================================
FILE: SCMKit/library/WebUtils.cs
================================================
using System;
using System.IO;
using System.Net;
using System.Net.Security;
using System.Security.Cryptography.X509Certificates;
using System.Threading.Tasks;

namespace SCMKit.library
{
    class WebUtils
    {

       /**
      * generate web request
      * 
      * */
        public static HttpWebRequest GenerateWebRequest(string credential, string url, string method)
        {
            // Have to use HttpWebRequest class in order to set the Accept property.
            // Can't set the Accept header directly - C# throws an error.
            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
            request.Method = method;
            request.ContentType = "application/json";
            request.Accept = "application/vnd.github.v3+json";
            request.UserAgent = "SCMKIT-5dc493ada400c79dd318abbe770dac7c";

            if (credential.Contains(":"))
            {
                request.Headers.Add("Authorization", "Basic " +
                                                       Convert.ToBase64String(System.Text.Encoding.UTF8.GetBytes(credential)));
            }
            else
            {
                request.Headers.Add("Authorization", "token " + credential);
            }

            return request;
        }



        /**
        * generate raw file web request
        * 
        * */
        public static HttpWebRequest GenerateRawFileWebRequest(string credential, string url)
        {
            // Have to use HttpWebRequest class in order to set the Accept property.
            // Can't set the Accept header directly - C# throws an error.
            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
            request.Method = "GET";
            request.Accept = "application/vnd.github.v3.raw+raw";
            request.UserAgent = "SCMKIT-5dc493ada400c79dd318abbe770dac7c";

            if (credential.Contains(":"))
            {
                request.Headers.Add("Authorization", "Basic " + Convert.ToBase64String(System.Text.Encoding.UTF8.GetBytes(credential)));
            }
            else
            {
                request.Headers.Add("Authorization", "token " + credential);
            }

            return request;
        }


        /**
        * get web response string
        * 
        * */
        public static async Task<string> GetRequestResponseString(HttpWebRequest request)
        {
            var responseAsync = await request.GetResponseAsync();
            var responseFromServer = "";
            using (var dataStream = responseAsync.GetResponseStream())
            {
                // Open the stream using a StreamReader for easy access.
                var reader = new StreamReader(dataStream);
                // Read the content.
                responseFromServer = reader.ReadToEnd();
            }
            // Close the response.
            responseAsync.Close();

            return responseFromServer;
        }


        /**
        * get web response
        * 
        * */
        public static async Task<WebResponse> GetRequestResponse(HttpWebRequest request)
        {
            var responseAsync = await request.GetResponseAsync();
            return responseAsync;
        }


        /**
        * ignore SSL
        * 
        * */
        public static void IgnoreSSL()
        {
            ServicePointManager.ServerCertificateValidationCallback =
                (object s, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) => true;
            ServicePointManager.Expect100Continue = true;
            ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
        }

    }
}


================================================
FILE: SCMKit/modules/bitbucket/AddAdmin.cs
================================================
using System;
using System.Net;
using System.Threading.Tasks;
using System.IO;
using System.Security.Cryptography.X509Certificates;
using System.Net.Security;

namespace SCMKit.modules.bitbucket
{
    class AddAdmin
    {
        public static async Task execute(string credential, string url, string options, string system)
        {

            // Generate module header
            Console.WriteLine(library.Utils.GenerateHeader("addadmin", credential, url, options, system));

            try
            {

                string sessID = "";

                // if username/password auth is used, get session ID for remainder of requests
                if (credential.Contains(":"))
                {
                    sessID = library.BitbucketUtils.GetSessionID(credential, url);
                    if (sessID == null)
                    {
                        Console.WriteLine("");
                        Console.WriteLine("[-] ERROR: Credentials provided are not valid.");
                        Console.WriteLine("");
                        return;

                    }
                }

                // if API token was provided, display message and return
                else
                {
                    Console.WriteLine("");
                    Console.WriteLine("[-] ERROR: API token authentication is not supported for this module. Please provide username/password with the appropriate permissions.");
                    Console.WriteLine("");
                    return;

                }


                ServicePointManager.ServerCertificateValidationCallback = delegate (object s, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) { return true; };
                ServicePointManager.Expect100Continue = true;
                ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;

                await library.Utils.HeartbeatRequest(url);

                // web request to add admin via rest API
                var webRequest = (HttpWebRequest)System.Net.WebRequest.Create(url + "/rest/api/1.0/admin/permissions/users?name=" + options + "&permission=ADMIN");
                if (webRequest != null)
                {
                    // set header values
                    webRequest.Method = "PUT";
                    webRequest.ContentType = "application/json";
                    webRequest.UserAgent = "SCMKIT-5dc493ada400c79dd318abbe770dac7c";

                    // if username/password auth was used, then pass the sessionID
                    if (credential.Contains(":"))
                    {
                        webRequest.Headers.Add("Cookie", "BITBUCKETSESSIONID= " + sessID);
                    }
                    // if user just specified http access token
                    else
                    {
                        webRequest.Headers.Add("Authorization", "Bearer " + credential);
                    }


                    // get web response
                    WebResponse myWebResponse = await webRequest.GetResponseAsync();
                    string content;
                    var reader = new StreamReader(myWebResponse.GetResponseStream());
                    content = reader.ReadToEnd();

                    bool addAdminSuccessful = false;

                    // figure out if request was successful
                    for (int i = 0; i < myWebResponse.Headers.Count; ++i)
                    {
                        if (myWebResponse.Headers.Keys[i].ToString().ToLower().Equals("x-auserid"))
                        {
                            addAdminSuccessful = true;
                        }

                    }


                    if (addAdminSuccessful)
                    {
                        Console.WriteLine("");
                        Console.WriteLine("[+] SUCCESS: Successfully added " + options + " user to the admin role.");
                        Console.WriteLine("");

                    }

                    // if not successful
                    else
                    {
                        Console.WriteLine("");
                        Console.WriteLine("[-] ERROR: Credentials (username/password OR API token) provided are not valid.");
                        Console.WriteLine("");
                    }

                }

            }

            catch (Exception ex)
            {
                Console.WriteLine("");
                Console.WriteLine("[-] ERROR: Could not add user to admin group. Exception: " + ex.ToString());
                Console.WriteLine("");
            }

        }


    }

}


================================================
FILE: SCMKit/modules/bitbucket/CodeSearch.cs
================================================
using System;
using System.Collections.Generic;
using System.Net;
using System.Threading.Tasks;
using System.IO;
using Newtonsoft.Json;
using System.Security.Cryptography.X509Certificates;
using System.Net.Security;

namespace SCMKit.modules.bitbucket
{


    // custom class to handle URL results
    public class URLResult
    {

        public URLResult(string link, string matchingLine, string fileName)
        {
            this.url = link;
            this.matchingLine = matchingLine;
            this.fileName = fileName;
        }

        public string url { get; set; }
        public string matchingLine { get; set; }
        public string fileName { get; set; }

    } // end URLResult class


    class CodeSearch
    {

        // dictionary to hold the list of repos and their URLs
        private static List<URLResult> urlResults = new List<URLResult>();

        private static int matchCount = 0;

        public static async Task execute(string credential, string url, string options, string system)
        {

            // Generate module header
            Console.WriteLine(library.Utils.GenerateHeader("searchcode", credential, url, options, system));

            try
            {

                string sessID = "";

                // if username/password auth is used, get session ID for remainder of requests
                if (credential.Contains(":"))
                {
                    sessID = library.BitbucketUtils.GetSessionID(credential, url);
                    if (sessID == null)
                    {
                        Console.WriteLine("");
                        Console.WriteLine("[-] ERROR: Credentials provided are not valid.");
                        Console.WriteLine("");
                        return;

                    }
                }


                ServicePointManager.ServerCertificateValidationCallback = delegate (object s, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) { return true; };
                ServicePointManager.Expect100Continue = true;
                ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;

                await library.Utils.HeartbeatRequest(url);

                // web request to search via rest API
                var webRequest = (HttpWebRequest)System.Net.WebRequest.Create(url + "/rest/search/latest/search");
                if (webRequest != null)
                {
                    // set header values
                    webRequest.Method = "POST";
                    webRequest.ContentType = "application/json";
                    webRequest.UserAgent = "SCMKIT-5dc493ada400c79dd318abbe770dac7c";

                    // if username/password auth was used, then pass the sessionID
                    if (credential.Contains(":"))
                    {
                        webRequest.Headers.Add("Cookie", "BITBUCKETSESSIONID= " + sessID);
                    }
                    // if user just specified http access token
                    else
                    {
                        webRequest.Headers.Add("Authorization", "Bearer " + credential);
                    }


                    // set body and send request
                    using (var streamWriter = new StreamWriter(webRequest.GetRequestStream()))
                    {
                        string json = "{\"query\":\"" + options + "\",\"entities\":{\"code\":{}},\"limits\":{\"primary\":100,\"secondary\":100}}";
                        streamWriter.Write(json);
                    }


                    // get web response
                    WebResponse myWebResponse = await webRequest.GetResponseAsync();
                    string content;
                    var reader = new StreamReader(myWebResponse.GetResponseStream());
                    content = reader.ReadToEnd();

                    bool validCreds = false;

                    // figure out if creds valid
                    for (int i = 0; i < myWebResponse.Headers.Count; ++i)
                    {
                        if (myWebResponse.Headers.Keys[i].ToString().ToLower().Equals("x-auserid"))
                        {
                            validCreds = true;
                        }

                    }


                    if (validCreds)
                    {

                        // parse the JSON output and display results
                        JsonTextReader jsonResult = new JsonTextReader(new StringReader(content));

                        string matchingLine = "";
                        string propName = "";
                        string projKey = "";
                        string repoName = "";
                        string fileName = "";
                        string nextPageStart = "";
                        string isLastPage = "";

                        // read the json results
                        while (jsonResult.Read())
                        {

                            switch (jsonResult.TokenType.ToString())
                            {

                                case "StartObject":
                                    break;
                                case "EndObject":
                                    break;
                                case "StartArray":
                                    break;
                                case "EndArray":
                                    // add the match to the list
                                    if (!matchingLine.Equals("") && !fileName.Equals(""))
                                    {
                                        bool alreadyExists = false;
                                        string fullURL = await library.BitbucketUtils.GetFullBitbucketRepoURLAsync(credential, sessID, projKey, repoName, url);

                                        URLResult singleResults = new URLResult(fullURL, matchingLine, fileName);

                                        // only add if not already found before
                                        foreach (URLResult item in urlResults)
                                        {
                                            if (item.fileName.Equals(fileName) && item.matchingLine.Equals(matchingLine) && item.url.Equals(fullURL))
                                            {

                                                alreadyExists = true;
                                            }
                                        }

                                        if (!alreadyExists)
                                        {
                                            urlResults.Add(singleResults);

                                        }

                                    }
                                    break;
                                case "PropertyName":
                                    propName = jsonResult.Value.ToString();
                                    break;
                                case "String":

                                    // get actual values
                                    if (propName.ToLower().Equals("text"))
                                    {

                                        string filteredResult = jsonResult.Value.ToString().ToLower();
                                        filteredResult = filteredResult.Replace("<em>", "");
                                        filteredResult = filteredResult.Replace("</em>", "");


                                        if (filteredResult.Contains(options.ToLower()))
                                        {
                                            matchingLine = jsonResult.Value.ToString();
                                        }
                                    }
                                    if (propName.ToLower().Equals("key"))
                                    {
                                        projKey = jsonResult.Value.ToString();
                                    }
                                    if (propName.ToLower().Equals("slug"))
                                    {
                                        repoName = jsonResult.Value.ToString();
                                    }
                                    if (propName.ToLower().Equals("file"))
                                    {
                                        fileName = jsonResult.Value.ToString();
                                    }
                                    break;
                                case "Integer":
                                    if (propName.ToLower().Equals("nextstart"))
                                    {
                                        nextPageStart = jsonResult.Value.ToString();

                                    }
                                    break;
                                case "Boolean":
                                    if (propName.ToLower().Equals("islastpage"))
                                    {
                                        isLastPage = jsonResult.Value.ToString();

                                    }
                                    break;
                                default:
                                    break;


                            }

                        }

                        // iterate through the dictionary of matching lines and print them
                        foreach (var item in urlResults)
                        {

                            string theMatch = item.matchingLine;
                            theMatch = theMatch.Replace("<em>", "");
                            theMatch = theMatch.Replace("</em>", "");
                            theMatch = WebUtility.HtmlDecode(theMatch);
                            Console.WriteLine("\n[>] REPO: " + item.url);
                            Console.WriteLine("    [>] FILE: " + item.fileName);
                            Console.WriteLine("            |_ " + theMatch);
                            matchCount++;

                        }

                        // if there are more pages, then make subsequent requests
                        if (!nextPageStart.Equals("") && isLastPage.Equals("False"))
                        {
                            await makeSubsequentRequestAsync(credential, url, options, sessID, nextPageStart);
                        }



                        Console.WriteLine("");
                        Console.WriteLine("Total matching results: " + matchCount);

                    }

                    // if creds invalid
                    else
                    {
                        Console.WriteLine("");
                        Console.WriteLine("[-] ERROR: Credentials (username/password OR API token) provided are not valid.");
                        Console.WriteLine("");
                    }

                }

            }

            catch (Exception ex)
            {
                Console.WriteLine("");
                Console.WriteLine("[-] ERROR: Could not perform code search. Exception: " + ex.ToString());
                Console.WriteLine("");
            }

        }

        // this is just placeholder for making more than 1 request due to paging of results. will have better global solution at some point than this band-aid
        public static async Task makeSubsequentRequestAsync(string credential, string url, string options, string sessID, string nextPage)
        {

            try
            {

                urlResults.Clear();

                ServicePointManager.ServerCertificateValidationCallback = delegate (object s, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) { return true; };
                ServicePointManager.Expect100Continue = true;
                ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;

                // web request to search via rest API
                var webRequest = (HttpWebRequest)System.Net.WebRequest.Create(url + "/rest/search/latest/search");
                if (webRequest != null)
                {
                    // set header values
                    webRequest.Method = "POST";
                    webRequest.ContentType = "application/json";
                    webRequest.UserAgent = "SCMKIT-5dc493ada400c79dd318abbe770dac7c";

                    // if username/password auth was used, then pass the sessionID
                    if (credential.Contains(":"))
                    {
                        webRequest.Headers.Add("Cookie", "BITBUCKETSESSIONID= " + sessID);
                    }
                    // if user just specified http access token
                    else
                    {
                        webRequest.Headers.Add("Authorization", "Bearer " + credential);
                    }


                    // set body and send request
                    using (var streamWriter = new StreamWriter(webRequest.GetRequestStream()))
                    {
                        string json = "{\"query\":\"" + options + "\",\"entities\":{\"code\":{\"start\":" + nextPage + "}},\"limits\":{\"primary\":100,\"secondary\":100}}";
                        streamWriter.Write(json);
                    }


                    // get web response
                    WebResponse myWebResponse = await webRequest.GetResponseAsync();
                    string content;
                    var reader = new StreamReader(myWebResponse.GetResponseStream());
                    content = reader.ReadToEnd();

                    bool validCreds = false;

                    // figure out if creds valid
                    for (int i = 0; i < myWebResponse.Headers.Count; ++i)
                    {
                        if (myWebResponse.Headers.Keys[i].ToString().ToLower().Equals("x-auserid"))
                        {
                            validCreds = true;
                        }

                    }


                    if (validCreds)
                    {

                        // parse the JSON output and display results
                        JsonTextReader jsonResult = new JsonTextReader(new StringReader(content));

                        string matchingLine = "";
                        string propName = "";
                        string projKey = "";
                        string repoName = "";
                        string fileName = "";
                        string nextPageStart = "";
                        string isLastPage = "";

                        // read the json results
                        while (jsonResult.Read())
                        {

                            switch (jsonResult.TokenType.ToString())
                            {

                                case "StartObject":
                                    break;
                                case "EndObject":
                                    break;
                                case "StartArray":
                                    break;
                                case "EndArray":
                                    // add the match to the list
                                    if (!matchingLine.Equals("") && !fileName.Equals(""))
                                    {
                                        bool alreadyExists = false;
                                        string fullURL = await library.BitbucketUtils.GetFullBitbucketRepoURLAsync(credential, sessID, projKey, repoName, url);

                                        URLResult singleResults = new URLResult(fullURL, matchingLine, fileName);

                                        // only add if not already found before
                                        foreach (URLResult item in urlResults)
                                        {
                                            if (item.fileName.Equals(fileName) && item.matchingLine.Equals(matchingLine) && item.url.Equals(fullURL))
                                            {

                                                alreadyExists = true;
                                            }
                                        }

                                        if (!alreadyExists)
                                        {
                                            urlResults.Add(singleResults);

                                        }

                                    }
                                    break;
                                case "PropertyName":
                                    propName = jsonResult.Value.ToString();
                                    break;
                                case "String":

                                    // get actual values
                                    if (propName.ToLower().Equals("text"))
                                    {

                                        string filteredResult = jsonResult.Value.ToString().ToLower();
                                        filteredResult = filteredResult.Replace("<em>", "");
                                        filteredResult = filteredResult.Replace("</em>", "");


                                        if (filteredResult.Contains(options.ToLower()))
                                        {
                                            matchingLine = jsonResult.Value.ToString();
                                        }
                                    }
                                    if (propName.ToLower().Equals("key"))
                                    {
                                        projKey = jsonResult.Value.ToString();
                                    }
                                    if (propName.ToLower().Equals("slug"))
                                    {
                                        repoName = jsonResult.Value.ToString();
                                    }
                                    if (propName.ToLower().Equals("file"))
                                    {
                                        fileName = jsonResult.Value.ToString();
                                    }
                                    break;
                                case "Integer":
                                    if (propName.ToLower().Equals("nextstart"))
                                    {
                                        nextPageStart = jsonResult.Value.ToString();

                                    }
                                    break;
                                case "Boolean":
                                    if (propName.ToLower().Equals("islastpage"))
                                    {
                                        isLastPage = jsonResult.Value.ToString();

                                    }
                                    break;
                                default:
                                    break;


                            }

                        }

                        // iterate through the dictionary of matching lines and print them
                        foreach (var item in urlResults)
                        {

                            string theMatch = item.matchingLine;
                            theMatch = theMatch.Replace("<em>", "");
                            theMatch = theMatch.Replace("</em>", "");
                            theMatch = WebUtility.HtmlDecode(theMatch);
                            Console.WriteLine("\n[>] REPO: " + item.url);
                            Console.WriteLine("    [>] FILE: " + item.fileName);
                            Console.WriteLine("            |_ " + theMatch);
                            matchCount++;

                        }

                        // if there are more pages, then make subsequent requests
                        if (!nextPageStart.Equals("") && isLastPage.Equals("False"))
                        {
                            await makeSubsequentRequestAsync(credential, url, options, sessID, nextPageStart);
                        }



                    }

                    // if creds invalid
                    else
                    {
                        Console.WriteLine("");
                        Console.WriteLine("[-] ERROR: Credentials (username/password OR API token) provided are not valid.");
                        Console.WriteLine("");
                    }

                }


            }

            catch (Exception ex)
            {
                Console.WriteLine("");
                Console.WriteLine("[-] ERROR: Could not perform code search. Exception: " + ex.ToString());
                Console.WriteLine("");
            }


        }


    }

}


================================================
FILE: SCMKit/modules/bitbucket/CreatePAT.cs
================================================
using System;
using System.Collections.Generic;
using System.Net;
using System.Threading.Tasks;
using System.IO;
using System.Security.Cryptography.X509Certificates;
using System.Net.Security;

namespace SCMKit.modules.bitbucket
{
    class CreatePAT
    {

        // hashtable to store mapping of PAT and permissions
        private static Dictionary<string, string> patMapping = new Dictionary<string, string>();

        public static async Task execute(string credential, string url, string options, string system)
        {

            // Generate module header
            Console.WriteLine(library.Utils.GenerateHeader("createpat", credential, url, options, system));

            try
            {

                string sessID = "";

                // if username/password auth is used, get session ID for remainder of requests
                if (credential.Contains(":"))
                {
                    sessID = library.BitbucketUtils.GetSessionID(credential, url);
                    if (sessID == null)
                    {
                        Console.WriteLine("");
                        Console.WriteLine("[-] ERROR: Credentials provided are not valid.");
                        Console.WriteLine("");
                        return;

                    }
                }

                // if API token was provided, display message and return
                else
                {
                    Console.WriteLine("");
                    Console.WriteLine("[-] ERROR: API token authentication is not supported for this module. Please provide username/password with the appropriate permissions.");
                    Console.WriteLine("");
                    return;

                }


                // create table header
                string tableHeader = string.Format("{0,25} | {1,15} | {2,50}", "ID", "Name", "Token");
                Console.WriteLine(tableHeader);
                Console.WriteLine(new String('-', tableHeader.Length));

                ServicePointManager.ServerCertificateValidationCallback = delegate (object s, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) { return true; };
                ServicePointManager.Expect100Continue = true;
                ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;

                await library.Utils.HeartbeatRequest(url);

                string[] splitCred = credential.Split(':');

                // web request to create PAT via REST api
                var webRequest = (HttpWebRequest)System.Net.WebRequest.Create(url + "/rest/access-tokens/1.0/users/" + splitCred[0]);
                if (webRequest != null)
                {
                    // set header values
                    webRequest.Method = "PUT";
                    webRequest.ContentType = "application/json";
                    webRequest.UserAgent = "SCMKIT-5dc493ada400c79dd318abbe770dac7c";

                    // if username/password auth was used, then pass the sessionID
                    if (credential.Contains(":"))
                    {
                        webRequest.Headers.Add("Cookie", "BITBUCKETSESSIONID= " + sessID);
                    }
                    // if user just specified http access token
                    else
                    {
                        webRequest.Headers.Add("Authorization", "Bearer " + credential);
                    }


                    // set body and send request
                    using (var streamWriter = new StreamWriter(webRequest.GetRequestStream()))
                    {

                        // create random token name
                        Random rd = new Random();
                        const string allowedChars = "ABCDEFGHJKLMNOPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
                        char[] chars = new char[5];

                        for (int i = 0; i < 5; i++)
                        {
                            chars[i] = allowedChars[rd.Next(0, allowedChars.Length)];
                        }
                        string personalAccessTokenName = new string(chars);
                        personalAccessTokenName = "SCMKIT-" + personalAccessTokenName;


                        string json = "{\"name\": \"" + personalAccessTokenName + "\",\"permissions\": [\"REPO_ADMIN\",\"PROJECT_ADMIN\"],\"expiryDays\": \"\"}";
                        streamWriter.Write(json);
                    }

                    // get web response
                    WebResponse myWebResponse = await webRequest.GetResponseAsync();
                    string content;
                    var reader = new StreamReader(myWebResponse.GetResponseStream());
                    content = reader.ReadToEnd();

                    bool validCreds = false;

                    // figure out if creds valid
                    for (int i = 0; i < myWebResponse.Headers.Count; ++i)
                    {
                        if (myWebResponse.Headers.Keys[i].ToString().ToLower().Equals("x-auserid"))
                        {
                            validCreds = true;
                        }

                    }


                    if (validCreds)
                    {

                        // get the PAT name and id
                        string patName = "";
                        int startIndex = content.IndexOf("\"id\":");
                        int endIndex = content.IndexOf("\"permissions\":");
                        patName = content.Substring(startIndex + "\"id\":".Length, endIndex - startIndex - "\"id\"".Length);
                        patName = patName.Replace("\"", "");
                        patName = patName.Replace(",", "");
                        string[] patNameArray = patName.Split(':');
                        patMapping.Add(patNameArray[0].Replace("createdDate", ""), patNameArray[patNameArray.Length - 1]);


                        //  parse the actual token
                        string tokenContent = "";
                        int startIndexContent = content.IndexOf("\"token\":");
                        int endIndexContent = content.Length - 1;
                        tokenContent = content.Substring(startIndexContent + "\"token\":".Length, endIndexContent - startIndexContent - "\"token\":".Length);
                        tokenContent = tokenContent.Replace("\"", "");


                        foreach (var item in patMapping)
                        {
                            Console.WriteLine("{0,25} | {1,15} | {2,50}", item.Key, item.Value, tokenContent);
                        }

                        Console.WriteLine("");
                        Console.WriteLine("[+] SUCCESS: The " + splitCred[0] + " user personal access token was successfully added.");
                        Console.WriteLine("");



                    }

                    // if creds invalid
                    else
                    {
                        Console.WriteLine("");
                        Console.WriteLine("[-] ERROR: Credentials (username/password OR API token) provided are not valid.");
                        Console.WriteLine("");
                    }

                }

            }

            catch (Exception ex)
            {
                Console.WriteLine("");
                Console.WriteLine("[-] ERROR: Could not create PAT. Exception: " + ex.ToString());
                Console.WriteLine("");
            }

        }


    }
}


================================================
FILE: SCMKit/modules/bitbucket/CreateSSHKey.cs
================================================
using System;
using System.Net;
using System.Threading.Tasks;
using System.IO;
using System.Security.Cryptography.X509Certificates;
using System.Net.Security;

namespace SCMKit.modules.bitbucket
{
    class CreateSSHKey
    {


        public static async Task execute(string credential, string url, string options, string system)
        {

            // Generate module header
            Console.WriteLine(library.Utils.GenerateHeader("createsshkey", credential, url, options, system));

            try
            {

                string sessID = "";

                // if username/password auth is used, get session ID for remainder of requests
                if (credential.Contains(":"))
                {
                    sessID = library.BitbucketUtils.GetSessionID(credential, url);
                    if (sessID == null)
                    {
                        Console.WriteLine("");
                        Console.WriteLine("[-] ERROR: Credentials provided are not valid.");
                        Console.WriteLine("");
                        return;

                    }
                }

                // if API token was provided, display message and return
                else
                {
                    Console.WriteLine("");
                    Console.WriteLine("[-] ERROR: API token authentication is not supported for this module. Please provide username/password with the appropriate permissions.");
                    Console.WriteLine("");
                    return;

                }



                // create table header
                string tableHeader = string.Format("{0,12}", "SSH Key ID");
                Console.WriteLine(tableHeader);
                Console.WriteLine(new String('-', tableHeader.Length));

                ServicePointManager.ServerCertificateValidationCallback = delegate (object s, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) { return true; };
                ServicePointManager.Expect100Continue = true;
                ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;

                await library.Utils.HeartbeatRequest(url);

                string[] splitCred = credential.Split(':');


                // web request to add SSH key via REST API
                var webRequest = (HttpWebRequest)System.Net.WebRequest.Create(url + "/rest/ssh/1.0/keys");
                if (webRequest != null)
                {
                    // set header values
                    webRequest.Method = "POST";
                    webRequest.ContentType = "application/json";
                    webRequest.UserAgent = "SCMKIT-5dc493ada400c79dd318abbe770dac7c";

                    // if username/password auth was used, then pass the sessionID
                    if (credential.Contains(":"))
                    {
                        webRequest.Headers.Add("Cookie", "BITBUCKETSESSIONID= " + sessID);
                    }
                    // if user just specified http access token
                    else
                    {
                        webRequest.Headers.Add("Authorization", "Bearer " + credential);
                    }


                    // set body and send request
                    using (var streamWriter = new StreamWriter(webRequest.GetRequestStream()))
                    {

                        // create random SSH Key label
                        Random rd = new Random();
                        const string allowedChars = "ABCDEFGHJKLMNOPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
                        char[] chars = new char[5];

                        for (int i = 0; i < 5; i++)
                        {
                            chars[i] = allowedChars[rd.Next(0, allowedChars.Length)];
                        }
                        string sshKeyLabel = new string(chars);
                        sshKeyLabel = "SCMKIT-" + sshKeyLabel;

                        string json = "{\"" + "text" + "\": \"" + options + " " + sshKeyLabel + "\"}";
                        streamWriter.Write(json);
                    }

                    // get web response
                    WebResponse myWebResponse = await webRequest.GetResponseAsync();
                    string content;
                    var reader = new StreamReader(myWebResponse.GetResponseStream());
                    content = reader.ReadToEnd();

                    bool validCreds = false;

                    // figure out if creds valid
                    for (int i = 0; i < myWebResponse.Headers.Count; ++i)
                    {
                        if (myWebResponse.Headers.Keys[i].ToString().ToLower().Equals("x-auserid"))
                        {
                            validCreds = true;
                        }

                    }


                    if (validCreds)
                    {

                        // get the SSH key ID
                        string sshKeyID = "";
                        int startIndex = content.IndexOf("\"id\":");
                        int endIndex = content.IndexOf("\"text\":");
                        sshKeyID = content.Substring(startIndex + "\"id\":".Length, endIndex - startIndex - "\"id\"".Length);
                        sshKeyID = sshKeyID.Replace("\"", "");
                        sshKeyID = sshKeyID.Replace(",", "");

                        Console.WriteLine("{0,12}", sshKeyID);
                        Console.WriteLine("");
                        Console.WriteLine("[+] SUCCESS: The " + splitCred[0] + " user SSH key was successfully added.");
                        Console.WriteLine("");


                    }

                    // if creds invalid
                    else
                    {
                        Console.WriteLine("");
                        Console.WriteLine("[-] ERROR: Credentials (username/password OR API token) provided are not valid.");
                        Console.WriteLine("");
                    }



                }

            }

            catch (Exception ex)
            {
                Console.WriteLine("");
                Console.WriteLine("[-] ERROR: Could not create SSH Key. Exception: " + ex.ToString());
                Console.WriteLine("");
            }

        }


    }
}


================================================
FILE: SCMKit/modules/bitbucket/FileSearch.cs
================================================
using System;
using System.Collections.Generic;
using System.Net;
using System.Threading.Tasks;
using System.IO;
using Newtonsoft.Json;
using System.Security.Cryptography.X509Certificates;
using System.Net.Security;

namespace SCMKit.modules.bitbucket
{
    class FileSearch
    {

        // dictionary to hold the list of repos and their URLs
        private static List<URLResult> urlResults = new List<URLResult>();

        private static int matchCount = 0;

        public static async Task execute(string credential, string url, string options, string system)
        {

            // Generate module header
            Console.WriteLine(library.Utils.GenerateHeader("searchfile", credential, url, options, system));

            try
            {

                string sessID = "";

                // if username/password auth is used, get session ID for remainder of requests
                if (credential.Contains(":"))
                {
                    sessID = library.BitbucketUtils.GetSessionID(credential, url);
                    if (sessID == null)
                    {
                        Console.WriteLine("");
                        Console.WriteLine("[-] ERROR: Credentials provided are not valid.");
                        Console.WriteLine("");
                        return;

                    }
                }


                ServicePointManager.ServerCertificateValidationCallback = delegate (object s, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) { return true; };
                ServicePointManager.Expect100Continue = true;
                ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;

                await library.Utils.HeartbeatRequest(url);

                // web request to search via rest API
                var webRequest = (HttpWebRequest)System.Net.WebRequest.Create(url + "/rest/search/latest/search");
                if (webRequest != null)
                {
                    // set header values
                    webRequest.Method = "POST";
                    webRequest.ContentType = "application/json";
                    webRequest.UserAgent = "SCMKIT-5dc493ada400c79dd318abbe770dac7c";

                    // if username/password auth was used, then pass the sessionID
                    if (credential.Contains(":"))
                    {
                        webRequest.Headers.Add("Cookie", "BITBUCKETSESSIONID= " + sessID);
                    }
                    // if user just specified http access token
                    else
                    {
                        webRequest.Headers.Add("Authorization", "Bearer " + credential);
                    }


                    // set body and send request
                    using (var streamWriter = new StreamWriter(webRequest.GetRequestStream()))
                    {
                        string json = "{\"query\":\"" + options + "\",\"entities\":{\"code\":{}},\"limits\":{\"primary\":100,\"secondary\":100}}";
                        streamWriter.Write(json);
                    }


                    // get web response
                    WebResponse myWebResponse = await webRequest.GetResponseAsync();
                    string content;
                    var reader = new StreamReader(myWebResponse.GetResponseStream());
                    content = reader.ReadToEnd();

                    bool validCreds = false;

                    // figure out if creds valid
                    for (int i = 0; i < myWebResponse.Headers.Count; ++i)
                    {
                        if (myWebResponse.Headers.Keys[i].ToString().ToLower().Equals("x-auserid"))
                        {
                            validCreds = true;
                        }

                    }


                    if (validCreds)
                    {

                        // parse the JSON output and display results
                        JsonTextReader jsonResult = new JsonTextReader(new StringReader(content));

                        string matchingLine = "";
                        string propName = "";
                        string projKey = "";
                        string repoName = "";
                        string fileName = "";
                        string nextPageStart = "";
                        string isLastPage = "";


                        // read the json results
                        while (jsonResult.Read())
                        {

                            switch (jsonResult.TokenType.ToString())
                            {

                                case "StartObject":
                                    break;
                                case "EndObject":
                                    break;
                                case "StartArray":
                                    break;
                                case "EndArray":
                                    // add the match to the list
                                    if (!matchingLine.Equals("") && !fileName.Equals(""))
                                    {
                                        bool alreadyExists = false;
                                        string fullURL = await library.BitbucketUtils.GetFullBitbucketRepoURLAsync(credential, sessID, projKey, repoName, url);


                                        URLResult singleResults = new URLResult(fullURL, matchingLine, fileName);

                                        // only add if not already found before
                                        foreach (URLResult item in urlResults)
                                        {
                                            if (item.fileName.Equals(fileName) && item.url.Equals(fullURL))
                                            {

                                                alreadyExists = true;
                                            }
                                        }

                                        if (!alreadyExists)
                                        {
                                            urlResults.Add(singleResults);

                                        }

                                    }
                                    break;
                                case "PropertyName":
                                    propName = jsonResult.Value.ToString();
                                    break;
                                case "String":

                                    // get the actual values
                                    if (propName.ToLower().Equals("text"))
                                    {
                                        if (jsonResult.Value.ToString().ToLower().Contains(options.ToLower()))
                                        {
                                            matchingLine = jsonResult.Value.ToString();
                                        }
                                    }
                                    if (propName.ToLower().Equals("key"))
                                    {
                                        projKey = jsonResult.Value.ToString();
                                    }
                                    if (propName.ToLower().Equals("slug"))
                                    {
                                        repoName = jsonResult.Value.ToString();
                                    }
                                    if (propName.ToLower().Equals("file"))
                                    {
                                        fileName = jsonResult.Value.ToString();
                                    }
                                    break;
                                case "Integer":
                                    if (propName.ToLower().Equals("nextstart"))
                                    {
                                        nextPageStart = jsonResult.Value.ToString();

                                    }
                                    break;
                                case "Boolean":
                                    if (propName.ToLower().Equals("islastpage"))
                                    {
                                        isLastPage = jsonResult.Value.ToString();

                                    }
                                    break;
                                default:
                                    break;


                            }


                        }

                        // iterate through the dictionary of matching lines and print them
                        foreach (var item in urlResults)
                        {
                            if (item.fileName.ToLower().Contains(options.ToLower()))
                            {

                                Console.WriteLine("\n[>] REPO: " + item.url);
                                Console.WriteLine("    [>] FILE: " + item.fileName);
                                matchCount++;

                            }

                        }

                        // if there are more pages, then make subsequent requests
                        if (!nextPageStart.Equals("") && isLastPage.Equals("False"))
                        {
                            await makeSubsequentRequestAsync(credential, url, options, sessID, nextPageStart);
                        }


                        Console.WriteLine("");
                        Console.WriteLine("Total matching results: " + matchCount);


                    }

                    // if creds invalid
                    else
                    {
                        Console.WriteLine("");
                        Console.WriteLine("[-] ERROR: Credentials (username/password OR API token) provided are not valid.");
                        Console.WriteLine("");
                    }

                }

            }

            catch (Exception ex)
            {
                Console.WriteLine("");
                Console.WriteLine("[-] ERROR: Could not perform repo search. Exception: " + ex.ToString());
                Console.WriteLine("");
            }

        }


        // this is just placeholder for making more than 1 request due to paging of results. will have better global solution at some point than this band-aid
        public static async Task makeSubsequentRequestAsync(string credential, string url, string options, string sessID, string nextPage)
        {



            try
            {


                urlResults.Clear();

                ServicePointManager.ServerCertificateValidationCallback = delegate (object s, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) { return true; };
                ServicePointManager.Expect100Continue = true;
                ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;

                // web request to search files via REST api
                var webRequest = (HttpWebRequest)System.Net.WebRequest.Create(url + "/rest/search/latest/search");
                if (webRequest != null)
                {
                    // set header values
                    webRequest.Method = "POST";
                    webRequest.ContentType = "application/json";
                    webRequest.UserAgent = "SCMKIT-5dc493ada400c79dd318abbe770dac7c";

                    // if username/password auth was used, then pass the sessionID
                    if (credential.Contains(":"))
                    {
                        webRequest.Headers.Add("Cookie", "BITBUCKETSESSIONID= " + sessID);
                    }
                    // if user just specified http access token
                    else
                    {
                        webRequest.Headers.Add("Authorization", "Bearer " + credential);
                    }


                    // set body and send request
                    using (var streamWriter = new StreamWriter(webRequest.GetRequestStream()))
                    {
                        string json = "{\"query\":\"" + options + "\",\"entities\":{\"code\":{\"start\":" + nextPage + "}},\"limits\":{\"primary\":100,\"secondary\":100}}";
                        streamWriter.Write(json);
                    }


                    // get web response
                    WebResponse myWebResponse = await webRequest.GetResponseAsync();
                    string content;
                    var reader = new StreamReader(myWebResponse.GetResponseStream());
                    content = reader.ReadToEnd();

                    bool validCreds = false;

                    // figure out if creds valid
                    for (int i = 0; i < myWebResponse.Headers.Count; ++i)
                    {
                        if (myWebResponse.Headers.Keys[i].ToString().ToLower().Equals("x-auserid"))
                        {
                            validCreds = true;
                        }

                    }


                    if (validCreds)
                    {

                        // parse the JSON output and display results
                        JsonTextReader jsonResult = new JsonTextReader(new StringReader(content));

                        string matchingLine = "";
                        string propName = "";
                        string projKey = "";
                        string repoName = "";
                        string fileName = "";
                        string nextPageStart = "";
                        string isLastPage = "";


                        // read the json results
                        while (jsonResult.Read())
                        {

                            switch (jsonResult.TokenType.ToString())
                            {

                                case "StartObject":
                                    break;
                                case "EndObject":
                                    break;
                                case "StartArray":
                                    break;
                                case "EndArray":
                                    // add the match to the list
                                    if (!matchingLine.Equals("") && !fileName.Equals(""))
                                    {
                                        bool alreadyExists = false;
                                        string fullURL = await library.BitbucketUtils.GetFullBitbucketRepoURLAsync(credential, sessID, projKey, repoName, url);



                                        URLResult singleResults = new URLResult(fullURL, matchingLine, fileName);

                                        // only add if not already found before
                                        foreach (URLResult item in urlResults)
                                        {
                                            if (item.fileName.Equals(fileName) && item.url.Equals(fullURL))
                                            {

                                                alreadyExists = true;
                                            }
                                        }

                                        if (!alreadyExists)
                                        {
                                            urlResults.Add(singleResults);

                                        }

                                    }
                                    break;
                                case "PropertyName":
                                    propName = jsonResult.Value.ToString();
                                    break;
                                case "String":

                                    // get the actual values
                                    if (propName.ToLower().Equals("text"))
                                    {
                                        if (jsonResult.Value.ToString().ToLower().Contains(options.ToLower()))
                                        {
                                            matchingLine = jsonResult.Value.ToString();
                                        }
                                    }
                                    if (propName.ToLower().Equals("key"))
                                    {
                                        projKey = jsonResult.Value.ToString();
                                    }
                                    if (propName.ToLower().Equals("slug"))
                                    {
                                        repoName = jsonResult.Value.ToString();
                                    }
                                    if (propName.ToLower().Equals("file"))
                                    {
                                        fileName = jsonResult.Value.ToString();
                                    }
                                    break;
                                case "Integer":
                                    if (propName.ToLower().Equals("nextstart"))
                                    {
                                        nextPageStart = jsonResult.Value.ToString();

                                    }
                                    break;
                                case "Boolean":
                                    if (propName.ToLower().Equals("islastpage"))
                                    {
                                        isLastPage = jsonResult.Value.ToString();

                                    }
                                    break;
                                default:
                                    break;


                            }


                        }

                        // iterate through the dictionary of matching lines and print them
                        foreach (var item in urlResults)
                        {
                            if (item.fileName.ToLower().Contains(options.ToLower()))
                            {

                                Console.WriteLine("\n[>] REPO: " + item.url);
                                Console.WriteLine("    [>] FILE: " + item.fileName);
                                matchCount++;

                            }

                        }

                        // if there are more pages, then make subsequent requests
                        if (!nextPageStart.Equals("") && isLastPage.Equals("False"))
                        {
                            await makeSubsequentRequestAsync(credential, url, options, sessID, nextPageStart);
                        }




                    }

                    // if creds invalid
                    else
                    {
                        Console.WriteLine("");
                        Console.WriteLine("[-] ERROR: Credentials (username/password OR API token) provided are not valid.");
                        Console.WriteLine("");
                    }

                }

            }

            catch (Exception ex)
            {
                Console.WriteLine("");
                Console.WriteLine("[-] ERROR: Could not perform file search. Exception: " + ex.ToString());
                Console.WriteLine("");
            }


        }

    }
}


================================================
FILE: SCMKit/modules/bitbucket/ListPAT.cs
================================================
using System;
using System.Linq;
using System.Collections.Generic;
using System.Net;
using System.Threading.Tasks;
using System.IO;
using System.Security.Cryptography.X509Certificates;
using System.Net.Security;


namespace SCMKit.modules.bitbucket
{
    class ListPAT
    {

        // hashtable to store mapping of PAT and permissions
        private static Dictionary<string, string> patMapping = new Dictionary<string, string>();

        public static async Task execute(string credential, string url, string options, string system)
        {

            // Generate module header
            Console.WriteLine(library.Utils.GenerateHeader("listpat", credential, url, options, system));

            try
            {

                string sessID = "";

                // if username/password auth is used, get session ID for remainder of requests
                if (credential.Contains(":"))
                {
                    sessID = library.BitbucketUtils.GetSessionID(credential, url);
                    if (sessID == null)
                    {
                        Console.WriteLine("");
                        Console.WriteLine("[-] ERROR: Credentials provided are not valid.");
                        Console.WriteLine("");
                        return;

                    }
                }

                // create table header
                string tableHeader = string.Format("{0,15} | {1,30} | {2,50}", "ID", "Name", "Permissions");
                Console.WriteLine(tableHeader);
                Console.WriteLine(new String('-', tableHeader.Length));

                ServicePointManager.ServerCertificateValidationCallback = delegate (object s, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) { return true; };
                ServicePointManager.Expect100Continue = true;
                ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;

                await library.Utils.HeartbeatRequest(url);

                string[] splitCred = credential.Split(':');
                string theUser = "";
                if (options.Equals(""))
                {
                    theUser = splitCred[0];
                }
                else
                {
                    theUser = options;
                }

                // web request to get pats via REST api
                var webRequest = (HttpWebRequest)System.Net.WebRequest.Create(url + "/rest/access-tokens/1.0/users/" + theUser);
                if (webRequest != null)
                {
                    // set header values
                    webRequest.Method = "GET";
                    webRequest.ContentType = "application/json";
                    webRequest.UserAgent = "SCMKIT-5dc493ada400c79dd318abbe770dac7c";

                    // if username/password auth was used, then pass the sessionID
                    if (credential.Contains(":"))
                    {
                        webRequest.Headers.Add("Cookie", "BITBUCKETSESSIONID= " + sessID);
                    }
                    // if user just specified http access token
                    else
                    {
                        webRequest.Headers.Add("Authorization", "Bearer " + credential);
                    }

                    // get web response
                    WebResponse myWebResponse = await webRequest.GetResponseAsync();
                    string content;
                    var reader = new StreamReader(myWebResponse.GetResponseStream());
                    content = reader.ReadToEnd();

                    bool validCreds = false;

                    // figure out if creds valid
                    for (int i = 0; i < myWebResponse.Headers.Count; ++i)
                    {
                        if (myWebResponse.Headers.Keys[i].ToString().ToLower().Equals("x-auserid"))
                        {
                            validCreds = true;
                        }

                    }


                    if (validCreds)
                    {
                        // get all instances of PAT ID's
                        IEnumerable<int> startingIndexesPATids = library.Utils.AllIndexesOf(content, "\"id\":\"");
                        IEnumerable<int> endingIndexesPATids = library.Utils.AllIndexesOf(content, "\"createdDate\":");

                        List<string> listOfPatIDs = new List<string>();
                        for (int i = 0; i < startingIndexesPATids.Count(); i++)
                        {

                            string patID = "";
                            patID = content.Substring(startingIndexesPATids.ElementAt(i) + "\"id\":\"".Length, endingIndexesPATids.ElementAt(i) - startingIndexesPATids.ElementAt(i) - "\"id\":\"".Length);
                            patID = patID.Replace("\"", "");
                            patID = patID.Replace(",", "");
                            listOfPatIDs.Add(patID);

                        }




                        // get all instances of the token name
                        IEnumerable<int> startingIndexesName = library.Utils.AllIndexesOf(content, "\"createdDate\":");
                        IEnumerable<int> endingIndexesName = library.Utils.AllIndexesOf(content, "\"permissions\":");

                        List<string> listOfPatNames = new List<string>();

                        for (int i = 0; i < startingIndexesName.Count(); i++)
                        {

                            string patName = "";
                            patName = content.Substring(startingIndexesName.ElementAt(i) + "\"createdDate\":".Length, endingIndexesName.ElementAt(i) - startingIndexesName.ElementAt(i) - "\"createdDate\"".Length);
                            patName = patName.Replace("\"", "");
                            patName = patName.Replace(",", "");
                            string[] patNameArray = patName.Split(':');
                            listOfPatNames.Add(patNameArray[patNameArray.Length - 1]);

                        }


                        // get all instances of the token permissions
                        IEnumerable<int> startingIndexesPermissions = library.Utils.AllIndexesOf(content, "\"permissions\":");
                        IEnumerable<int> endingIndexesPermissions = library.Utils.AllIndexesOf(content, "\"user\":");

                        List<string> listOfPatPermissions = new List<string>();


                        for (int i = 0; i < startingIndexesPermissions.Count(); i++)
                        {

                            string patPermissions = "";
                            patPermissions = content.Substring(startingIndexesPermissions.ElementAt(i) + "\"permissions\":".Length, endingIndexesPermissions.ElementAt(i) - startingIndexesPermissions.ElementAt(i) - "\"permissions\"".Length);
                            patPermissions = patPermissions.Replace("\"],\"", "");
                            patPermissions = patPermissions.Replace("[", "");
                            patPermissions = patPermissions.Replace("]", "");
                            patPermissions = patPermissions.Replace("\"", "");
                            listOfPatPermissions.Add(patPermissions);

                        }


                        // the pat names and permissions lists with have same counts, each index is associated with the other list, so list the permissions for each token
                        for (int i = 0; i < listOfPatNames.Count(); i++)
                        {
                            Console.WriteLine("{0,15} | {1,30} | {2,50}", listOfPatIDs[i], listOfPatNames[i], listOfPatPermissions[i]);



                        }

                    }

                    // if creds invalid
                    else
                    {
                        Console.WriteLine("");
                        Console.WriteLine("[-] ERROR: Credentials (username/password OR API token) provided are not valid.");
                        Console.WriteLine("");
                    }

                }

            }

            catch (Exception ex)
            {
                Console.WriteLine("");
                Console.WriteLine("[-] ERROR: Could not retrieve listing of PATs. Exception: " + ex.ToString());
                Console.WriteLine("");
            }

        }


    }
}


================================================
FILE: SCMKit/modules/bitbucket/ListSSHKeys.cs
================================================
using System;
using System.Linq;
using System.Collections.Generic;
using System.Net;
using System.Threading.Tasks;
using System.IO;
using System.Security.Cryptography.X509Certificates;
using System.Net.Security;


namespace SCMKit.modules.bitbucket
{


    class ListSSHKeys
    {


        public static async Task execute(string credential, string url, string options, string system)
        {

            // Generate module header
            Console.WriteLine(library.Utils.GenerateHeader("listsshkey", credential, url, options, system));

            try
            {

                string sessID = "";

                // if username/password auth is used, get session ID for remainder of requests
                if (credential.Contains(":"))
                {
                    sessID = library.BitbucketUtils.GetSessionID(credential, url);
                    if (sessID == null)
                    {
                        Console.WriteLine("");
                        Console.WriteLine("[-] ERROR: Credentials provided are not valid.");
                        Console.WriteLine("");
                        return;

                    }
                }

                // create table header
                string tableHeader = string.Format("{0,12} | {1,25} | {2,20}", "SSH Key ID", "SSH Key Value", "Label");
                Console.WriteLine(tableHeader);
                Console.WriteLine(new String('-', tableHeader.Length));

                ServicePointManager.ServerCertificateValidationCallback = delegate (object s, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) { return true; };
                ServicePointManager.Expect100Continue = true;
                ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;

                await library.Utils.HeartbeatRequest(url);

                string[] splitCred = credential.Split(':');


                // web request to list SSH keys via REST API
                var webRequest = (HttpWebRequest)System.Net.WebRequest.Create(url + "/rest/ssh/1.0/keys");
                if (webRequest != null)
                {
                    // set header values
                    webRequest.Method = "GET";
                    webRequest.ContentType = "application/json";
                    webRequest.UserAgent = "SCMKIT-5dc493ada400c79dd318abbe770dac7c";

                    // if username/password auth was used, then pass the sessionID
                    if (credential.Contains(":"))
                    {
                        webRequest.Headers.Add("Cookie", "BITBUCKETSESSIONID= " + sessID);
                    }
                    // if user just specified http access token
                    else
                    {
                        webRequest.Headers.Add("Authorization", "Bearer " + credential);
                    }

                    // get web response
                    WebResponse myWebResponse = await webRequest.GetResponseAsync();
                    string content;
                    var reader = new StreamReader(myWebResponse.GetResponseStream());
                    content = reader.ReadToEnd();

                    bool validCreds = false;

                    // figure out if creds valid
                    for (int i = 0; i < myWebResponse.Headers.Count; ++i)
                    {
                        if (myWebResponse.Headers.Keys[i].ToString().ToLower().Equals("x-auserid"))
                        {
                            validCreds = true;
                        }

                    }


                    // only proceed if valid creds
                    if (validCreds)
                    {



                        // get all instances of the SSH key id
                        IEnumerable<int> startingIndexesID = library.Utils.AllIndexesOf(content, "\"id\":");
                        IEnumerable<int> endingIndexesID = library.Utils.AllIndexesOf(content, "\"text\":");

                        List<string> listOfIndexIDs = new List<string>();

                        for (int i = 0; i < startingIndexesID.Count(); i++)
                        {

                            string sshKeyID = "";
                            sshKeyID = content.Substring(startingIndexesID.ElementAt(i) + "\"id\":".Length, endingIndexesID.ElementAt(i) - startingIndexesID.ElementAt(i) - "\"id\"".Length);
                            sshKeyID = sshKeyID.Replace("\"", "");
                            sshKeyID = sshKeyID.Replace(",", "");
                            listOfIndexIDs.Add(sshKeyID);

                        }


                        // get all instances of the SSH key value
                        IEnumerable<int> startingIndexesValue = library.Utils.AllIndexesOf(content, "\"text\":");
                        IEnumerable<int> endingIndexesValue = library.Utils.AllIndexesOf(content, "\"label\":");

                        List<string> listOfIndexValues = new List<string>();

                        for (int i = 0; i < startingIndexesValue.Count(); i++)
                        {

                            string sshKeyValue = "";
                            sshKeyValue = content.Substring(startingIndexesValue.ElementAt(i) + "\"text\":".Length, endingIndexesValue.ElementAt(i) - startingIndexesValue.ElementAt(i) - "\"text\"".Length);
                            sshKeyValue = sshKeyValue.Replace("\"", "");
                            sshKeyValue = sshKeyValue.Replace(",", "");
                            listOfIndexValues.Add(sshKeyValue);


                        }


                        // iterate through and print the ssh key ID's and contents
                        for (int i = 0; i < listOfIndexIDs.Count(); i++)
                        {

                            string[] sshKeyArray = listOfIndexValues[i].Split(' ');
                            string justSSHKey = sshKeyArray[1].Substring(sshKeyArray[1].Length - 20, 20);
                            string justSSHLabel = "";
                            //the ssh key label is array value [2]
                            if (sshKeyArray.Length == 3)
                            {
                                justSSHLabel = sshKeyArray[2];
                            }

                            Console.WriteLine("{0,12} | {1,20} | {2,20}", listOfIndexIDs[i], "....." + justSSHKey, justSSHLabel);
                        }


                    }

                    // if creds invalid
                    else
                    {
                        Console.WriteLine("");
                        Console.WriteLine("[-] ERROR: Credentials (username/password OR API token) provided are not valid.");
                        Console.WriteLine("");
                    }



                }

            }

            catch (Exception ex)
            {
                Console.WriteLine("");
                Console.WriteLine("[-] ERROR: Could not create SSH Key. Exception: " + ex.ToString());
                Console.WriteLine("");
            }

        }



    }
}


================================================
FILE: SCMKit/modules/bitbucket/RemoveAdmin.cs
================================================
using System;
using System.Net;
using System.Threading.Tasks;
using System.IO;
using System.Security.Cryptography.X509Certificates;
using System.Net.Security;

namespace SCMKit.modules.bitbucket
{
    class RemoveAdmin
    {

        public static async Task execute(string credential, string url, string options, string system)
        {

            // Generate module header
            Console.WriteLine(library.Utils.GenerateHeader("removeadmin", credential, url, options, system));

            try
            {

                string sessID = "";

                // if username/password auth is used, get session ID for remainder of requests
                if (credential.Contains(":"))
                {
                    sessID = library.BitbucketUtils.GetSessionID(credential, url);
                    if (sessID == null)
                    {
                        Console.WriteLine("");
                        Console.WriteLine("[-] ERROR: Credentials provided are not valid.");
                        Console.WriteLine("");
                        return;

                    }
                }

                // if API token was provided, display message and return
                else
                {
                    Console.WriteLine("");
                    Console.WriteLine("[-] ERROR: API token authentication is not supported for this module. Please provide username/password with the appropriate permissions.");
                    Console.WriteLine("");
                    return;

                }


                ServicePointManager.ServerCertificateValidationCallback = delegate (object s, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) { return true; };
                ServicePointManager.Expect100Continue = true;
                ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;

                await library.Utils.HeartbeatRequest(url);

                // web request to remove admin via rest API
                var webRequest = (HttpWebRequest)System.Net.WebRequest.Create(url + "/rest/api/1.0/admin/permissions/users?name=" + options + "&permission=PROJECT_CREATE");
                if (webRequest != null)
                {
                    // set header values
                    webRequest.Method = "PUT";
                    webRequest.ContentType = "application/json";
                    webRequest.UserAgent = "SCMKIT-5dc493ada400c79dd318abbe770dac7c";

                    // if username/password auth was used, then pass the sessionID
                    if (credential.Contains(":"))
                    {
                        webRequest.Headers.Add("Cookie", "BITBUCKETSESSIONID= " + sessID);
                    }
                    // if user just specified http access token
                    else
                    {
                        webRequest.Headers.Add("Authorization", "Bearer " + credential);
                    }


                    // get web response
                    WebResponse myWebResponse = await webRequest.GetResponseAsync();
                    string content;
                    var reader = new StreamReader(myWebResponse.GetResponseStream());
                    content = reader.ReadToEnd();

                    bool validCreds = false;

                    // figure out if creds valid
                    for (int i = 0; i < myWebResponse.Headers.Count; ++i)
                    {
                        if (myWebResponse.Headers.Keys[i].ToString().ToLower().Equals("x-auserid"))
                        {
                            validCreds = true;
                        }

                    }


                    if (validCreds)
                    {
                        Console.WriteLine("");
                        Console.WriteLine("[+] SUCCESS: Successfully removed " + options + " user from the admin role.");
                        Console.WriteLine("");

                    }

                    // if creds invalid
                    else
                    {
                        Console.WriteLine("");
                        Console.WriteLine("[-] ERROR: Credentials (username/password OR API token) provided are not valid.");
                        Console.WriteLine("");
                    }

                }

            }

            catch (Exception ex)
            {
                Console.WriteLine("");
                Console.WriteLine("[-] ERROR: Could not remove user from admin group. Exception: " + ex.ToString());
                Console.WriteLine("");
            }

        }
    }
}


================================================
FILE: SCMKit/modules/bitbucket/RemovePAT.cs
================================================
using System;
using System.Net;
using System.Threading.Tasks;
using System.IO;
using System.Security.Cryptography.X509Certificates;
using System.Net.Security;

namespace SCMKit.modules.bitbucket
{
    class RemovePAT
    {

        public static async Task execute(string credential, string url, string options, string system)
        {

            // Generate module header
            Console.WriteLine(library.Utils.GenerateHeader("removepat", credential, url, options, system));

            try
            {

                string sessID = "";

                // if username/password auth is used, get session ID for remainder of requests
                if (credential.Contains(":"))
                {
                    sessID = library.BitbucketUtils.GetSessionID(credential, url);
                    if (sessID == null)
                    {
                        Console.WriteLine("");
                        Console.WriteLine("[-] ERROR: Credentials provided are not valid.");
                        Console.WriteLine("");
                        return;

                    }
                }

                // if API token was provided, display message and return
                else
                {
                    Console.WriteLine("");
                    Console.WriteLine("[-] ERROR: API token authentication is not supported for this module. Please provide username/password with the appropriate permissions.");
                    Console.WriteLine("");
                    return;

                }




                ServicePointManager.ServerCertificateValidationCallback = delegate (object s, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) { return true; };
                ServicePointManager.Expect100Continue = true;
                ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;

                await library.Utils.HeartbeatRequest(url);

                string[] splitCred = credential.Split(':');

                // if user didn't specify an ID, display message and return
                if (options.Equals(""))
                {
                    Console.WriteLine("");
                    Console.WriteLine("[-] ERROR: Must supply ID of PAT to remove.");
                    Console.WriteLine("");
                    return;
                }

                // web request to get pats via REST api
                var webRequest = (HttpWebRequest)System.Net.WebRequest.Create(url + "/rest/access-tokens/1.0/users/" + splitCred[0] + "/" + options);
                if (webRequest != null)
                {
                    // set header values
                    webRequest.Method = "DELETE";
                    webRequest.ContentType = "application/json";
                    webRequest.UserAgent = "SCMKIT-5dc493ada400c79dd318abbe770dac7c";

                    // if username/password auth was used, then pass the sessionID
                    if (credential.Contains(":"))
                    {
                        webRequest.Headers.Add("Cookie", "BITBUCKETSESSIONID= " + sessID);
                    }
                    // if user just specified http access token
                    else
                    {
                        webRequest.Headers.Add("Authorization", "Bearer " + credential);
                    }


                    // get web response
                    WebResponse myWebResponse = await webRequest.GetResponseAsync();
                    string content;
                    
Download .txt
gitextract_g9j8xacg/

├── .gitignore
├── Detections/
│   ├── SCMKit.rules
│   └── SCMKit.yar
├── LICENSE
├── README.md
├── SCMKit/
│   ├── App.config
│   ├── FodyWeavers.xml
│   ├── Properties/
│   │   └── AssemblyInfo.cs
│   ├── SCMKit.cs
│   ├── SCMKit.csproj
│   ├── library/
│   │   ├── BitbucketUtils.cs
│   │   ├── GitHubUtils.cs
│   │   ├── GitLabUtils.cs
│   │   ├── Utils.cs
│   │   └── WebUtils.cs
│   ├── modules/
│   │   ├── bitbucket/
│   │   │   ├── AddAdmin.cs
│   │   │   ├── CodeSearch.cs
│   │   │   ├── CreatePAT.cs
│   │   │   ├── CreateSSHKey.cs
│   │   │   ├── FileSearch.cs
│   │   │   ├── ListPAT.cs
│   │   │   ├── ListSSHKeys.cs
│   │   │   ├── RemoveAdmin.cs
│   │   │   ├── RemovePAT.cs
│   │   │   ├── RemoveSSHKey.cs
│   │   │   ├── RepoList.cs
│   │   │   └── RepoSearch.cs
│   │   ├── github/
│   │   │   ├── AddAdmin.cs
│   │   │   ├── AdminStats.cs
│   │   │   ├── BranchProtection.cs
│   │   │   ├── CodeSearch.cs
│   │   │   ├── CreatePAT.cs
│   │   │   ├── CreateSSHKey.cs
│   │   │   ├── FileSearch.cs
│   │   │   ├── GistList.cs
│   │   │   ├── ListPAT.cs
│   │   │   ├── ListSSHKeys.cs
│   │   │   ├── OrgList.cs
│   │   │   ├── Privs.cs
│   │   │   ├── RemoveAdmin.cs
│   │   │   ├── RemovePAT.cs
│   │   │   ├── RemoveSSHKey.cs
│   │   │   ├── RepoList.cs
│   │   │   └── RepoSearch.cs
│   │   └── gitlab/
│   │       ├── AddAdmin.cs
│   │       ├── CodeSearch.cs
│   │       ├── CreatePAT.cs
│   │       ├── CreateSSHKey.cs
│   │       ├── FileSearch.cs
│   │       ├── ListPAT.cs
│   │       ├── ListSSHKeys.cs
│   │       ├── Privs.cs
│   │       ├── RemoveAdmin.cs
│   │       ├── RemovePAT.cs
│   │       ├── RemoveSSHKey.cs
│   │       ├── RepoList.cs
│   │       ├── RepoSearch.cs
│   │       ├── RunnerList.cs
│   │       └── SnippetList.cs
│   └── packages.config
└── SCMKit.sln
Download .txt
SYMBOL INDEX (137 symbols across 50 files)

FILE: SCMKit/SCMKit.cs
  class SCMKit (line 7) | class SCMKit
    method Main (line 19) | static async Task Main(string[] args)

FILE: SCMKit/library/BitbucketUtils.cs
  class BitbucketUtils (line 11) | class BitbucketUtils
    method GetSessionID (line 19) | public static string GetSessionID(string credentials, string url)
    method GetFullBitbucketRepoURLAsync (line 116) | public static async Task<string> GetFullBitbucketRepoURLAsync(string c...

FILE: SCMKit/library/GitHubUtils.cs
  class GitHubUtils (line 11) | class GitHubUtils
    method AuthToGitHub (line 18) | public static dynamic AuthToGitHub(string credentials, string url)
    method callGitHubApiGet (line 60) | public static async Task<string> callGitHubApiGet(string credential, s...

FILE: SCMKit/library/GitLabUtils.cs
  class GitLabUtils (line 11) | class GitLabUtils
    method GetGitLabProjectVisibility (line 19) | public static async Task<string> GetGitLabProjectVisibility(string cre...
    method AuthToGitLabAsync (line 82) | public static async Task<GitLabClient> AuthToGitLabAsync(string creden...
    method GetAccessToken (line 126) | public static string GetAccessToken(string credential, string url)

FILE: SCMKit/library/Utils.cs
  class Utils (line 10) | class Utils
    method ParseTheArguments (line 17) | public static Dictionary<string, string> ParseTheArguments(string[] args)
    method HelpMe (line 47) | public static void HelpMe()
    method GenerateHeader (line 60) | public static string GenerateHeader(string module, string credential, ...
    method HeartbeatRequest (line 92) | public static async Task<WebResponse> HeartbeatRequest(string url)
    method AllIndexesOf (line 137) | public static int[] AllIndexesOf(string str, string substr, bool ignor...

FILE: SCMKit/library/WebUtils.cs
  class WebUtils (line 10) | class WebUtils
    method GenerateWebRequest (line 17) | public static HttpWebRequest GenerateWebRequest(string credential, str...
    method GenerateRawFileWebRequest (line 46) | public static HttpWebRequest GenerateRawFileWebRequest(string credenti...
    method GetRequestResponseString (line 72) | public static async Task<string> GetRequestResponseString(HttpWebReque...
    method GetRequestResponse (line 94) | public static async Task<WebResponse> GetRequestResponse(HttpWebReques...
    method IgnoreSSL (line 105) | public static void IgnoreSSL()

FILE: SCMKit/modules/bitbucket/AddAdmin.cs
  class AddAdmin (line 10) | class AddAdmin
    method execute (line 12) | public static async Task execute(string credential, string url, string...

FILE: SCMKit/modules/bitbucket/CodeSearch.cs
  class URLResult (line 15) | public class URLResult
    method URLResult (line 18) | public URLResult(string link, string matchingLine, string fileName)
  class CodeSearch (line 32) | class CodeSearch
    method execute (line 40) | public static async Task execute(string credential, string url, string...
    method makeSubsequentRequestAsync (line 278) | public static async Task makeSubsequentRequestAsync(string credential,...

FILE: SCMKit/modules/bitbucket/CreatePAT.cs
  class CreatePAT (line 11) | class CreatePAT
    method execute (line 17) | public static async Task execute(string credential, string url, string...

FILE: SCMKit/modules/bitbucket/CreateSSHKey.cs
  class CreateSSHKey (line 10) | class CreateSSHKey
    method execute (line 14) | public static async Task execute(string credential, string url, string...

FILE: SCMKit/modules/bitbucket/FileSearch.cs
  class FileSearch (line 12) | class FileSearch
    method execute (line 20) | public static async Task execute(string credential, string url, string...
    method makeSubsequentRequestAsync (line 255) | public static async Task makeSubsequentRequestAsync(string credential,...

FILE: SCMKit/modules/bitbucket/ListPAT.cs
  class ListPAT (line 13) | class ListPAT
    method execute (line 19) | public static async Task execute(string credential, string url, string...

FILE: SCMKit/modules/bitbucket/ListSSHKeys.cs
  class ListSSHKeys (line 15) | class ListSSHKeys
    method execute (line 19) | public static async Task execute(string credential, string url, string...

FILE: SCMKit/modules/bitbucket/RemoveAdmin.cs
  class RemoveAdmin (line 10) | class RemoveAdmin
    method execute (line 13) | public static async Task execute(string credential, string url, string...

FILE: SCMKit/modules/bitbucket/RemovePAT.cs
  class RemovePAT (line 10) | class RemovePAT
    method execute (line 13) | public static async Task execute(string credential, string url, string...

FILE: SCMKit/modules/bitbucket/RemoveSSHKey.cs
  class RemoveSSHKey (line 10) | class RemoveSSHKey
    method execute (line 13) | public static async Task execute(string credential, string url, string...

FILE: SCMKit/modules/bitbucket/RepoList.cs
  class RepoList (line 12) | class RepoList
    method execute (line 18) | public static async Task execute(string credential, string url, string...
    method makeSubsequentRequestAsync (line 197) | public static async Task makeSubsequentRequestAsync(string credential,...

FILE: SCMKit/modules/bitbucket/RepoSearch.cs
  class RepoSearch (line 12) | class RepoSearch
    method execute (line 20) | public static async Task execute(string credential, string url, string...
    method makeSubsequentRequestAsync (line 205) | public static async Task makeSubsequentRequestAsync(string credential,...

FILE: SCMKit/modules/github/AddAdmin.cs
  class AddAdmin (line 10) | class AddAdmin
    method execute (line 13) | public static async Task execute(string credential, string url, string...

FILE: SCMKit/modules/github/AdminStats.cs
  class AdminStats (line 7) | class AdminStats
    method execute (line 10) | public static async Task execute(string credential, string url, string...

FILE: SCMKit/modules/github/BranchProtection.cs
  class BranchProtection (line 11) | class BranchProtection
    method execute (line 13) | public static async Task execute(string credential, string url, string...

FILE: SCMKit/modules/github/CodeSearch.cs
  class CodeSearch (line 9) | class CodeSearch
    method execute (line 13) | public static async Task execute(string credential, string url, string...
    method getLinesInFile (line 82) | public static async Task getLinesInFile(String credential, String url,...

FILE: SCMKit/modules/github/CreatePAT.cs
  class CreatePAT (line 10) | class CreatePAT
    method execute (line 12) | public static async Task execute(string credential, string url, string...

FILE: SCMKit/modules/github/CreateSSHKey.cs
  class CreateSSHKey (line 10) | class CreateSSHKey
    method execute (line 14) | public static async Task execute(string credential, string url, string...

FILE: SCMKit/modules/github/FileSearch.cs
  class FileSearch (line 11) | class FileSearch
    method execute (line 14) | public static async Task execute(string credential, string url, string...

FILE: SCMKit/modules/github/GistList.cs
  class GistList (line 8) | class GistList
    method execute (line 12) | public static async Task execute(string credential, string url, string...

FILE: SCMKit/modules/github/ListPAT.cs
  class ListPAT (line 9) | class ListPAT
    method execute (line 12) | public static async Task execute(string credential, string url, string...

FILE: SCMKit/modules/github/ListSSHKeys.cs
  class ListSSHKeys (line 12) | class ListSSHKeys
    method execute (line 15) | public static async Task execute(string credential, string url, string...

FILE: SCMKit/modules/github/OrgList.cs
  class OrgList (line 8) | class OrgList
    method execute (line 10) | public static async Task execute(string credential, string url, string...

FILE: SCMKit/modules/github/Privs.cs
  class Privs (line 10) | class Privs
    method execute (line 14) | public static async Task execute(string credential, string url, string...

FILE: SCMKit/modules/github/RemoveAdmin.cs
  class RemoveAdmin (line 10) | class RemoveAdmin
    method execute (line 13) | public static async Task execute(string credential, string url, string...

FILE: SCMKit/modules/github/RemovePAT.cs
  class RemovePAT (line 11) | class RemovePAT
    method execute (line 14) | public static async Task execute(string credential, string url, string...

FILE: SCMKit/modules/github/RemoveSSHKey.cs
  class RemoveSSHKey (line 11) | class RemoveSSHKey
    method execute (line 14) | public static async Task execute(string credential, string url, string...

FILE: SCMKit/modules/github/RepoList.cs
  class RepoList (line 8) | class RepoList
    method execute (line 13) | public static async Task execute(string credential, string url, string...

FILE: SCMKit/modules/github/RepoSearch.cs
  class RepoSearch (line 8) | class RepoSearch
    method execute (line 11) | public static async Task execute(string credential, string url, string...

FILE: SCMKit/modules/gitlab/AddAdmin.cs
  class AddAdmin (line 12) | class AddAdmin
    method execute (line 16) | public static async Task execute(string credential, string url, string...

FILE: SCMKit/modules/gitlab/CodeSearch.cs
  class gitlabSearchResult (line 16) | public class gitlabSearchResult
    method gitlabSearchResult (line 28) | public gitlabSearchResult()
  class CodeSearch (line 36) | class CodeSearch
    method execute (line 39) | public static async Task execute(string credential, string url, string...

FILE: SCMKit/modules/gitlab/CreatePAT.cs
  class CreatePAT (line 12) | class CreatePAT
    method execute (line 15) | public static async Task execute(string credential, string url, string...

FILE: SCMKit/modules/gitlab/CreateSSHKey.cs
  class CreateSSHKey (line 11) | class CreateSSHKey
    method execute (line 14) | public static async Task execute(string credential, string url, string...

FILE: SCMKit/modules/gitlab/FileSearch.cs
  class fileSearchResult (line 16) | public class fileSearchResult
    method fileSearchResult (line 26) | public fileSearchResult()
  class FileSearch (line 33) | class FileSearch
    method execute (line 36) | public static async Task execute(string credential, string url, string...

FILE: SCMKit/modules/gitlab/ListPAT.cs
  class patResult (line 15) | public class patResult
    method patResult (line 28) | public patResult()
  class ListPAT (line 34) | class ListPAT
    method execute (line 37) | public static async Task execute(string credential, string url, string...
    method makeSubsequentRequestAsync (line 192) | public static async Task makeSubsequentRequestAsync(string credential,...

FILE: SCMKit/modules/gitlab/ListSSHKeys.cs
  class ListSSHKeys (line 12) | class ListSSHKeys
    method execute (line 15) | public static async Task execute(string credential, string url, string...

FILE: SCMKit/modules/gitlab/Privs.cs
  class apiPermissions (line 14) | public class apiPermissions
    method apiPermissions (line 25) | public apiPermissions()
  class Privs (line 34) | class Privs
    method execute (line 37) | public static async Task execute(string credential, string url, string...
    method makeSubsequentRequestAsync (line 237) | public static async Task makeSubsequentRequestAsync(string credential,...

FILE: SCMKit/modules/gitlab/RemoveAdmin.cs
  class RemoveAdmin (line 12) | class RemoveAdmin
    method execute (line 15) | public static async Task execute(string credential, string url, string...

FILE: SCMKit/modules/gitlab/RemovePAT.cs
  class RemovePAT (line 11) | class RemovePAT
    method execute (line 14) | public static async Task execute(string credential, string url, string...

FILE: SCMKit/modules/gitlab/RemoveSSHKey.cs
  class RemoveSSHKey (line 12) | class RemoveSSHKey
    method execute (line 15) | public static async Task execute(string credential, string url, string...

FILE: SCMKit/modules/gitlab/RepoList.cs
  class RepoList (line 7) | class RepoList
    method execute (line 10) | public static async Task execute(string credential, string url, string...

FILE: SCMKit/modules/gitlab/RepoSearch.cs
  class RepoSearch (line 12) | class RepoSearch
    method execute (line 16) | public static async Task execute(string credential, string url, string...
    method AllIndexesOf (line 189) | public static int[] AllIndexesOf(string str, string substrOne, string ...
    method makeSubsequentRequestAsync (line 221) | public static async Task makeSubsequentRequestAsync(string credential,...

FILE: SCMKit/modules/gitlab/RunnerList.cs
  class aRunner (line 15) | public class aRunner
    method aRunner (line 23) | public aRunner(string id, string name, string project)
  class RunnerList (line 33) | class RunnerList
    method execute (line 41) | public static async Task execute(string credential, string url, string...
    method getOwnedRunners (line 207) | public static async Task getOwnedRunners(string credential, string url...
    method GetRunnerDetails (line 351) | public static void GetRunnerDetails(string credential, string url, str...

FILE: SCMKit/modules/gitlab/SnippetList.cs
  class snippetResult (line 14) | public class snippetResult
    method snippetResult (line 32) | public snippetResult()
  class SnippetList (line 40) | class SnippetList
    method execute (line 44) | public static async Task execute(string credential, string url, string...
Condensed preview — 61 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (446K chars).
[
  {
    "path": ".gitignore",
    "chars": 7005,
    "preview": "## Ignore Visual Studio temporary files, build results, and\r\n## files generated by popular Visual Studio add-ons.\r\n##\r\n#"
  },
  {
    "path": "Detections/SCMKit.rules",
    "chars": 302,
    "preview": "alert tcp $HOME_NET any -> any $HTTP_PORTS (flow:established,to_server; content:\"SCMKIT-5dc493ada400c79dd318abbe770dac7c"
  },
  {
    "path": "Detections/SCMKit.yar",
    "chars": 618,
    "preview": "rule SCMKit_Signatures\n{\n    meta:\n        description = \"Static signatures for the SCMKit tool.\"\n        md5 = \"9b4b2a0"
  },
  {
    "path": "LICENSE",
    "chars": 11343,
    "preview": "                                 Apache License\n                           Version 2.0, January 2004\n                   "
  },
  {
    "path": "README.md",
    "chars": 39989,
    "preview": "# SCMKit\n\n## Description\n**S**ource **C**ode **M**anagement Attack Tool**kit** - SCMKit is a toolkit that can be used to"
  },
  {
    "path": "SCMKit/App.config",
    "chars": 540,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<configuration>\r\n    <startup> \r\n        <supportedRuntime version=\"v4.0\" sku=\""
  },
  {
    "path": "SCMKit/FodyWeavers.xml",
    "chars": 179,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<Weavers xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:noNamespaceS"
  },
  {
    "path": "SCMKit/Properties/AssemblyInfo.cs",
    "chars": 1371,
    "preview": "using System.Reflection;\nusing System.Runtime.CompilerServices;\nusing System.Runtime.InteropServices;\n\n// General Infor"
  },
  {
    "path": "SCMKit/SCMKit.cs",
    "chars": 17931,
    "preview": "using System;\r\nusing System.Collections.Generic;\r\nusing System.Threading.Tasks;\r\n\r\nnamespace SCMKit\r\n{\r\n    class SCMKi"
  },
  {
    "path": "SCMKit/SCMKit.csproj",
    "chars": 8159,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<Project ToolsVersion=\"15.0\" xmlns=\"http://schemas.microsoft.com/developer/msbu"
  },
  {
    "path": "SCMKit/library/BitbucketUtils.cs",
    "chars": 7471,
    "preview": "using System;\r\nusing System.IO;\r\nusing System.Net;\r\nusing System.Net.Security;\r\nusing System.Security.Cryptography.X509"
  },
  {
    "path": "SCMKit/library/GitHubUtils.cs",
    "chars": 3078,
    "preview": "using System;\r\nusing System.IO;\r\nusing System.Net;\r\nusing System.Net.Security;\r\nusing System.Security.Cryptography.X509"
  },
  {
    "path": "SCMKit/library/GitLabUtils.cs",
    "chars": 6027,
    "preview": "using System;\r\nusing System.IO;\r\nusing System.Net;\r\nusing System.Net.Security;\r\nusing System.Security.Cryptography.X509"
  },
  {
    "path": "SCMKit/library/Utils.cs",
    "chars": 4816,
    "preview": "using System;\r\nusing System.Collections.Generic;\r\nusing System.Net;\r\nusing System.Net.Security;\r\nusing System.Security."
  },
  {
    "path": "SCMKit/library/WebUtils.cs",
    "chars": 3801,
    "preview": "using System;\r\nusing System.IO;\r\nusing System.Net;\r\nusing System.Net.Security;\r\nusing System.Security.Cryptography.X509"
  },
  {
    "path": "SCMKit/modules/bitbucket/AddAdmin.cs",
    "chars": 4756,
    "preview": "using System;\r\nusing System.Net;\r\nusing System.Threading.Tasks;\r\nusing System.IO;\r\nusing System.Security.Cryptography.X"
  },
  {
    "path": "SCMKit/modules/bitbucket/CodeSearch.cs",
    "chars": 21252,
    "preview": "using System;\r\nusing System.Collections.Generic;\r\nusing System.Net;\r\nusing System.Threading.Tasks;\r\nusing System.IO;\r\nu"
  },
  {
    "path": "SCMKit/modules/bitbucket/CreatePAT.cs",
    "chars": 7672,
    "preview": "using System;\r\nusing System.Collections.Generic;\r\nusing System.Net;\r\nusing System.Threading.Tasks;\r\nusing System.IO;\r\nu"
  },
  {
    "path": "SCMKit/modules/bitbucket/CreateSSHKey.cs",
    "chars": 6485,
    "preview": "using System;\r\nusing System.Net;\r\nusing System.Threading.Tasks;\r\nusing System.IO;\r\nusing System.Security.Cryptography.X"
  },
  {
    "path": "SCMKit/modules/bitbucket/FileSearch.cs",
    "chars": 19782,
    "preview": "using System;\r\nusing System.Collections.Generic;\r\nusing System.Net;\r\nusing System.Threading.Tasks;\r\nusing System.IO;\r\nu"
  },
  {
    "path": "SCMKit/modules/bitbucket/ListPAT.cs",
    "chars": 8562,
    "preview": "using System;\r\nusing System.Linq;\r\nusing System.Collections.Generic;\r\nusing System.Net;\r\nusing System.Threading.Tasks;\r"
  },
  {
    "path": "SCMKit/modules/bitbucket/ListSSHKeys.cs",
    "chars": 7267,
    "preview": "using System;\r\nusing System.Linq;\r\nusing System.Collections.Generic;\r\nusing System.Net;\r\nusing System.Threading.Tasks;\r"
  },
  {
    "path": "SCMKit/modules/bitbucket/RemoveAdmin.cs",
    "chars": 4743,
    "preview": "using System;\r\nusing System.Net;\r\nusing System.Threading.Tasks;\r\nusing System.IO;\r\nusing System.Security.Cryptography.X"
  },
  {
    "path": "SCMKit/modules/bitbucket/RemovePAT.cs",
    "chars": 5145,
    "preview": "using System;\r\nusing System.Net;\r\nusing System.Threading.Tasks;\r\nusing System.IO;\r\nusing System.Security.Cryptography.X"
  },
  {
    "path": "SCMKit/modules/bitbucket/RemoveSSHKey.cs",
    "chars": 5089,
    "preview": "using System;\r\nusing System.Net;\r\nusing System.Threading.Tasks;\r\nusing System.IO;\r\nusing System.Security.Cryptography.X"
  },
  {
    "path": "SCMKit/modules/bitbucket/RepoList.cs",
    "chars": 14558,
    "preview": "using System;\r\nusing System.Collections.Generic;\r\nusing System.Net;\r\nusing System.Threading.Tasks;\r\nusing System.IO;\r\nu"
  },
  {
    "path": "SCMKit/modules/bitbucket/RepoSearch.cs",
    "chars": 15195,
    "preview": "using System;\r\nusing System.Collections.Generic;\r\nusing System.Net;\r\nusing System.Threading.Tasks;\r\nusing System.IO;\r\nu"
  },
  {
    "path": "SCMKit/modules/github/AddAdmin.cs",
    "chars": 1372,
    "preview": "using Octokit;\r\nusing System;\r\nusing System.Net;\r\nusing System.Net.Security;\r\nusing System.Security.Cryptography.X509Ce"
  },
  {
    "path": "SCMKit/modules/github/AdminStats.cs",
    "chars": 2724,
    "preview": "using System;\r\nusing System.Threading.Tasks;\r\nusing Octokit;\r\n\r\nnamespace SCMKit.modules.github\r\n{\r\n    class AdminStat"
  },
  {
    "path": "SCMKit/modules/github/BranchProtection.cs",
    "chars": 22387,
    "preview": "using System;\r\nusing System.Collections.Generic;\r\nusing System.Linq;\r\nusing System.Threading.Tasks;\r\nusing Newtonsoft.J"
  },
  {
    "path": "SCMKit/modules/github/CodeSearch.cs",
    "chars": 4287,
    "preview": "using System;\r\nusing System.Collections.Generic;\r\nusing System.Text.RegularExpressions;\r\nusing System.Threading.Tasks;\r\n"
  },
  {
    "path": "SCMKit/modules/github/CreatePAT.cs",
    "chars": 988,
    "preview": "using System;\r\nusing System.Collections.Generic;\r\nusing System.Linq;\r\nusing System.Text;\r\nusing System.Threading.Tasks;"
  },
  {
    "path": "SCMKit/modules/github/CreateSSHKey.cs",
    "chars": 1966,
    "preview": "using Octokit;\r\nusing System;\r\nusing System.Net;\r\nusing System.Net.Security;\r\nusing System.Security.Cryptography.X509Ce"
  },
  {
    "path": "SCMKit/modules/github/FileSearch.cs",
    "chars": 3632,
    "preview": "using System;\r\nusing System.Collections.Generic;\r\nusing System.Threading.Tasks;\r\nusing Octokit;\r\n\r\nnamespace SCMKit.mod"
  },
  {
    "path": "SCMKit/modules/github/GistList.cs",
    "chars": 1812,
    "preview": "using System;\r\nusing System.Collections.Generic;\r\nusing System.Threading.Tasks;\r\nusing Octokit;\r\n\r\nnamespace SCMKit.mod"
  },
  {
    "path": "SCMKit/modules/github/ListPAT.cs",
    "chars": 972,
    "preview": "using System;\r\nusing System.Collections.Generic;\r\nusing System.Linq;\r\nusing System.Text;\r\nusing System.Threading.Tasks;"
  },
  {
    "path": "SCMKit/modules/github/ListSSHKeys.cs",
    "chars": 2179,
    "preview": "using Octokit;\r\nusing System;\r\nusing System.Collections.Generic;\r\nusing System.Net;\r\nusing System.Net.Security;\r\nusing "
  },
  {
    "path": "SCMKit/modules/github/OrgList.cs",
    "chars": 1573,
    "preview": "using System;\r\nusing System.Collections.Generic;\r\nusing System.Threading.Tasks;\r\nusing Octokit;\r\n\r\nnamespace SCMKit.mod"
  },
  {
    "path": "SCMKit/modules/github/Privs.cs",
    "chars": 7458,
    "preview": "using System;\r\nusing System.Collections.Generic;\r\nusing System.Net;\r\nusing System.Net.Security;\r\nusing System.Security."
  },
  {
    "path": "SCMKit/modules/github/RemoveAdmin.cs",
    "chars": 1388,
    "preview": "using Octokit;\r\nusing System;\r\nusing System.Net;\r\nusing System.Net.Security;\r\nusing System.Security.Cryptography.X509Ce"
  },
  {
    "path": "SCMKit/modules/github/RemovePAT.cs",
    "chars": 990,
    "preview": "using System;\r\nusing System.Collections.Generic;\r\nusing System.Linq;\r\nusing System.Text;\r\nusing System.Threading.Tasks;"
  },
  {
    "path": "SCMKit/modules/github/RemoveSSHKey.cs",
    "chars": 1814,
    "preview": "using Octokit;\r\nusing System;\r\nusing System.Net;\r\nusing System.Net.Security;\r\nusing System.Security.Cryptography.X509Ce"
  },
  {
    "path": "SCMKit/modules/github/RepoList.cs",
    "chars": 4624,
    "preview": "using System;\r\nusing System.Collections.Generic;\r\nusing System.Threading.Tasks;\r\nusing Octokit;\r\n\r\nnamespace SCMKit.mod"
  },
  {
    "path": "SCMKit/modules/github/RepoSearch.cs",
    "chars": 4317,
    "preview": "using System;\r\nusing System.Collections.Generic;\r\nusing System.Threading.Tasks;\r\nusing Octokit;\r\n\r\nnamespace SCMKit.mod"
  },
  {
    "path": "SCMKit/modules/gitlab/AddAdmin.cs",
    "chars": 4595,
    "preview": "using System;\r\nusing System.Collections.Generic;\r\nusing System.Net;\r\nusing System.Net.Security;\r\nusing System.Security."
  },
  {
    "path": "SCMKit/modules/gitlab/CodeSearch.cs",
    "chars": 5968,
    "preview": "using System;\r\nusing System.Collections.Generic;\r\nusing System.Net;\r\nusing System.Net.Security;\r\nusing System.Security."
  },
  {
    "path": "SCMKit/modules/gitlab/CreatePAT.cs",
    "chars": 6777,
    "preview": "using System;\r\nusing System.Collections.Generic;\r\nusing System.Net;\r\nusing System.Net.Security;\r\nusing System.Security."
  },
  {
    "path": "SCMKit/modules/gitlab/CreateSSHKey.cs",
    "chars": 5776,
    "preview": "using System;\r\nusing System.Collections.Generic;\r\nusing System.Net;\r\nusing System.Net.Security;\r\nusing System.Security."
  },
  {
    "path": "SCMKit/modules/gitlab/FileSearch.cs",
    "chars": 5566,
    "preview": "using System;\r\nusing System.Collections.Generic;\r\nusing System.Net;\r\nusing System.Net.Security;\r\nusing System.Security."
  },
  {
    "path": "SCMKit/modules/gitlab/ListPAT.cs",
    "chars": 12172,
    "preview": "using System;\r\nusing System.Collections.Generic;\r\nusing System.Net;\r\nusing System.Net.Security;\r\nusing System.Security."
  },
  {
    "path": "SCMKit/modules/gitlab/ListSSHKeys.cs",
    "chars": 6787,
    "preview": "using System;\r\nusing System.Collections.Generic;\r\nusing System.Net;\r\nusing System.Net.Security;\r\nusing System.Security."
  },
  {
    "path": "SCMKit/modules/gitlab/Privs.cs",
    "chars": 17466,
    "preview": "using System;\r\nusing System.Collections.Generic;\r\nusing System.Net;\r\nusing System.Net.Security;\r\nusing System.Security."
  },
  {
    "path": "SCMKit/modules/gitlab/RemoveAdmin.cs",
    "chars": 4618,
    "preview": "using System;\r\nusing System.Collections.Generic;\r\nusing System.Net;\r\nusing System.Net.Security;\r\nusing System.Security."
  },
  {
    "path": "SCMKit/modules/gitlab/RemovePAT.cs",
    "chars": 4449,
    "preview": "using System;\r\nusing System.Collections.Generic;\r\nusing System.Net;\r\nusing System.Net.Security;\r\nusing System.Security."
  },
  {
    "path": "SCMKit/modules/gitlab/RemoveSSHKey.cs",
    "chars": 4529,
    "preview": "using System;\r\nusing System.Collections.Generic;\r\nusing System.Net;\r\nusing System.Net.Security;\r\nusing System.Security."
  },
  {
    "path": "SCMKit/modules/gitlab/RepoList.cs",
    "chars": 2536,
    "preview": "using System;\r\nusing System.Threading.Tasks;\r\nusing GitLabApiClient;\r\n\r\nnamespace SCMKit.modules.gitlab\r\n{\r\n    class R"
  },
  {
    "path": "SCMKit/modules/gitlab/RepoSearch.cs",
    "chars": 15530,
    "preview": "using System;\r\nusing System.Collections.Generic;\r\nusing System.Net;\r\nusing System.Net.Security;\r\nusing System.Security."
  },
  {
    "path": "SCMKit/modules/gitlab/RunnerList.cs",
    "chars": 16298,
    "preview": "using System;\r\nusing System.Collections.Generic;\r\nusing System.Net;\r\nusing System.Net.Security;\r\nusing System.Security."
  },
  {
    "path": "SCMKit/modules/gitlab/SnippetList.cs",
    "chars": 4494,
    "preview": "using System;\r\nusing System.Collections.Generic;\r\nusing System.Net;\r\nusing System.Net.Security;\r\nusing System.Security."
  },
  {
    "path": "SCMKit/packages.config",
    "chars": 452,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<packages>\r\n  <package id=\"Costura.Fody\" version=\"3.3.3\" targetFramework=\"net48"
  },
  {
    "path": "SCMKit.sln",
    "chars": 1122,
    "preview": "\r\nMicrosoft Visual Studio Solution File, Format Version 12.00\r\n# Visual Studio Version 16\r\nVisualStudioVersion = 16.0.3"
  }
]

About this extraction

This page contains the full source code of the h4wkst3r/SCMKit GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 61 files (407.0 KB), approximately 75.7k tokens, and a symbol index with 137 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!