Address
304 North Cardinal St.
Dorchester Center, MA 02124
Work Hours
Monday to Friday: 7AM - 7PM
Weekend: 10AM - 5PM
Address
304 North Cardinal St.
Dorchester Center, MA 02124
Work Hours
Monday to Friday: 7AM - 7PM
Weekend: 10AM - 5PM
I know that I haven’t released anything in a while, but I’d like to introduce IpExpander v1.0.
The need for IpExpander arose from the fact that clients will use different conventions when submitting IP addresses that are in scope for engagements. Sometimes I will get a list of individual IPs, sometimes the file has both IPs and CIDRs, and sometimes it is a “range” (i.e.: 192.168.0.1-165). While most tools can handle these various formats, some cannot. In these situations, I’ve found it useful to just have a list of individual IP addresses to prevent issues.
First, I tried to see if there were any open source libraries that would solve this problem for me.
The netaddr library came pretty close, and supports everything but the ranges that I was dealing with.
In this case, I decided to install the module and use it as the basis for my tool.
Rays-MacBook-Pro:Documents doyler$ pip install netaddr Collecting netaddr Downloading netaddr-0.7.19-py2.py3-none-any.whl (1.6MB) 100% |################################| 1.6MB 423kB/s Installing collected packages: netaddr Successfully installed netaddr-0.7.19
Next, I read through the tutorial to understand the library and what I could or couldn’t do with it.
With the library installed, I decided to play around with it a bit to get a better feel for it.
First, I worked out what was acceptable as an IP address.
Python 2.7.11 (v2.7.11:6d1b6a68f775, Dec 5 2015, 20:32:19) [MSC v.1500 32 bit (Intel)] on win32 Type "copyright", "credits" or "license()" for more information. >>> from netaddr import * import pprint >>> ip = IPAddress('192.0.5.1') >>> ip IPAddress('192.0.5.1') >>> ip2 = IPAddress('192.168.5.0/24') Traceback (most recent call last): File "", line 1, in ip2 = IPAddress('192.168.5.0/24') File "C:\Python27\Lib\site-packages\netaddr\ip\__init__.py", line 280, in __init__ % self.__class__.__name__) ValueError: IPAddress() does not support netmasks or subnet prefixes! See documentation for details.
Next, I used the list functionality to verify that it would handle CIDR addresses as expected.
>>> ip_list = list(IPNetwork('192.168.5.0/24')) >>> ip_list [IPAddress('192.168.5.0'), IPAddress('192.168.5.1'), IPAddress('192.168.5.2'), IPAddress('192.168.5.3'), IPAddress('192.168.5.4'), IPAddress('192.168.5.5'), IPAddress('192.168.5.6'), IPAddress('192.168.5.7'), IPAddress('192.168.5.8'), IPAddress('192.168.5.9'), IPAddress('192.168.5.10'), IPAddress('192.168.5.11'), IPAddress('192.168.5.12'), IPAddress('192.168.5.13'), IPAddress('192.168.5.14'), IPAddress('192.168.5.15') ...
Finally, I tried to see if it would support my hyphenated ranges out of the box.
>>> ip_list = list(IPNetwork('192.168.5.1-100')) Traceback (most recent call last): File "", line 1, in ip_list = list(IPNetwork('192.168.5.1-100')) File "C:\Python27\Lib\site-packages\netaddr\ip\__init__.py", line 938, in __init__ raise AddrFormatError('invalid IPNetwork %s' % addr) AddrFormatError: invalid IPNetwork 192.168.5.1-100
With a better understanding for the library, I wrote up my IpExpander script.
This will take in an input file of IP addresses, CIDRs, and ranges and output a file with one IP address per line.
Note that it will only support ranges where the last octet has a hyphen, and not any others yet.
from netaddr import * import pprint def isIP(inLine): try: ip = IPAddress(inLine) except: return False return True def isCIDR(inLine): try: ip_list = IPNetwork(inLine) except: return False return True def expandCIDR(inCIDR): return list(IPNetwork(inCIDR)) def isRange(inLine): if "-" in inLine: return True else: return False def expandRange(inRange): splitRange = inRange.split("-") try: startIP = IPAddress(splitRange[0]) except: print "***** ERROR *****: " + splitRange[0] endRange = splitRange[1] try: int(endRange) if int(endRange) <= 255: endNet = str(IPNetwork(str(startIP).strip() + '/24').network) endIP = endNet.rsplit(".", 1)[0] + "." + endRange else: print "***** ERROR *****: " + endRange except ValueError: try: endIP = IPAddress(endRange) except: print "***** ERROR *****: " + splitRange[0] return list(iter_iprange(startIP, endIP)) def getTargets(inFile): with open(inFile) as f: lines = f.readlines() return lines def newFile(outList, fileName): with open(fileName.split(".")[0] + "-expanded.txt", "w") as text_file: for addr in outList: text_file.write(str(addr) + "\n") def main(): inFile = "external-targets.txt" lines = getTargets(inFile) finalList = [] for line in lines: line = line.strip() if isIP(line): finalList.append(IPAddress(line)) elif isCIDR(line): expanded = expandCIDR(line) finalList.extend(expanded) elif isRange(line): expanded = expandRange(line) finalList.extend(expanded) else: print "***** ERROR *****: " + line newFile(sorted(finalList), inFile) if __name__ == '__main__': main()
When I tested the script on my engagement, it worked, and I expanded my target list to 385 individual IP addresses!
Rays-MacBook-Pro:Documents doyler$ wc -l external-targets.txt 47 external-targets.txt Rays-MacBook-Pro:Documents doyler$ python ipExpander.py Rays-MacBook-Pro:Documents doyler$ wc -l external-targets-expanded.txt 385 external-targets-expanded.txt
Let me know if you have any questions, comments, suggestions, or ideas!
For now, I know that I'd like to have v1.1 support even crazier ranges (192.168.0-5.10-45).
Finally, you can find the code and updates in my GitHub repository.
Ray Doyle is an avid pentester/security enthusiast/beer connoisseur who has worked in IT for almost 16 years now. From building machines and the software on them, to breaking into them and tearing it all down; he’s done it all. To show for it, he has obtained an OSCE, OSCP, eCPPT, GXPN, eWPT, eWPTX, SLAE, eMAPT, Security+, ICAgile CP, ITIL v3 Foundation, and even a sabermetrics certification!
He currently serves as a Senior Staff Adversarial Engineer for Avalara, and his previous position was a Principal Penetration Testing Consultant for Secureworks.
This page contains links to products that I may receive compensation from at no additional cost to you. View my Affiliate Disclosure page here. As an Amazon Associate, I earn from qualifying purchases.