- Changed base URLs and targets in multiple modules to point to insecure.newploit.com for testing purposes. - Updated README.md to reflect the new domain and provide instructions for setting up the reverse proxy. - Adjusted configurations in AdminFinder, AutoPwn, Banner, DirFuzz, DnsTools, FormBrute, HttpProbe, PortScan, Repeater, Sqli, SslScan, SubEnum, Xploiter, and Xss components.
136 lines
4.9 KiB
Vue
136 lines
4.9 KiB
Vue
<script setup lang="ts">
|
|
import { onMounted, onUnmounted, ref } from "vue";
|
|
import { invoke } from "@tauri-apps/api/core";
|
|
import { listen, type UnlistenFn } from "@tauri-apps/api/event";
|
|
import Terminal from "../Terminal.vue";
|
|
import Prompt from "../Prompt.vue";
|
|
import { useTerminal } from "../../composables/useTerminal";
|
|
|
|
interface AdminHit {
|
|
url: string;
|
|
status: number;
|
|
size: number;
|
|
title?: string;
|
|
platform?: string;
|
|
login_form: boolean;
|
|
auth_header?: string;
|
|
redirect?: string;
|
|
}
|
|
|
|
const baseUrl = ref("https://insecure.newploit.com");
|
|
const useBuiltin = ref(true);
|
|
const extraPaths = ref("");
|
|
const acceptStatusStr = ref("200,301,302,401,403");
|
|
const concurrency = ref(40);
|
|
const timeoutMs = ref(5000);
|
|
const followRedirects = ref(false);
|
|
const running = ref(false);
|
|
const progress = ref({ done: 0, total: 0 });
|
|
const hits = ref<AdminHit[]>([]);
|
|
const log = useTerminal();
|
|
const unlistens: UnlistenFn[] = [];
|
|
const builtinCount = ref(0);
|
|
|
|
async function loadCount() {
|
|
try {
|
|
const list: string[] = await invoke("admin_finder_wordlist");
|
|
builtinCount.value = list.length;
|
|
} catch {}
|
|
}
|
|
|
|
async function run() {
|
|
if (running.value) return;
|
|
running.value = true;
|
|
hits.value = [];
|
|
progress.value = { done: 0, total: 0 };
|
|
log.clear();
|
|
|
|
const extras = extraPaths.value.split(/[\s\n,]+/).map(s => s.trim()).filter(Boolean);
|
|
const statuses = acceptStatusStr.value.split(/[,\s]+/).map(s => parseInt(s, 10)).filter(n => !isNaN(n));
|
|
|
|
log.info(`target: ${baseUrl.value}`);
|
|
log.info(`paths: builtin=${useBuiltin.value ? builtinCount.value : 0} + ${extras.length} extra`);
|
|
|
|
unlistens.push(await listen<string>("adminfind:status", (e) => log.dim(String(e.payload))));
|
|
unlistens.push(await listen<{ done: number; total: number }>("adminfind:progress", (e) => { progress.value = e.payload; }));
|
|
unlistens.push(await listen<AdminHit>("adminfind:hit", (e) => {
|
|
const h = e.payload;
|
|
hits.value.push(h);
|
|
const flags: string[] = [];
|
|
if (h.login_form) flags.push("LOGIN");
|
|
if (h.auth_header) flags.push("AUTH");
|
|
if (h.platform) flags.push(h.platform);
|
|
const flagStr = flags.length ? `[${flags.join("|")}]` : "";
|
|
const line = `${String(h.status).padEnd(4)} ${h.url} ${flagStr}${h.title ? ` "${h.title.slice(0, 50)}"` : ""}`;
|
|
if (h.login_form || h.auth_header) log.hit(line);
|
|
else log.valid(line);
|
|
}));
|
|
|
|
try {
|
|
await invoke("admin_finder_run", {
|
|
req: {
|
|
base_url: baseUrl.value.trim(),
|
|
extra_paths: extras,
|
|
use_builtin: useBuiltin.value,
|
|
accept_status: statuses,
|
|
concurrency: concurrency.value,
|
|
timeout_ms: timeoutMs.value,
|
|
follow_redirects: followRedirects.value,
|
|
},
|
|
});
|
|
const logins = hits.value.filter(h => h.login_form || h.auth_header).length;
|
|
log.ok(`done: ${hits.value.length} responses, ${logins} login panel(s) found`);
|
|
} catch (e: any) {
|
|
log.err(String(e));
|
|
} finally {
|
|
running.value = false;
|
|
cleanup();
|
|
}
|
|
}
|
|
|
|
function cleanup() { while (unlistens.length) { const u = unlistens.pop(); if (u) u(); } }
|
|
|
|
onMounted(loadCount);
|
|
onUnmounted(cleanup);
|
|
</script>
|
|
|
|
<template>
|
|
<div class="module">
|
|
<div class="form">
|
|
<Prompt label="target" v-model="baseUrl" placeholder="https://target.com" />
|
|
|
|
<div class="row">
|
|
<label class="mini wide"><span>status</span><input v-model="acceptStatusStr" placeholder="200,301,302,401,403" /></label>
|
|
</div>
|
|
|
|
<div class="row">
|
|
<label class="toggle"><input type="checkbox" v-model="useBuiltin" /><span>builtin ({{ builtinCount }})</span></label>
|
|
<label class="toggle"><input type="checkbox" v-model="followRedirects" /><span>follow</span></label>
|
|
<label class="mini"><span>conc</span><input v-model.number="concurrency" type="number" min="1" max="200" /></label>
|
|
<label class="mini"><span>t/out</span><input v-model.number="timeoutMs" type="number" min="500" max="30000" /></label>
|
|
</div>
|
|
|
|
<details class="adv">
|
|
<summary>extra paths (optional)</summary>
|
|
<textarea class="term-input" v-model="extraPaths" rows="3" spellcheck="false" placeholder="one path per line, e.g. panel/admin, custom-admin-path" />
|
|
</details>
|
|
|
|
<button class="exec" :disabled="running" @click="run">{{ running ? "[ probing... ]" : "> find admin" }}</button>
|
|
|
|
<div v-if="progress.total" class="bar">
|
|
<div class="bar-fill" :style="{ width: (progress.done / progress.total) * 100 + '%' }" />
|
|
<span class="bar-text">{{ progress.done }} / {{ progress.total }}</span>
|
|
</div>
|
|
</div>
|
|
|
|
<Terminal :lines="log.lines.value" title="admin-finder // panel discovery" @clear="log.clear()" />
|
|
</div>
|
|
</template>
|
|
|
|
<style scoped>
|
|
.adv { border: 1px solid var(--border); background: var(--bg-panel); padding: 4px 8px; }
|
|
.adv summary { cursor: pointer; font-size: 10px; color: var(--fg-dim); text-transform: uppercase; letter-spacing: 0.1em; padding: 2px 0; }
|
|
.adv summary:hover { color: var(--fg); }
|
|
.adv > *:not(summary) { margin-top: 6px; }
|
|
</style>
|