├── .gitignore
├── LICENSE
├── README.md
├── netbyte
├── __init__.py
└── netbyte.py
├── setup.py
└── testserver.py
/.gitignore:
--------------------------------------------------------------------------------
1 | # Byte-compiled / optimized / DLL files
2 | __pycache__/
3 | *.py[cod]
4 | *$py.class
5 |
6 | # C extensions
7 | *.so
8 |
9 | # Distribution / packaging
10 | .Python
11 | env/
12 | build/
13 | develop-eggs/
14 | dist/
15 | downloads/
16 | eggs/
17 | .eggs/
18 | lib/
19 | lib64/
20 | parts/
21 | sdist/
22 | var/
23 | wheels/
24 | *.egg-info/
25 | .installed.cfg
26 | *.egg
27 |
28 | # PyInstaller
29 | # Usually these files are written by a python script from a template
30 | # before PyInstaller builds the exe, so as to inject date/other infos into it.
31 | *.manifest
32 | *.spec
33 |
34 | # Installer logs
35 | pip-log.txt
36 | pip-delete-this-directory.txt
37 |
38 | # Unit test / coverage reports
39 | htmlcov/
40 | .tox/
41 | .coverage
42 | .coverage.*
43 | .cache
44 | nosetests.xml
45 | coverage.xml
46 | *.cover
47 | .hypothesis/
48 |
49 | # Translations
50 | *.mo
51 | *.pot
52 |
53 | # Django stuff:
54 | *.log
55 | local_settings.py
56 |
57 | # Flask stuff:
58 | instance/
59 | .webassets-cache
60 |
61 | # Scrapy stuff:
62 | .scrapy
63 |
64 | # Sphinx documentation
65 | docs/_build/
66 |
67 | # PyBuilder
68 | target/
69 |
70 | # Jupyter Notebook
71 | .ipynb_checkpoints
72 |
73 | # pyenv
74 | .python-version
75 |
76 | # celery beat schedule file
77 | celerybeat-schedule
78 |
79 | # SageMath parsed files
80 | *.sage.py
81 |
82 | # dotenv
83 | .env
84 |
85 | # virtualenv
86 | .venv
87 | venv/
88 | ENV/
89 |
90 | # Spyder project settings
91 | .spyderproject
92 | .spyproject
93 |
94 | # Rope project settings
95 | .ropeproject
96 |
97 | # mkdocs documentation
98 | /site
99 |
100 | # mypy
101 | .mypy_cache/
102 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2017 Henry Prince
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Netbyte
2 |
3 | 
4 | 
5 | 
6 | [](https://twitter.com/sc0tfree)
7 |
8 | Netbyte is a Netcat-style tool that facilitates probing proprietary TCP and UDP services.
9 | It is lightweight, fully interactive and provides formatted output in both hexadecimal and ASCII.
10 |
11 | ## Why
12 |
13 | When testing proprietary or custom-written services on pentests, I’ve frequently been disappointed while trying to reverse engineer
14 | these protocols.
15 |
16 | In the past, this has been done using netcat with wireshark and/or hexdump.
17 | However, due to truncation issues with using hexdump (i.e.: `nc domain.com 1234 | hexdump -C`)
18 | and wireshark’s tedious process, I decided to create Netbyte as quick and easy alternative when opening unknown ports.
19 |
20 | ## Install
21 |
22 | Clone the git:
23 | ```
24 | git clone https://github.com/sc0tfree/netbyte.git
25 | ```
26 | Enter the directory:
27 | ```
28 | cd netbyte
29 | ```
30 | Run setup.py script with 'install':
31 | ```
32 | python setup.py install
33 | ```
34 |
35 | ## Usage
36 |
37 | ```
38 | $ netbyte example.com 12345
39 | ������!��'
40 | FF FB 01 FF FB 03 FF FD 21(!) FF FD 27(')
41 |
42 |
43 | Enter your user id:
44 | 0D 0A(\n)
45 | 0D 0A(\n)
46 | 45(E) 6E(n) 74(t) 65(e) 72(r) 20 79(y) 6F(o) 75(u) 72(r) 20 75(u) 73(s) 65(e) 72(r) 20 69(i) 64(d) 3A(:) 20 07
47 | admin
48 | user password:
49 | 61(a) 64(d) 6D(m) 69(i) 6E(n) 0D 0A(\n)
50 | 75(u) 73(s) 65(e) 72(r) 20 70(p) 61(a) 73(s) 73(s) 77(w) 6F(o) 72(r) 64(d) 3A(:) 20
51 | admin
52 |
53 | Invalid user or password
54 |
55 | Connection closed
56 | ```
57 | You can also pipe input into netbyte:
58 | ```
59 | $ echo "GET /" | netbyte test.com 80
60 |
61 |
302 Found
62 |
63 | 302 Found
64 |
nginx/1.11.13
65 |
66 |
67 |
68 | 3C(<) 68(h) 74(t) 6D(m) 6C(l) 3E(>) 0D 0A(\n)
69 | 3C(<) 68(h) 65(e) 61(a) 64(d) 3E(>) 3C(<) 74(t) 69(i) 74(t) 6C(l) 65(e) 3E(>) 33(3) 30(0) 32(2) 20 46(F) 6F(o) 75(u) 6E(n) 64(d) 3C(<) 2F(/) 74(t) 69(i) 74(t) 6C(l) 65(e) 3E(>) 3C(<) 2F(/) 68(h) 65(e) 61(a) 64(d) 3E(>) 0D 0A(\n)
70 | 3C(<) 62(b) 6F(o) 64(d) 79(y) 20 62(b) 67(g) 63(c) 6F(o) 6C(l) 6F(o) 72(r) 3D(=) 22 77(w) 68(h) 69(i) 74(t) 65(e) 22 3E(>) 0D 0A(\n)
71 | 3C(<) 63(c) 65(e) 6E(n) 74(t) 65(e) 72(r) 3E(>) 3C(<) 68(h) 31(1) 3E(>) 33(3) 30(0) 32(2) 20 46(F) 6F(o) 75(u) 6E(n) 64(d) 3C(<) 2F(/) 68(h) 31(1) 3E(>) 3C(<) 2F(/) 63(c) 65(e) 6E(n) 74(t) 65(e) 72(r) 3E(>) 0D 0A(\n)
72 | 3C(<) 68(h) 72(r) 3E(>) 3C(<) 63(c) 65(e) 6E(n) 74(t) 65(e) 72(r) 3E(>) 6E(n) 67(g) 69(i) 6E(n) 78(x) 2F(/) 31(1) 2E 31(1) 31(1) 2E 31(1) 33(3) 3C(<) 2F(/) 63(c) 65(e) 6E(n) 74(t) 65(e) 72(r) 3E(>) 0D 0A(\n)
73 | 3C(<) 2F(/) 62(b) 6F(o) 64(d) 79(y) 3E(>) 0D 0A(\n)
74 | 3C(<) 2F(/) 68(h) 74(t) 6D(m) 6C(l) 3E(>) 0D 0A(\n)
75 |
76 | Connection closed
77 | ```
78 |
79 | ## Test Server
80 |
81 | I have included a test server to better view the functionality of netbyte. The server has two tests:
82 | * Echo Test - echo back a user entered string
83 | * Hex Test - send a random hexadecimal string of user-specified size
84 |
85 | To run the test server:
86 | ```
87 | $ python testserver.py
88 | ```
89 | In another terminal, connect to the test server using netbyte:
90 | ```
91 | $ netbyte localhost 12345
92 | ```
93 |
94 | ## Modifying Output Colors
95 |
96 | To modify the color scheme, change the functions `print_ascii` and `print_hex` inside the netbyte package.
97 | See the [colorama page](https://pypi.python.org/pypi/colorama) for color options.
98 |
99 | ## License and Contributions
100 |
101 | Netbyte is under the MIT License.
102 |
103 | Questions, comments and suggestions are always welcomed!
104 |
105 | ## Future Work
106 |
107 | * Ability to enter input sent as hex
108 | * Listen option to interact with custom-built clients
109 | * Proper unit tests
110 |
--------------------------------------------------------------------------------
/netbyte/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sc0tfree/netbyte/81975d53a85766990618617178fc7d755cef7e73/netbyte/__init__.py
--------------------------------------------------------------------------------
/netbyte/netbyte.py:
--------------------------------------------------------------------------------
1 | # __ __ __
2 | # ____ ___ / /_/ /_ __ __/ /____
3 | # / __ \/ _ \/ __/ __ \/ / / / __/ _ \
4 | # / / / / __/ /_/ /_/ / /_/ / /_/ __/
5 | # /_/ /_/\___/\__/_.___/\__, /\__/\___/
6 | # /____/
7 | # Author: sc0tfree
8 | # Twitter: @sc0tfree
9 | # Email: henry@sc0tfree.com
10 |
11 | import socket
12 | import errno
13 | import argparse
14 | import sys
15 | import time
16 | from colorama import Fore, Style
17 | from threading import Thread
18 | from Queue import Queue, Empty
19 |
20 |
21 | def is_symbol(character):
22 | '''
23 | Checks to see if a character is a symbol.
24 |
25 | Returns:
26 | bool: True if character is symbol
27 | '''
28 | symbols = "~`!@#$%^&*()_-+={}[]:>;',?*-+"
29 | if character not in symbols:
30 | return False
31 | else:
32 | return True
33 |
34 |
35 | def to_hex(string):
36 | '''
37 | Converts string to formatted hex and ASCII reference values
38 |
39 | Returns:
40 | str: Formatted hex & ASCII reference
41 | '''
42 |
43 | results = []
44 |
45 | new_line = True
46 |
47 | for character in string:
48 |
49 | # Convert ASCII to unicode
50 | unicode_value = ord(character)
51 |
52 | # Convert unicode to hex
53 | hex_value = hex(unicode_value).replace('0x', '')
54 |
55 | # Add a preceding 0
56 | if len(hex_value) == 1:
57 | hex_value = '0' + hex_value
58 |
59 | # Make upper case
60 | hex_value = hex_value.upper()
61 |
62 | # Add reference ASCII for readability
63 | if character.isalpha() or character.isdigit() or is_symbol(character):
64 | hex_value = hex_value + '(' + character + ')'
65 |
66 | # Add a space in between hex values (not to a new line)
67 | if not new_line:
68 | hex_value = ' ' + hex_value
69 |
70 | # Add a newline for readability (corresponding to ASCII)
71 | if '0A' in hex_value and not string.isspace():
72 | hex_value = hex_value + '(\\n)\n'
73 | # Next line will be a newline
74 | new_line = True
75 | else:
76 | new_line = False
77 |
78 | results.append(hex_value)
79 |
80 | full_hex = ''
81 | for result in results:
82 | full_hex += result
83 |
84 | return full_hex
85 |
86 |
87 | def print_ascii(string):
88 | '''
89 | Print string with ASCII color configuration
90 | '''
91 | if string.isspace():
92 | # Add a space to show colors on a non-ASCII line
93 | string = ' ' + string
94 | print(Fore.MAGENTA + Style.BRIGHT + string + Style.RESET_ALL)
95 |
96 |
97 | def print_hex(string):
98 | '''
99 | Print string with hex color configuration
100 | '''
101 | print(Fore.BLUE + Style.BRIGHT + string + Style.RESET_ALL)
102 |
103 |
104 | def print_error(string):
105 | '''
106 | Print string with error color configuration and exit with code 1
107 | '''
108 | print(Fore.RED + Style.BRIGHT + string + Style.RESET_ALL)
109 | exit(1)
110 |
111 |
112 | class ReadAsync(object):
113 | '''
114 | ReadAsync starts a queue thread to accept stdin
115 | '''
116 | def __init__(self, blocking_function, *args):
117 | self.args = args
118 |
119 | self.read = blocking_function
120 |
121 | self.thread = Thread(target=self.enqueue)
122 |
123 | self.queue = Queue()
124 |
125 | self.thread.daemon = True
126 |
127 | self.thread.start()
128 |
129 | def enqueue(self):
130 | while True:
131 | buffer = self.read(*self.args)
132 | self.queue.put(buffer)
133 |
134 | def dequeue(self):
135 | return self.queue.get_nowait()
136 |
137 |
138 | def description():
139 | '''
140 | argparse description text
141 | '''
142 | return '''
143 | Netbyte is a Netcat-style tool that facilitates probing proprietary TCP and UDP services.
144 | It is lightweight, fully interactive and provides formatted output in both hexadecimal and ASCII.'''
145 |
146 |
147 | def parse_arguments():
148 | '''
149 | Parse command line arguments
150 |
151 | Returns:
152 | argparse Namespace object
153 | '''
154 | parser = argparse.ArgumentParser(description=description(), formatter_class=argparse.RawTextHelpFormatter)
155 |
156 | parser.add_argument('hostname', metavar='HOSTNAME', help='Host or IP to connect to')
157 | parser.add_argument('port', metavar='PORT', help='Connection port')
158 | parser.add_argument('-u', dest='udp', action="store_true", default=False, help='Use UDP instead of default TCP')
159 |
160 | if len(sys.argv) == 1:
161 |
162 | parser.print_help()
163 |
164 | exit(1)
165 |
166 | args = parser.parse_args()
167 | return args
168 |
169 |
170 | def main():
171 | '''
172 | Main function: Connects to host/port and spawns ReadAsync
173 | '''
174 |
175 | args = parse_arguments()
176 |
177 | if args.udp:
178 | connection = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
179 | else:
180 | connection = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
181 |
182 | connection.settimeout(2)
183 |
184 | address = (args.hostname, int(args.port))
185 |
186 | try:
187 | connection.connect(address)
188 |
189 | except socket.error:
190 | print_error("Could not establish connection to " + address[0] + ":" + str(address[1]))
191 |
192 | print(Fore.GREEN + Style.BRIGHT + "Connection established" + Style.RESET_ALL)
193 |
194 | try:
195 | connection.setblocking(0)
196 | stdin = ReadAsync(sys.stdin.readline)
197 |
198 | while True:
199 | try:
200 | data = connection.recv(4096)
201 | if not data:
202 | raise socket.error
203 | print_ascii(data)
204 | print_hex(to_hex(data))
205 | except socket.error, e:
206 | if e.errno != errno.EWOULDBLOCK:
207 | raise
208 | try:
209 | connection.send(stdin.dequeue())
210 | except Empty:
211 | time.sleep(0.1)
212 |
213 | except KeyboardInterrupt:
214 | connection.close()
215 | print_error("\nExiting...")
216 | except socket.error:
217 | print_error("Connection closed")
--------------------------------------------------------------------------------
/setup.py:
--------------------------------------------------------------------------------
1 | from setuptools import setup
2 |
3 | setup(
4 | name='netbyte',
5 | version='0.5',
6 | url='http://www.sc0tfree.com',
7 | license='MIT License',
8 | author='sc0tfree',
9 | author_email='henry@sc0tfree.com',
10 | description='Netbyte is a Netcat-style tool that facilitates probing proprietary TCP and UDP services. It is lightweight, fully interactive and provides formatted output in both hexadecimal and ASCII.',
11 | keywords='utils cli netcat hexadecimal',
12 | packages=['netbyte'],
13 | install_requires=[
14 | 'colorama',
15 | ],
16 | entry_points = {
17 | "console_scripts" : ['netbyte = netbyte.netbyte:main']
18 | },
19 | )
20 |
--------------------------------------------------------------------------------
/testserver.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 |
3 | # Author: sc0tfree
4 | # Twitter: @sc0tfree
5 | # Email: henry@sc0tfree.com
6 |
7 | import os
8 | import socket
9 |
10 |
11 | def generate_random_hex(length):
12 | '''
13 | Generates a hex string of arbitrary length - 1, ending in a newline.
14 | '''
15 | hex_string = os.urandom(length - 1)
16 | hex_string += '\x0a'
17 | return hex_string
18 |
19 |
20 | host = '127.0.0.1'
21 | port = 12345
22 |
23 | s = socket.socket()
24 |
25 | s.bind((host, port))
26 |
27 | s.listen(5)
28 |
29 | try:
30 |
31 | while True:
32 |
33 | c, addr = s.accept()
34 |
35 | print 'Connection established from', addr[0], ':', addr[1]
36 |
37 | c.send('Hello from Test Server\n')
38 |
39 | # Echo Test
40 | c.send('Echo Test - enter string:')
41 | data = c.recv(1024)
42 | print 'Echo Test - received: ', data
43 | c.send('Echo Test - received: ' + data + '\n')
44 |
45 | # Hex Test
46 | c.send('Hex Test - enter length:')
47 | data = c.recv(1024)
48 |
49 | try:
50 | hex_length = int(data)
51 | except ValueError:
52 | c.send('You must enter a number. Defaulting to 10.\n')
53 | hex_length = 10
54 |
55 | hex_string = generate_random_hex(hex_length)
56 | c.send('Sending hex string...\n\n')
57 | print 'Hex Test - sending: ', hex_string
58 | c.send(hex_string)
59 |
60 | c.close()
61 | print 'Closed connection to ', addr[0], ':', addr[1]
62 |
63 | except KeyboardInterrupt:
64 | c.close()
65 | print '\nExiting...'
66 | exit(0)
67 |
--------------------------------------------------------------------------------