คลัง
crypto

ROT13 / ROT47

ROT คือการ 'หมุน' ตัวอักษร/อักขระไปตามจำนวนคงที่แล้ววนรอบ เป็น Caesar cipher รูปแบบเฉพาะ: ROT13 หมุน 13 บน a-z (self-inverse), ROT5 หมุน 5 บนตัวเลข 0-9, ROT18 = ROT13+ROT5 รวมกัน, ROT47 หมุน 47 บนช่วง ASCII printable 94 ตัว ทั้งหมดเป็น self-inverse (เข้ารหัส = ถอดรหัส) และพบบ่อยเป็นด่านอุ่นเครื่องหรือชั้นหนึ่งของ encoding ซ้อนชั้น บทนี้ครอบคลุมทุกตัวแปร วิธีรู้จำ คำสั่งถอด (tr/python/CyberChef) และ nested rotation

Beginner#rot13#rot5#rot18#rot47#rotation#encoding#caesar#crypto

1. ROT ตระกูลต่างๆ

ROT (rotate) หมุนอักขระไปตามจำนวนคงที่ภายในช่วงหนึ่งแบบวนรอบ (modulo ขนาดช่วง) — มันคือ Caesar cipher นั่นเอง แต่ตั้งชื่อตามจำนวน shift และช่วงที่ใช้ ตัวแปรที่พบใน CTF มีดังนี้ จุดร่วมสำคัญคือทุกตัว shift = ครึ่งหนึ่งของขนาดช่วง จึงเป็น self-inverse: เข้ารหัสและถอดรหัสใช้การดำเนินการเดียวกัน

ตัวแปรช่วงที่หมุนshiftself-inverse
ROT13a-z A-Z (26 ตัว)13ใช่ (13 = 26/2)
ROT50-9 (10 ตัว)5ใช่ (5 = 10/2)
ROT18a-z A-Z + 0-913 ตัวอักษร + 5 ตัวเลขใช่
ROT47ASCII 33–126 (94 ตัว)47ใช่ (47 = 94/2)

ROT13 เป็นตัวที่พบบ่อยที่สุด: flagsynt, thegur (จำ gur ได้จะรู้ทันทีว่าเป็น ROT13) ROT5 ใช้กับตัวเลขล้วน (1234567890) ROT18 รวม ROT13 กับ ROT5 เข้าด้วยกัน หมุนตัวอักษร 13 และตัวเลข 5 พร้อมกัน ROT47 ครอบคลุมทั้งช่วง printable รวมสัญลักษณ์ จึงเหมาะเมื่อข้อความมี !@#{} ปน

ROT13 vs ROT47 — ช่วงที่หมุน
ROT13 (26 ตัว, หมุน 13) A B C ... M | N O P ... Z A<->N B<->O C<->P ... M<->Z (13 คู่ สลับกัน) ROT47 (94 ตัว ASCII 33-126, หมุน 47) ! " # $ % ... 0-9 ... A-Z ... a-z ... } ~ '!'(33) <-> 'P'(80) ครอบคลุมเลข+สัญลักษณ์+ตัวอักษร มีสัญลักษณ์/ตัวเลขปน = น่าจะ ROT47 ไม่ใช่ ROT13

2. วิธีรู้จำว่าเป็น ROT ตัวไหน

  • a-z ล้วน (ไม่มีตัวเลข/สัญลักษณ์) → ลอง ROT13 ก่อน; ถ้าไม่ออก brute Caesar 25 shift
  • ตัวเลขล้วน → ROT5
  • ตัวอักษร + ตัวเลขปน แต่ไม่มีสัญลักษณ์อื่น → ROT18
  • มีสัญลักษณ์ !@#$%{} ปนเยอะ → ROT47 (เพราะ ROT13/5 ไม่แตะสัญลักษณ์)
  • เห็นคำว่า gur (=the), vf (=is), synt (=flag) → ROT13 แน่นอน
  • ข้อความมี { } แต่ตัวในวงเล็บอ่านไม่ออก และรอบๆ เป็นสัญลักษณ์ → ROT47
เคล็ดลับเร็ว: ROT13 ของ flag คือ synt และ ROT13 ของ CTF คือ PGS — ถ้าเห็น synt{ หรือ PGS{ ในโจทย์ ตอบ ROT13 ได้เลย

3. คำสั่งถอด

ROT13 ด้วย tr (self-inverse)
# ถอด/เข้า ROT13 (คำสั่งเดียวกัน เพราะ self-inverse)
echo 'Uryyb Jbeyq' | tr 'A-Za-z' 'N-ZA-Mn-za-m'
# -> Hello World

# ROT5 บนตัวเลขด้วย tr
echo '12345' | tr '0-9' '5-90-4'
# -> 67890

# ROT13 ทั้งไฟล์
tr 'A-Za-z' 'N-ZA-Mn-za-m' < cipher.txt
'N-ZA-Mn-za-m' คือ alphabet ที่หมุนไป 13 — จำ pattern นี้ไว้ใช้ได้ตลอด
ROT ทุกตัวแปรด้วย Python
import codecs

# ROT13 (built-in)
print(codecs.encode("Uryyb Jbeyq", "rot13"))   # -> Hello World

# ROT47
def rot47(s):
    out = []
    for c in s:
        o = ord(c)
        if 33 <= o <= 126:
            out.append(chr(33 + (o - 33 + 47) % 94))
        else:
            out.append(c)          # อักขระนอกช่วง เก็บไว้เดิม
    return "".join(out)

print(rot47('%C6H:?8'))            # self-inverse: เรียกซ้ำได้ค่าเดิม

# ROT5 (ตัวเลข) + ROT18 (ตัวอักษร+ตัวเลข)
def rot_n(s, n_alpha=13, n_dig=5):
    out = []
    for c in s:
        if c.isupper():   out.append(chr((ord(c)-65+n_alpha)%26+65))
        elif c.islower(): out.append(chr((ord(c)-97+n_alpha)%26+97))
        elif c.isdigit(): out.append(chr((ord(c)-48+n_dig)%10+48))
        else:             out.append(c)
    return "".join(out)

print(rot_n("Uryyb123", 13, 5))    # ROT18
codecs.encode(..., 'rot13') คือทางลัดที่สุดสำหรับ ROT13 ใน Python
CyberChef มี operation ROT13 (ปรับ amount ได้ = ทำ Caesar shift ใดก็ได้), ROT13 Brute Force (พ่นทุก shift), ROT47 และ ROT8000 ลากวางเทสต์ได้เร็ว ส่วน dcode.fr มีหน้าเฉพาะสำหรับแต่ละตัวแปร

4. Nested / ซ้อนชั้นกับ encoding อื่น

แพทเทิร์นคลาสสิกใน CTF คือ ROT ถูกซ้อนกับ encoding อื่นหลายชั้น เช่น Base64 → ROT13, ROT13 → Hex, หรือ ROT47 → Base64 ต้องไล่ decode ทีละชั้นจนอ่านออก จุดสำคัญคือ ROT13 กับ Base64 มักถูกสับสน เพราะทั้งคู่ให้ผลเป็นตัวอักษร a-z/A-Z ให้ดูว่ามี = ท้าย หรือมีตัวเลข/+// ปน (บ่งชี้ Base64) หรือเป็นตัวอักษรล้วน (บ่งชี้ ROT)

ไล่ decode ซ้อนชั้น (Python)
import base64, codecs

data = "Vm0wd..."       # ciphertext ที่ได้มา

# ลองไล่ทีละชั้น: base64 -> rot13
step1 = base64.b64decode(data).decode()
step2 = codecs.encode(step1, "rot13")
print(step2)

# ถ้ายังไม่ออก ลองสลับลำดับ / เพิ่มชั้น hex
# bytes.fromhex(...) , base64.b64decode(...) , codecs.encode(..., 'rot13')
ไม่แน่ใจลำดับชั้น → ใช้ CyberChef operation 'Magic' ให้มันเดา recipe อัตโนมัติ
CyberChef operation Magic (มี option 'Intensive mode') จะไล่ลอง decode หลายชั้นให้อัตโนมัติ รวมถึง ROT/Base/Hex — เป็นตัวช่วยที่ดีที่สุดเมื่อไม่รู้ว่าซ้อนกี่ชั้นและลำดับใด

5. รูปแบบโจทย์ CTF

  • ROT13 ตรงๆ: synt{...} → ROT13 → flag{...} ด่านอุ่นเครื่อง
  • ROT47: ข้อความมีสัญลักษณ์ปน เช่น u=B8m... → ROT47 ได้ flag
  • ROT18: ข้อความมีตัวอักษร+ตัวเลขที่ทั้งคู่ถูกเลื่อน (ตัวเลขก็เพี้ยน) → ROT18
  • ซ้อนชั้น: Base64 → ROT13, หรือ ROT13 → Base64 → ต้อง decode หลายชั้น
  • shift ไม่ใช่ 13: ROT13 ไม่ออก → เป็น Caesar shift อื่น → brute 25 (ดูหัวข้อ caesar)
เจอข้อความที่ดูถูกหมุน — ไล่ตามนี้
ประกอบด้วยอักขระแบบไหน?
a-z ล้วนROT13 → ถ้าไม่ออก brute Caesar
ตัวเลขล้วนROT5
ตัวอักษร+ตัวเลขROT18
มีสัญลักษณ์ปนROT47
ลองถอดด้วยตัวแปรที่เดา
tr / python / CyberChef
อ่านออกไหม?
ออกได้ flag
ได้ตัวอักษรแต่ยังไม่อ่านออกอาจซ้อนชั้น → Magic / decode ต่อ
ไม่ออกเลยshift อื่น → หัวข้อ caesar (brute 25)
เจอ flag / ข้อความอ่านออก

6. Quick Reference

  • ROT13 = Caesar k=13 บน a-z, self-inverse (เข้า=ถอด)
  • ROT5 = ตัวเลข 0-9 · ROT18 = ROT13+ROT5 · ROT47 = ASCII 33-126
  • a-z ล้วน → ROT13 · มีสัญลักษณ์ปน → ROT47 · ตัวเลข → ROT5
  • tr 'A-Za-z' 'N-ZA-Mn-za-m' = ROT13
  • codecs.encode(s, 'rot13') ใน Python
  • จำ: gur=the, synt=flag, PGS=CTF → ROT13
  • อ่านตัวอักษรได้แต่ไม่เป็นคำ → อาจซ้อนชั้น (Base64/Hex) → CyberChef Magic
  • ROT13 ไม่ออก + a-z ล้วน → brute Caesar 25 shift (ดูหัวข้อ caesar)

🧭 จับมือทำทีละขั้น (มีแค่ Kali) + ถ้าติดไปไหนต่อ

สมมติเจอ ciphertext ที่ดู 'หมุน' ตัวอักษรอยู่แบบนี้ มีแค่เครื่อง Kali เปล่าๆ ไม่รู้จะเริ่มยังไง ทำตามขั้นตอนนี้ทีละสเต็ป

  1. 1ดู charset ของข้อความก่อน: `cat chal.txt` — เป็น a-z ล้วน? ตัวเลขล้วน? ตัวอักษร+ตัวเลขปน? หรือมีสัญลักษณ์ `!@#{}` ปนเยอะ
  2. 2a-z ล้วน → ลอง ROT13 ก่อนเสมอ: `echo '...' | tr 'A-Za-z' 'N-ZA-Mn-za-m'` (self-inverse ใช้คำสั่งเดียวถอดได้เลย)
  3. 3ตัวเลขล้วน → ลอง ROT5: `echo '12345' | tr '0-9' '5-90-4'`
  4. 4ตัวอักษร+ตัวเลขปนแต่ไม่มีสัญลักษณ์อื่น → ลอง ROT18 (เขียน python สั้นๆ ตามโค้ดด้านบน หรือ dcode.fr/rot-18)
  5. 5มีสัญลักษณ์ปนเยอะ → ลอง ROT47 ด้วย python function หรือ CyberChef operation 'ROT47'
  6. 6ยังไม่ออก → เปิด https://gchq.github.io/CyberChef วาง ciphertext ใน Input แล้วลาก operation 'Magic' มาวาง เปิด 'Intensive mode' ให้มันไล่เดา recipe (ROT/Base64/Hex ซ้อนกัน) อัตโนมัติ
  7. 7เจอตัวอักษรอ่านได้แต่ไม่เป็นคำ (เช่นมี `=` ท้าย หรือมีเลข/`+`/`/` ปน) → สงสัยว่าเป็น Base64 ซ้อนอยู่ ลอง decode ชั้นนอกก่อนด้วย `base64 -d` แล้วค่อยกลับมาลอง ROT
  8. 8ลองครบทุกตัวแปร ROT แล้วยังไม่ออก → สงสัยว่า shift ไม่ใช่ 13/5/47 (เป็น Caesar shift อื่น) → ไปทำ brute ทั้ง 25 shift ที่หัวข้อ Caesar
  9. 9ได้ผลอ่านออกแล้ว → เช็ค flag format ให้ตรงกับที่โจทย์กำหนด แล้วส่งคำตอบ
เจอข้อความที่ดูถูกหมุน มีแค่ Kali — ไล่ตามนี้
cat chal.txt — ดู charset
a-z ล้วน / ตัวเลขล้วน / ตัวอักษร+เลข / มีสัญลักษณ์ปน?
a-z ล้วน → ลอง ROT13 (tr 'A-Za-z' 'N-ZA-Mn-za-m')
✅ อ่านออก→ จบ ส่ง flag
❌ ไม่ออก→ เช็ค charset แบบอื่นต่อ
charset เป็นแบบไหน?
ตัวเลขล้วน→ ลอง ROT5
ตัวอักษร+เลขปน ไม่มีสัญลักษณ์อื่น→ ลอง ROT18
มีสัญลักษณ์ !@#{} ปนเยอะ→ ลอง ROT47
ลอง ROT5 (tr '0-9' '5-90-4')
✅ อ่านออก→ จบ
❌ ไม่ออก→ ลอง CyberChef Magic
ลอง ROT18 (python / dcode.fr)
✅ อ่านออก→ จบ
❌ ไม่ออก→ ลอง CyberChef Magic
ลอง ROT47 (python / CyberChef)
✅ อ่านออก→ จบ
❌ ไม่ออก→ ลอง CyberChef Magic
เปิด CyberChef ลาก operation 'Magic' (Intensive mode)
เดา recipe อัตโนมัติ ครอบคลุม ROT + Base64/Hex ซ้อนกัน
✅ เจอ flag→ จบ
❌ ไม่เจอ→ สงสัย shift อื่น (ไม่ใช่ 13/5/47)
ขั้นตอน/งานเครื่องมือใน Kaliติดตั้งเพิ่ม (ถ้าไม่มี)เครื่องมือออนไลน์
ดู charset ของข้อความcat, file--
ถอด ROT13tr, python3 (codecs)-gchq.github.io/CyberChef (ROT13)
ถอด ROT47python3-CyberChef (ROT47)
ถอด ROT5 (ตัวเลข)tr-dcode.fr/rot-5
ถอด ROT18python3-dcode.fr/rot-18
เดา recipe อัตโนมัติ (ซ้อนชั้น)--CyberChef (operation Magic, Intensive mode)
Caesar shift อื่นที่ไม่ใช่ 13python3-dcode.fr/caesar-cipher
🚑 ถ้าตันสนิท ลองท่าถัดไป: Caesar — ถ้า ROT13/47/5/18 ไม่ออกเลย ให้ brute shift ทุกค่า 1-25 แทน · Vigenère — ถ้า shift ดูไม่คงที่ตลอดข้อความ (บางช่วงหมุนมาก บางช่วงหมุนน้อย) · XOR — ถ้า decode ออกมาเป็น byte สุ่มไม่ใช่ตัวอักษร a-z · Hash Cracking — ถ้าสิ่งที่ได้จริงๆ คือ hash คงที่ (32/40/64 hex) ไม่ใช่ cipher

โน้ตของฉัน

ยังไม่มีโน้ตสำหรับหัวข้อนี้