Sinisterly
Weekend project: Socks5 scanner - Printable Version

+- Sinisterly (https://sinister.ly)
+-- Forum: Coding (https://sinister.ly/Forum-Coding)
+--- Forum: Coding (https://sinister.ly/Forum-Coding--71)
+--- Thread: Weekend project: Socks5 scanner (/Thread-Weekend-project-Socks5-scanner)



Weekend project: Socks5 scanner - Rou - 02-07-2016

I tend to have weekend projects every now and then. These weekend projects are mostly just for fun and are educational in nature, so I thought it would probably be a good idea to share it with you guys. Maybe you'll learn something too?

This weekend, I felt like scanning for Socks5 proxies with zmap.

I know there's a lot of proxy lists out there, which often contains a socks5 section, but those are often being exploited pretty hard with click fraud and what not. I need to find Socks5 proxies before they're tainted by fraudsters.

So what is this?
It's just an application backend to zmap, that takes the output of zmap, connects to the IP and makes a Socks5 connection request. And that's about it. Pretty simple, huh?

I probably won't continue working on this project, though, but it was fun making a Socks5 client in nodejs.

Feel free to use for whatever, and feel free to comment. If you have any questions, then feel free to ask! I'm more than happy explain my decisions in the snippet below, or just explain how it works in general.

I've included a list in the header of the script of things that should be improved, because I'm a shitty coder. If you want a challenge, make some improvements and share with the rest of us!

Note: I have only tested this on Linux. It also expects that you already have the latest version of zmap from GitHub compiled and installed. I have no idea if it'll work with a different setup, and quite frankly, I don't care.

Resources:
zmap on GitHub.
Socks5 RFC.

Edit:
I should add that I also haven't tested this with zmap at full speed. If you remove the -B 10M from the command line options, I'm sure you'll get some interesting results.
If you're not familiar with zmap; It can scan the ENTIRE IPv4 range in an insanely short amount of time... If you internet connection is good enough. I managed to crash the firewall at one of my previous jobs by running zmap at full speed.

Code:
//------------------------------------------------------------------------------ // // Socks5 Scanner // // This is a simple Socks5 proxy scanner to be used in conjunction with zmap. // It's a simple weekend project, but I thought someone might find it useful // as a starting point, or as a little piece of a larger puzzle. // // I wrote this because the zgrab tools are fucking awful and far too // complicated for me to bother adding more functionality to it. // Besides, zgrab is written in Go, and I don't feel like learning a new // language. // // Here's a few things that should be improved upon in this script: // 1) Refractor the testProxy function. It does way too much. // 2a) Replace the BufferWriter with something built into nodejs. // 2b) Or make the BufferWriter grow its internal buffer on overflow. // 3) Add proper error handling. // 4) Make the input parser nicer. // 5) Better checking of proxies. I.E. let them connect to a server that // allows you to check latency, IP and more. // 6) IPv6 support. // // How to run: // $ sudo zmap -B 10M -p 1080 -q --output-field=* | nodejs socks5.js // // zmap can be found here: https://github.com/zmap/zmap // // Released under the Simplified BSD License. // Copyright (c) February 2016, rou <rousawyer@keemail.me> // //------------------------------------------------------------------------------ // Required built-in nodejs modules var net = require('net'); var fs = require('fs'); // Wrapper around the nodejs buffers, because I couldn't figure out how to // dynamically grow buffers, and I don't feel like keeping track of a pointer. // So fuck it. // It's unfinished, but is good enough for my purposes. var BufferWriter = function() { var bin = new Uint8Array(32); var buf = new Buffer(bin); var size = 0; var reservedSize = 32; var writeString = function(data) { buf.write(data, size, 'ascii'); size += data.length; } var write8 = function(data) { buf.writeUInt8(data, size); size++; } var write16BE = function(data) { buf.writeUInt16BE(data, size); size += 2; } var write32LE = function(data) { buf.writeUInt32LE(data, size); size += 4; } var getSize = function() { return size; } var get = function() { return buf.slice(0, size); } return { writeString: writeString, write8: write8, write16BE: write16BE, write32LE: write32LE, getSize: getSize, get: get } } // Convert an IPv4 address to a 32bit integer. function ipToBin(ip) { var ipNum = 0; var parts = ip.split('.'); if(parts.length != 4) return false; for(var i = 0; i < 4; i++) { var n = Number(parts[i]); if(!n || n > 255 || n < 0) return false; ipNum = (ipNum << 8) | n; } return ipNum; } // Counts the number of active connections. Useful in large scans // so that you know when you're about to run out of file descriptors. var active = 0; // Human-readable Socks5 connection errors, taken straight from the RFC. var socksErrors = { 0x00: 'succeeded', 0x01: 'general SOCKS server failure', 0x02: 'connection not allowed by ruleset', 0x03: 'Network unreachable', 0x04: 'Host unreachable', 0x05: 'Connection refused', 0x06: 'TTL expired', 0x07: 'Command not supported', 0x08: 'Address type not supported' } // Connect to a proxy, connect to a website through the proxy, // and write the result to a file if successful. // REWRITE THIS FUNCTION! IT PUTS THE FUN IN FUN-CTION! function testProxy(host, port, proxy_host, proxy_port, callback) { var state = 0; var ip = ipToBin(host); // Connect active++; var client = net.connect({ port: proxy_port, host: proxy_host, }, function(){ // Tell the server we're a Socks5 client, and that we only support // non-authenticated connections. var buf = new BufferWriter(); buf.write8(0x05); // Version 5 buf.write8(0x01); // 1 authentication method supported buf.write8(0x00); // No authentication client.write(buf.get()); }); // Data handler client.on('data', function(data) { // Do stuff depending on which state we're in. // This could be replaced with callbacks instead of this ugly fuck. switch(state) { // Authentication response case 0: // Validate version if(data[0] != 5) { active--; // You get a lot of funny responses sometimes. Let's check if it's an HTTP response, // because it can be fun to check up on those later. if(data[0] == 72 && data[1] == 84 && data[2] == 84 && data[3] == 80) console.log(' (' + active + ') ' + proxy_host + ': Failed (This is an HTTP server...)'); else { console.log(data); console.log(' (' + active + ') ' + proxy_host + ': Failed (Version is not 5, said '+ data[0] +')'); } client.destroy(); return; } // Make sure the server selected no authentication as the // authentication, else we cannot use this proxy. if(data[1] != 0) { active--; console.log(' (' + active + ') ' + proxy_host + ': Failed (Server wants authentication)'); client.destroy(); return; } // Make a connection to a test server var buf = new BufferWriter(); buf.write8(0x05); // Version 5 buf.write8(0x01); // CONNECT buf.write8(0x00); // Reserved if(ip !== false) { buf.write8(0x01); // Type: IPv4 buf.write32LE(ip); // IP } else { buf.write8(0x03); // Type: Hostname buf.write8(host.length); // String length buf.writeString(host); // Hostname } buf.write16BE(port); // Port number in network byte order client.write(buf.get()); state = 1; break; // Connection response case 1: // Validate version if(data[0] != 5) { active--; console.log(' (' + active + ') ' + proxy_host + ': Failed (Version is not 5)'); client.destroy(); return; } // Check that there is no error reported if(data[1] != 0) { active--; console.log(' (' + active + ') ' + proxy_host + ': Failed (Responded with ' + data[1] + ': ' + socksErrors[data[1]] + ')'); client.destroy(); // Sometimes it can be useful to try the server again later. // At least we KNOW this is a Socks5 server! if(socksErrors[data[1]]) fs.appendFile('error.txt', proxy_host + ':' + proxy_port + ' - (' + data[1] + ')' + socksErrors[data[1]], function(err){}); return; } // Validate reserved byte if(data[2] != 0) { active--; console.log(' (' + active + ') ' + proxy_host + ': Failed (Reserved value in non-null)'); client.destroy(); return; } // Dumbass test client.write("GET / HTTP/1.0\r\n\r\n"); state = 2; break; // Check that we got a reply from the test server case 2: active--; // Dumbass test: I KNOW the server responds with more than 100 bytes. // Any less is strange, so the proxy probably does something shady with my request. if(data.toString().length > 100) { console.log('+++ (' + active + ') ' + proxy_host + ': Working!'); fs.appendFile('working.txt', proxy_host + ':' + proxy_port, function(err){}); } else { console.log('??? (' + active + ') ' + proxy_host + ': Strange...'); fs.appendFile('strange.txt', proxy_host + ':' + proxy_port, function(err){}); } client.end(); default: } }); // ECONNREFUSED and ECONNRESET are the most common errors that can occur client.on('error', function(e) { active--; console.log(' (' + active + ') ' + proxy_host + ': Failed (' + e + ')' + (state ? ', state: ' + state : '')); }); // nodejs doesn't close the connection on timeout, it only tells us that the timeout limit // has been exceeded. Let's kill it and move on. client.on('timeout', function() { client.destroy(); active--; console.log(' (' + active + ') ' + proxy_host + ': Failed (Timeout)' + (state ? ', state: ' + state : '')); }); // Don't trust these as "errors". Successfully found client.on('end', function() { active--; console.log(' (' + active + ') ' + proxy_host + ': End' + (state ? ', state: ' + state : '')); }); // This timeout is important, because otherwise nodejs will keep the // connections alive for a very, very long time. client.setTimeout(10000); } var stdin = process.stdin; var stdout = process.stdout; var colNames = null; stdin.resume(); stdin.setEncoding('utf8'); stdin.on('data', function (chunk) { if(!colNames) { colNames = chunk.split(','); return; } else { var tryip = chunk.split(',')[0]; console.log(' (' + active + ') ' + tryip + ': Trying...'); testProxy('example.com', 80, tryip, 1080); } });



RE: Weekend project: Socks5 scanner - Bish0pQ - 03-07-2016

Very nice coded, it looks very good.