Skip to content

Commit

Permalink
Merge pull request #69 from Hugo-C/fix/shodan-count
Browse files Browse the repository at this point in the history
Fix shodan host count
  • Loading branch information
Hugo-C authored Sep 9, 2024
2 parents 61df72d + 11d8dc7 commit 26cabdd
Show file tree
Hide file tree
Showing 11 changed files with 1,060 additions and 890 deletions.
537 changes: 205 additions & 332 deletions Cargo.lock

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,14 @@ serde = { version = "1.0", features = ["derive"] }
lazy_static = "1.4"
regex = "1.7"
csv = "1.3"
openssl = { version = "~0.10.55", features = ["vendored"] } # Required for sentry
openssl = { version = "~0.10.66", features = ["vendored"] } # Required for sentry
sentry = "^0.34"
rocket-sentry = "0.18"
redis = "0.26"
log = "0.4"
env_logger = "0.11"
async-std = { version = "1.12", features = ["attributes", "tokio1"] }
reqwest = { version = "0.12.2", features = ["stream"] }
reqwest = { version = "^0.12.2", features = ["stream"] }
tempfile = "3.10.1"

[dependencies.rocket_db_pools]
Expand Down
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM rust:1.80-bullseye AS build-stage
FROM rust:1.81-bullseye AS build-stage

ARG BUILD_TARGET="x86_64-unknown-linux-musl"
ARG BUILD_OPTIONS="--release --target $BUILD_TARGET"
Expand Down
8 changes: 8 additions & 0 deletions examples/shodan_host_count.hurl
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# Request for no overlap
GET {{host}}/shodan-host-count?jarm_hash=3fd3fd00000000000043d3fd3fd43d79451d8c63b099acafdbabb24551d0e6

HTTP 200
Content-Type: application/json
[Asserts]
jsonpath "$.total" != null

File renamed without changes.
1,245 changes: 754 additions & 491 deletions jarm_online_gui/package-lock.json

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion jarm_online_gui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
"vuetify": "^3.3"
},
"devDependencies": {
"@codecov/vite-plugin": "^0.0.1-beta.10",
"@codecov/vite-plugin": "^1.0",
"@sentry/vite-plugin": "^2.7",
"@vitejs/plugin-vue": "^5",
"eslint": "^9.6.0",
Expand Down
2 changes: 1 addition & 1 deletion jarm_online_gui/src/App.vue
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<title>Jarm online</title>
<meta name="description" content="Compute jarm hash online with this cybersecurity tool. List of malicious hashes included. Disclaimer: results are saved in database">
</Head>
<MainPage/>
<MainPage />
</template>

<script>
Expand Down
124 changes: 62 additions & 62 deletions jarm_online_gui/src/components/MainPage.vue
Original file line number Diff line number Diff line change
Expand Up @@ -3,30 +3,31 @@
rel="stylesheet">
<link href="https://fonts.googleapis.com/css?family=Material+Icons" rel="stylesheet">
<link rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/github-fork-ribbon-css/0.2.3/gh-fork-ribbon.min.css"/>
href="https://cdnjs.cloudflare.com/ajax/libs/github-fork-ribbon-css/0.2.3/gh-fork-ribbon.min.css">
<a id="darkRibbon" class="github-fork-ribbon right-top" href="https://github.com/Hugo-C/jarm-online"
data-ribbon="Fork me on GitHub" title="Fork me on GitHub">Fork me on GitHub</a>
<v-layout>
<v-main>
<form class="searchBarDiv" @submit="onSubmit">
<form class="searchBarDiv"
@submit="onSubmit">
<v-text-field
variant="solo-inverted"
label="Compute JARM hash"
placeholder="8.8.8.8 | host.com/path"
prepend-inner-icon="search"
autofocus
loading
@click:prepend-inner="onSubmit"
v-model="inputUrl"
variant="solo-inverted"
label="Compute JARM hash"
placeholder="8.8.8.8 | host.com/path"
prepend-inner-icon="search"
autofocus
loading
v-model="inputUrl"
@click:prepend-inner="onSubmit"
>
<template v-slot:loader>
<v-progress-linear
:active="computingJarmHash"
color="secondary"
rounded
height="5"
indeterminate
></v-progress-linear>
:active="computingJarmHash"
color="secondary"
rounded
height="5"
indeterminate
/>
</template>
</v-text-field>
<p id="disclaimerLine">
Expand All @@ -39,7 +40,7 @@
<div class="hashDisplay">
<v-card variant="outlined" class="mx-auto pa-5" width="70%">
JARM hash is: <b size="large">{{ jarmHashResult.hash }}</b>
<v-btn @click="copy" variant="text" prepend-icon="content_copy" class="ml-2" size="small" stacked>
<v-btn variant="text" prepend-icon="content_copy" class="ml-2" size="small" stacked @click="copy" >
Copy Me
<v-tooltip :open-on-hover="false" :open-on-click="true" :no-click-animation="true" text="Copied!"
activator="parent"/>
Expand Down Expand Up @@ -69,18 +70,18 @@
<v-chip label variant="elevated" color="primary">No match found</v-chip>
</span>
<v-divider
vertical
color="info"
:thickness="2"
class="ma-1 border-opacity-100"
vertical
color="info"
:thickness="2"
class="ma-1 border-opacity-100"
></v-divider>
Known malicious malware family:
<a href="https://github.com/Hugo-C/jarm-online" target="_blank" rel="noopener noreferrer">
<v-chip label size="small" class="ma-1" variant="elevated" color="bg-surface-variant">Not yet
implemented
<v-tooltip
text="Star the github repo to see new releases in your feed"
location="bottom" activator="parent"/>
text="Star the github repo to see new releases in your feed"
location="bottom" activator="parent" />
</v-chip>
</a>
</div>
Expand All @@ -89,21 +90,20 @@
<v-expansion-panel-title class="d-flex justify-center bg-surface-variant">
<span class="pa-2">Shodan</span>
<v-progress-linear v-if="computingShodanResultCount" indeterminate color="primary"
:absolute="true"></v-progress-linear>
<v-chip v-else label variant="elevated" color="primary">{{
this.jarmHashResult.shodanResultCount
}}
:absolute="true" />
<v-chip v-else label variant="elevated" color="primary">
{{ this.jarmHashResult.shodanResultCount }}
</v-chip>
</v-expansion-panel-title>
<v-expansion-panel-text>
<a :href="shodanSearchLink" target="_blank" rel="noopener noreferrer">
<v-img :src="shodanImageLink" lazy-src="/shodan_placeholder.png" height="480">
<template v-slot:placeholder>
<template #placeholder>
<div class="d-flex align-center justify-center fill-height">
<v-progress-circular
color="grey-lighten-4"
indeterminate
></v-progress-circular>
color="grey-lighten-4"
indeterminate
/>
</div>
</template>
</v-img>
Expand All @@ -118,24 +118,24 @@

<!-- Latest URLs part -->
<v-container fill-height class="w-75">
<v-divider :thickness="2" class="border-opacity-100" color="info" inset/>
<v-divider :thickness="2" class="border-opacity-100" color="info" inset />
<h4> Latest urls requested</h4>
<v-progress-circular
v-if="lastScans === null"
indeterminate
color="secondary"
></v-progress-circular>
v-if="lastScans === null"
indeterminate
color="secondary"
/>
<v-expansion-panels v-else multiple fill-width>
<v-slide-y-reverse-transition
class="py-0"
group
tag="v-expansion-panel"
class="py-0"
group
tag="v-expansion-panel"
>
<v-expansion-panel
v-for="scan in lastScans.slice().reverse()"
:key="scan.host"
class="ma-1"
eager
v-for="scan in lastScans.slice().reverse()"
:key="scan.host"
class="ma-1"
eager
>
<v-expansion-panel-title>
<span class="text-secondary mr-1">{{ scan.port }}</span><span>{{ scan.host }}</span>
Expand All @@ -152,7 +152,7 @@
<v-row justify="center" no-gutters>
<h5 id="footernote">
hosted with 💙 on
<v-img id="gcpimg" src="gcp.png" height="20" width="20" inline></v-img>
<v-img id="gcpimg" src="gcp.png" height="20" width="20" inline />
<span class="ma-5"> |</span>
<a href="https://jarm.statuspage.io/" target="_blank" rel="noopener noreferrer">status page</a>
</h5>
Expand All @@ -161,23 +161,23 @@
</v-layout>
<!-- Snackbar for notifications-->
<v-snackbar
v-model="this.notification.isDisplayed"
:timeout="10000"
variant="flat"
color="error"
:absolute="true"
class="ma-5 opacity-100"
location="top right"
z-index="15000"
multi-line
vertical
v-model="this.notification.isDisplayed"
:timeout="10000"
variant="flat"
color="error"
:absolute="true"
class="ma-5 opacity-100"
location="top right"
z-index="15000"
multi-line
vertical
>
<div class="text-subtitle-1 pb-2">{{ notification.title }}</div>
<p>{{ notification.body }}</p>
<template v-slot:actions>
<template #actions>
<v-btn
variant="text"
@click="notification.clear()"
variant="text"
@click="notification.clear()"
>
Close
</v-btn>
Expand Down Expand Up @@ -316,15 +316,15 @@ export default {
},
async shodanCount(hash) {
this.computingShodanResultCount = true;
const path = `https://api.shodan.io/shodan/host/count?query=ssl.jarm:${hash}`;
let result;
const path = `/api/v1/shodan-host-count?jarm_hash=${hash}`;
let result = 0;
try {
const res = await axios.get(path);
result = res.total
this.computingShodanResultCount = false;
result = res.data.total
} catch (error) {
console.log(error) // locally we get a CORS error
console.log(error)
}
this.computingShodanResultCount = false;
return result;
},
async fetchLastScans() {
Expand Down
1 change: 1 addition & 0 deletions jarm_online_gui/vite.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ export default defineConfig({
enableBundleAnalysis: process.env.CODECOV_TOKEN !== undefined,
bundleName: "jarm-online",
uploadToken: process.env.CODECOV_TOKEN,
gitService: "github",
}),
],
resolve: {
Expand Down
25 changes: 25 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ use rocket::serde::json::Json;
use rust_jarm::Jarm;
use serde::Serialize;
use std::time::{Duration, SystemTime, UNIX_EPOCH};
use reqwest::Url;
use rocket::fairing::AdHoc;
use rocket::response::status::Custom;
use rocket::http::Status;
Expand All @@ -25,6 +26,7 @@ use rocket_db_pools::deadpool_redis::redis::AsyncCommands;

pub const DEFAULT_SCAN_TIMEOUT_IN_SECONDS: u64 = 15;
pub const REDIS_LAST_SCAN_LIST_KEY: &str = "redis_last_scan_list_key";
pub const SHODAN_HOST_COUNT_URL: &str = "https://api.shodan.io/shodan/host/count";

pub const LAST_SCAN_SIZE_RETURNED: isize = 10;

Expand Down Expand Up @@ -69,6 +71,11 @@ struct TrancoOverlapResponse {
overlapping_domains: Vec<TrancoRankedDomain>,
}

#[derive(Serialize)]
struct ShodanHostCountResponse {
total: u64,
}

pub fn scan_timeout_in_seconds() -> u64 {
env::var("SCAN_TIMEOUT_IN_SECONDS")
.unwrap_or(DEFAULT_SCAN_TIMEOUT_IN_SECONDS.to_string())
Expand Down Expand Up @@ -132,6 +139,23 @@ async fn tranco_overlap(redis_client: Connection<Db>, jarm_hash: String) -> Resu
Ok(Json(TrancoOverlapResponse { overlapping_domains }))
}

#[get("/?<jarm_hash>")]
async fn shodan_host_count(jarm_hash: String) -> Json<ShodanHostCountResponse> {
let shodan_api_key = env::var("SHODAN_API_KEY").unwrap_or_default();
let query_param = format!("ssl.jarm:{jarm_hash}");
let url = Url::parse_with_params(SHODAN_HOST_COUNT_URL,&[
("query", query_param),
("key", shodan_api_key),
]).unwrap();
let client = reqwest::Client::new();
let response = client.get(url)
.header("Accept", "application/json")
.send().await.unwrap();
let json_response = response.json::<serde_json::Value>().await.unwrap();
let total = json_response["total"].as_u64().unwrap();
Json(ShodanHostCountResponse { total })
}

fn build_error_json(jarm_error: JarmError) -> Json<JarmResponse> {
// error_message is a debug view of a an unknown error, to be improved.
let (error_type, error_message) = match jarm_error {
Expand All @@ -158,6 +182,7 @@ pub fn build_rocket_without_tranco_initialisation() -> Rocket<Build> {
.mount("/jarm", routes![jarm])
.mount("/last-scans", routes![last_scans])
.mount("/tranco-overlap", routes![tranco_overlap])
.mount("/shodan-host-count", routes![shodan_host_count])
.attach(Db::init())
}

Expand Down

0 comments on commit 26cabdd

Please sign in to comment.