poniedziałek, 10 sierpnia 2026

picoCTF - Rail-fence

Tym razem chciałem opisać rozwiązanie zadania Rail fence cipher z działu Cryptography. 


Do zadania dołączono plik z wiadomością:

  1. Ta _7N6DDDhlg:W3D_H3C31N__0D3ef sHR053F38N43D0F i33___NA

Zgodnie z zadaniem jest to zabezpieczone za pomocą Rail Fence Cipher. Jest to szyfr transpozycyjny. Znaki tekstu nie są zamieniane na inne. Zamieniana jest jedynie ich kolejność. Tekst zapisywany jest zygzakiem pomiędzy określoną liczbą wierszy zwanych rails. Następnie jest on odczytywany wiersz po wierszu. Wykorzystam tutaj narzędzie online.


Dekrypt też zadziała bardzo sprawnie:


Podczas deszyfrowania należy odtworzyć schemat zygzaka, a następnie umieścić znaki szyfrogramu w odpowiednich pozycjach. Na końcu odczytać je zgodnie z kolejnością zygzaka.

Aby rozwiązać zadanie najprościej posłużyć się narzędziem online opisanym wcześniej i dostosować parametry metodą prób i błędów, lub od razu zgodnie z danymi na screenie poniżej.


Obudowujemy flagę odpowiednim formatem:


Zadanie zakończone. 

Trochę szybko, więc spróbujmy zadanie rozwiązać z pomocą Pythona:

  1. def rail_fence_decrypt(ciphertext, rails):
  2.     #Tworzymy pustą macierz
  3.     fence = [["" for _ in range(len(ciphertext))]
  4.              for _ in range(rails)]
  5.  
  6.     #Rozpczynamy wyznaczanie pozycji zygzaka
  7.     row = 0
  8.     direction = 1
  9.  
  10.     for col in range(len(ciphertext)):
  11.         fence[row][col] = "*"
  12.  
  13.         if row == 0:
  14.             direction = 1
  15.         elif row == rails - 1:
  16.             direction = -1
  17.  
  18.         row += direction
  19.  
  20.     #Wstawiamy odpowiedni szyfrogram
  21.     index = 0
  22.  
  23.     for row in range(rails):
  24.         for col in range(len(ciphertext)):
  25.             if fence[row][col] == "*" and index < len(ciphertext):
  26.                 fence[row][col] = ciphertext[index]
  27.                 index += 1
  28.  
  29.     #Odczytujemy tekst zgodnie z przebiegiem zygzaka
  30.     plaintext = ""
  31.     row = 0
  32.     direction = 1
  33.  
  34.     for col in range(len(ciphertext)):
  35.         plaintext += fence[row][col]
  36.  
  37.         if row == 0:
  38.             direction = 1
  39.         elif row == rails - 1:
  40.             direction = -1
  41.  
  42.         row += direction
  43.  
  44.     return plaintext
  45.  
  46.  
  47. ciphertext = "Ta _7N6DDDhlg:W3D_H3C31N__0D3ef sHR053F38N43D0F i33___NA"
  48.  
  49. for rails in range(2, 11):
  50.     print(f"Rails = {rails}:")
  51.     print(rail_f

Program najpierw odtwarza układ zygzaka. Następnie rozmieszcza znaki na odpowiednich szynach i odczytuje je w kolejności. Sprawdzamy od razu przypadki dla wartości od 2 do 10. 

Wynik działania programu jest następujący:

  1. Rails = 2:
  2. T3ae f_ 7sNH6RD0D5D3hFl3g8:NW433DD_0HF3 Ci3313N_____0NDA
  3.  
  4. Rails = 3:
  5. TW43aD3_ HD3_C0371FNN_ _60iDD33eDf3 Ds_HhR_0l5_3gFN3:8AN
  6.  
  7. Rails = 4:
  8. The flag is: WH3R3_D035_7H3_F3NC3_8361N_4ND_3ND_D00AFDD3
  9.  
  10. Rails = 5:
  11. TD30351DaDN33F_h l_3_80g_:DN_43W73e3_DfDN_ 0NFsH63H AiRC
  12.  
  13. Rails = 6:
  14. T6_3338eHDaD3fN_4 CD h3s3_DH1l_gNR0_F0_:7W_5 Ni303NDDF3A
  15.  
  16. Rails = 7:
  17. TNWNsN_4H_36aDD_R3_D00_D DHD50_F333h_lCeF Ni3f3g7:1 83A3
  18.  
  19. Rails = 8:
  20. T7gC35D_03e3:Na6W1fFF_ 3 N3D DD_s8iN3NH__D_hH0R43A_30D3l
  21.  
  22. Rails = 9:
  23. T7lH_s3F_ 8H03gNa6:CDRNiN34033WD D31e533A_D3fNDD_h__ F0_
  24.  
  25. Rails = 10:
  26. T7l_Ne0N _i45f_HgNa6:3_ 333N3DFs0CWD D33DH30_A_F8R31DD_h
  27.  
  28. ** Process exited - Return Code: 0 **
  29. ^C

Jak widać w tym przypadku na podstawie odszyfrowanego tekstu możemy stwierdzić który przypadek powinien być poprawny.