Skip to content
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
17 changes: 15 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -103,13 +103,13 @@

```bash
./gradlew shadowJar
java -jar build/libs/anarcry-1.4.2.jar
java -jar build/libs/anarcry-1.5.0.jar
```

With `.env.local` for pre-configured targets:

```bash
java -jar build/libs/anarcry-1.4.2.jar --env .env.local
java -jar build/libs/anarcry-1.5.0.jar --env .env.local
```

---
Expand Down Expand Up @@ -334,6 +334,17 @@ ScanRunner.run(ScanContext)

## 09 - Changelog

### v1.5.0

- **WAF evasion engine**: WafState + WafEvasion in scanner/util/ -- 5 bypass strategies (DOUBLE_ENCODE, CASE_MUTATION, UNICODE_NORMALIZE, CHARSET_EBCDIC, HPP)
- **ScanRunner Phase 1.5**: automatic WAF probe between Crawler recon and scanner modules -- detects effective bypass strategy
- **Module integration**: SQLi, XSS, LFI, SSTI, CmdInjection, XXE apply evasion payloads transparently when WAF detected
- **HeadersModule WAF state**: marks shared WafState on 403 + WAF signature detection
- **Test harness**: 26 WAF tests (18 unit + 8 integration with mock WAF server)

<details>
<summary><kbd>Previous releases (click to expand)</kbd></summary>

### v1.4.2

- **CVE-enriched reports**: scan reports (MD, HackerOne, Bugcrowd) now include Known CVEs table per vulnerability class, sourced from the knowledge base
Expand Down Expand Up @@ -376,6 +387,8 @@ ScanRunner.run(ScanContext)

- Initial public release with 25 attack modules, CVSS v3.1 auto-scoring, HackerOne/Bugcrowd export, and TUI

</details>

---

## 10 - Ethical Use
Expand Down
12 changes: 8 additions & 4 deletions anarchrypto
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
#!/bin/bash
JAR="$(dirname "$(realpath "$0")")/build/libs/anarcry-1.4.2.jar"
DIR="$(dirname "$(realpath "$0")")"
SELF="$(realpath "$0")"

if [ ! -f "$JAR" ]; then
echo "AnarCry: JAR nao encontrado. Execute: ./gradlew shadowJar"
# Resolve version from build.gradle so the launcher never goes stale
VERSION=$(grep -oP "^version\s*=\s*'\K[^']+" "$DIR/build.gradle" 2>/dev/null || echo "")
JAR="$DIR/build/libs/anarcry-${VERSION}.jar"

if [ -z "$VERSION" ] || [ ! -f "$JAR" ]; then
echo "AnarCry: JAR nao encontrado (v${VERSION:-?}). Execute: ./gradlew shadowJar"
exit 1
fi

Expand All @@ -21,7 +25,7 @@ if [ "$TUI_MODE" = true ]; then
exec kitty \
--override initial_window_width=180c \
--override initial_window_height=82c \
--title "AnarCry v1.4.2" \
--title "AnarCry v${VERSION}" \
bash "$SELF" "$@"
fi
printf '\e[8;54;220t'
Expand Down
11 changes: 9 additions & 2 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ plugins {
}

group = 'gg.effront'
version = '1.4.2'
version = '1.5.0'

java {
toolchain {
Expand All @@ -23,7 +23,8 @@ repositories {
dependencies {
implementation 'com.googlecode.lanterna:lanterna:3.1.3'
implementation 'org.bouncycastle:bcprov-jdk18on:1.80'
implementation 'org.bouncycastle:bctls-jdk18on:1.80'
implementation 'com.github.zhkl0228:impersonator-okhttp:1.11.0'
implementation 'com.microsoft.playwright:playwright:1.49.0'
implementation 'com.google.code.gson:gson:2.11.0'

// GUI (Swing + FlatLaf)
Expand All @@ -39,6 +40,12 @@ dependencies {
spotbugsPlugins 'com.h3xstream.findsecbugs:findsecbugs-plugin:1.13.0'
}

processResources {
filesMatching('version.properties') {
expand(version: project.version)
}
}

shadowJar {
archiveBaseName = 'anarcry'
archiveVersion = version
Expand Down
37 changes: 37 additions & 0 deletions src/main/java/gg/effront/anarcry/Version.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package gg.effront.anarcry;

import java.io.InputStream;
import java.util.Properties;

public final class Version {

private static final String VERSION;

static {
String v = "dev";
try (InputStream is = Version.class.getResourceAsStream("/version.properties")) {
if (is != null) {
Properties p = new Properties();
p.load(is);
v = p.getProperty("version", "dev");
}
} catch (Exception ignored) {
}
VERSION = v;
}

private Version() {
}

public static String get() {
return VERSION;
}

public static String label() {
return "AnarCry v" + VERSION;
}

public static String userAgent() {
return "AnarCry/" + VERSION;
}
}
6 changes: 4 additions & 2 deletions src/main/java/gg/effront/anarcry/gui/AnarCryGui.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package gg.effront.anarcry.gui;

import gg.effront.anarcry.EnvLoader;
import gg.effront.anarcry.Version;
import gg.effront.anarcry.gui.components.FindingDetailPanel;
import gg.effront.anarcry.gui.components.FindingsTable;
import gg.effront.anarcry.gui.components.GuiModulesPanel;
Expand Down Expand Up @@ -49,7 +50,7 @@

public class AnarCryGui {

private static final String FRAME_TITLE = "AnarCry v1.3";
private static final String FRAME_TITLE = Version.label();
private static final int FRAME_WIDTH = 1400;
private static final int FRAME_HEIGHT = 950;
private static final int MODULES_PANEL_WIDTH = 260;
Expand Down Expand Up @@ -397,7 +398,8 @@ private JMenu buildHelpMenu() {

JMenuItem about = new JMenuItem("About AnarCry");
about.addActionListener(e -> JOptionPane.showMessageDialog(frame,
"AnarCry v1.3\nSecurity Scanner\nAuthorized testing only.", "About", JOptionPane.INFORMATION_MESSAGE));
Version.label() + "\nSecurity Scanner\nAuthorized testing only.", "About",
JOptionPane.INFORMATION_MESSAGE));
menu.add(about);

return menu;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ private JPanel buildRequestPanel() {
JLabel headersLabel = new JLabel(" Headers (Key: Value, one per line):");
headersArea = new JTextArea(5, 40);
headersArea.setFont(monoFont());
headersArea.setText("User-Agent: AnarCry/1.2\nAccept: */*");
headersArea.setText("User-Agent: " + gg.effront.anarcry.Version.userAgent() + "\nAccept: */*");
JScrollPane headersScroll = new JScrollPane(headersArea);
headersScroll.setPreferredSize(new Dimension(0, 100));

Expand Down
39 changes: 29 additions & 10 deletions src/main/java/gg/effront/anarcry/report/ReportEngine.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,11 @@
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

public class ReportEngine {

Expand Down Expand Up @@ -75,17 +78,33 @@ private String buildMarkdown(List<Finding> findings, String targetUrl, String ti
sb.append("\n");

sb.append("## Details\n\n");
Map<String, List<Finding>> groups = new LinkedHashMap<>();
for (Finding f : findings) {
sb.append("### [").append(f.severity()).append("] ").append(f.title()).append("\n\n");
sb.append("**Module:** ").append(f.module()).append(" \n");
sb.append("**Endpoint:** ").append(f.endpoint()).append(" \n");
sb.append("**Evidence:** ").append(f.evidence()).append(" \n");
sb.append("**Impact:** ").append(f.impact()).append(" \n");
sb.append("**Reproduction:**\n```\n").append(f.reproduction()).append("\n```\n");
sb.append("**Recommendation:** ").append(f.recommendation()).append(" \n");
sb.append("**CWE:** ").append(f.cweId()).append(" -- ").append(f.cweTitle()).append(" \n");
sb.append("**CVSS v3.1:** ").append(f.cvssScore()).append(" (").append(f.cvssVector()).append(") \n");
appendCves(sb, f.module());
groups.computeIfAbsent(f.module() + "|" + f.title(), k -> new ArrayList<>()).add(f);
}
for (List<Finding> group : groups.values()) {
Finding rep = group.getFirst();
sb.append("### [").append(rep.severity()).append("] ").append(rep.title()).append("\n\n");
sb.append("**Module:** ").append(rep.module()).append(" \n");
if (group.size() == 1) {
sb.append("**Endpoint:** ").append(rep.endpoint()).append(" \n");
sb.append("**Evidence:** ").append(rep.evidence()).append(" \n");
} else {
sb.append("\n**Affected Endpoints (").append(group.size()).append("):**\n\n");
sb.append("| Endpoint | Evidence |\n");
sb.append("|----------|----------|\n");
for (Finding f : group) {
sb.append("| ").append(escape(f.endpoint())).append(" | ").append(escape(f.evidence()))
.append(" |\n");
}
sb.append("\n");
}
sb.append("**Impact:** ").append(rep.impact()).append(" \n");
sb.append("**Reproduction:**\n```\n").append(rep.reproduction()).append("\n```\n");
sb.append("**Recommendation:** ").append(rep.recommendation()).append(" \n");
sb.append("**CWE:** ").append(rep.cweId()).append(" -- ").append(rep.cweTitle()).append(" \n");
sb.append("**CVSS v3.1:** ").append(rep.cvssScore()).append(" (").append(rep.cvssVector()).append(") \n");
appendCves(sb, rep.module());
sb.append("\n---\n\n");
}
return sb.toString();
Expand Down
14 changes: 8 additions & 6 deletions src/main/java/gg/effront/anarcry/scanner/ScanContext.java
Original file line number Diff line number Diff line change
@@ -1,37 +1,39 @@
package gg.effront.anarcry.scanner;

import gg.effront.anarcry.model.RequestRecord;
import gg.effront.anarcry.scanner.util.WafState;

import java.net.URI;
import java.util.Set;
import java.util.function.Consumer;

public record ScanContext(String targetUrl, String jwtToken, String jwtToken2, Set<String> enabledModules,
ScanConfig config, Consumer<RequestRecord> requestLog, DiscoveredPaths discoveredPaths) {
ScanConfig config, Consumer<RequestRecord> requestLog, DiscoveredPaths discoveredPaths, WafState wafState) {

public ScanContext(String targetUrl, String jwtToken, Set<String> enabledModules) {
this(targetUrl, jwtToken, "", enabledModules, ScanConfig.defaults(), r -> {
}, new DiscoveredPaths());
}, new DiscoveredPaths(), new WafState());
}

public ScanContext(String targetUrl, String jwtToken, String jwtToken2, Set<String> enabledModules) {
this(targetUrl, jwtToken, jwtToken2, enabledModules, ScanConfig.defaults(), r -> {
}, new DiscoveredPaths());
}, new DiscoveredPaths(), new WafState());
}

public ScanContext(String targetUrl, String jwtToken, Set<String> enabledModules, String jwtToken2) {
this(targetUrl, jwtToken, jwtToken2, enabledModules, ScanConfig.defaults(), r -> {
}, new DiscoveredPaths());
}, new DiscoveredPaths(), new WafState());
}

public ScanContext(String targetUrl, String jwtToken, Set<String> enabledModules, String jwtToken2,
Consumer<RequestRecord> requestLog) {
this(targetUrl, jwtToken, jwtToken2, enabledModules, ScanConfig.defaults(), requestLog, new DiscoveredPaths());
this(targetUrl, jwtToken, jwtToken2, enabledModules, ScanConfig.defaults(), requestLog, new DiscoveredPaths(),
new WafState());
}

public ScanContext(String targetUrl, String jwtToken, Set<String> enabledModules, String jwtToken2,
ScanConfig config, Consumer<RequestRecord> requestLog) {
this(targetUrl, jwtToken, jwtToken2, enabledModules, config, requestLog, new DiscoveredPaths());
this(targetUrl, jwtToken, jwtToken2, enabledModules, config, requestLog, new DiscoveredPaths(), new WafState());
}

public String host() {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package gg.effront.anarcry.scanner;

import gg.effront.anarcry.model.RequestRecord;
import gg.effront.anarcry.scanner.util.WafState;

import java.util.LinkedHashSet;
import java.util.Set;
Expand All @@ -18,7 +19,7 @@ private ScanOrchestrator() {
public static ScanContext buildContext(String target, String jwt, String jwt2, Set<String> modules,
Consumer<RequestRecord> requestLogCb) {
ScanConfig cfg = new ScanConfig(0, "", Set.of(), SuppressionLoader.loadFromCwd(), "");
return new ScanContext(target, jwt, jwt2, modules, cfg, requestLogCb, new DiscoveredPaths());
return new ScanContext(target, jwt, jwt2, modules, cfg, requestLogCb, new DiscoveredPaths(), new WafState());
}

public static ScanContext buildContext(String target, String jwt, String jwt2, Set<String> modules) {
Expand Down
Loading
Loading