คลัง
stego

LSB Steganography

LSB (Least Significant Bit) เป็นเทคนิค steganography ที่ใช้บ่อยที่สุด — ซ่อนข้อมูลใน bit ต่ำสุดของแต่ละ pixel/sample ซึ่งเปลี่ยนค่าสีนิดเดียวจนตาคนมองไม่ออก บทนี้ลงลึกถึงกลไก bit-plane, ลำดับการอ่าน (channel/bit order), เครื่องมือทุกตัว, และการเขียน solver เองเมื่อ tool สำเร็จรูปแก้ไม่ได้

BeginnerIntermediateAdvanced#lsb#stego#least-significant-bit#bit-plane#zsteg#stegsolve#ctf

1. LSB ทำงานอย่างไร

ภาพแบบ lossless (PNG/BMP) เก็บแต่ละ pixel เป็นค่าสี เช่น RGB ช่องละ 8 bit (0–255) bit ขวาสุด (LSB) ของแต่ละช่องมีน้ำหนักแค่ 1 — เปลี่ยนจาก 0→1 ทำให้สีเพี้ยนไปแค่ 1/255 ตาคนแยกไม่ออก ผู้ซ่อนจึงแทนที่ LSB ของแต่ละ pixel ด้วย bit ของข้อความลับ ทีละ bit เรียงต่อกัน

การฝัง 1 byte ('A' = 01000001) ลงใน LSB ของ pixel
ข้อความ 'A' = 0 1 0 0 0 0 0 1 (8 bit) pixel เดิม (byte สี): 10010110 11001011 00110100 11110001 ... แทน LSB ด้วย bit ของ 'A': 10010110 11001011 00110100 11110000 ... ค่าสีเปลี่ยนไม่เกิน ±1 ต่อช่อง = ตามองไม่เห็น อ่านกลับ: เก็บ LSB ทุก byte มาต่อกันทีละ 8 = 1 ตัวอักษร
LSB ใช้ได้เฉพาะ lossless format (PNG, BMP, WAV) เท่านั้น — JPEG ใช้ lossy compression ที่ทำลาย LSB ตอน save ดังนั้นเจอ JPEG ต้องใช้เทคนิคอื่น (ดูหัวข้อ stego-jpg)
เจอภาพ/ไฟล์ — ไล่หา LSB
file + exiftool (ชั้นนอกก่อน)
ดูชนิดจริง + metadata/comment
format อะไร?
PNG/BMPzsteg -a (LSB อัตโนมัติ)
JPEGLSB ใช้ไม่ได้ → steghide/stego-jpg
WAVLSB audio / spectrogram
zsteg ไม่เจอ → Stegsolve ไล่ทีละ bit-plane
ดู R/G/B plane 0, alpha, row/col order
ยังไม่เจอ → ลอง LSB หลาย channel/order เอง
เขียน script อ่าน LSB ตาม pattern
เจอข้อความซ่อน / flag

2. ตัวแปรที่ต้องเดา/ลอง

ปัญหาของ LSB คือผู้ซ่อนเลือก 'วิธีเรียง' ได้หลายแบบ การ extract ต้องลองทุก combination จนเจอข้อมูลที่อ่านรู้เรื่อง ตัวแปรหลักมีดังนี้:

ตัวแปรค่าที่เป็นไปได้หมายเหตุ
channelR, G, B, A, หรือผสมซ่อนในช่องไหน หรือหลายช่อง
bit orderLSB-first / MSB-firstอ่าน bit จากต่ำหรือสูงก่อน
pixel orderrow-major / column-majorอ่านแนวนอนหรือแนวตั้ง
bit planebit 0 (LSB) หรือ bit 1,2...บางทีซ่อนใน bit ที่สูงกว่า LSB
จำนวน bit/channel1, 2, หรือมากกว่าซ่อนหลาย bit ต่อช่อง
start offsetเริ่ม pixel ที่เท่าไหร่อาจข้าม header

3. zsteg — ลองทุก combination อัตโนมัติ (PNG/BMP)

zsteg คือเครื่องมือแรกที่ต้องลองกับ PNG/BMP — มันลองทุก combination ของ channel/bit-order/plane ให้อัตโนมัติ แล้วโชว์อันที่ดูเป็นข้อมูล (text, file signature)

zstegLinux
# ลองทุก combination
zsteg image.png
# ละเอียด (ทุก channel/bit)
zsteg -a image.png
# ดึงข้อมูลจาก channel/bit ที่เจอ (เช่น b1,rgb,lsb,xy)
zsteg -E "b1,rgb,lsb,xy" image.png > extracted.bin
file extracted.bin            # เช็คว่าได้ไฟล์อะไร

# ติดตั้ง
gem install zsteg
zsteg แสดง payload เช่น 'b1,r,lsb,xy .. text: "flag{...}"' — ตัว b1,r,lsb,xy คือ parameter ที่ใช้ดึงด้วย -E

4. StegSolve — ดู bit-plane ด้วยตา

StegSolve (Java GUI) ให้ดูภาพแยกทีละ bit-plane ของแต่ละ channel — ถ้าข้อมูลซ่อนใน plane ไหน plane นั้นจะเห็นเป็น pattern/ข้อความชัดเจน (ไม่ใช่ noise สุ่ม)

  1. 1เปิดภาพใน StegSolve
  2. 2กดปุ่ม < > ไล่ดู bit-plane ทีละอัน (Red 0–7, Green 0–7, Blue 0–7, Alpha)
  3. 3plane ที่มีข้อมูลจะเห็น text/QR/pattern แทน noise
  4. 4ใช้ 'Data Extract' เลือก channel+bit ที่เจอ แล้ว save ออกมา
  5. 5ลอง 'Image Combiner' ถ้าโจทย์มีหลายภาพ (XOR/diff สองภาพ)
ถ้าเห็น bit-plane บนสุด (เช่น Red plane 0) เป็น noise สม่ำเสมอทั้งภาพ = น่าจะมีข้อมูลซ่อน (ภาพปกติ bit-plane ต่ำจะมี pattern ตามภาพ ไม่ใช่ noise ล้วน)

5. เขียน solver เอง (เมื่อ tool แก้ไม่ได้)

เมื่อ zsteg/StegSolve แก้ไม่ได้ (เช่น bit order แปลก, ซ่อนแบบ custom) ต้องเขียน Python อ่าน LSB เองด้วย PIL — ควบคุมทุกตัวแปรได้

extract LSB ด้วย Python/PILLinux
from PIL import Image

img = Image.open("image.png")
pixels = list(img.getdata())   # [(r,g,b), ...] หรือ (r,g,b,a)

bits = ""
for px in pixels:
    for ch in px[:3]:          # R,G,B (ลอง [:3] หรือเลือกช่องเดียว)
        bits += str(ch & 1)    # ดึง LSB

# แปลง bit -> bytes ทีละ 8
chars = ""
for i in range(0, len(bits) - 7, 8):
    byte = bits[i:i+8]
    chars += chr(int(byte, 2))

print(chars[:500])             # หา flag{...}

# variant: MSB-first ให้กลับ byte = byte[::-1]
# variant: ช่องเดียว -> วน ch in [px[0]] เท่านั้น
# variant: 2 bit/channel -> str(ch & 3) ... ปรับ step เป็น 4
ปรับ channel/bit-order/จำนวน bit ตามตาราง section 2 จนได้ข้อความอ่านรู้เรื่อง
ดู bit-plane เองด้วย numpy (เมื่อไม่มี StegSolve)Linux
import numpy as np
from PIL import Image

arr = np.array(Image.open("image.png"))
# ดึง bit-plane 0 ของ channel R ออกมาเป็นภาพขาวดำ
plane = (arr[:,:,0] & 1) * 255
Image.fromarray(plane.astype('uint8')).save("plane_r0.png")
# เปิด plane_r0.png ดู — ถ้ามี text/QR = เจอ

6. เครื่องมือ all-in-one

  • stegoveritas — รันชุดใหญ่: แยกทุก bit-plane, metadata, LSB, สี → output โฟลเดอร์เดียว (stegoveritas image.png)
  • zsteg — PNG/BMP LSB อัตโนมัติ (ตัวแรกที่ลอง)
  • StegSolve — ดู plane ด้วยตา + extract + combine
  • stegseek — ถ้าสงสัยว่าเป็น steghide (มี passphrase) ดูหัวข้อ Steghide
  • เริ่มจาก zsteg → StegSolve → stegoveritas → เขียน solver เอง

7. Quick Reference

  • LSB = ซ่อนใน bit ต่ำสุดของ pixel (เฉพาะ lossless: PNG/BMP/WAV)
  • PNG/BMP: zsteg image.png → zsteg -E 'b1,rgb,lsb,xy' ดึง
  • ดูด้วยตา: StegSolve ไล่ bit-plane
  • all-in-one: stegoveritas
  • ตัวแปร: channel, bit-order, pixel-order, plane, bit/channel
  • tool ไม่ได้ → เขียน PIL: ch & 1 ต่อ bit แล้วแปลงทีละ 8
  • JPEG ใช้ LSB ไม่ได้ → ดูหัวข้อ stego-jpg

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

สมมติเจอโจทย์ให้ไฟล์ PNG/BMP มา มีแค่ Kali เปล่าๆ สงสัยว่าเป็น LSB — ทำตามนี้ทีละขั้น เริ่มจากเครื่องมืออัตโนมัติก่อนเสมอ ก่อนจะไล่ดูด้วยตาหรือเขียน script เอง

  1. 1พิมพ์ file image.png และ exiftool image.png — ยืนยันชนิดไฟล์ + เช็ค metadata ก่อนเสมอ
  2. 2พิมพ์ zsteg image.png — ลอง combination มาตรฐาน ดูว่ามีบรรทัดไหนโชว์ text/file ที่ไม่ใช่ noise
  3. 3ถ้าไม่เจอ พิมพ์ zsteg -a image.png — ลองละเอียดขึ้น (ทุก channel/bit/order)
  4. 4เจอ payload ที่น่าสนใจ (เช่น b1,r,lsb,xy .. text: "flag{...}") → ดึงด้วย zsteg -E "b1,r,lsb,xy" image.png
  5. 5ถ้า zsteg ไม่เจออะไรเลย เปิดภาพใน StegSolve (หรือ stegsolve.jar) แล้วกด < > ไล่ดูทุก bit-plane ของ R/G/B/Alpha ทีละอัน
  6. 6plane ไหนที่เห็นเป็น noise สม่ำเสมอ (ไม่ตามรูปทรงภาพ) = น่าสงสัยว่ามีข้อมูล — ลองใช้ 'Data Extract' ใน StegSolve เลือก channel/bit นั้น
  7. 7ถ้ายังไม่เจอ รัน stegoveritas image.png ให้มันลองทุกอย่างรวดเดียว (แยก bit-plane, metadata, สี) แล้วดูโฟลเดอร์ output
  8. 8ถ้ายังไม่เจอ เขียน Python เอง (PIL) อ่าน LSB แล้วสลับ channel/bit-order/pixel-order ตามตารางในหัวข้อนี้จนได้ข้อความอ่านรู้เรื่อง
  9. 9ถ้าลองครบทุก combination แล้วยังไม่เจอ ให้กลับไปเช็คว่าไฟล์เป็น PNG/BMP จริงไหม หรือจริงๆ เป็น JPG/WAV ที่ใช้ LSB ไม่ได้
ไล่หา LSB — ถ้าติดไปไหนต่อ
เจอ payload ที่อ่านออกไหม?
✅ เจอ text/file→ zsteg -E ดึงออกมา จบ
❌ ไม่เจอ→ ลอง zsteg -a ละเอียดขึ้น
zsteg -a image.png
ลองทุก combination ละเอียด
ยังไม่เจอ?
✅ เจอแล้ว→ จบ ได้ flag
❌ ยังไม่เจอ→ ไล่ดูด้วยตาด้วย StegSolve
StegSolve ไล่ bit-plane ทีละอัน
หา plane ที่เป็น noise ผิดปกติ
เจอ plane ที่มี pattern/ข้อความไหม?
✅ เจอ→ Data Extract เลือก channel/bit นั้น จบ
❌ ไม่เจอ→ รัน stegoveritas กวาดทุกอย่าง
stegoveritas image.png
รันชุดใหญ่อัตโนมัติ
ยังไม่เจอ?
✅ เจอ→ จบ ได้ flag
❌ ไม่เจอเลย→ เขียน Python เอง หรือกลับไปเช็คว่าไฟล์ไม่ใช่ PNG/BMP
ไฟล์จริงเป็น JPG/WAV?
LSB ใช้ไม่ได้กับ JPG (lossy)
ชนิดไฟล์จริง?
JPG→ ไป steghide/outguess
WAV→ ไป stego-wav (spectrogram/LSB audio)
ขั้นตอน/งานเครื่องมือใน Kaliติดตั้งเพิ่ม (ถ้าไม่มี)เครื่องมือออนไลน์
สแกน LSB อัตโนมัติ (PNG/BMP)zsteggem install zstegaperisolve.com
ดู bit-plane ด้วยตาStegSolve (java -jar)wget stegsolve.jarstylesuxx.github.io/steganography
รันชุดใหญ่อัตโนมัติstegoveritaspipx install stegoveritasaperisolve.com
เขียน solver เองpython3 + PIL/numpypip install pillow numpyCyberChef (Extract LSB operation)
เช็ค metadata ก่อนเสมอexiftoolsudo apt install libimage-exiftool-perlexifdata.com
เช็คไฟล์ฝัง/ต่อท้ายbinwalksudo apt install binwalkaperisolve.com
ถ้าเป็น JPG แทน PNGsteghidesudo apt install steghidefutureboy.us/stegano
🚑 ถ้าตันสนิท ลองท่าถัดไป: zsteg ถ้ายังไม่ลอง -a, stego-png ถ้าสงสัยว่าซ่อนใน chunk ไม่ใช่ LSB, stego-jpg ถ้าไฟล์จริงเป็น JPEG (LSB ใช้ไม่ได้), binwalk ถ้ายังไม่เช็คไฟล์ต่อท้าย, exiftool ถ้ายังไม่เช็ค metadata — LSB คือทางตันบ่อยที่สุดถ้าลืมเช็คชนิดไฟล์ที่แท้จริงก่อน

โน้ตของฉัน

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