Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Option to include crypto library flows in reachables #126

Merged
merged 5 commits into from
Jan 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/containers.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ jobs:
distribution: 'temurin'
java-version: '21'
- name: Use Node.js
uses: actions/setup-node@v3
uses: actions/setup-node@v4
with:
node-version: '21.x'
- name: Delete `.rustup` directory
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/nodejstests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ jobs:
steps:
- uses: actions/checkout@v4
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v3
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
- uses: actions/checkout@v4
Expand Down Expand Up @@ -66,7 +66,7 @@ jobs:
steps:
- uses: actions/checkout@v4
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v3
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
- uses: actions/checkout@v4
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/npm-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ jobs:
steps:
- uses: actions/checkout@v4
- name: Use Node.js
uses: actions/setup-node@v3
uses: actions/setup-node@v4
with:
node-version: 18.x
registry-url: https://registry.npmjs.org/
Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/pr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -67,9 +67,9 @@ jobs:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- run: |
npm install -g @cyclonedx/cdxgen --omit=optional
cdxgen -t python --deep -o $GITHUB_WORKSPACE/repotests/django-DefectDojo/bom.json $GITHUB_WORKSPACE/repotests/django-DefectDojo
./atom.sh reachables -o /tmp/django-DefectDojo.atom -l python $GITHUB_WORKSPACE/repotests/django-DefectDojo -Dlog4j.configurationFile=log4j2.xml --slice-outfile /tmp/django-DefectDojo.reachables.json
./atom.sh usages -o /tmp/django-DefectDojo.atom -l python $GITHUB_WORKSPACE/repotests/django-DefectDojo -Dlog4j.configurationFile=log4j2.xml --slice-outfile /tmp/django-DefectDojo.usages.json
cdxgen -t python --deep -o $GITHUB_WORKSPACE/repotests/DjanGoat/bom.json $GITHUB_WORKSPACE/repotests/DjanGoat
./atom.sh reachables -o /tmp/DjanGoat.atom -l python $GITHUB_WORKSPACE/repotests/DjanGoat -Dlog4j.configurationFile=log4j2.xml --slice-outfile /tmp/DjanGoat.reachables.json
./atom.sh usages -o /tmp/DjanGoat.atom -l python $GITHUB_WORKSPACE/repotests/DjanGoat -Dlog4j.configurationFile=log4j2.xml --slice-outfile /tmp/DjanGoat.usages.json
env:
JAVA_TOOL_OPTIONS: "-Dfile.encoding=UTF-8"
if: runner.os != 'Windows'
Expand Down
14 changes: 10 additions & 4 deletions .github/workflows/repotests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@ jobs:
with:
repository: 'ShiftLeftSecurity/shiftleft-java-example'
path: 'repotests/shiftleft-java-example'
- uses: actions/checkout@v4
with:
repository: 'rodbate/bouncycastle-examples'
path: 'repotests/bouncycastle-examples'
- uses: actions/checkout@v4
with:
repository: 'juice-shop/juice-shop'
Expand Down Expand Up @@ -59,7 +63,7 @@ jobs:
distribution: 'temurin'
java-version: ${{ matrix.java-version }}
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v3
uses: actions/setup-node@v4
with:
node-version: '21.x'
- run: |
Expand Down Expand Up @@ -91,12 +95,14 @@ jobs:
JAVA_TOOL_OPTIONS: "-Dfile.encoding=UTF-8"
- run: |
npm install -g @cyclonedx/cdxgen --omit=optional
cdxgen -t java --deep -o $GITHUB_WORKSPACE/repotests/bouncycastle-examples/bom.json $GITHUB_WORKSPACE/repotests/bouncycastle-examples
./atom.sh reachables --include-crypto --remove-atom -o /tmp/bouncycastle-examples.atom -l java $GITHUB_WORKSPACE/repotests/bouncycastle-examples -Dlog4j.configurationFile=log4j2.xml --slice-outfile /tmp/bouncycastle-examples.reachables.json
cdxgen -t java --deep -o $GITHUB_WORKSPACE/repotests/java-sec-code/bom.json $GITHUB_WORKSPACE/repotests/java-sec-code
./atom.sh reachables --remove-atom -o /tmp/java-sec-code.atom -l java $GITHUB_WORKSPACE/repotests/java-sec-code -Dlog4j.configurationFile=log4j2.xml --slice-outfile /tmp/java-sec-code.reachables.json
./atom.sh reachables --include-crypto --remove-atom -o /tmp/java-sec-code.atom -l java $GITHUB_WORKSPACE/repotests/java-sec-code -Dlog4j.configurationFile=log4j2.xml --slice-outfile /tmp/java-sec-code.reachables.json
cdxgen -t c --deep -o $GITHUB_WORKSPACE/repotests/aws-doc-sdk-examples/cpp/bom.json $GITHUB_WORKSPACE/repotests/aws-doc-sdk-examples/cpp
./atom.sh reachables --remove-atom -o /tmp/aws-doc-sdk-examples.atom -l c $GITHUB_WORKSPACE/repotests/aws-doc-sdk-examples/cpp -Dlog4j.configurationFile=log4j2.xml --slice-outfile /tmp/aws-doc-sdk-examples.reachables.json
cdxgen -t python --deep -o $GITHUB_WORKSPACE/repotests/django-DefectDojo/bom.json $GITHUB_WORKSPACE/repotests/django-DefectDojo
./atom.sh reachables --remove-atom -o /tmp/django-DefectDojo.atom -l python $GITHUB_WORKSPACE/repotests/django-DefectDojo -Dlog4j.configurationFile=log4j2.xml --slice-outfile /tmp/django-DefectDojo.reachables.json
cdxgen -t python --deep -o $GITHUB_WORKSPACE/repotests/DjanGoat/bom.json $GITHUB_WORKSPACE/repotests/DjanGoat
./atom.sh reachables --remove-atom -o /tmp/DjanGoat.atom -l python $GITHUB_WORKSPACE/repotests/DjanGoat -Dlog4j.configurationFile=log4j2.xml --slice-outfile /tmp/DjanGoat.reachables.json
if: runner.os != 'Windows'
env:
JAVA_TOOL_OPTIONS: "-Dfile.encoding=UTF-8"
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ Command: reachables [options]
Extract reachable data-flow slices based on automated framework tags
--source-tag <value> source tag - defaults to framework-input.
--sink-tag <value> sink tag - defaults to framework-output.
--include-crypto includes crypto library flows - defaults to false.
--help display this help message
```

Expand Down
5 changes: 2 additions & 3 deletions build.sbt
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
name := "atom"
ThisBuild / organization := "io.appthreat"
ThisBuild / version := "2.0.6"
ThisBuild / version := "2.0.7"
ThisBuild / scalaVersion := "3.3.1"

val chenVersion = "2.0.5"
val chenVersion = "2.0.6"

lazy val atom = Projects.atom

Expand Down Expand Up @@ -40,7 +40,6 @@ ThisBuild / scalacOptions ++= Seq(
)

ThisBuild / compile / javacOptions ++= Seq(
"-g", // debug symbols
"-Xlint",
"--release=21"
) ++ {
Expand Down
2 changes: 1 addition & 1 deletion codemeta.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"downloadUrl": "https://github.com/AppThreat/atom",
"issueTracker": "https://github.com/AppThreat/atom/issues",
"name": "atom",
"version": "2.0.6",
"version": "2.0.7",
"description": "Atom is a novel intermediate representation for next-generation code analysis.",
"applicationCategory": "code-analysis",
"keywords": [
Expand Down
19 changes: 17 additions & 2 deletions src/main/scala/io/appthreat/atom/Atom.scala
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,13 @@ object Atom:
c match
case c: AtomReachablesConfig => c.copy(sliceDepth = x)
case _ => c
),
opt[Unit]("include-crypto")
.text(s"includes crypto library flows - defaults to false.")
.action((_, c) =>
c match
case c: AtomReachablesConfig => c.copy(includeCryptoFlows = true)
case _ => c
)
)
help("help").text("display this help message")
Expand Down Expand Up @@ -388,7 +395,12 @@ object Atom:
!config.includeMethodSource
)
case config: AtomReachablesConfig =>
ReachablesConfig(config.sourceTag, config.sinkTag, config.sliceDepth)
ReachablesConfig(
config.sourceTag,
config.sinkTag,
config.sliceDepth,
config.includeCryptoFlows
)
case _ => x
).withInputPath(x.inputPath)
.withOutputSliceFile(x.outputSliceFile)
Expand Down Expand Up @@ -561,7 +573,10 @@ object Atom:
Left(exception.getMessage)
case Success(ag) =>
config match
case x: AtomConfig if x.dataDeps || x.isInstanceOf[AtomDataFlowConfig] =>
case x: AtomConfig
if x.dataDeps || x.isInstanceOf[AtomDataFlowConfig] || x.isInstanceOf[
AtomReachablesConfig
] =>
println("Generating data-flow dependencies from atom. Please wait ...")
// Enhance with simple and easy tags
new EasyTagsPass(ag).createAndApply()
Expand Down
3 changes: 2 additions & 1 deletion src/main/scala/io/appthreat/atom/package.scala
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,8 @@ package object atom:
case class AtomReachablesConfig(
sourceTag: String = FRAMEWORK_INPUT_TAG,
sinkTag: String = FRAMEWORK_OUTPUT_TAG,
sliceDepth: Int = DEFAULT_SLICE_DEPTH
sliceDepth: Int = DEFAULT_SLICE_DEPTH,
includeCryptoFlows: Boolean = false
) extends AtomConfig

import io.appthreat.atom.slicing.*
Expand Down
39 changes: 35 additions & 4 deletions src/main/scala/io/appthreat/atom/slicing/ReachableSlicing.scala
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,13 @@ object ReachableSlicing:
private def API_TAG = "api"
private def FRAMEWORK_TAG = "framework"

private def LIBRARY_CALL_TAG = "library-call"
private def CLI_SOURCE_TAG = "cli-source"
private def DRIVER_SOURCE_TAG = "driver-source"
private def HTTP_TAG = "http"
private def LIBRARY_CALL_TAG = "library-call"
private def CLI_SOURCE_TAG = "cli-source"
private def DRIVER_SOURCE_TAG = "driver-source"
private def HTTP_TAG = "http"
private def CRYPTO_GENERATE_TAG = "crypto-generate"
private def CRYPTO_TAG = "crypto"
private def CRYPTO_ALGORITHM_TAG = "crypto-algorithm"

def calculateReachableSlice(atom: Cpg, config: ReachablesConfig): ReachableSlice =
val language = atom.metaData.language.head
Expand All @@ -41,6 +44,11 @@ object ReachableSlicing:
atom.tag.name(API_TAG).parameter.reachableByFlows(atom.tag.name(API_TAG).parameter).map(
toSlice
).toList
if config.includeCryptoFlows && (language == Languages.JAVA || language == Languages.JAVASRC)
then
flowsList ++= atom.tag.name(CRYPTO_GENERATE_TAG).call.reachableByFlows(
atom.tag.name(CRYPTO_ALGORITHM_TAG).literal
).map(toSlice).toList
// For JavaScript and Python, we need flows between arguments of call nodes to track callbacks and middlewares
if
language == Languages.JSSRC || language == Languages.JAVASCRIPT || language == Languages.PYTHON || language == Languages.PYTHONSRC
Expand Down Expand Up @@ -192,6 +200,29 @@ object ReachableSlicing:
columnNumber = ret.columnNumber
)
tableRows += sliceNode
case literal: Literal =>
val methodName = literal.method.name
if tags.isEmpty && literal.inCall.nonEmpty && literal.inCall.head.tag.nonEmpty
then
tags = tagAsString(literal.inCall.head.tag)
purls ++= purlsFromTag(literal.inCall.head.tag)
if !addedPaths.contains(
s"${fileName}#${lineNumber}"
)
then
sliceNode = sliceNode.copy(
name = literal.code.replaceAll("""(['"])""", ""),
code = literal.code.replaceAll("""(['"])""", ""),
typeFullName = literal.typeFullName,
parentMethodName = methodName,
parentMethodSignature = literal.method.signature,
parentPackageName = literal.method.location.packageName,
parentClassName = literal.method.location.className,
lineNumber = literal.lineNumber,
columnNumber = literal.columnNumber,
tags = tags
)
tableRows += sliceNode
case identifier: Identifier =>
val methodName = identifier.method.name
if tags.isEmpty && identifier.inCall.nonEmpty && identifier.inCall.head.tag.nonEmpty
Expand Down
8 changes: 6 additions & 2 deletions src/main/scala/io/appthreat/atom/slicing/package.scala
Original file line number Diff line number Diff line change
Expand Up @@ -78,8 +78,12 @@ package object slicing:
excludeMethodSource: Boolean = true
) extends BaseConfig

case class ReachablesConfig(sourceTag: String, sinkTag: String, sliceDepth: Int)
extends BaseConfig
case class ReachablesConfig(
sourceTag: String,
sinkTag: String,
sliceDepth: Int,
includeCryptoFlows: Boolean
) extends BaseConfig

/** Adds extensions to modify a method traversal based on config options
*/
Expand Down
12 changes: 6 additions & 6 deletions wrapper/nodejs/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions wrapper/nodejs/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@appthreat/atom",
"version": "2.0.6",
"version": "2.0.7",
"description": "Create atom (⚛) representation for your application, packages and libraries",
"exports": "./index.js",
"type": "module",
Expand All @@ -9,7 +9,7 @@
"lint": "eslint *.mjs *.js"
},
"dependencies": {
"@babel/parser": "^7.23.6",
"@babel/parser": "^7.23.9",
"typescript": "^5.3.3",
"yargs": "^17.7.2"
},
Expand Down
Loading