Created
November 2, 2020 23:15
-
-
Save HarmJ0y/a8a5fe987f2b7751eb2ce55c2eec155d to your computer and use it in GitHub Desktop.
Rubeus Jenkinsfile
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@Library('ci-jenkins-common') _ | |
// Jenkins build pipeline (declarative) | |
// Project: Seatbelt | |
// URL: https://github.com/GhostPack/Seatbelt | |
// Author: @tifkin_/@harmj0y | |
// Pipeline Author: harmj0y | |
def gitURL = "https://github.com/GhostPack/Seatbelt" | |
def commitHash = "08314908a5676f597722d8f374cd3a74220638b4"; // Oct 19, 2020 | |
pipeline { | |
// run everything on an existing agent configured with a label 'windows' | |
agent { label 'windows' } | |
options { | |
// add timestamps to the console log | |
timestamps() | |
// discard old builds, keeping a max number of 5 builds | |
buildDiscarder(logRotator(numToKeepStr: '5')) | |
} | |
// Note: parameters/options don't appear until the job is run once | |
parameters { | |
// unique project ID that's used to track the build runs | |
string name: 'ProjectID', defaultValue: 'Master', description: 'ProjectID associated with the build.', trim: true | |
} | |
stages { | |
stage('checkout') { | |
steps { | |
// clone the code base with up to 5 retries on failure | |
script { | |
try { | |
checkout([ | |
$class: 'GitSCM', | |
branches: [[name: "${commitHash}"]], | |
doGenerateSubmoduleConfigurations: false, | |
extensions: [[$class: 'CleanBeforeCheckout']], | |
submoduleCfg: [], | |
userRemoteConfigs: [[url: "${gitURL}"]] | |
]) | |
} | |
catch(error) { | |
echo "Clone of ${gitURL} failed: ${error} . Retrying." | |
retry(5) { | |
checkout([ | |
$class: 'GitSCM', | |
branches: [[name: "${commitHash}"]], | |
doGenerateSubmoduleConfigurations: false, | |
extensions: [[$class: 'CleanBeforeCheckout']], | |
submoduleCfg: [], | |
userRemoteConfigs: [[url: "${gitURL}"]] | |
]) | |
} | |
} | |
} | |
} | |
} | |
stage('prep') { | |
steps { | |
// common function to replace a known "bad" term | |
replaceAll("*.cs", "Mimikatz", "PROJECT") | |
script { | |
// replace AssemblyInfo.cs with a clean one | |
replaceAssemblyInfo() | |
// replace the assembly name | |
replaceAssemblyName() | |
} | |
} | |
} | |
stage('build') { | |
steps { | |
script { | |
// build the project for .NET 3.5 and 4.0 | |
// 'ci-jenkins-common' library function -> 'msbuild("PROJECT.sln", ".NET_VERSION")' | |
msbuild("${JOB_NAME}.sln", "3.5") | |
msbuild("${JOB_NAME}.sln", "4.0") | |
} | |
// rename the build output binaries to "{JOB_NAME}_{.NET_VERSION}.exe" | |
fileOperations( | |
[ | |
fileRenameOperation( | |
source: "${JOB_NAME}/bin/3.5/${JOB_NAME}.exe", | |
destination: "${JOB_NAME}/bin/3.5/${JOB_NAME}_3.5.exe" | |
), | |
fileRenameOperation( | |
source: "${JOB_NAME}/bin/4.0/${JOB_NAME}.exe", | |
destination: "${JOB_NAME}/bin/4.0/${JOB_NAME}_4.0.exe" | |
) | |
] | |
) | |
} | |
} | |
stage('obfuscation') { | |
steps { | |
script { | |
// obfuscate the binary using a 'ci-jenkins-common' library function | |
obfuscateDotnetBinary("3.5", "Seatbelt", "Seatbelt") | |
obfuscateDotnetBinary("4.0", "Seatbelt", "Seatbelt") | |
} | |
} | |
} | |
stage('opsec tests') { | |
steps { | |
script { | |
// test the build artifacts using a 'ci-jenkins-common' library function | |
testOpsec("${JOB_NAME}\\bin\\3.5\\${JOB_NAME}_3.5.exe") | |
testOpsec("${JOB_NAME}\\bin\\3.5\\${JOB_NAME}_3.5_obf.exe") | |
testOpsec("${JOB_NAME}\\bin\\4.0\\${JOB_NAME}_4.0.exe") | |
testOpsec("${JOB_NAME}\\bin\\4.0\\${JOB_NAME}_4.0_obf.exe") | |
} | |
} | |
} | |
stage('fingerprinting') { | |
steps { | |
script { | |
// fingerprint the build artifacts using a 'ci-jenkins-common' library function | |
fingerprintArtifact("${JOB_NAME}\\bin\\3.5\\${JOB_NAME}_3.5.exe") | |
fingerprintArtifact("${JOB_NAME}\\bin\\3.5\\${JOB_NAME}_3.5_obf.exe") | |
fingerprintArtifact("${JOB_NAME}\\bin\\4.0\\${JOB_NAME}_4.0.exe") | |
fingerprintArtifact("${JOB_NAME}\\bin\\4.0\\${JOB_NAME}_4.0_obf.exe") | |
} | |
} | |
} | |
// Publish to Artifactory | |
// Note: have to use ${params.PARAM_NAME} syntax here to access a parameter value (instead of an env var) | |
stage('publish') { | |
steps { | |
rtBuildInfo() | |
script { | |
bat 'git rev-parse HEAD > commit' | |
def commit = readFile('commit').trim() | |
rtUpload ( | |
serverId: "artifactory-prod", | |
spec: | |
"""{ | |
"files": [ | |
{ | |
"pattern": "*/bin/*/*_*.exe", | |
"target": "OffensiveToolkit/Projects/${params.ProjectID}/", | |
"props": "language=csharp;ext=exe;type=postex;ProjectID=${params.ProjectID};rev=${commit}" | |
}, | |
{ | |
"pattern": "*.iocs", | |
"target": "IOCS/Projects/${params.ProjectID}/", | |
"props": "language=iocs;ext=iocs;type=iocs;ProjectID=${params.ProjectID};rev=${commit}" | |
}, | |
{ | |
"pattern": "*.iocs", | |
"target": "IOCS/Tools/${JOB_NAME}/${BUILD_NUMBER}/", | |
"props": "language=iocs;ext=iocs;type=iocs;ProjectID=${params.ProjectID};rev=${commit}" | |
} | |
] | |
}""" | |
) | |
} | |
} | |
} | |
} | |
post { | |
always { | |
// report the report results | |
nunit testResultsPattern: '*/bin/*/*.exe.xml' | |
} | |
success { | |
// archive the artifacts | |
archiveArtifacts artifacts: '*/bin/*/*_*.exe', fingerprint: true | |
} | |
cleanup { | |
// clean up our workspace | |
deleteDir() | |
// clean up tmp directory | |
dir("${workspace}@tmp") { | |
deleteDir() | |
} | |
// clean up script directory | |
dir("${workspace}@script") { | |
deleteDir() | |
} | |
// clean up libs directory | |
dir("${workspace}@libs") { | |
deleteDir() | |
} | |
} | |
} | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment