A Python TrueRand-Like Script Based On Signals, Alarms, Clocks, Counters, & SHA256

So I was watching some new Defcon videos from some of my favourite speakers (Jeff Moss, Bruce Schneier, Renderman, Dan Kaminsky, Moxie Marlinspike, Joshua Wright, Johnny Long, Charlie Miller, etc.) and Dan mentioned the ability to generate random numbers on a given system with nothing more than a CPU clock type device. I don’t understand it much but I think the basics includes setting an alarm trap signal and setting an infinite loop to increase a counter variable and then using that resulting integer as a source of randomness. You can repeat this process multiple times in a row to generate a larger amount of random data. Here’s my take on it, however, it is *very* slow and most likely mathematically/statistically wrong:

import hashlib
import signal

c = 0; f = 0
r = ""; l = 0
n = 3

def handler(signum, frame):
	global c, f
	global r, l
	global n
	f = 1
	s = str(c); m = len(s)
	if ((m % 2) == 1):
		s = s[1:]; m = len(s)
	#print(c)
	p = (m / 2)
	for x in range(0, p):
		d = ((int(s[x]) + int(s[x + p])) % 10)
		if (d > 7):
			if (int(s[x + p]) > 7):
				continue
			d = int(s[x + p])
		r += str(d); l += n

def srnd(size):
	global c, f
	global r, l
	global n
	signal.signal(signal.SIGALRM, handler)
	o = ""; m = 0
	while (m < size):
		r = ""; l = 0
		while (l < 256):
			signal.alarm(1)
			c = 0; f = 0
			while (f == 0):
				c += 1
			signal.alarm(0)
		print(r)
		h = hashlib.sha256(r).digest()
		for d in h:
			if (m < size):
				o += d; m += 1
	return o

def stoh(inpt):
	h = ""
	for d in inpt:
		a = hex(ord(d))
		a = a[2:]
		if (len(a) < 2):
			a = ("0" + a)
		h += a
	return h

e = stoh(srnd(32))
print(e)
$ python sigrnd.py 
003052717203640343422444177105135642455155135417632775634425154765734347724627720521226
c2638300e80d2fb7ab0230c4a6534191dda4b86b997508ff445adc577a7426c3
A Python TrueRand-Like Script Based On Signals, Alarms, Clocks, Counters, & SHA256

A small whois server and a nice holiday video

So here’s the most basic whois server in Python (connects to a PostgreSQL DB for the cached data):

Also, a funny holiday reminder that the NSA is spying on all of us!

ACLU NSA Vid [funny]

whois_limit

limiter.py

#!/usr/bin/python

import ast
import getpass
import hashlib
import os
import random
import re
import socket
import string
import sys
import time

def rstr(size):
	outp = ""
	for x in range(0, size):
		outp += random.choice(string.digits + string.ascii_uppercase + string.ascii_lowercase + "[email protected]#$%^&*-_=+?")
	return outp

fobj = open(sys.argv[1], "r")
conf = ast.literal_eval(fobj.read().strip())
fobj.close()

servport = conf["limiter"]["port"]
password = conf["limiter"]["pass"]
numtimes = conf["limiter"]["conn"]
timeouts = conf["limiter"]["time"]

prepad = rstr(8); pospad = rstr(8); cntrlist = []
addrlist = {}

sockobjc = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sockobjc.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sockobjc.bind(("", servport))
sockobjc.listen(1)

while (1):
	(sockconn, sockaddr) = sockobjc.accept()
	print("conn open:", sockaddr)
	try:
		sockconn.settimeout(1)
		datalist = sockconn.recv(1024).strip().split(" ")
		try:
			sendflag = 0
			scounter = datalist[0].strip()
			inetaddr = datalist[1].strip()
			authhash = datalist.pop()
			sharedsec = (prepad + " " + password + " " + pospad)
			temphash = hashlib.sha256(sharedsec + " " + " ".join(datalist) + " " + sharedsec).hexdigest()
			if (temphash != authhash):
				sockconn.send("0" + " " + prepad + " " + pospad)
				sendflag = 1
			else:
				if (len(cntrlist) >= 65536):
					prepad = rstr(8); pospad = rstr(8); cntrlist = []
				if (scounter in cntrlist):
					sockconn.send("1" + " " + scounter)
					sendflag = 1
				else:
					cntrlist.append(scounter)
					if (not inetaddr in addrlist.keys()):
						addrlist[inetaddr] = [0, 0]
					prestime = time.time()
					if ((prestime - addrlist[inetaddr][0]) >= timeouts):
						addrlist[inetaddr][0] = prestime
						addrlist[inetaddr][1] = 0
					print("conn info:", sockaddr, scounter, datalist, addrlist[inetaddr])
					if (addrlist[inetaddr][1] < numtimes):
						addrlist[inetaddr][1] += 1
						sockconn.send("2" + " " + "ok")
						sendflag = 1
			if (sendflag != 1):
				sockconn.send("2" + " " + "no")
		except:
			pass
	except:
		pass
	try:
		print("conn closed:", sockaddr)
		sockconn.shutdown(socket.SHUT_RDWR)
		sockconn.close()
	except:
		pass

whoiss.py

#!/usr/bin/python

import ast
import getpass
import hashlib
import os
import psycopg2
import random
import re
import socket
import string
import sys
import time

def sstr(inpt):
	outp = ""
	yesl = (string.digits + string.ascii_uppercase + string.ascii_lowercase + "-_.")
	for chrl in inpt:
		if (chrl in yesl):
			outp += chrl
	return outp

def rnum(size):
	random.seed(time.time())
	outp = ""
	for x in range(0, size):
		outp += random.choice(string.digits)
	return outp

def lims(connaddr):
	global limhost, limport
	global limpass, limpre, limpos
	x = 0
	limresp = ["-1"]
	try:
		while ((x < 8) and (limresp[0] != "2")):
			limnumb = rnum(8)
			limobjc = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
			limobjc.connect((limhost, limport))
			limdata = (limnumb + " " + connaddr)
			limsec = (limpre + " " + limpass + " " + limpos)
			limhash = hashlib.sha256(limsec + " " + limdata + " " + limsec).hexdigest()
			limobjc.sendall(limdata + " " + limhash)
			limresp = limobjc.recv(1024).strip().split(" ")
			limobjc.close()
			if (len(limresp) < 1):
				limresp = ["-1"]
			if (limresp[0] == "0"):
				limpre = limresp[1]
				limpos = limresp[2]
			elif (limresp[0] == "1"):
				pass
			print("recv limit:", limdata, limresp)
			x += 1
	except:
		pass
	return limresp

'''{
"db":{"host":"127.0.0.1", "user":"whois", "pass":"Siohw1!", "name":"dbname", "table":"whois_cache", "col":"text"},
"limiter":{"host":"127.0.0.1", "port":3434, "pass":"Limiter1!", "conn":1, "time":10},
"whois":{"port":4343},
}'''
fobj = open(sys.argv[1], "r")
conf = ast.literal_eval(fobj.read().strip())
fobj.close()

servport = conf["whois"]["port"]
childlist = []

limhost = conf["limiter"]["host"]
limport = conf["limiter"]["port"]
limpass = conf["limiter"]["pass"]
limpre = ""; limpos = ""

sqlshost = conf["db"]["host"]
sqlsuser = conf["db"]["user"]
sqlspass = conf["db"]["pass"]
sqlsdb = conf["db"]["name"]
sqlstbl = conf["db"]["table"]
sqlscol = conf["db"]["col"]

sockobjc = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sockobjc.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sockobjc.bind(("", servport))
sockobjc.listen(1)

while (1):
	for x in range(0, len(childlist)):
		try:
			os.waitpid(childlist[x], os.WNOHANG)
		except:
			childlist[x] = -1
	while (-1 in childlist):
		childlist.remove(-1)
	lims("127.0.0.1")
	(sockconn, sockaddr) = sockobjc.accept()
	print("conn open:", sockaddr)
	try:
		childpid = os.fork()
	except:
		childpid = -1
	if (childpid == 0):
		resplim = lims(sockaddr[0])
		try:
			sqldom = sockconn.recv(1024).strip()
			sqldom = sstr(sqldom.upper())
			connresp = ""
			print("conn data:", sockaddr, sqldom)
			if ((resplim[0] == "2") and (resplim[1] == "ok")):
				try:
					conn = psycopg2.connect("host='%s' dbname='%s' user='%s' password='%s'" % (sqlshost, sqlsdb, sqlsuser, sqlspass))
					curs = conn.cursor()
					curs.execute("SELECT %s FROM %s WHERE name = '%s';" % (sqlscol, sqlstbl, sqldom))
					rows = curs.fetchall()
					conn.close()
					leng = 0
					for rowo in rows:
						connresp = ("%s\n\n\n" % (rowo[0].strip()))
						leng += 1
						break
					if (leng < 1):
						connresp = ("NOT FOUND\n")
				except:
					connresp = ("SERVER ERROR (1)\n")
			else:
				connresp = ("LIMIT REACHED\n")
			sockconn.send(connresp)
		except:
			pass
		try:
			print("conn closed:", sockaddr)
			sockconn.shutdown(socket.SHUT_RDWR)
			sockconn.close()
		except:
			pass
		sys.exit(0)
	else:
		try:
			sockconn.close()
		except:
			pass
		childlist.append(childpid)

Limiter Notes:

  • The shared secret is padded with 2 random strings:
    • shared-secret = (pre-pad + common-password + post-pad)
    • These 2 strings are re-generated after 2^16 unique nonces are used
  • The message data is prefixed with a unique nonce string:
    • message-data = (uniq-nonce + message-body)
  • The limiter server uses sha256 hashing to authenticate data:
    • auth-message = sha256(shared-secret + message-data + shared-secret)
    • Can switch to a basic HMAC call if greater security is needed
  • The limiter server is a single process which communicates with any connecting clients
    • Can switch to a forked-child setup if faster connections are needed

Whois Notes:

  • The whois server uses forked-child processes to communicate with multiple clients at the same time
    • Each client process will make its own connection to the database server
A small whois server and a nice holiday video

A Simple Puppet Master/Node/Agent Starter Guide

If you’re looking for a simple, quick starter guide to setting up a basic Puppet master/agent between VM’s then you should take a look at this blog I came across from a Google search. I’m putting this here as a bookmark to myself:

http://www.6tech.org/2013/01/how-to-install-puppet-open-source-on-centos-6-3/

Edit:

Pushing an example shell script to some agents (puppetnode):

[master ~]# cat /etc/puppet/manifests/site.pp
node "puppetnode"
{
	file { "/usr/local/bin/repoconf.sh" :
		mode => 0755,
		owner => root,
		group => root,
		source => "puppet:///modules/bin/repoconf.sh"
	}
	exec { "/usr/local/bin/repoconf.sh" :
		require => File["/usr/local/bin/repoconf.sh"]
	}
	package { "nc" :
		ensure => latest,
		require => Exec["/usr/local/bin/repoconf.sh"]
	}
}
[master ~]# cat /etc/puppet/modules/bin/files/repoconf.sh
#!/bin/bash
echo `date` >> /tmp/custom.puppet.sh.log
[puppetnode ~]# puppet agent -t
Info: Retrieving plugin
Info: Caching catalog for puppetnode
Info: Applying configuration version '1386822999'
Notice: /Stage[main]/Main/Node[puppetnode]/File[/usr/local/bin/repoconf.sh]/ensure: defined content as '{md5}dfd896a6b7b57885fac7bac43f2bd263'
Notice: /Stage[main]/Main/Node[puppetnode]/Exec[/usr/local/bin/repoconf.sh]/returns: executed successfully
Notice: /Stage[main]/Main/Node[puppetnode]/Package[nc]/ensure: created
Notice: Finished catalog run in 6.84 seconds
A Simple Puppet Master/Node/Agent Starter Guide

Converting CSV Data To Wiki Tables Via Python

#!/usr/bin/python
import sys
x = 0; l = 1
print('{| border="1" class="wikitable"')
for line in sys.stdin.readlines():
	type = "|"
	if (x == 0):
		type = "!"
	if (x != 0):
		print('|-')
	if ("," in line):
		l = 0
		for coli in line.split(","):
			print(type + ' style="white-space:nowrap;" | ' + coli.strip())
			l += 1
	else:
		print('| colspan="'+str(l)+'" align="middle" | ' + line)
	x += 1
print('|}')
Converting CSV Data To Wiki Tables Via Python

POC – An Encrypted File Upload/Download Site In PHP

There is no site currently running this script but I have posted the code on github just in case anyone would like to play with it or run it. [GIT Repo]

Sfts0

Sfts2

<?php
	# sudo su -
	# mkdir -p /var/www/uploads/$sub
	# for d in /var /var/www /var/www/uploads ; do chown root:root $d ; chmod 755 $d ; done
	# chown root:apache /var/www/uploads/$sub
	# chmod 770 /var/www/uploads/$sub
	
	function safe_valu($vkeyname)
	{
		if (isset($_GET[$vkeyname])) { return $_GET[$vkeyname]; }
		if (isset($_POST[$vkeyname])) { return $_POST[$vkeyname]; }
		return "";
	}
	
	function rand_numb()
	{
		$o = "";
		for ($x = 0; $x < 6; $x += 1) { $o .= rand(0, 9); }
		return $o;
	}
	
	function remo_file($pathname)
	{
		if (!is_file($pathname)) { return 0; }
		$fmodtime = filectime($pathname);
		$lastfmod = intval((time() - $fmodtime) / (60 * 60));
		if ($lastfmod >= 48) { unlink($pathname); return 1; }
		return 0;
	}
	
	date_default_timezone_set("America/Toronto");
	srand(microtime() * 1000000);
	$WEB_EOL = "<br/>";
	$writedir = "/var/www/uploads/jon";
	
	$scptmode = safe_valu("mode");
	$pinncode = preg_replace("/[^0-9]/i", "", safe_valu("pinc"));
	$password = safe_valu("pass");
	$aeskhash = hash("SHA256", $password, true);
	
	if ($scptmode == "e")
	{
		$aesinitv = openssl_random_pseudo_bytes(16);
		if (($_FILES["file"]["error"] < 1) && ($_FILES["file"]["size"] < 4096000))
		{
			while (1)
			{
				$pinncode = rand_numb();
				$filename = ($writedir."/".$pinncode);
				if (!file_exists($filename)) { break; }
				if (remo_file($filename) == 1) { break; }
			}
			$fsrcobjc = fopen($_FILES["file"]["tmp_name"], "rb");
			$fdstobjc = fopen($filename, "wb");
			if (($fsrcobjc !== false) && ($fdstobjc !== false))
			{
				fwrite($fdstobjc, "".$_FILES["file"]["name"].""); # filename as string (unknown length)
				fwrite($fdstobjc, "\1"); # non-printable separator (1 byte)
				fwrite($fdstobjc, "".$_FILES["file"]["size"].""); # filesize in bytes (unknown length)
				fwrite($fdstobjc, "\1"); # non-printable separator (1 byte)
				$emessage = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $aeskhash, "magicstring", MCRYPT_MODE_CBC, $aesinitv);
				fwrite($fdstobjc, $emessage); # encrypted magic string (16 bytes)
				fwrite($fdstobjc, $aesinitv); # initialization vector (16 bytes)
				while (!feof($fsrcobjc))
				{
					$fsrcdata = fread($fsrcobjc, 16);
					$emessage = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $aeskhash, $fsrcdata, MCRYPT_MODE_CBC, $aesinitv);
					fwrite($fdstobjc, $emessage);
					$aesinitv = $emessage;
				}
				fclose($fdstobjc);
				fclose($fsrcobjc);
				chmod($filename, 0770);
			}
		}
	}
	
	if ($scptmode == "d")
	{
		$filelist = scandir($writedir);
		foreach ($filelist as $fileitem)
		{
			$itemname = ($writedir."/".$fileitem);
			if (remo_file($itemname) == 1) { continue; }
			if ($fileitem != $pinncode) { continue; }
			$fsrcobjc = fopen($itemname, "rb");
			if ($fsrcobjc !== false)
			{
				$filename = ""; $filechar = "";
				while ($filechar != "\1") { $filename .= $filechar; $filechar = fread($fsrcobjc, 1); }
				$filesize = ""; $filechar = "";
				while ($filechar != "\1") { $filesize .= $filechar; $filechar = fread($fsrcobjc, 1); }
				$filesize = intval($filesize);
				$magicode = fread($fsrcobjc, 16);
				$aesinitv = fread($fsrcobjc, 16);
				$dmessage = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $aeskhash, $magicode, MCRYPT_MODE_CBC, $aesinitv);
				if (rtrim($dmessage) == "magicstring")
				{
					header('Content-Type: application/octet-stream');
					header('Content-Disposition: attachment; filename="'.$filename.'"');
					header('Content-Length: '.$filesize);
					$tempinit = $aesinitv;
					while ($filesize > 0)
					{
						$aesinitv = $tempinit;
						$fsrcdata = fread($fsrcobjc, 16);
						$tempinit = $fsrcdata;
						$dmessage = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $aeskhash, $fsrcdata, MCRYPT_MODE_CBC, $aesinitv);
						$templeng = 16; if ($filesize < 16) { $templeng = $filesize; }
						print(substr($dmessage, 0, $templeng));
						$filesize -= 16;
					}
					fclose($fsrcobjc);
					exit(0);
				}
				fclose($fsrcobjc);
			}
		}
	}
?>

<html>
	<head>
		<title>Secure File Transfer Site</title>
		<style>
			body
			{
				background: #EEEEEE;
			}
			
			a
			{
				color: #000000;
				border-bottom: 1px dotted;
				text-decoration: none;
			}
			
			.minwide
			{
				width: 480px;
			}
			
			.blue
			{
				background: linear-gradient(#2E88C4, #075698) repeat scroll 0 0 rgba(0, 0, 0, 0);
			}
			
			.green
			{
				background: linear-gradient(#B8DB29, #5A8F00) repeat scroll 0 0 rgba(0, 0, 0, 0);
			}
			
			.red
			{
				background: linear-gradient(#F04349, #C81E2B) repeat scroll 0 0 rgba(0, 0, 0, 0);
			}
			
			.bubble
			{
				border-radius: 10px;
				color: #FFFFFF;
				margin: 15px;
				padding: 15px;
			}
			
			.info
			{
				background: linear-gradient(#F9D835, #F3961C) repeat scroll 0 0 rgba(0, 0, 0, 0);
				border-radius: 10px;
				color: #000000;
				margin: 15px;
				padding: 15px;
			}
		</style>
	</head>
	
	<body>
		<center>
			<form method="post" action="index.php" enctype="multipart/form-data">
				<input type="hidden" name="mode" value="e" />
				<table class="minwide bubble green">
					<tr>
						<td colspan="3">
							<center><b>Upload A File</b></center>
						</td>
					</tr>
					<tr>
						<td colspan="3">
							&nbsp;
						</td>
					</tr>
					<tr>
						<td align="right" style="width:1%;">
							<label for="file">Filename:</label>
						</td>
						<td align="left">
							<input type="file" name="file" />
						</td>
						<td align="left" style="width:1%;">
							&nbsp;
						</td>
					</tr>
					<tr>
						<td align="right" style="width:1%;">
							<label for="pass">Password:</label>
						</td>
						<td align="left">
							<input type="text" name="pass" style="width:100%;" />
						</td>
						<td align="left" style="width:1%;">
							<input type="submit" name="submit" value="Upload" />
						</td>
					</tr>
				</table>
			</form>
			
			<table class="minwide info">
				<tr>
					<td>
						<center>
						&nbsp;
						<?php
							if ($pinncode != "") { print("<a href='?pinc=".$pinncode."'>"."Your PIN code is: ".$pinncode."</a>".PHP_EOL); }
							else { print("No PIN code detected".PHP_EOL); }
						?>
						&nbsp;
						</center>
					</td>
				</tr>
			</table>
			
			<form method="post" action="index.php">
				<input type="hidden" name="mode" value="d" />
				<table class="minwide bubble blue">
					<tr>
						<td colspan="3">
							<center><b>Download A File</b></center>
						</td>
					</tr>
					<tr>
						<td colspan="3">
							&nbsp;
						</td>
					</tr>
					<tr>
						<td align="right" style="width:1%;">
							<label for="pinc">Pincode:</label>
						</td>
						<td align="left">
							<input type="text" name="pinc" size="8" value="<?php print($pinncode); ?>" />
						</td>
						<td align="left" style="width:1%;">
							&nbsp;
						</td>
					</tr>
					<tr>
						<td align="right" style="width:1%;">
							<label for="pass">Password:</label>
						</td>
						<td align="left">
							<input type="password" name="pass" style="width:100%;" />
						</td>
						<td align="left" style="width:1%;">
							<input type="submit" name="submit" value="Download" />
						</td>
					</tr>
				</table>
			</form>
			
			<table class="bubble red">
				<tr>
					<td>
						<center><b>How does this thing work?</b></center> <br /> <br />
						* You first upload a file along with a password string <br />
						&nbsp; * You then copy the PIN code link above and send that to another person <br />
						&nbsp; * You also tell them the shared, secret password over a different medium <br />
						* Any PIN code which points to a file that was created over 48 hours ago will be deleted <br />
						* The server generates a random 128 bit Initialization Vector & a unique 6 digit PIN code <br />
						&nbsp; * [iv = rand-bytes(16)] <br />
						* The server calculates a secret 256 bit key using a hashing algorithm & your password <br />
						&nbsp; * [passhash = SHA-256(password)] <br />
						* The server encrypts your file data using a symmetric block cipher <br />
						&nbsp; * [encdata = AES-256-CBC(filedata, passhash, iv)] <br />
						* The server encrypts a magic string so that the password can be validated before decryption <br />
						&nbsp; * [encmagic = AES-256-CBC("magicstr", passhash, iv)] <br />
						* The server writes out a final file named by the PIN code with the following data: <br />
						&nbsp; * [filepin = (filename + \1 + filesize + \1 + encmagic + iv + encdata)] <br />
						* There is a 4 MB file size upload limit
					</td>
				</tr>
			</table>
		</center>
	</body>
</html>
POC – An Encrypted File Upload/Download Site In PHP

Proof Of Concept Script – Allowing Incoming Server Connections Through An Outbound Client Connection Only (All Through An External Public Server)

#!/usr/bin/python

import os
import random
import select
import socket
import string
import sys
import time

def rndstr(size):
	o = ""
	for x in range(0, size):
		o += random.choice(string.digits + string.ascii_uppercase + string.ascii_lowercase)
	return o

def tryclose(sockobjc):
	try:
		sockobjc.close()
	except:
		pass

def childrwe(socklist):
	buffsize = 1024
	bufflist = ["", ""]
	erroflag = 0; dataflag = 1
	while (erroflag == 0):
		if (dataflag == 0):
			for x in range(0, 2):
				if (bufflist[x]):
					y = ((x + 1) % 2)
					#print("send:",y,"data:",bufflist[x])
					try:
						socklist[y].send(bufflist[x])
						bufflist[x] = ""
					except:
						erroflag = 1
		dataflag = 0
		(readlist, writlist, errolist) = select.select(socklist, [], [], 0.01)
		for x in range(0, 2):
			if (socklist[x] in readlist):
				try:
					databuff = socklist[x].recv(buffsize)
				except:
					databuff = ""
					erroflag = 1
				if (not databuff):
					erroflag = 1
				else:
					bufflist[x] += databuff
					dataflag = 1
	tryclose(socklist[0]); tryclose(socklist[1])
	sys.exit(0)

def main():
	print("%s public [public_port] [private_port] [private_password]" % (sys.argv[0]))
	print("%s private [public_host] [private_port] [private_password] [local_port]" % (sys.argv[0]))
	print("")
	
	buffsize = 1024
	
	if (sys.argv[1] == "public"):
		clieport = int(sys.argv[2])
		servport = int(sys.argv[3])
		password = sys.argv[4]
		
		clieobjc = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
		clieobjc.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
		clieobjc.bind(("0.0.0.0", clieport))
		clieobjc.listen(1)
		clielist = []
		
		servobjc = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
		servobjc.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
		servobjc.bind(("0.0.0.0", servport))
		servobjc.listen(1)
		servlist = []
		
		childlst = []
		while (1):
			templist = [clieobjc, servobjc]
			for clieitem in clielist:
				if (clieitem[0]):
					templist.append(clieitem[0])
			for servitem in servlist:
				if (servitem[0]):
					templist.append(servitem[0])
			
			(readlist, writlist, errolist) = select.select(templist, [], [])
			
			if (clieobjc in readlist):
				(connobjc, addrobjc) = clieobjc.accept()
				uniqstri = rndstr(16)
				print(int(time.time()),"clie:","connection opened:",addrobjc,"id:",uniqstri)
				clielist.append([connobjc, None, "", addrobjc, uniqstri])
				sentflag = 0
				delelist = []
				for servitem in servlist:
					if (servitem[1] == "control"):
						print(int(time.time()),"serv:","sending notice:",servitem[2],"data:",uniqstri)
						try:
							servitem[0].send(uniqstri)
							sentflag = 1
						except:
							delelist.append(servitem)
					if (sentflag == 1):
						break
				for deleitem in delelist:
					print(int(time.time()),"serv:","connection closed:",deleitem[2])
					tryclose(deleitem[0])
					servlist.remove(deleitem)
			
			elif (servobjc in readlist):
				(connobjc, addrobjc) = servobjc.accept()
				print(int(time.time()),"serv:","connection opened:",addrobjc)
				servlist.append([connobjc, "", addrobjc])
			
			else:
				delelist = []
				for servitem in servlist:
					if (servitem[0] in readlist):
						try:
							databuff = servitem[0].recv(buffsize)
						except:
							delelist.append(servitem)
						if (not databuff):
							delelist.append(servitem)
						else:
							print(int(time.time()),"serv:","recv from:",servitem[2])
							#print(int(time.time()),"serv:","recv from:",servitem[2],"data:",databuff)
							if (databuff.strip() == password):
								print(int(time.time()),"serv:","verified auth:",servitem[2])
								servitem[1] = "control"
							else:
								for clieitem in clielist:
									if (databuff.strip() == clieitem[4]):
										print(int(time.time()),"serv:","est. middle:",clieitem[3],"*----",clieitem[4],"----*",servitem[2])
										clieitem[1] = servitem[0]
				for deleitem in delelist:
					print(int(time.time()),"serv:","connection closed:",deleitem[2])
					tryclose(deleitem[0])
					servlist.remove(deleitem)
				
				delelist = []
				for clieitem in clielist:
					if (clieitem[0] in readlist):
						try:
							databuff = clieitem[0].recv(buffsize)
						except:
							delelist.append(clieitem)
						if (not databuff):
							delelist.append(clieitem)
						else:
							print(int(time.time()),"clie:","recv from:",clieitem[3],"id:",clieitem[4])
							#print(int(time.time()),"clie:","recv from:",clieitem[3],"id:",clieitem[4],"data:",databuff)
							clieitem[2] += databuff
				for deleitem in delelist:
					print(int(time.time()),"clie:","connection closed:",deleitem[3],"id:",deleitem[4])
					tryclose(deleitem[0])
					clielist.remove(deleitem)
			
			delelist = []
			for childpid in childlst:
				try:
					os.waitpid(childpid, os.WNOHANG)
				except:
					delelist.append(childpid)
			for deleitem in delelist:
				print(int(time.time()),"fork:","child exit:",deleitem)
				childlst.remove(deleitem)
			
			for clieitem in clielist:
				if (clieitem[1]):
					childpid = os.fork()
					if (childpid == 0):
						for sockitem in clielist:
							if (sockitem[0] != clieitem[0]):
								tryclose(sockitem[0]); tryclose(sockitem[1])
						for sockitem in servlist:
							if (sockitem[0] != clieitem[1]):
								tryclose(sockitem[0])
						if (clieitem[2]):
							try:
								clieitem[1].send(clieitem[2])
							except:
								pass
						childrwe([clieitem[0], clieitem[1]])
						sys.exit(0)
					else:
						print(int(time.time()),"fork:","child start:",childpid)
						delelist = []
						for sockitem in clielist:
							if (sockitem[0] == clieitem[0]):
								delelist.append(sockitem)
						for deleitem in delelist:
							tryclose(deleitem[0]); tryclose(deleitem[1])
							clielist.remove(deleitem)
						delelist = []
						for sockitem in servlist:
							if (sockitem[0] == clieitem[1]):
								delelist.append(sockitem)
						for deleitem in delelist:
							tryclose(deleitem[0])
							servlist.remove(deleitem)
						childlst.append(childpid)
	
	if (sys.argv[1] == "private"):
		servport = int(sys.argv[3])
		password = sys.argv[4]
		loclport = int(sys.argv[5])
		
		servobjc = None
		childlst = []
		while (1):
			forkitem = None
			if (servobjc == None):
				try:
					servaddr = socket.gethostbyaddr(sys.argv[2])
					servobjc = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
					servobjc.connect((servaddr[2][0], servport))
					servobjc.send(password)
				except:
					servobjc = None
			if (servobjc == None):
				time.sleep(1)
				continue
			
			(readlist, writlist, errolist) = select.select([servobjc], [], [])
			
			if (servobjc in readlist):
				try:
					databuff = servobjc.recv(buffsize)
					clieaddr = socket.gethostbyaddr(sys.argv[2])
					clieobjc = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
					clieobjc.connect((clieaddr[2][0], servport))
					clieobjc.send(databuff)
					middobjc = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
					middobjc.connect(("127.0.0.1", loclport))
					forkitem = [clieobjc, middobjc, databuff]
				except:
					servobjc = None
			
			delelist = []
			for childpid in childlst:
				try:
					os.waitpid(childpid, os.WNOHANG)
				except:
					delelist.append(childpid)
			for deleitem in delelist:
				childlst.remove(deleitem)
			
			if (forkitem):
				childpid = os.fork()
				if (childpid == 0):
					childrwe([forkitem[0], forkitem[1]])
					sys.exit(0)
				else:
					tryclose(forkitem[0]); tryclose(forkitem[1])
					childlst.append(childpid)

if (__name__ == "__main__"):
	main()

[[email protected] ~]$ ./fwbust.py public 61337 51337 abcxyz

[[email protected] ~]$ ./fwbust.py private public.server.com 51337 abcxyz 22

[[email protected] ~]$ ssh -p 61337 [email protected]
[[email protected] ~]$ hostname …

Figured it out yet? 🙂

Proof Of Concept Script – Allowing Incoming Server Connections Through An Outbound Client Connection Only (All Through An External Public Server)

A Simple Server/Router Firewall

This simple firewall achieves the following:

  • Drops all layer-2 ARP traffic from being forwarded between bridged clients (WiFi)
    • Security: Prevents ARP cache poisoning attacks between clients only
    • Note: This breaks the ability for clients to learn about each others addresses to talk to each other
    • Trick: Clients could still talk to each other by setting static ARP entries to the MAC of the router with each others IP addresses
  • Router loops through the DHCP lease table and sets a static ARP entry for each IP / MAC combo found for every client
    • Security: Prevents ARP cache poisoning attacks coming from a client into the router
    • Note: This does not prevent attackers with Rogue DHCP servers from answering other clients first
  • Drops all layer-3 UDP-DHCP traffic from being broadcasted between clients (WiFi)
    • Security: Prevents rogue DHCP server traffic from being sent between clients
  • General firewalling rules
    • Allows specific inbound traffic only: lo/dhcp/ssh/related/established – drops all else
    • Allow a Destination-NAT port forwarding to a given server IP/Port
    • Allow a Source-NAT for clients of the router to get out
    • Note: Does not prevent DHCP starvation DoS attacks
  • Routing rules to direct traffic to the main VLANs
    • 192.168.0.0/18 is used for the local DHCP VLSM
    • 192.168.96.0/19 -> 192.168.64.2/24 (Part of the 192.168.64.0/18 VLSM)
    • 192.168.160.0/19 -> 192.168.128.2/24 (Part of the 192.168.128.0/18 VLSM)
    • 192.168.192.0/18 is a free VLSM block

 

LAN="br-lan"
WAN="eth0.2"
SRV="192.168.161.2:22"
ROU="192.168.96.0/19:192.168.64.2 192.168.160.0/19:192.168.128.2"


C=`/usr/sbin/ebtables -L FORWARD | grep -i '.p ARP.*.j DROP'`
if [ "$C" == "" ] ; then
	echo "Setting ebtables"
	
	/usr/sbin/ebtables -F
	
	for INTF in -i -o ; do
		/usr/sbin/ebtables -A FORWARD "$INTF" "$LAN" -p ARP -j DROP
		
		for PORT in 67 68 ; do
			for TYPE in sport dport ; do
				/usr/sbin/ebtables -A FORWARD "$INTF" "$LAN" -p ip --ip-protocol udp --ip-"$TYPE" "$PORT" -j DROP
			done
		done
	done
fi


while read E ; do
	M=`echo "$E" | awk '{ print $2 }'`
	I=`echo "$E" | awk '{ print $3 }'`
	/usr/sbin/ip neighbor change "$I" lladdr "$M" dev "$LAN" nud permanent
done < /tmp/dhcp.leases


C=`/usr/sbin/iptables -nvL | grep -i '^chain' | tail -n +4`
if [ "$C" != "" ] ; then
	echo "Setting iptables"
	
	/usr/sbin/iptables -F ; /usr/sbin/iptables -X
	/usr/sbin/iptables -t nat -F ; /usr/sbin/iptables -t nat -X
	/usr/sbin/iptables -t mangle -F ; /usr/sbin/iptables -t mangle -X
	/usr/sbin/iptables -t raw -F ; /usr/sbin/iptables -t raw -X
	
	/usr/sbin/iptables -P INPUT ACCEPT
	/usr/sbin/iptables -A INPUT -i lo -j ACCEPT
	/usr/sbin/iptables -A INPUT -p udp --dport 67 -j ACCEPT
	/usr/sbin/iptables -A INPUT -p tcp --dport 22 -j ACCEPT
	/usr/sbin/iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
	/usr/sbin/iptables -A INPUT -j DROP
	
	/usr/sbin/iptables -P FORWARD ACCEPT
	/usr/sbin/iptables -P OUTPUT ACCEPT
	
	if [ "$WAN" != "" ] ; then
		if [ "$SRV" != "" ] ; then
			/usr/sbin/iptables -t nat -A PREROUTING -i "$WAN" -p tcp --dport 443 -j DNAT --to "$SRV"
		fi
		/usr/sbin/iptables -t nat -A POSTROUTING -o "$WAN" -j MASQUERADE
	fi
fi

for ROUTE in $ROU ; do
	SRC=`echo "$ROUTE" | awk -F':' '{ print $1 }'`
	DST=`echo "$ROUTE" | awk -F':' '{ print $2 }'`
	C=`/usr/sbin/ip route | grep -i "$SRC"`
	if [ "$C" == "" ] ; then
		echo "Adding route [$SRC] -> [$DST]"
		
		/usr/sbin/ip route add "$SRC" via "$DST"
	fi
done

A Simple Server/Router Firewall