Skip to content

Commit 1eb5e3c

Browse files
committed
Version 0.2.1 - Impersonation
1 parent 4e2658e commit 1eb5e3c

File tree

9 files changed

+330
-294
lines changed

9 files changed

+330
-294
lines changed

CHANGELOG.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Release History
22

3-
## pyp0f 0.2.0
3+
## pyp0f 0.2.1
44

55
* Added impersonation utility.
66

README.md

Lines changed: 26 additions & 239 deletions
Original file line numberDiff line numberDiff line change
@@ -1,276 +1,63 @@
11
<h1 align="center">pyp0f</h1>
2-
<p align="center">
3-
<em>Native implementation of <strong>p0f v3</strong> in typed Python 3.</em>
4-
</p>
2+
<p align="center">Native implementation of <strong>p0f v3</strong> in typed Python 3.</p>
3+
4+
5+
---
6+
7+
**Documentation**: <a href="https://github.com/Nisitay/pyp0f/blob/master/docs/README.md" target="_blank">https://github.com/Nisitay/pyp0f/blob/master/docs/README.md</a>
8+
9+
**Source Code**: <a href="https://github.com/Nisitay/pyp0f" target="_blank">https://github.com/Nisitay/pyp0f</a>
510

611
---
712

813
`pyp0f` is able to accurately guess the source OS or user application of a given packet with passive fingerprinting, as well as impersonate packets so that `p0f` will think it has been sent by a specific OS.
914

1015
## Motivation
1116
- `pyp0f` is platform independent (using [Scapy](https://scapy.net)), while `p0f` can be cumbersome to run on some platforms (such as Windows).
12-
- The implementation and concepts behind `p0f` are very sophisticated, but the tool is written in C which makes it harder to understand and extend.
13-
Performance is expected to be slower in Python, but `pyp0f` still performs well enough (see [Performance benchmarks](#performance-benchmarks))
17+
- The implementation and concepts behind `p0f` are very sophisticated, but the tool is written in C which makes it harder to understand and extend. Performance is expected to be slower in Python, but `pyp0f` still performs well enough (see [Performance benchmarks](https://github.com/Nisitay/pyp0f/blob/master/docs/README.md#performance-benchmarks))
1418
- `p0f` heavily depends on full packet flow details, while `pyp0f` attempts to use as little information as possible. For example, you may be able to fingerprint a SYN+ACK packet from a session without having the matching SYN packet.
1519
- `pyp0f` aims to be highly configurable and used as a library, without limiting its effectiveness to one packet format/library, as opposed to `p0f` which runs on a seperate process and you query the results using an API.
1620

1721
## Installation
18-
1922
```console
2023
$ pip install pyp0f
2124
```
2225

2326
## Features
24-
- [X] Full p0f fingerprinting (MTU, TCP, HTTP)
25-
- [X] p0f spoof - impersonation (MTU, TCP)
26-
- [ ] Flow tracking (In progress)
27-
- [ ] TCP uptime detection (In progress)
28-
- [ ] NAT detection (In progress)
29-
30-
## Docs
31-
* [Database configuration](#database-configuration)
32-
* [Fingerprinting](#fingerprinting)
33-
* [Impersonation](#impersonation)
34-
* [Real world examples](#real-world-examples)
35-
* [Sniff connection attempts](#sniff-connection-attempts)
36-
* [Block connections by certain OS fingerprint](#block-connections-by-certain-os-fingerprint)
37-
* [Spoof p0f with impersonation](#spoof-p0f-with-impersonation)
38-
* [Performance benchmarks](#performance-benchmarks)
27+
- Full p0f fingerprinting (MTU, TCP, HTTP)
28+
- p0f spoofing - impersonation (MTU, TCP)
3929

40-
## Database Configuration
41-
Before using `pyp0f`, make sure to load the p0f signatures database.
42-
43-
By default, the included (p0f v3.09b) database will be loaded. However, you can specify a custom database path to parse.
30+
## In Progress
31+
- Flow tracking
32+
- TCP uptime detection
33+
- NAT detection
4434

35+
## Getting Started
4536
```python
37+
from scapy.layers.inet import IP, TCP
4638
from pyp0f.database import DATABASE
39+
from pyp0f.fingerprint import fingerprint_mtu, fingerprint_tcp, fingerprint_http
40+
from pyp0f.fingerprint.results import MTUResult, TCPResult, HTTPResult
4741

48-
DATABASE.load() # or DATABASE.load("custom/database/file/p0f.fp")
49-
```
50-
51-
## Fingerprinting
52-
`pyp0f` accepts SYN, SYN+ACK and HTTP packets. Invalid packets raise `pyp0f.exceptions.PacketError`.
53-
54-
`pyp0f` makes sure to copy the packet before using it, to not modify the original accidentally.
55-
56-
Each fingerprint function returns a custom result instance which includes some informative fields that are typed appropriately.
57-
58-
<details markdown="1">
59-
<summary>MTU fingerprinting example</summary>
60-
61-
```python
62-
from scapy.layers.inet import IP, TCP
63-
from pyp0f.fingerprint import fingerprint_mtu
64-
from pyp0f.fingerprint.results import MTUResult
42+
DATABASE.load() # Load the fingerprints database
6543

44+
# MTU Fingerprinting
6645
google_packet = IP() / TCP(options=[("MSS", 1430)])
67-
result: MTUResult = fingerprint_mtu(google_packet)
68-
print(result.packet_signature) # MTUPacketSignature(mtu=1470)
69-
print(result.match)
70-
# MTURecord(
71-
# label=MTULabel(name="Google"),
72-
# signature=MTUSignature(mtu=1470),
73-
# raw_signature="1470",
74-
# line_number=67,
75-
# )
76-
```
77-
78-
</details>
79-
80-
<details markdown="1">
81-
<summary>TCP fingerprinting example</summary>
82-
83-
```python
84-
from scapy.layers.inet import IP, TCP
85-
from pyp0f.fingerprint import fingerprint_tcp
86-
from pyp0f.fingerprint.results import TCPResult
46+
mtu_result: MTUResult = fingerprint_mtu(google_packet)
8747

48+
# TCP Fingerprinting
8849
linux_packet = IP(tos=0x10, flags=0x02, ttl=58) / TCP(
8950
seq=1,
9051
window=29200,
9152
options=[("MSS", 1460), ("SAckOK", b""), ("Timestamp", (177816630, 0)), ("NOP", None), ("WScale", 7)],
9253
)
93-
result: TCPResult = fingerprint_tcp(linux_packet)
94-
print(result.distance) # 6
95-
print(result.match)
96-
# TCPMatch(
97-
# type=<TCPMatchType.EXACT: 1>,
98-
# record=TCPRecord(
99-
# label=Label(name='Linux', is_generic=False, os_class='unix', flavor='3.11 and newer', sys=()),
100-
# signature=TCPSignature(
101-
# ip_version=-1,
102-
# ip_options_length=0,
103-
# ttl=64,
104-
# is_bad_ttl=False,
105-
# window=WindowSignature(type=<WindowType.MSS: 4>, size=20, scale=7),
106-
# options=OptionsSignature(
107-
# layout=[<TCPOption.MSS: 2>, <TCPOption.SACKOK: 4>, <TCPOption.TS: 8>, <TCPOption.NOP: 1>, <TCPOption.WS: 3>],
108-
# mss=-1,
109-
# eol_padding_length=0
110-
# ),
111-
# payload_class=0,
112-
# quirks=<Quirk.NZ_ID|DF: 6>
113-
# ),
114-
# raw_signature='*:64:0:*:mss*20,7:mss,sok,ts,nop,ws:df,id+:0',
115-
# line_number=97
116-
# )
117-
# )
118-
```
119-
120-
</details>
121-
122-
<details markdown="1">
123-
<summary>HTTP fingerprinting example</summary>
124-
125-
```python
126-
from pyp0f.fingerprint import fingerprint_http
127-
from pyp0f.fingerprint.results import HTTPResult
54+
tcp_result: TCPResult = fingerprint_tcp(linux_packet)
12855

56+
# HTTP Fingerprinting
12957
apache_payload = b"HTTP/1.1 200 OK\r\nDate: Fri, 10 Jun 2011 13:27:01 GMT\r\nServer: Apache\r\nLast-Modified: Thu, 09 Jun 2011 17:25:43 GMT\r\nExpires: Mon, 13 Jun 2011 17:25:43 GMT\r\nETag: 963D6BC0ED128283945AF1FB57899C9F3ABF50B3\r\nCache-Control: max-age=272921,public,no-transform,must-revalidate\r\nContent-Length: 491\r\nConnection: close\r\nContent-Type: application/ocsp-response\r\n\r\n"
130-
result: HTTPResult = fingerprint_http(apache_payload)
131-
print(result.dishonest) # False
132-
print(result.match)
133-
# HTTPRecord(
134-
# label=Label(
135-
# name="Apache",
136-
# is_generic=False,
137-
# os_class="!",
138-
# flavor="2.x",
139-
# sys=("@unix", "Windows"),
140-
# ),
141-
# signature=HTTPSignature(
142-
# version=1,
143-
# headers=[
144-
# SignatureHeader(
145-
# name=b"Date", lower_name=b"date", is_optional=False, value=None
146-
# ),
147-
# SignatureHeader(
148-
# name=b"Server", lower_name=b"server", is_optional=False, value=None
149-
# ),
150-
# ...
151-
# ],
152-
# expected_software=b"Apache",
153-
# absent_headers={b"keep-alive"},
154-
# ...
155-
# ),
156-
# raw_signature="1:Date,Server,?Last-Modified,?Accept-Ranges=[bytes],?Content-Length,?Connection=[close],?Transfer-Encoding=[chunked],Content-Type:Keep-Alive:Apache",
157-
# line_number=883,
158-
# )
58+
http_result: HTTPResult = fingerprint_http(apache_payload)
15959
```
16060

161-
</details>
162-
163-
## Impersonation
164-
`pyp0f` provides functionality to modify Scapy packets so that `p0f` will think it has been sent by a specific OS.
165-
166-
Each impersonation method must be provided with a record label or signature to impersonate.
167-
168-
<details markdown="1">
169-
<summary>MTU impersonation example</summary>
170-
171-
```python
172-
from scapy.layers.inet import IP, TCP
173-
from pyp0f.impersonate import impersonate_mtu
174-
from pyp0f.fingerprint import fingerprint_mtu
175-
176-
impersonated_packet = impersonate_mtu(
177-
IP() / TCP(),
178-
raw_label="generic tunnel or VPN", # impersonate using a label
179-
raw_signature="1300", # or using a signature
180-
)
181-
result = fingerprint_mtu(impersonated_packet) # MTUResult for "generic tunnel or VPN"
182-
```
183-
184-
</details>
185-
186-
187-
<details markdown="1">
188-
<summary>TCP impersonation example</summary>
189-
190-
```python
191-
from scapy.layers.inet import IP, TCP
192-
from pyp0f.impersonate import impersonate_tcp
193-
from pyp0f.fingerprint import fingerprint_tcp
194-
195-
impersonated_packet = impersonate_tcp(
196-
IP() / TCP(),
197-
raw_label="s:unix:OpenVMS:7.x", # impersonate using a label
198-
raw_signature="4:64:0:1460:61440,0:mss,nop,ws::0", # or using a signature
199-
)
200-
result = fingerprint_tcp(impersonated_packet) # TCPResult for "s:unix:OpenVMS:7.x"
201-
```
202-
203-
</details>
204-
205-
## Real World Examples
206-
`pyp0f` can be used in real world scenarios, whether its to passivly fingerprint remote hosts,
207-
or to deceive remote `p0f`.
208-
209-
### Sniff connection attempts
210-
Using `scapy` to sniff incoming packets, we passively fingerprint remote hosts attempting to connect to our HTTP server.
211-
212-
See example [source code](./examples/fingerprint/scapy-sniff.py)
213-
214-
### Block connections by certain OS fingerprint
215-
With `pyp0f.fingerprint` we can block certain OS users attempting to connect to our HTTP server (in this example - Windows).
216-
217-
We use `pydivert` to capture incoming packets before they enter the network stack, fingerprint them, and drop every connection attempt to our server from Windows hosts.
218-
219-
See example [source code](./examples/fingerprint/block-os.py)
220-
221-
### Spoof p0f with impersonation
222-
With `pyp0f.impersonate` we can spoof running p0f by impersonating a certain OS.
223-
224-
In this case, I used Windows 10 with Ethernet, and impersonated Linux 2.2.x-3.x (barebone) with Google MTU.
225-
226-
[Browser leaks (TCP/IP Fingerprint section)](https://browserleaks.com/ip):
227-
<div align="center">
228-
<img src="./docs/images/browserleaks-normal.PNG">
229-
<img src="./docs/images/browserleaks-spoof.PNG">
230-
</div>
231-
232-
Local Ubuntu VM running p0f:
233-
<div align="center">
234-
<img src="./docs/images/p0f-normal.PNG">
235-
<img src="./docs/images/p0f-spoof.PNG">
236-
</div>
237-
238-
We use `pydivert` to capture packets before they leave the network stack, create a new packet that impersonates an OS, and finally re-inject the impersonated packet back to the network stack to spoof p0f on the other end.
239-
240-
See example [source code](./examples/impersonate/spoof-p0f.py)
241-
242-
## Performance benchmarks
243-
`pyp0f` includes a file to benchmark the main methods it provides - fingerprint, impersonate.
244-
The latest results were ran using an i5 7th gen.
245-
246-
```console
247-
Performance benchmark: Load Database
248-
Ran 1000 iterations in 9.76s
249-
Average time for one iteration of Load Database: 9ms
250-
-----------------------------------
251-
Performance benchmark: MTU Fingerprint (25 Packets)
252-
Ran 1000 iterations in 19.808s
253-
Average time for one iteration of MTU Fingerprint (25 Packets): 19ms
254-
-----------------------------------
255-
Performance benchmark: TCP Fingerprint (153 Packets)
256-
Ran 1000 iterations in 227.91s
257-
Average time for one iteration of TCP Fingerprint (153 Packets): 227ms
258-
-----------------------------------
259-
Performance benchmark: HTTP Fingerprint (3 Packets)
260-
Ran 1000 iterations in 0.15791s
261-
Average time for one iteration of HTTP Fingerprint (3 Packets): 0ms
262-
-----------------------------------
263-
Performance benchmark: MTU Impersonation (25 Signatures)
264-
Ran 1000 iterations in 4.5696s
265-
Average time for one iteration of MTU Impersonation (25 Signatures): 4ms
266-
-----------------------------------
267-
Performance benchmark: TCP Impersonation (153 Signatures)
268-
Ran 1000 iterations in 103.97s
269-
Average time for one iteration of TCP Impersonation (153 Signatures): 103ms
270-
```
271-
272-
See benchmark [source code](./scripts/benchmark.py)
273-
27461
## Sources
27562
- [p0f source code](https://github.com/p0f/p0f)
27663
- [Scapy docs & source code](https://scapy.net)

0 commit comments

Comments
 (0)