Skip to content

Instantly share code, notes, and snippets.

@theSoberSobber
Created May 16, 2024 17:47
Show Gist options
  • Save theSoberSobber/59d1eca9e8becd2d401c7a8e84417582 to your computer and use it in GitHub Desktop.
Save theSoberSobber/59d1eca9e8becd2d401c7a8e84417582 to your computer and use it in GitHub Desktop.
create a user_agents.txt and IPs.txt in the same directory, int user_agents.txt paste the comment at the end, needs libcurl, install by sudo apt-get install libcurl4-openssl-dev, compile using ++ -o scanner main.cpp -lcurl -pthread
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <thread>
#include <curl/curl.h>
#include <cstdlib>
#include <ctime>
#include <sstream>
#include <mutex>
#include <algorithm>
#include <cctype>
const std::string USER_AGENT_FILE = "user_agents.txt";
const std::string IP_FILE = "IPs.txt";
const int NUM_THREADS = 2;
const std::vector<std::string> ENDPOINTS = {"mjpg/video.mjpg"};
std::mutex ip_file_mutex;
bool check_ip(const std::string& ip_address) {
CURL* curl = curl_easy_init();
if (!curl) return false;
curl_easy_setopt(curl, CURLOPT_URL, ("http://" + ip_address + ":80").c_str());
curl_easy_setopt(curl, CURLOPT_NOBODY, 1L);
curl_easy_setopt(curl, CURLOPT_TIMEOUT, 2L);
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);
CURLcode res = curl_easy_perform(curl);
curl_easy_cleanup(curl);
return (res == CURLE_OK);
}
bool is_cam(const std::string& content_type) {
return content_type == "multipart/x-mixed-replace; boundary=myboundary";
}
void save_ip(const std::string& ip_address, const std::string& endpoint) {
std::lock_guard<std::mutex> guard(ip_file_mutex);
std::ofstream file(IP_FILE, std::ios::app);
if (file.is_open()) {
file << "http://" << ip_address << "/" << endpoint << "\n";
file.close();
}
}
size_t header_callback(char* buffer, size_t size, size_t nitems, std::string* headers) {
headers->append(buffer, size * nitems);
return size * nitems;
}
void scan_one(const std::vector<std::string>& user_agents) {
std::ostringstream ip_address;
ip_address << rand() % 256 << '.' << rand() % 256 << '.' << rand() % 256 << '.' << rand() % 256;
std::string selected_user_agent = user_agents[rand() % user_agents.size()];
if (!check_ip(ip_address.str())) {
std::cerr << "IP Address " << ip_address.str() << " at port 80 did not respond.\n";
return;
}
CURL* curl = curl_easy_init();
if (!curl) return;
for (const auto& endpoint : ENDPOINTS) {
std::string url = "http://" + ip_address.str() + "/" + endpoint;
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
curl_easy_setopt(curl, CURLOPT_NOBODY, 1L);
curl_easy_setopt(curl, CURLOPT_TIMEOUT, 2L);
curl_easy_setopt(curl, CURLOPT_USERAGENT, selected_user_agent.c_str());
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);
std::string headers;
curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, header_callback);
curl_easy_setopt(curl, CURLOPT_HEADERDATA, &headers);
CURLcode res = curl_easy_perform(curl);
if (res == CURLE_OK) {
long response_code;
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response_code);
if (response_code == 200) {
std::cout << "http://" << ip_address.str() << "/" << endpoint << "\n";
std::cout << "Generated IP Address: " << ip_address.str() << ", Endpoint: " << endpoint << "\n";
std::cout << "User Agent: " << selected_user_agent << "\n";
std::cout << "Response Headers:\n" << headers;
std::size_t pos = headers.find("Content-Type:");
if (pos != std::string::npos) {
std::size_t end = headers.find("\r\n", pos);
std::string content_type = headers.substr(pos + 14, end - pos - 14);
if (is_cam(content_type)) {
std::cout << "Response suggests it's from a camera. Saving IP to " << IP_FILE << "\n";
save_ip(ip_address.str(), endpoint);
}
}
} else {
std::cerr << "Received response with status code " << response_code << ". Skipping processing.\n";
}
} else {
std::cerr << "Failed to retrieve headers from " << url << ": " << curl_easy_strerror(res) << "\n";
}
}
curl_easy_cleanup(curl);
}
void scan(const std::vector<std::string>& user_agents) {
while (true) {
scan_one(user_agents);
}
}
std::vector<std::string> read_lines(const std::string& file_path) {
std::vector<std::string> lines;
std::ifstream file(file_path);
if (file.is_open()) {
std::string line;
while (std::getline(file, line)) {
line.erase(line.begin(), std::find_if(line.begin(), line.end(), [](unsigned char ch) {
return !std::isspace(ch);
}));
if (!line.empty()) {
lines.push_back(line);
}
}
file.close();
}
return lines;
}
int main() {
srand(static_cast<unsigned int>(time(0)));
std::vector<std::string> user_agents = read_lines(USER_AGENT_FILE);
std::ofstream file(IP_FILE, std::ios::app); // Create the file if it doesn't exist
file.close();
std::vector<std::thread> threads;
for (int i = 0; i < NUM_THREADS; ++i) {
threads.emplace_back(scan, user_agents);
}
for (auto& thread : threads) {
thread.join();
}
return 0;
}
// Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.121 Safari/537.36
// Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.121 Safari/537.36
// Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.121 Safari/537.36
// Mozilla/5.0 (Macintosh; Intel Mac OS X 11_1_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.121 Safari/537.36
// Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.85 Safari/537.36
// Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.85 Safari/537.36
// Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.85 Safari/537.36
// Mozilla/5.0 (Macintosh; Intel Mac OS X 11_1_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.85 Safari/537.36
// Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Edge/90.0.818.56 Safari/537.36
// Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Edge/90.0.818.56 Safari/537.36 Edg/90.0.818.56
// Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.107 Safari/537.36
// Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.164 Safari/537.36
// Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.212 Safari/537.36
// Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.90 Safari/537.36
// Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.150 Safari/537.36
// Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36
// Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.111 Safari/537.36
// Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.121 Safari/537.36
// Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.121 Safari/537.36
// Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.121 Safari/537.36
// Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.121 Safari/537.36
// Mozilla/5.0 (Macintosh; Intel Mac OS X 11_1_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.121 Safari/537.36
// Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_6) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.0.3 Safari/605.1.15
// Mozilla/5.0 (Macintosh; Intel Mac OS X 11_1_0) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.0.3 Safari/605.1.15
// Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.0.3 Safari/605.1.15
// Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.212 Safari/537.36
// Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.90 Safari/537.36
// Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.150 Safari/537.36
// Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36
// Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.111 Safari/537.36
@theSoberSobber
Copy link
Author

Updated to handle redirects and not skip 308's

#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <thread>
#include <curl/curl.h>
#include <cstdlib>
#include <ctime>
#include <sstream>
#include <mutex>
#include <algorithm>
#include <cctype>
#include <csignal>
#include <atomic>

const std::string USER_AGENT_FILE = "user_agents.txt";
const std::string IP_FILE = "IPs.txt";
const std::string LOG_FILE = "scanner.log";
const int NUM_THREADS = 2;
const std::vector<std::string> ENDPOINTS = {"mjpg/video.mjpg"};

std::mutex ip_file_mutex;
std::mutex log_file_mutex;
std::atomic<bool> keep_running(true);

void log_message(const std::string &message) {
    std::lock_guard<std::mutex> guard(log_file_mutex);
    std::ofstream log(LOG_FILE, std::ios::app);
    if (log.is_open()) {
        log << message << std::endl;
    }
}

void signal_handler(int signal) {
    if (signal == SIGINT) {
        log_message("SIGINT received. Shutting down...");
        keep_running = false;
    }
}

bool check_ip(const std::string &ip_address) {
    CURL *curl = curl_easy_init();
    if (!curl) return false;

    curl_easy_setopt(curl, CURLOPT_URL, ("http://" + ip_address + ":80").c_str());
    curl_easy_setopt(curl, CURLOPT_NOBODY, 1L);
    curl_easy_setopt(curl, CURLOPT_TIMEOUT, 2L);
    curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
    curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);

    CURLcode res = curl_easy_perform(curl);
    curl_easy_cleanup(curl);

    return (res == CURLE_OK);
}

bool is_cam(const std::string &content_type) {
    return content_type == "multipart/x-mixed-replace; boundary=myboundary";
}

void save_ip(const std::string &ip_address, const std::string &endpoint) {
    std::lock_guard<std::mutex> guard(ip_file_mutex);
    std::ofstream file(IP_FILE, std::ios::app);
    if (file.is_open()) {
        file << "http://" << ip_address << "/" << endpoint << "\n";
        file.close();
    }
}

size_t header_callback(char *buffer, size_t size, size_t nitems, std::string *headers) {
    headers->append(buffer, size * nitems);
    return size * nitems;
}

void scan_one(const std::vector<std::string> &user_agents) {
    std::ostringstream ip_address;
    ip_address << rand() % 256 << '.' << rand() % 256 << '.' << rand() % 256 << '.' << rand() % 256;

    if (user_agents.empty()) {
        log_message("User agents list is empty. Exiting scan_one.");
        return;
    }

    std::string selected_user_agent = user_agents[rand() % user_agents.size()];

    if (!check_ip(ip_address.str())) {
        log_message("IP Address " + ip_address.str() + " at port 80 did not respond.");
        return;
    }

    CURL *curl = curl_easy_init();
    if (!curl) return;

    for (const auto &endpoint : ENDPOINTS) {
        std::string url = "http://" + ip_address.str() + "/" + endpoint;
        curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
        curl_easy_setopt(curl, CURLOPT_NOBODY, 0L);
        curl_easy_setopt(curl, CURLOPT_TIMEOUT, 2L);
        curl_easy_setopt(curl, CURLOPT_USERAGENT, selected_user_agent.c_str());
        curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
        curl_easy_setopt(curl, CURLOPT_MAXREDIRS, 5L);
        curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
        curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);

        std::string headers;
        curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, header_callback);
        curl_easy_setopt(curl, CURLOPT_HEADERDATA, &headers);

        CURLcode res = curl_easy_perform(curl);

        if (res == CURLE_OK) {
            long response_code;
            curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response_code);
            if (response_code == 200) {
                std::ostringstream log;
                log << "http://" << ip_address.str() << "/" << endpoint << "\n"
                    << "Generated IP Address: " << ip_address.str() << ", Endpoint: " << endpoint << "\n"
                    << "User Agent: " << selected_user_agent << "\n"
                    << "Response Headers:\n" << headers;

                std::size_t pos = headers.find("Content-Type:");
                if (pos != std::string::npos) {
                    std::size_t end = headers.find("\r\n", pos);
                    std::string content_type = headers.substr(pos + 14, end - pos - 14);
                    if (is_cam(content_type)) {
                        log << "Response suggests it's from a camera. Saving IP to " << IP_FILE << "\n";
                        save_ip(ip_address.str(), endpoint);
                    }
                }
                log_message(log.str());
            } else {
                log_message("Received response with status code " + std::to_string(response_code) + ". Skipping processing.");
            }
        } else {
            log_message("Failed to retrieve headers from " + url + ": " + curl_easy_strerror(res));
        }
    }

    curl_easy_cleanup(curl);
}

void scan(const std::vector<std::string> &user_agents) {
    while (keep_running) {
        scan_one(user_agents);
    }
}

std::vector<std::string> read_lines(const std::string &file_path) {
    std::vector<std::string> lines;
    std::ifstream file(file_path);
    if (file.is_open()) {
        std::string line;
        while (std::getline(file, line)) {
            line.erase(line.begin(), std::find_if(line.begin(), line.end(), [](unsigned char ch) {
                return !std::isspace(ch);
            }));
            if (!line.empty()) {
                lines.push_back(line);
            }
        }
        file.close();
    }
    return lines;
}

int main() {
    std::signal(SIGINT, signal_handler);

    srand(static_cast<unsigned int>(time(0)));

    std::vector<std::string> user_agents = read_lines(USER_AGENT_FILE);

    if (user_agents.empty()) {
        std::cerr << "User agent file is empty or not found.\n";
        return 1;
    }

    std::ofstream file(IP_FILE, std::ios::app); // Create the file if it doesn't exist
    file.close();

    std::vector<std::thread> threads;
    for (int i = 0; i < NUM_THREADS; ++i) {
        threads.emplace_back(scan, user_agents);
    }

    for (auto &thread : threads) {
        thread.join();
    }

    return 0;
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment