Skip to content

Commit ac33a70

Browse files
authored
Port FakeNet to Python 3 (#157)
* Port FakeNet to Python 3 * Migrate diverters, listeners and other components to Python 3 * Retire BITS listener for now * Fix hard-coded FakeNet path for linux platform in test.py * Update README and developement documentation * Add copyright notice to modified files * Update FakeNet-NG version
1 parent 68da2d7 commit ac33a70

33 files changed

+432
-901
lines changed

CHANGELOG.txt

+8
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,11 @@
1+
Version 3.0 (alpha)
2+
-----------
3+
* Migrate diverters, listeners and other components to Python 3
4+
* Retire BITS listener for now
5+
* Fix hard-coded FakeNet path for linux platform in test.py
6+
* Update README and developement documentation
7+
* Add copyright notice to modified files
8+
19
Version 1.4.13
210
--------------
311
* Port test scripts to Python 3

README.md

+7-24
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,3 @@
1-
Development Suspended
2-
=====================
3-
4-
The FLARE Team must suspend development and maintenance of FakeNet-NG for the
5-
time being.
6-
7-
FLARE has opted to indicate the project status here instead of archiving the
8-
project. This will allow users and maintainers to continue to log issues
9-
documenting valuable information about problems, troubleshooting, and
10-
work-arounds.
11-
12-
Original Documentation Follows
13-
==============================
141
______ _ ________ _ _ ______ _______ _ _ _____
152
| ____/\ | |/ / ____| \ | | ____|__ __| | \ | |/ ____|
163
| |__ / \ | ' /| |__ | \| | |__ | |______| \| | | __
@@ -20,7 +7,7 @@ Original Documentation Follows
207

218
D O C U M E N T A T I O N
229

23-
FakeNet-NG is a next generation dynamic network analysis tool for malware
10+
FakeNet-NG 3.0 (alpha) is a next generation dynamic network analysis tool for malware
2411
analysts and penetration testers. It is open source and designed for the latest
2512
versions of Windows (and Linux, for certain modes of operation). FakeNet-NG is
2613
based on the excellent Fakenet tool developed by Andrew Honig and Michael
@@ -57,10 +44,6 @@ analysis machine.
5744

5845
Installing module
5946
-----------------
60-
61-
Installation on Windows requires the following dependency:
62-
* [Microsoft Visual C++ Compiler for Python 2.7](https://aka.ms/vcpython27)
63-
6447
Installation on Linux requires the following dependencies:
6548
* Python pip package manager (e.g. python-pip for Ubuntu).
6649
* Python development files (e.g. python-dev for Ubuntu).
@@ -94,7 +77,7 @@ Finally if you would like to avoid installing FakeNet-NG and just want to run it
9477
as-is (e.g. for development), then you would need to obtain the source code and
9578
install dependencies as follows:
9679

97-
1) Install 64-bit or 32-bit Python 2.7.x for the 64-bit or 32-bit versions
80+
1) Install 64-bit or 32-bit Python 3.7.x for the 64-bit or 32-bit versions
9881
of Windows respectively.
9982

10083
2) Install Python dependencies:
@@ -116,7 +99,7 @@ install dependencies as follows:
11699
Execute FakeNet-NG by running it with a Python interpreter in a privileged
117100
shell:
118101

119-
python fakenet.py
102+
python -m fakenet.fakenet
120103

121104
Usage
122105
=====
@@ -133,12 +116,12 @@ parameter to get simple help:
133116
| | / ____ \| . \| |____| |\ | |____ | | | |\ | |__| |
134117
|_|/_/ \_\_|\_\______|_| \_|______| |_| |_| \_|\_____|
135118

136-
Version 1.0
119+
Version 3.0 (alpha)
137120
_____________________________________________________________
138121
Developed by FLARE Team
139-
Copyright (C) 2016-2022 Mandiant, Inc. All rights reserved.
122+
Copyright (C) 2016-2023 Mandiant, Inc. All rights reserved.
140123
_____________________________________________________________
141-
Usage: fakenet.py [options]:
124+
Usage: python -m fakenet.fakenet [options]:
142125

143126
Options:
144127
-h, --help show this help message and exit
@@ -188,7 +171,7 @@ and an HTTP connection:
188171
| | / ____ \| . \| |____| |\ | |____ | | | |\ | |__| |
189172
|_|/_/ \_\_|\_\______|_| \_|______| |_| |_| \_|\_____|
190173

191-
Version 1.0
174+
Version 3.0 (alpha)
192175
_____________________________________________________________
193176
Developed by FLARE Team
194177
Copyright (C) 2016-2022 Mandiant, Inc. All rights reserved.

docs/srs.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ currently implemented in any FakeNet-NG release), and `Auto`.
116116
### Configuration Settings and Sections
117117
The configuration file used on each platform must conform to the format used by
118118
the others. As of this writing, it is based on the Python
119-
[ConfigParser](https://docs.python.org/2/library/configparser.html) package,
119+
[ConfigParser](https://docs.python.org/3/library/configparser.html) package,
120120
which is similar to an INI file.
121121

122122
### Quick Glossary of Miscellaneous Terms

docs/testing.md

+3-2
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ into `pytest`, that is fine, but the current script serves.
127127
The salient peculiarity of `test.py` is that on Windows it requires you to
128128
install FakeNet and it then runs the global `fakenet.exe` script entry point
129129
available via the Windows path environment variable; and on Linux, it executes
130-
`python fakenet.py` directly. Alas, this is for purely undocumented and
130+
`python -m fakenet.fakenet` directly. Alas, this is for purely undocumented and
131131
forgettable reasons. It shouldn't be too difficult to make these consistent if
132132
that becomes important to someone.
133133

@@ -210,7 +210,8 @@ modes, and clients:
210210

211211
In each combination, FakeNet must be tested against the full range of
212212
applicable tests in the Automated Test Suite provided by the test script
213-
`test/test.py`.
213+
`test/test.py`. It should be noted that some tests are expected to output
214+
errors such as socket errors even when the tests are successful.
214215

215216
As of this writing, the Manual Test Suite must also be executed if the FakeNet
216217
feature set is to be fully exercised for quality assurance of a given release.

fakenet/configs/CustomProviderExample.py

+7-5
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
# Copyright (C) 2016-2023 Mandiant, Inc. All rights reserved.
2+
13
import socket
24

35
# To read about customizing HTTP responses, see docs/CustomResponse.md
@@ -14,7 +16,7 @@ def HandleRequest(req, method, post_data=None):
1416
The HTTP post data received by calling `rfile.read()` against the
1517
BaseHTTPRequestHandler that received the request.
1618
"""
17-
response = 'Ahoy\r\n'
19+
response = b'Ahoy\r\n'
1820

1921
if method == 'GET':
2022
req.send_response(200)
@@ -51,8 +53,8 @@ def HandleTcp(sock):
5153
if not data:
5254
break
5355

54-
resp = raw_input('\nEnter a response for the TCP client: ')
55-
sock.sendall(resp)
56+
resp = input('\nEnter a response for the TCP client: ')
57+
sock.sendall(resp.encode())
5658

5759

5860
def HandleUdp(sock, data, addr):
@@ -68,5 +70,5 @@ def HandleUdp(sock, data, addr):
6870
The host and port of the remote peer
6971
"""
7072
if data:
71-
resp = raw_input('\nEnter a response for the UDP client: ')
72-
sock.sendto(resp, addr)
73+
resp = input('\nEnter a response for the UDP client: ')
74+
sock.sendto(resp.encode(), addr)

fakenet/configs/default.ini

+1-2
Original file line numberDiff line numberDiff line change
@@ -178,7 +178,6 @@ BlackListPortsUDP: 67, 68, 137, 138, 443, 1900, 5355
178178
# * Webroot - Set webroot path for HTTPListener.
179179
# * DumpHTTPPosts - Store HTTP Post requests for the HTTPListener.
180180
# * DumpHTTPPostsFilePrefix - File prefix for the stored HTTP Post requests used by the HTTPListener.
181-
# * BITSFilePrefix - File prefix for the stored BITS uploads used by the BITSListener.
182181
# * TFTPFilePrefix - File prefix for the stored tftp uploads used by the TFTPListener.
183182
# * DNSResponse - IP address to respond with for A record DNS queries. (DNSListener)
184183
# * NXDomains - A number of DNS requests to ignore to let the malware cycle through
@@ -206,7 +205,7 @@ Enabled: True
206205
Protocol: TCP
207206
Listener: ProxyListener
208207
Port: 38926
209-
Listeners: HTTPListener, RawListener, FTPListener, DNSListener, POPListener, SMTPListener, TFTPListener, IRCListener, BITSListener
208+
Listeners: HTTPListener, RawListener, FTPListener, DNSListener, POPListener, SMTPListener, TFTPListener, IRCListener
210209
Hidden: False
211210

212211
[ProxyUDPListener]

fakenet/diverters/debuglevels.py

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
# Copyright (C) 2016-2023 Mandiant, Inc. All rights reserved.
2+
13
# Debug print levels for fine-grained debug trace output control
24
DNFQUEUE = (1 << 0) # netfilterqueue
35
DGENPKT = (1 << 1) # Generic packet handling
@@ -39,4 +41,4 @@
3941
DMISC: 'MISC',
4042
}
4143

42-
DLABELS_INV = {v.upper(): k for k, v in DLABELS.iteritems()}
44+
DLABELS_INV = {v.upper(): k for k, v in DLABELS.items()}

fakenet/diverters/diverterbase.py

+13-6
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
# Copyright (C) 2016-2023 Mandiant, Inc. All rights reserved.
2+
13
import os
24
import abc
35
import sys
@@ -10,7 +12,7 @@
1012
import subprocess
1113
from . import fnpacket
1214
from . import fnconfig
13-
from debuglevels import *
15+
from .debuglevels import *
1416
from collections import namedtuple
1517
from collections import OrderedDict
1618

@@ -92,7 +94,7 @@ def first_packet_new_session(self):
9294
(self.pkt.dst_ip, self.pkt.dport))
9395

9496

95-
class DiverterPerOSDelegate(object):
97+
class DiverterPerOSDelegate(object, metaclass=abc.ABCMeta):
9698
"""Delegate class for OS-specific methods that FakeNet-NG implementors must
9799
override.
98100
@@ -105,7 +107,6 @@ class DiverterPerOSDelegate(object):
105107
check_gateways (currently only a warning)
106108
check_dns_servers (currently only a warning)
107109
"""
108-
__metaclass__ = abc.ABCMeta
109110

110111
@abc.abstractmethod
111112
def check_active_ethernet_adapters(self):
@@ -332,7 +333,7 @@ def isHidden(self, proto, port):
332333

333334
def getPortList(self, proto):
334335
if proto in self.protos:
335-
return self.protos[proto].keys()
336+
return list(self.protos[proto].keys())
336337
return []
337338

338339
def intersectsWithPorts(self, proto, ports):
@@ -540,7 +541,7 @@ def __init__(self, diverter_config, listeners_config, ip_addrs,
540541
stringlists = ['HostBlackList']
541542
self.configure(diverter_config, portlists, stringlists)
542543
self.listeners_config = dict((k.lower(), v)
543-
for k, v in listeners_config.iteritems())
544+
for k, v in listeners_config.items())
544545

545546
# Local IP address
546547
self.external_ip = socket.gethostbyname(socket.gethostname())
@@ -773,7 +774,7 @@ def parse_listeners_config(self, listeners_config):
773774

774775
#######################################################################
775776
# Populate diverter ports and process filters from the configuration
776-
for listener_name, listener_config in listeners_config.iteritems():
777+
for listener_name, listener_config in listeners_config.items():
777778

778779
if 'port' in listener_config:
779780

@@ -1238,6 +1239,12 @@ def formatPkt(self, pkt, pid, comm):
12381239
Returns:
12391240
A str containing the log line
12401241
"""
1242+
if pid == None:
1243+
pid = 'None'
1244+
1245+
if comm == None:
1246+
comm = 'None'
1247+
12411248
logline = ''
12421249

12431250
if pkt.proto == 'UDP':

fakenet/diverters/fnconfig.py

+6-4
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
# Copyright (C) 2016-2023 Mandiant, Inc. All rights reserved.
2+
13
class Config(object):
24
"""Configuration primitives.
35
@@ -19,7 +21,7 @@ def configure(self, config_dict, portlists=[], stringlists=[]):
1921
2.) Turn string lists into arrays for quicker access
2022
3.) Expand port range specifications
2123
"""
22-
self._dict = dict((k.lower(), v) for k, v in config_dict.iteritems())
24+
self._dict = dict((k.lower(), v) for k, v in config_dict.items())
2325

2426
for entry in portlists:
2527
portlist = self.getconfigval(entry)
@@ -51,8 +53,8 @@ def _expand_ports(self, ports_list):
5153
if '-' not in i:
5254
ports.append(int(i))
5355
else:
54-
l, h = map(int, i.split('-'))
55-
ports += range(l, h + 1)
56+
l, h = list(map(int, i.split('-')))
57+
ports += list(range(l, h + 1))
5658
return ports
5759

5860
def _fuzzy_true(self, value):
@@ -62,7 +64,7 @@ def _fuzzy_false(self, value):
6264
return value.lower() in ['no', 'off', 'false', 'disable', 'disabled']
6365

6466
def is_configured(self, opt):
65-
return opt.lower() in self._dict.keys()
67+
return opt.lower() in list(self._dict.keys())
6668

6769
def is_unconfigured(self, opt):
6870
return not self.is_configured(opt)

fakenet/diverters/fnpacket.py

+4-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
1+
# Copyright (C) 2016-2023 Mandiant, Inc. All rights reserved.
2+
13
import dpkt
24
import socket
35
import logging
4-
import debuglevels
6+
from . import debuglevels
57

68

79
class PacketCtx(object):
@@ -64,7 +66,7 @@ def __init__(self, label, raw):
6466
self.dkey = None
6567

6668
# Parse as much as possible
67-
self.ipver = ((ord(self._raw[0]) & 0xf0) >> 4)
69+
self.ipver = ((self._raw[0] & 0xf0) >> 4)
6870
if self.ipver == 4:
6971
self._parseIpv4()
7072
elif self.ipver == 6:

fakenet/diverters/linutil.py

+8-6
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
# Copyright (C) 2016-2023 Mandiant, Inc. All rights reserved.
2+
13
import os
24
import re
35
import glob
@@ -8,7 +10,7 @@
810
import threading
911
import subprocess
1012
import netfilterqueue
11-
from debuglevels import *
13+
from .debuglevels import *
1214
from collections import defaultdict
1315
from . import diverterbase
1416

@@ -263,7 +265,7 @@ class LinUtilMixin(diverterbase.DiverterPerOSDelegate):
263265

264266
def init_linux_mixin(self):
265267
self.old_dns = None
266-
self.iptables_captured = ''
268+
self.iptables_captured = b''
267269

268270
def getNewDestinationIp(self, ip):
269271
"""On Linux, FTP tests fail if IP redirection uses the external IP, so
@@ -294,18 +296,18 @@ def fix_dns(self):
294296
return False
295297

296298
def linux_capture_iptables(self):
297-
self.iptables_captured = ''
299+
self.iptables_captured = b''
298300
ret = None
299301

300302
try:
301303
p = subprocess.Popen(['iptables-save'], stdout=subprocess.PIPE)
302304
while True:
303305
buf = p.stdout.read()
304-
if buf == '':
306+
if buf == b'':
305307
break
306308
self.iptables_captured += buf
307309

308-
if self.iptables_captured == '':
310+
if self.iptables_captured == b'':
309311
self.logger.warning('Null iptables-save output, likely not ' +
310312
'privileged')
311313
ret = p.wait()
@@ -397,7 +399,7 @@ def linux_get_next_nfqueue_numbers(self, n):
397399
existing_queues = self.linux_get_current_nfnlq_bindings()
398400

399401
next_qnos = list()
400-
for qno in xrange(QNO_MAX + 1):
402+
for qno in range(QNO_MAX + 1):
401403
if qno not in existing_queues:
402404
next_qnos.append(qno)
403405
if len(next_qnos) == n:

fakenet/diverters/linux.py

+5-3
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
# Copyright (C) 2016-2023 Mandiant, Inc. All rights reserved.
2+
13
import sys
24
import dpkt
35
import time
@@ -7,10 +9,10 @@
79
import threading
810
import subprocess
911
import netfilterqueue
10-
from linutil import *
12+
from .linutil import *
1113
from . import fnpacket
12-
from debuglevels import *
13-
from diverterbase import *
14+
from .debuglevels import *
15+
from .diverterbase import *
1416
from collections import namedtuple
1517
from netfilterqueue import NetfilterQueue
1618

0 commit comments

Comments
 (0)