Skip to content

Commit f85e512

Browse files
Merge pull request #97 from alexandreborges/dev
Malwoverview 8.0.2
2 parents 1dd24cb + 2917b5b commit f85e512

6 files changed

Lines changed: 340 additions & 204 deletions

File tree

README.md

Lines changed: 65 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Malwoverview
22

3-
[<img alt="GitHub release (latest by date)" src="https://img.shields.io/github/v/release/alexandreborges/malwoverview?color=red&style=for-the-badge">](https://github.com/alexandreborges/malwoverview/releases/tag/v8.0.1) [<img alt="GitHub last commit" src="https://img.shields.io/github/last-commit/alexandreborges/malwoverview?color=Yellow&style=for-the-badge">](https://github.com/alexandreborges/malwoverview/releases) [<img alt="GitHub Release Date" src="https://img.shields.io/github/release-date/alexandreborges/malwoverview?label=Release%20Date&style=for-the-badge">](https://github.com/alexandreborges/malwoverview/releases) [<img alt="GitHub" src="https://img.shields.io/github/license/alexandreborges/malwoverview?style=for-the-badge">](https://github.com/alexandreborges/malwoverview/blob/master/LICENSE)
3+
[<img alt="GitHub release (latest by date)" src="https://img.shields.io/github/v/release/alexandreborges/malwoverview?color=red&style=for-the-badge">](https://github.com/alexandreborges/malwoverview/releases/tag/v8.0.2) [<img alt="GitHub last commit" src="https://img.shields.io/github/last-commit/alexandreborges/malwoverview?color=Yellow&style=for-the-badge">](https://github.com/alexandreborges/malwoverview/releases) [<img alt="GitHub Release Date" src="https://img.shields.io/github/release-date/alexandreborges/malwoverview?label=Release%20Date&style=for-the-badge">](https://github.com/alexandreborges/malwoverview/releases) [<img alt="GitHub" src="https://img.shields.io/github/license/alexandreborges/malwoverview?style=for-the-badge">](https://github.com/alexandreborges/malwoverview/blob/master/LICENSE)
44
[<img alt="GitHub stars" src="https://img.shields.io/github/stars/alexandreborges/malwoverview?logoColor=Red&style=for-the-badge">](https://github.com/alexandreborges/malwoverview/stargazers)
55
[<img alt="Twitter Follow" src="https://img.shields.io/twitter/follow/ale_sp_brazil?style=for-the-badge&logo=X&color=blueviolet">](https://twitter.com/ale_sp_brazil)
66
[![Downloads](https://static.pepy.tech/personalized-badge/malwoverview?period=month&units=international_system&left_color=grey&right_color=orange&left_text=Last%2030%20days)](https://pepy.tech/project/malwoverview)
@@ -46,7 +46,7 @@
4646
See GNU Public License on <http://www.gnu.org/licenses/>.
4747

4848

49-
## Current Version: 8.0.1 (Codename: Revolutions)
49+
## Current Version: 8.0.2 (Codename: Revolutions)
5050

5151
Important note: Malwoverview does NOT submit samples to any endpoint by default,
5252
so it respects possible Non-Disclosure Agreements (NDAs). There're specific options
@@ -119,6 +119,7 @@ This tool aims to :
119119
52. TUI (Text User Interface) dashboard mode with panel-based navigation.
120120
53. Gather threat hunting information from URLScan.io — submit URLs, retrieve scan results, and search scans.
121121
54. LLM-powered threat enrichment — AI-generated risk assessment, MITRE ATT&CK mapping, and analyst recommendations appended to any query result. Supports Claude, Gemini, OpenAI, and Ollama (local).
122+
55. Batch IP check against VirusTotal from a file containing IP addresses, showing a summary table (IP Address, Country, AS Owner, Detection).
122123

123124
## CONTRIBUTORS
124125

@@ -530,7 +531,7 @@ usage: python malwoverview.py -c <API configuration file> -d <directory> -o <0|1
530531
-V <argument> -a <1-17> -A <filename> -l <1-7> -L <hash> -j <1-7>
531532
-J <argument> -p <1-8> -P <argument> -y <1-5> -Y <file name> -n <1-5>
532533
-N <argument> -m <1-8> -M <argument> -b <1-12> -B <argument> -x <1-9> -X <argument>
533-
-ip <1-7> -IP <argument> -O <directory> --nist <1-5> --NIST <argument> -vc <1-8>
534+
-ip <1-8> -IP <argument> -O <directory> --nist <1-5> --NIST <argument> -vc <1-8>
534535
-VC <argument> -s <1-2> -S <argument> -ab <1> -AB <argument> -gn <1> -GN <argument>
535536
-wh <1-2> -WH <argument> -u <1-5> -U <arg> --correlate-hash <hash> --extract-iocs <file|url> --yara <rules>
536537
--yara-target <target> --output-format text|json|csv --proxy <url> --quiet --verbose
@@ -850,12 +851,17 @@ MALWARE OPTIONS:
850851
+ 4: Get details for an IP address from Shodan;
851852
+ 5: Get details for an IP address from AbuseIPDB;
852853
+ 6: Get details for an IP address from GreyNoise;
853-
+ 7: Get details for an IP address from all services (comprehensive).
854+
+ 7: Get details for an IP address from all services (comprehensive);
855+
+ 8: Batch check IP addresses from a file (one per line) against
856+
VirusTotal and show a summary table (IP Address, Country, AS Owner,
857+
Detection). Use -D to choose between Public (-D 1) and Premium
858+
(-D 0, default) VT API.
854859

855860
-IP IPARG, --iparg IPARG
856861

857-
+ Provides an IP address (IPv4 or IPv6) for the -ip option. All -ip
858-
options (1 through 7) require a valid IP address.
862+
+ Provides an argument for the -ip option. For -ip 1 through 7 it
863+
must be a valid IP address (IPv4 or IPv6); for -ip 8 it must be a
864+
file containing IP addresses (one per line).
859865

860866
-s SHODAN, --shodan SHODAN
861867

@@ -1070,6 +1076,7 @@ Subcommand examples (equivalent to flag-based syntax):
10701076
malwoverview triage batch <hashfile> # same as: malwoverview -x 8 -X <hashfile>
10711077
malwoverview ip all <ipaddr> # same as: malwoverview -ip 7 -IP <ipaddr>
10721078
malwoverview ip shodan <ipaddr> # same as: malwoverview -ip 4 -IP <ipaddr>
1079+
malwoverview ip batch <ipfile> # same as: malwoverview -ip 8 -IP <ipfile>
10731080
malwoverview whois domain <domain> # same as: malwoverview -wh 1 -WH <domain>
10741081
malwoverview correlate hash <sha256> # same as: malwoverview --correlate-hash <sha256>
10751082
malwoverview extract <file|url> # same as: malwoverview --extract-iocs <file|url>
@@ -1193,6 +1200,8 @@ Use --help with any subcommand for details:
11931200
malwoverview -ip 5 -IP 8.8.8.8
11941201
malwoverview -ip 6 -IP 8.8.8.8
11951202
malwoverview -ip 7 -IP 8.8.8.8
1203+
malwoverview -ip 8 -IP /home/remnux/malware/ip_list.txt
1204+
malwoverview -ip 8 -IP /home/remnux/malware/ip_list.txt -D 1
11961205
malwoverview -s 1 -S 8.8.8.8
11971206
malwoverview -s 2 -S "apache"
11981207
malwoverview -ab 1 -AB 185.220.100.243
@@ -1406,6 +1415,56 @@ Use --help with any subcommand for details:
14061415

14071416
## HISTORY
14081417

1418+
Version 8.0.2:
1419+
1420+
This version:
1421+
1422+
* Introduces a batch IP check against VirusTotal (-ip 8 / "ip
1423+
batch" subcommand). Given a file with one IP address per line,
1424+
it queries VirusTotal for each address and prints a summary
1425+
table with the IP Address, Country, AS Owner and Detection
1426+
ratio (e.g. 8/94). Use -D to choose between the Public (-D 1,
1427+
sleeps 61s every 4 IPs to honour the rate limit) and Premium
1428+
(-D 0, default) VT API.
1429+
1430+
* Fixes the Android device-scan options (-y 1, -y 2 and -y 3),
1431+
which had stopped working on current Android versions. The
1432+
package listing is now parsed to support the modern /data/app
1433+
layout (the '~~' prefix and '==' path segments introduced in
1434+
Android 10+), and adb's CRLF output is handled so the options
1435+
also work on Windows. The on-device hashing now uses sha256sum
1436+
instead of md5sum, so the table shows the SHA256 hash. Clear
1437+
messages are also printed when adb is not in the PATH or when
1438+
no third-party packages are found.
1439+
1440+
* Fixes a second SSRF bypass in the IOC extraction feature
1441+
(--extract-iocs <url>). The URL validator only checked the
1442+
initial address, but the fetch followed HTTP redirects
1443+
automatically, so a public URL could redirect to an internal or
1444+
cloud-metadata address (e.g. 169.254.169.254) after the check had
1445+
already passed. Redirects are now followed manually and every hop
1446+
is re-validated against the private/reserved-address allowlist,
1447+
with a maximum redirect limit.
1448+
1449+
* Hardens the Android send options (-y 4 and -y 5) against a path
1450+
traversal triggered by a malicious/compromised connected device.
1451+
The package name reported by adb is now restricted to valid
1452+
Android package characters and the output file name is reduced to
1453+
its base name, so a crafted package listing can no longer cause a
1454+
file to be written outside the output directory.
1455+
1456+
* Fixes an SSRF bypass vulnerability (issue #96) in the IOC
1457+
extraction URL validator (ioc_extract.py). The previous
1458+
validation used urlparse() while the actual HTTP request was
1459+
made by requests, which normalize URLs differently. Crafted
1460+
inputs such as http://127.0.0.1:6666\@1.1.1.1 could pass the
1461+
public-hostname check yet still cause requests to connect to
1462+
an internal address. The validator now rejects URLs containing
1463+
backslashes, whitespace, or control characters, derives the
1464+
effective URL via requests.PreparedRequest so the hostname
1465+
that is actually contacted is the one being validated, and
1466+
passes that normalized URL to session.get.
1467+
14091468
Version 8.0.1:
14101469

14111470
This version:

malwoverview/malwoverview.py

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
# Corey Forman (https://github.com/digitalsleuth)
2222
# Christian Clauss (https://github.com/cclauss)
2323

24-
# Malwoverview.py: version 8.0.1 (codename: Revolutions)
24+
# Malwoverview.py: version 8.0.2 (codename: Revolutions)
2525

2626
import os
2727
import sys
@@ -68,7 +68,7 @@
6868
__author__ = "Alexandre Borges"
6969
__copyright__ = "Copyright 2018-2026 Alexandre Borges"
7070
__license__ = "GNU General Public License v3.0"
71-
__version__ = "8.0.1"
71+
__version__ = "8.0.2"
7272
__email__ = "reverseexploit at proton.me"
7373

7474
def finish_hook(signum, frame):
@@ -109,7 +109,7 @@ def main():
109109
USER_HOME_DIR = str(Path.home()) + '/'
110110
cv.windows = 0
111111

112-
parser = argparse.ArgumentParser(prog=None, description="Malwoverview is a first response tool for threat hunting written by Alexandre Borges. This version is " + __version__, usage="usage: python malwoverview.py -c <API configuration file> -d <directory> -o <0|1> -v <1-13> -V <virustotal arg> -a <1-17> -A <filename> -l <1-7> -L <hash> -j <1-7> -J <URLhaus argument> -p <1-8> -P <polyswarm argument> -y <1-5> -Y <file name> -n <1-5> -N <argument> -m <1-8> -M <argument> -b <1-12> -B <arg> -x <1-9> -X <arg> --nist <1-5> --NIST <argument> -O <output directory> -ip <1-7> -IP <IP address> -vc <1-8> -VC <argument> -s <1-2> -S <arg> -ab <1> -AB <arg> -gn <1> -GN <arg> -wh <1-2> -WH <arg> -u <1-5> -U <arg> --correlate-hash <hash> --extract-iocs <file> --yara <rules> --yara-target <target> --output-format text|json|csv --proxy <url> --quiet --verbose --no-cache --interactive --attack-map")
112+
parser = argparse.ArgumentParser(prog=None, description="Malwoverview is a first response tool for threat hunting written by Alexandre Borges. This version is " + __version__, usage="usage: python malwoverview.py -c <API configuration file> -d <directory> -o <0|1> -v <1-13> -V <virustotal arg> -a <1-17> -A <filename> -l <1-7> -L <hash> -j <1-7> -J <URLhaus argument> -p <1-8> -P <polyswarm argument> -y <1-5> -Y <file name> -n <1-5> -N <argument> -m <1-8> -M <argument> -b <1-12> -B <arg> -x <1-9> -X <arg> --nist <1-5> --NIST <argument> -O <output directory> -ip <1-8> -IP <IP address> -vc <1-8> -VC <argument> -s <1-2> -S <arg> -ab <1> -AB <arg> -gn <1> -GN <arg> -wh <1-2> -WH <arg> -u <1-5> -U <arg> --correlate-hash <hash> --extract-iocs <file> --yara <rules> --yara-target <target> --output-format text|json|csv --proxy <url> --quiet --verbose --no-cache --interactive --attack-map")
113113

114114
malware_group = parser.add_argument_group('MALWARE OPTIONS', 'Malware analysis and intelligence query options')
115115
malware_group.add_argument('-c', '--config', dest='config', type=str, metavar="CONFIG FILE", default=(USER_HOME_DIR + '.malwapi.conf'), help='Use a custom config file to specify API\'s.')
@@ -137,8 +137,8 @@ def main():
137137
malware_group.add_argument('-x', '--triage', dest='triage', type=int, default=0, metavar="TRIAGE", help='Provides information from TRIAGE according to the specified value: <1> this option gets sample\'s general information by providing an argument with -X option in the following possible formats: sha256:<value>, sha1:<value>, md5:<value>, family:<value>, score:<value>, tag:<value>, url:<value>, wallet:<value>, ip:<value>; <2> Get a sumary report for a given Triage ID (got from option -x 1) ; <3> Submit a sample for analysis ; <4> Submit a sample through a URL for analysis ; <5> Download sample specified by the Triage ID; <6> Download pcapng file from sample associated to given Triage ID; <7> Get a dynamic report for the given Triage ID (got from option -x 1); <8> Batch hash check from a file (one hash per line); <9> Directory scan - computes SHA256 for each file and checks against Triage.')
138138
malware_group.add_argument('-X', '--triagearg', dest='triagearg', type=str, default='', metavar="TRIAGE_ARG", help='Provides argument for -x option from TRIAGE. If "-x 1" then -X must be a search query (e.g., sha256:<hash>, family:<name>, tag:<tag>, ip:<ip>); If "-x 2" then -X must be a Triage sample ID (obtained from -x 1); If "-x 3" then -X must be a file path to submit; If "-x 4" then -X must be a URL to submit; If "-x 5" or "-x 6" then -X must be a Triage sample ID to download; If "-x 7" then -X must be a Triage sample ID for dynamic report; If "-x 8" then -X must be a file containing hashes (one per line); If "-x 9" then -X must be a directory path to scan.')
139139
malware_group.add_argument('-O', '--output-dir', dest='output_dir', type=str, default='.', help='Set output directory for all sample downloads.')
140-
malware_group.add_argument('-ip', '--ip', dest='ipoption', type=int, default=0, metavar="IP", help='Get IP information from various sources. The possible values are: 1: Get details for an IP address provided with -IP from IPInfo; 2: Get details for an IP address provided with -IP from BGPView; 3: Get details for an IP address provided with -IP from all available intel services (VirusTotal/Alienvault); 4: Get details from Shodan; 5: Get details from AbuseIPDB; 6: Get details from GreyNoise; 7: Get details from all services (comprehensive).')
141-
malware_group.add_argument('-IP', '--iparg', dest='iparg', type=str, metavar="IP_ARG", help='Provides an IP address for the -ip option. All -ip options (1 through 7) require a valid IPv4 or IPv6 address.')
140+
malware_group.add_argument('-ip', '--ip', dest='ipoption', type=int, default=0, metavar="IP", help='Get IP information from various sources. The possible values are: 1: Get details for an IP address provided with -IP from IPInfo; 2: Get details for an IP address provided with -IP from BGPView; 3: Get details for an IP address provided with -IP from all available intel services (VirusTotal/Alienvault); 4: Get details from Shodan; 5: Get details from AbuseIPDB; 6: Get details from GreyNoise; 7: Get details from all services (comprehensive); 8: Batch check IP addresses from a file (one per line) against VirusTotal and show a summary table (IP Address, Country, AS Owner, Detection). Use -D to choose between Public (-D 1) and Premium (-D 0, default) VT API.')
141+
malware_group.add_argument('-IP', '--iparg', dest='iparg', type=str, metavar="IP_ARG", help='Provides an argument for the -ip option. For -ip 1 through 7 it must be a valid IPv4 or IPv6 address; for -ip 8 it must be a file containing IP addresses (one per line).')
142142
malware_group.add_argument('-s', '--shodan', dest='shodanoption', type=int, default=0, metavar="SHODAN", help='SHODAN options: 1: IP lookup; 2: Search query.')
143143
malware_group.add_argument('-S', '--shodanarg', dest='shodanarg', type=str, default='', metavar="SHODAN_ARG", help='Provides argument for -s option from SHODAN. If "-s 1" then -S must be an IP address; If "-s 2" then -S must be a search query (e.g., "apache", "port:22 country:BR").')
144144
malware_group.add_argument('-ab', '--abuseipdb', dest='abuseipdb', type=int, default=0, metavar="ABUSEIPDB", help='ABUSEIPDB options: 1: Check IP reputation.')
@@ -275,6 +275,8 @@ def main():
275275
ip_greynoise.add_argument('target', help='IP address')
276276
ip_all = ip_sub.add_parser('all', help='All services lookup')
277277
ip_all.add_argument('target', help='IP address')
278+
ip_batch = ip_sub.add_parser('batch', help='Batch VirusTotal check from a file (one IP per line)')
279+
ip_batch.add_argument('target', help='File containing IP addresses (one per line)')
278280

279281
wh_parser = subparsers.add_parser('whois', help='Whois/RDAP lookups')
280282
wh_sub = wh_parser.add_subparsers(dest='wh_action')
@@ -352,7 +354,7 @@ def main():
352354
args.hausoption = uh_map.get(args.uh_action, 0)
353355
args.hausarg = args.target
354356
elif args.command == 'ip':
355-
ip_map = {'info': 1, 'bgp': 2, 'shodan': 4, 'abuse': 5, 'greynoise': 6, 'all': 7}
357+
ip_map = {'info': 1, 'bgp': 2, 'shodan': 4, 'abuse': 5, 'greynoise': 6, 'all': 7, 'batch': 8}
356358
if args.ip_action:
357359
args.ipoption = ip_map.get(args.ip_action, 0)
358360
args.iparg = args.target
@@ -538,6 +540,7 @@ def getoption(section, name):
538540
'uh_url': (hausoptionx, hausargx, [3], sanitize_url),
539541
'uh_tag': (hausoptionx, hausargx, [4, 5], sanitize_tag),
540542
'ip_addr': (ipoptionx, ipargx, [1, 2, 3, 4, 5, 6, 7], sanitize_ip),
543+
'ip_batch': (ipoptionx, ipargx, [8], sanitize_path),
541544
'sh_ip': (shodanoptionx, shodanargx, [1], sanitize_ip),
542545
'sh_gen': (shodanoptionx, shodanargx, [2], sanitize_general),
543546
'ab_ip': (abuseipdbx, abuseipdbargx, [1], sanitize_ip),
@@ -609,7 +612,7 @@ def getoption(section, name):
609612
args.malsharelist not in optval8,
610613
args.virustotaloption not in optval9,
611614
args.vtpubpremium not in optval,
612-
args.ipoption not in range(8),
615+
args.ipoption not in range(9),
613616
args.androidoption not in optval5,
614617
args.shodanoption not in range(3),
615618
args.abuseipdb not in range(2),
@@ -623,7 +626,7 @@ def getoption(section, name):
623626
virustotaloptionx and virustotalargx, args.direct, fprovided,
624627
haoptionx and haargx, mallist, args.malsharehash, args.hausoption,
625628
polyoptionx and polyargx,
626-
androidoptionx and androidargx, alienx and alienargsx,
629+
androidoptionx in (1, 2, 3) or (androidoptionx and androidargx), alienx and alienargsx,
627630
malpediax, bazaarx, triagex and triageargx,
628631
ipoptionx and ipargx,
629632
nistoption and nistarg,
@@ -865,7 +868,8 @@ def ha_show_and_down(haargx, xx=0):
865868
4: (shodan_ext.shodan_ip, [ipargx]),
866869
5: (abuseipdb_ext.check_ip, [ipargx]),
867870
6: (greynoise_ext.quick_check, [ipargx]),
868-
7: (multipleip.get_multiple_ip_details, [ipargx])
871+
7: (multipleip.get_multiple_ip_details, [ipargx]),
872+
8: (virustotal.vtipbatchcheck, [ipargx, vtpubpremiumx])
869873
}
870874
},
871875
{

0 commit comments

Comments
 (0)