13 | PicoCTF (CTF Write-Up)
Category: Cryptanalysis Difficulty: Very Easy Tags: Substitution Cipher, ROT13, Caesar Cipher
13 | PicoCTF (CTF Write-Up)
Category: Cryptanalysis Difficulty: Very Easy Tags: Substitution Cipher, ROT13, Caesar Cipher
Challenge Description
Cryptography can be easy, do you know what ROT13 is?
cvpbPGS{abg_gbb_onq_bs_n_ceboyrz}
Walkthrough
Based on the task description, it appears that the ciphertext has been encoded with ROT13. A rather simple substitution cipher, ROT13 is a special instance of the well known Caesar Cipher, a substitution cipher where letters in plaintext are shifted in the alphabet by some predetermined number of spaces and thus resulting in an encoded alphabet.

More formally, let


A Caesar shift by


Decryption is

Computationally, you can think of the Casear Cipher as a function, such that it encrypts the plaintext by rotating each letter by a value of n:
FUNCTION CaesarCipher(plaintext, n):
shift := n MOD 26
out := EMPTY_STRING
FOR letter IN plainext:
IF 'A' <= letter <= 'Z':
idx := ORD(letter) - ORD('A')
out := out + CHR( ORD('A') + ((idx + shift) MOD 26) )
ELSE IF 'a' <= letter <= 'z':
idx := ORD(letter) - ORD('a')
out := out + CHR( ORD('a') + ((idx + shift) MOD 26) )
ELSE:
out := out + letter
RETURN out
ROT13, however, is a Caesar Cipher function with an argument of n = 13 for the Caesar function, hence ROT13 can be referred as ‘rotate by 13’.

Therefore, we can make minimal changes to the previous pseudocode to represent a Caesar Cipher function such that n is already determined to be 13:
FUNCTION ROT13(plaintext):
out := EMPTY_STRING
FOR letter IN plaintext:
IF 'A' <= letter <= 'Z':
idx := ORD(letter) - ORD('A')
out := out + CHR( ORD('A') + ((idx + 13) MOD 26) )
ELSE IF 'a' <= letter <= 'z':
idx := ORD(letter) - ORD('a')
out := out + CHR( ORD('a') + ((idx + 13) MOD 26) )
ELSE:
out := out + letter
RETURN out
The interesting nature of ROT13 lies in its inverse. Typically, the inverse of


Hence

ROT13, however, is self-inverse such that for k = 13 we have

so

thus

This means that we can apply the same function we used to encrypt the plaintext to decrypt the ciphertext. Incredible, I know. Formally, for any plaintext p,

since for each letter index x,

Therefore, to decrypt the ciphertext, we can simply apply the ROT13 function. There are plenty of great resources online that allow for such simple decryption… but that wouldn’t be any fun. Rather, we can write a simple python program that takes the ciphertext and shifts each letter by 13 places:
def rot13(ciphertext):
plaintext = []
for c in ciphertext:
if 'A' <= c <= 'Z':
plaintext.append(chr(ord('A') + (ord(c) - ord('A') + 13) % 26))
elif 'a' <= c <= 'z':
plaintext.append(chr(ord('a') + (ord(c) - ord('a') + 13) % 26))
else:
plaintext.append(c)
return ''.join(plaintext)
rot13("cvpbPGS{abg_gbb_onq_bs_n_ceboyrz}")
Thus, after decrypting the ciphertext, the solution is
picoCTF{not_too_bad_of_a_problem}
메타데이터
- post_id
- 18c46b5d8395
- slug
- 13-picoctf-ctf-write-up-18c46b5d8395
- url
- https://medium.com/@z3r0kn0wl3dg3/13-picoctf-ctf-write-up-18c46b5d8395
- canonical_url
- https://medium.com/@z3r0kn0wl3dg3/13-picoctf-ctf-write-up-18c46b5d8395
- author_url
- https://medium.com/@z3r0kn0wl3dg3
- status
- ok
- fetched_at
- 2026-07-17 21:41:29