Unit 1: Python for defenders · Lesson 2 of 6 · 18 min
Strings, lists and dictionaries
Cut one inventory line into fields and file them under names you can query.
mission
- You are
- the engineer asked to review exposed services
- Situation
- The inventory is one text line per host. Before you can check anything at scale you need to turn a line into data Python understands.
- Goal
- Turn the legacy01 line into a dictionary and read its open ports.
- Hand in
- The number of open ports on legacy01.
A line through the sorting rack
Find the line
grep legacy01 data/inventory.txt
legacy01 file centos-7 21,22,23,111,445,2049,3306
you should see Four fields separated by spaces: name, role, operating system and ports.
Split the string into a list
split() cuts on whitespace and returns a list. Unpacking names each piece in one line.
line = 'legacy01 file centos-7 21,22,23,111,445,2049,3306' line.split() ['legacy01', 'file', 'centos-7', '21,22,23,111,445,2049,3306'] name, role, system, ports = line.split() ports '21,22,23,111,445,2049,3306' ports.split(',') ['21', '22', '23', '111', '445', '2049', '3306']
you should see The ports start as one string, then become a list of strings.
File the fields in a dictionary
A dict gives each value a name, so code reads host['ports'] instead of remembering positions.
line = 'legacy01 file centos-7 21,22,23,111,445,2049,3306' name, role, system, ports = line.split() host = {'name': name, 'role': role, 'os': system, 'ports': ports.split(',')} host['os'] 'centos-7' len(host['ports']) 7 '23' in host['ports'] True 23 in host['ports'] False
you should see '23' in is True but 23 in is False: the ports are text, not numbers.
defender tip Convert with int() as soon as you parse, or every later comparison gets this wrong.
Convert ports to numbers
ports = [int(p) for p in '21,22,23,111,445,2049,3306'.split(',')] ports [21, 22, 23, 111, 445, 2049, 3306] max(ports) 3306 [p for p in ports if p < 1024] [21, 22, 23, 111, 445]
you should see A list comprehension builds a new list in one line, here keeping only well known ports.
Positions versus names
fields = line.split()
if '23' in fields[3]:
print(fields[0])Breaks the day someone adds a column, and '23' also matches '2375'.
name, role, system, ports = line.split()
ports = [int(p) for p in ports.split(',')]
if 23 in ports:
print(name)Named fields and real numbers. Unpacking fails loudly if the format changes.
What a defender takes away
- 1Strings split into lists, and lists of pairs become dicts.
- 2Parse values into the right type straight away: ports are numbers.
- 3Substring checks on text are a classic source of false matches.
Questions
0 of 3 solved
Answer each one from what you find on your lab machine.