Einen SOCKS5 Proxy Scanner implementiert in PHP

View this thread on: d.buzz | hive.blog | peakd.com | ecency.com
·@stubenhocker·
0.000 HBD
Einen SOCKS5 Proxy Scanner implementiert in PHP
## Die Suche mit nmap
Unauthentifizierte Proxy-Server gehören nach wie vor zu den grössten Problemen, mit denen das Internet zu kämpfen hat.
Falsch konfigurierte Proxy-Server oder Firewalls, welche als Proxies dienen, werden dadurch zu einem Gateway für allerlei unseriösen Traffic. Mit einigen simplen Google Queries findet man Tausende von HTTP/SOCKS4/SOCKS5-Proxy-Servern. Ich habe mich gefragt, wie schwierig es wohl ist, solche schlecht konfigurierten Proxyserver selbst zu finden. Mein erster Anhaltspunkt war der gute alte Netzwerkmapper nmap. Einfachheitshalber konzentriere ich mich ausschliesslich auf SOCKS5-Proxys.


![Abstrakter Scan - Generiert von ChatGPT](https://files.peakd.com/file/peakd-hive/stubenhocker/Eo6DaDVAYcmay9yqG1LSoUqiTiCUSaAiHwZRfeHoXj9epKjKxDuFNDXUstnCHJ5ocDo.jpeg)



Nmap angeschmissen und mal 50.000 zufällige Hosts nach dem offenen Port 1080 (SOCKS5) abgesucht.
```nmap -T4 -sV -iR 50000 -p1080```
Das Ergebnis ist ernüchternd, ich finde zwar einige Server mit offenem Port, doch keiner davon ist unauthentifiziert und funktioniert. Zur Validierung nutze ich curl:
```curl -x socks5://{ip}:1080 https://api.ipify.org```
Der Endpoint https://api.ipify.org müsste mir die entsprechende IP-Adresse des Proxyservers zurückgeben, wenn alles klappt.


## Eine eigene Implementierung in PHP 
Der Vorteil ist, dass ich bei einer eigenen Implementierung die Server gleich via ```curl -x socks5://{ip}:1080 https://api.ipify.org``` gegenchecken kann und mir so sicher bin, dass ich nur funktionierende speichern werde.

Als Erstes brauche ich eine Funktion, welche mir zufällige IP-Adressen generiert. Da die IPv6-Range viel zu groß ist und es schon reines Glück wäre, mal einen Host zu finden, welcher überhaupt online ist, beschränke ich mich auf IPv4.
```
function generateRandomPublicIp(): string
{
    do {
        $ip = implode('.', [rand(1, 255), rand(0, 255), rand(0, 255), rand(1, 254)]);
    } while (isPrivateIp($ip));
    return $ip;
}
```
Natürlich möchte ich keine IP-Adressen scannen, welche gar nicht existieren können oder internen Netzwerken zugeordnet sind.

```
function isPrivateIp(string $ip): bool
{
    $privateRanges = [
        '10.0.0.0|10.255.255.255',
        '172.16.0.0|172.31.255.255',
        '192.168.0.0|192.168.255.255',
    ];

    foreach ($privateRanges as $range) {
        [$start, $end] = explode('|', $range);
        if (ip2long($ip) >= ip2long($start) && ip2long($ip) <= ip2long($end)) {
            return true;
        }
    }

    return false;
}
```

Da ich gleich einen Batch an IP-Adressen haben möchte, wrappe ich die ```generateRandomPublicIp()``` Funktion zusätzlich um ein Array an validen IP-Adressen zu bekommen


```
function generateRandomPublicIps(int $noOfIps): array
{
    $ips = [];
    for ($i = 0; $i < $noOfIps; $i++) {
        $ips[] = generateRandomPublicIp();
    }
    return $ips;
}
```

Jetzt benötige ich eine Funktion, welche checkt, ob ich mit der entsprechenden zufälligen IP eine Verbindung auf Port 1080 aufbauen kann und von https://api.ipify.org eine gültige Antwort erhalte. Da ich nicht jede IP-Adresse seriell prüfen möchte und dabei ewig lange auf die Antwort des Proxys warten will, nutze ich curl_multi_init, damit ich diese Anfragen parallelisieren kann.

```
function testProxies(array $ips): array
{
    $multiHandle = curl_multi_init();
    $curlHandles = [];
    $results = [];

    foreach ($ips as $ip) {
        $proxyUrl = 'socks5://' . $ip . ":1080";

        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, "https://api.ipify.org");
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_TIMEOUT, value: 60);
        curl_setopt($ch, CURLOPT_PROXY, $proxyUrl);
        curl_setopt($ch, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS5);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);

        curl_multi_add_handle($multiHandle, $ch);
        $curlHandles[$proxyUrl] = $ch;
    }

    do {
        $status = curl_multi_exec($multiHandle, $active);
        curl_multi_select($multiHandle);
    } while ($active && $status == CURLM_OK);

    foreach ($curlHandles as $proxyUrl => $ch) {
        $response = curl_multi_getcontent($ch);
        $results[$proxyUrl] = [
            'proxyUrl' => $proxyUrl,
            'response' => filter_var($response, FILTER_VALIDATE_IP) ? true : false,
        ];

        curl_multi_remove_handle($multiHandle, $ch);
        curl_close($ch);
    }

    curl_multi_close($multiHandle);

    return $results;
}
```

Jetzt muss ich gefundenen Server nur noch in eine Datei speichern.

```
function writeValidProxiesToFile($result)
{
    $outputFile = __DIR__ . '/proxer.txt';
    $handle = fopen($outputFile, 'a');

    $data = $result['proxyUrl'] . "\n";
    fwrite($handle, $data);
    fclose($handle);
}
```

Die Funktionssammlung ist komplett, nun muss ich diese nur noch implementieren.

```
$found = 0;
$rounds = 0;
$batchSize = 500;

do {
    $rounds++;
    echo "Iteration: $rounds | Scanned Ips => " . $rounds * $batchSize . " | Found Proxys => $found\n";
    $ips = generateRandomPublicIps($batchSize);
    $results = testProxies(ips: $ips);

    foreach ($results as $result) {
        if ($result['response']) {
            echo "Found working Proxy:" . $result['proxyUrl'] . "\n";
            writeValidProxiesToFile($result);
            $found++;
        }
    }

} while ($found != 100);
```


## Das ganze Skript zum copy & pasten
```
<?php


$found = 0;
$rounds = 0;
$batchSize = 500;

do {
    $rounds++;
    echo "Iteration: $rounds | Scanned Ips => " . $rounds * $batchSize . " | Found Proxys => $found\n";
    $ips = generateRandomPublicIps($batchSize);
    $results = testProxies(ips: $ips);

    foreach ($results as $result) {
        if ($result['response']) {
            echo "Found working Proxy:" . $result['proxyUrl'] . "\n";
            writeValidProxiesToFile($result);
            $found++;
        }
    }

} while ($found != 100);



function writeValidProxiesToFile($result)
{
    $outputFile = __DIR__ . '/proxer.txt';
    $handle = fopen($outputFile, 'a');

    $data = $result['proxyUrl'] . "\n";
    fwrite($handle, $data);
    fclose($handle);
}



function testProxies(array $ips): array
{
    $multiHandle = curl_multi_init();
    $curlHandles = [];
    $results = [];

    foreach ($ips as $ip) {
        $proxyUrl = 'socks5://' . $ip . ":1080";

        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, "https://api.ipify.org");
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_TIMEOUT, value: 60);
        curl_setopt($ch, CURLOPT_PROXY, $proxyUrl);
        curl_setopt($ch, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS5);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);

        curl_multi_add_handle($multiHandle, $ch);
        $curlHandles[$proxyUrl] = $ch;
    }

    do {
        $status = curl_multi_exec($multiHandle, $active);
        curl_multi_select($multiHandle);
    } while ($active && $status == CURLM_OK);

    foreach ($curlHandles as $proxyUrl => $ch) {
        $response = curl_multi_getcontent($ch);
        $results[$proxyUrl] = [
            'proxyUrl' => $proxyUrl,
            'response' => filter_var($response, FILTER_VALIDATE_IP) ? true : false,
        ];

        curl_multi_remove_handle($multiHandle, $ch);
        curl_close($ch);
    }

    curl_multi_close($multiHandle);

    return $results;
}


function generateRandomPublicIps(int $noOfIps): array
{
    $ips = [];
    for ($i = 0; $i < $noOfIps; $i++) {
        $ips[] = generateRandomPublicIp();
    }
    return $ips;
}


function generateRandomPublicIp(): string
{
    do {
        $ip = implode('.', [rand(1, 255), rand(0, 255), rand(0, 255), rand(1, 254)]);
    } while (isPrivateIp($ip));
    return $ip;
}

function isPrivateIp(string $ip): bool
{
    $privateRanges = [
        '10.0.0.0|10.255.255.255',
        '172.16.0.0|172.31.255.255',
        '192.168.0.0|192.168.255.255',
    ];

    foreach ($privateRanges as $range) {
        [$start, $end] = explode('|', $range);
        if (ip2long($ip) >= ip2long($start) && ip2long($ip) <= ip2long($end)) {
            return true;
        }
    }

    return false;
}
```


## Fazit
Das ganze Skript verfrachtet ich auf einen meiner Raspberry Pi und lasse es rennen.
Aus Stunden werden Tage und mittlerweile 5'823'000 gescannter Hosts später habe ich noch keinen Treffer. Fairerweise muss man sagen, dass diese 5'823'000 Hosts gerade mal etwa 0,157 % des gesamten öffentlichen IPv4-Adressraums entsprechen. Ich bin noch nicht gewillt, aufzugeben, und mache mindestens die 10 Mio Hosts noch voll, um zu sehen, ob ich einen Treffer finde, und danach ... mal sehen, ich halt euch auf dem Laufenden!

![Das laufende Skript](https://files.peakd.com/file/peakd-hive/stubenhocker/23tGTPgUBBMTE6xZHcmLW3SvkgWS5PgqV7XdGef7sM7KG6iwqgsAAXMk8gVLZCzcBDLaU.png)

 Derweil frage ich mich, ob mein ISP wohl schon wieder sauer auf mich ist.
👍 , , , , , , ,