This post is originally migrated from Medium.com

บทนำ

สวัสดีครับ ผมเป็นนักศึกษาปีสาม Com En คนนึงที่เพิ่งรู้จัก cybersecurity เมื่อตอนจบปีสอง และได้ศึกษาเรื่อย ๆ ช่วงปิดเทอมจนไปเจอว่ามันมีการแข่งขันที่เรียกว่า Capture the Flag (CTF) ซึ่งคือการใช้ทักษะเจาะระบบ ทักษะความช่างสังเกต และประสบการณ์ในการเอาสิ่งที่เรียกว่า flag หรือธงออกมาจากโจทย์ประเภทต่าง ๆ

การเตรียมตัว

การเตรียมตัวก็ไม่ได้หวือหวาอะไร สู้พวกน้อง ๆ มัธยมที่เดินสายแข่งไม่ได้แน่นอน เราก็อาศัย:

  • picoCTF
  • Try Hack Me
  • โจทย์เก่า ๆ
  • เข้าอบรมออนไลน์บ่อย ๆ (งานไหนฟรีเข้าหมด)

โดยธง หรือ flag มันก็มักจะมีหน้าตาแบบนี้:

CTF{h€110_th1s_1s_th€_fl@g}

หมายเหตุ: งานนี้หน้าตา flag จะมีหลายรูปแบบเพราะออกโดยหลายทีมงาน

เมื่อนำธงไปใส่ในโจทย์ก็จะได้คะแนน โดยคะแนนก็จะแบ่งตามโจทย์ข้อง่าย กลาง ยาก นั่นเอง

งาน NCSA CTF Boot Camp

งานแรกที่ผมได้ไปเลยคืองาน NCSA CTF Boot Camp ซึ่งจัดโดย สกมช. (สำนักงานคณะกรรมการการรักษาความมั่นคงปลอดภัยไซเบอร์แห่งชาติ) เป็นงานที่จัดขึ้นเพื่อเตรียมความพร้อมให้น้อง ๆ มัธยมและมหาลัยได้ลองฝีมือก่อนไปแข่งจริงในงาน Cyber Top Talent

โดยใน Boot Camp ก็จะมีทั้ง:

  • การสอนทำโจทย์ในหมวดต่าง ๆ
  • การแข่งขัน Mini CTF ให้ได้วัดฝีมือกันในวันสุดท้าย

Atmosphere

เบลอหน้าไว้ก่อน แต่ก็มีกันแต่คนเดิม ๆ แหละเห็นเงาก็เดาออก 5555

บรรยากาศ

บรรยากาศก็นั่งกันทีมละ 3 คนคละกันไป การเชื่อมไวไฟโรงแรมในจังหวะนี้คือสุ่มเสี่ยงใช้ได้ เพราะต่างกันก็ต่างแสกนกัน 😂 (สงสารเครื่องปริ้นไวไฟของโรงแรม) มีคนเปิด SSID ดักเพื่อนอีก

Mini CTF Competition

เมื่อถึงวันที่สองเราก็เข้าเรื่อง writeup ดีกว่า วันนี้จะได้เล่น Mini CTF กันตั้งแต่ 12.00–15.00 เวลาเรียกว่าค่อนข้างน้อย แค่นั่งคิดก็หมดเวลาแล้ว

ตอนแรกหวังว่าอยากได้คะแนนซัก 30% เพราะส่วนตัวมีจุดอ่อนสำคัญคือหมวด:

  • Web
  • Reverse Engineering
  • Mobile App

ที่เริ่มไม่ออก บอกไม่ถูกว่าจะทิ้งอย่างเดียว 😅

โจทย์ทั้งหมด

โดยก็จะมีโจทย์ทั้งหมด 15 ข้อ ข้อละ 100, 300, 400, 500 คะแนน แบ่งตามหมวดดังนี้:

  • Misc: 3 ข้อ (แก้ได้ 3)
  • Web: 4 ข้อ (แก้ได้ 1)
  • Forensics: 3 ข้อ (แก้ได้ 1)
  • Network: 3 ข้อ (แก้ได้ 2)
  • Mobile: 1 ข้อ
  • Programming + Pwnable: 1 ข้อ

โดยทีมเราจะแบ่งกันทำเป็นข้อ ๆ ไป และบอกกันตลอดหากเปลี่ยนข้อ หากเพื่อนทำข้อไหนได้ เราก็จะเมินข้อนั้นไปดูข้อที่เหลือ เพื่อใช้เวลาให้คุ้ม

Scoreboard

สังเกตว่าเราทำได้แต่ข้อที่คนอื่น ๆ ก็ทำได้นั่นแหละ 55555

Writeups

Misc0

ข้อนี้แจกฟรีเป็น Sanity Check และให้เทสระบบ

For sanity check, you have free flag here.

Flag: STH{20cda557cfa098c65f372b745e11a21e}

Misc1

โจทย์:

XOR message below with a letter.

Message:

00071b283735323237366a37303232616b353062656036326463643136313566616364642e

ข้อนี้พี่ทีมเราเอาไปแก้ โดยการใช้ XOR cipher decoder ออนไลน์

Misc1 XOR Decoder

Misc1 Solution

ก็สั่ง brute force ไปเลย เจอที่ String = S (ASCII 53) เป็น key พอดี

Misc2

โจทย์:

Base64 is too easy. I have applied 3 BaseXX encoding to the message below.

Message:

SFcUFnKydQ9L1q6jfZXKvbZVY3uQPyENV2g4WveejUrptAkcru4pRbMP8ceGxhe9DMoptJen43SwYrDi5mBDMFN1wadt439ZjbNS6QbtBBPvuCTH4Vp5A8h1b4zbgnaMUV4

อันนี้ง่ายมาก ใส่ CyberChef ก็ออก เจอที่ Base58 → Base45 → Base32 ตามลำดับ

Misc2 CyberChef

Web0

โจทย์:

Find flag in HTTP responses of https://sth.sh

Flag จะอยู่ในรูปแบบ {…} ให้หาค่ามาใส่ใน … ที่ถูกต้อง ตัวอย่างเช่น {PENTEST}

อันนี้น้องในกลุ่มแก้ได้แบบงง ๆ เราก็ไม่รู้ว่าทำยังไง เลยลองหาเองดู คิดว่าน่าจะเจอเป็นแบบนี้แหละ อันนี้เปิดด้วย Burpsuite เดาว่าเป็นอันเดียวกัน

Web0 Burpsuite

Network1

จริง ๆ ข้อนี้มีเนื้อเรื่องแถมมาให้ด้วย โดยได้ไฟล์ PCAP มา 1 ไฟล์

Network1 PCAP File

Network1 Wireshark

เลื่อนดูผ่าน ๆ ก็เจอเจ้านี่เข้า เอ็งนี่แหละน่าสงสัยสุดแล้ว ก็คลิกขวา follow HTTP stream ไป แต่ก็ยังไม่เจออะไรผิดสังเกต เจอแค่หน้าเว็บ HTML ที่ไป GET มาเฉย ๆ

จนกระทั่งไปเจอเจ้านี่เข้าอีก แค่ชื่อก็เสียวแล้ว bitcoin_miner น่าสงสัยจัด

Network1 Bitcoin Miner

ส่วนเนื้อในก็เป็นประมาณนี้:

Network1 Content

เห็นว่าน่าจะเป็นการ shell ทำอะไรซักอย่างเพราะมีการเรียก /bin/sh

มาดูกันต่อ เหมือนว่าข้อมูลในแพ็กเก็ตที่เป็น HTTP เขียว ๆ จะหมดลงแล้ว จากที่เห็นว่าการเชื่อมต่อ GET /bincoin_miner/elf ก็โดนปิด (TCP terminate) จนจบไป แต่ยังมีแพ็กเก็ตด้านล่างที่เป็นส่วนของ TCP handshake เพื่อเริ่มการเชื่อมต่อใหม่อยู่

Network1 TCP Handshake

พอ follow TCP stream ไปต่อก็เจอดังนี้ เป็นการเช็ค user, dir เรียลร้อบแล้ว cat ไปดู flag.txt

Network1 TCP Stream

ถ้านี่คือ secret_half2.txt แล้ว half1 ล่ะ 😂 เลยไปหาดี ๆ อีกรอบ เจอ packet ที่มี HTTP request เป็น POST

Network1 POST Request

โอเค ได้ 2 พาร์ทแล้วล่ะ ลักษณะรวมกันเป็น:

ZmxhZ3tqdW5pb3JfbmV0MV9kZDEwNjQKOGVlZTJiZjJkNzE4OTMwYzliMmZiZWJhZTF9Cg==

ล่ะก็คง Base64 แน่นอน

Network1 Base64 Decode

Network2

ข้อนี้มีไฟล์ PCAP กับไฟล์ .pem มาให้พร้อมคำใบ้:

rsa_padding_mode:oaep
rsa_oaep_md:sha256

ชัดเจนเลยว่า encrypt แบบ Char Aznable …. เอ้ย SHA-256 ชัวร์

เริ่มที่ส่องไฟล์ PCAP กันก่อนเลย พบว่าไม่มีอะไรมาก เจอแค่นี้เลย 17 แพ็กเก็ต เป็น TCP ล้วน 1 connection ถ้วน สังเกตจากพอร์ตและ handshake, terminate

Network2 PCAP Overview

จากนั้นเรา follow TCP stream เปิดมาเจอดังนี้:

Network2 TCP Stream

ดูแล้วเป็น RSA encrypted + plain text นิดหน่อยให้ได้รู้บริบทเรื่องราว เป็นการสื่อสารกันของ user สีฟ้า กับ reply ของระบบสีแดง ๆ โดยสีแดงโดน encrypt ไว้ ที่น่าสนใจคือ cat /tmp/flag.txt ที่คิดว่าน่าจะเป็น flag แน่นอน

เราก็ไป cat ดูไฟล์ .pem ที่แถมมา ได้ว่า:

Network2 PEM File

คราวนี้เราก็จะลองแกะข้อความที่ system ตอบกลับนาย longcat (พี่ตะ Siam Thanat Hack) ทีละข้อความ โดยตัวผมเองไม่เคยใช้ tool อะไรแกะ RSA มาก่อน เลยถาม ChatGPT มันแนะนำ openssl และวิธีเตรียม payload ต่าง ๆ ดังนี้

ผมก็อบข้อความส่วนที่เป็นสีแดง แยกเป็นไฟล์ 1.b64, 2.b64 และ 3.b64 ก่อน เพราะลักษณะข้อความที่ได้มา ลงท้ายด้วย == มีโอกาสเป็น Base64 สูง

Network2 Base64 Files

จากนั้นมันบอกว่า openssl รับ input ที่เป็น .bin ก็เลยให้เอาทุกตัวไป decode จาก b64 ก่อน แล้วเอาผลลัพธ์ไปทำไฟล์ bin ก็เลยมั่วเอาตามนี้ ทุกไฟล์:

base64 -d 1.b64 > 1.bin

แล้วก็ decrypt RSA ดังนี้:

openssl pkeyutl -decrypt -in 1.bin -inkey private_key.pem -pkeyopt rsa_padding_mode:oaep -pkeyopt rsa_oaep_md:sha256

ไฟล์แรก ได้แบบนี้ ก็โอเคยืนยันว่า system ตอบกลับคำสั่ง id:

uid=1000(user) gid=1000(user) groups=1000(user),4(adm),24(cdrom),27(sudo),30(dip),46(plugdev),100(users),114(lpadmin)

ไฟล์ที่ 2 ก็แน่นอนว่า เพราะคำสั่งคือ echo "longcat is here, where is the security?" system ก็เลยตอบ echo ไป:

longcat is here, where is the security?

ไฟล์ที่สาม ที่น่าสนใจ โอเค นี่แหละ FLAG:

flag{junior_net2_8a95ca672a65f751efd70d1340cf835a}

Network3

ข้อนี้แก้ไม่ออกในห้องครับ หลายคะแนนอยู่ คิดออก รู้ว่ามันจะเล่นอะไร แต่ผมก็ทำไม่ทัน เลยกลับมาลองต่อที่บ้าน (โหลดไฟล์ไว้)

Network3 Medium Paywall 1

Network3 Medium Paywall 2

ได้ไฟล์ PCAP มา 1 ไฟล์ ตามภาพ:

Network3 PCAP File

คือข้อนี้ไม่ต้องสืบ แค้นมากครับ เจอสองรอบ รอบก่อนในโจทย์เก่า (แก้ไม่ได้ทั้งสองรอบ) มันคือ DNS exfiltration นี่แหละครับ

สังเกตจากไอ้ 192.168.191.111 พยายามส่งหา DNS ของ Google เพื่อหา domain อะไรซักอย่างลงท้าย .c2.sth.sh ซึ่งไอ้ข้างหน้าเนี่ยแหละที่ปัญหา มันเป็น Base64 encoded พยายามเอาข้อมูลมาซ่อนไว้ ต้องเอามารวมกันทุกเฟรม แล้วได้อะไรออกมาแน่นอน

ข้อนี้ทำด้วยมือคงยาก เพราะว่ามีมากถึง 7,605 เฟรม (Wireshark ดักจับที่ NIC ซึ่งเป็น Layer 2 พอดี ผมเลยเรียกเฟรม ไม่เรียกแพ็กเก็ต ถูกผิดขออภัย)

การกรองข้อมูล

ผมกรองอย่างง่ายก่อนด้วยการ filter เอาแค่ขาเดียว จากการที่ DNS query แล้ว Google มันตอบอะนะ ผมเลือกแค่ฝั่งส่งออกพอ:

dns && ip.dst == 8.8.8.8

จากนั้นผมเลยขอความช่วยเหลือ ChatGPT หน่อย เพราะต้องใช้ tool ไม่คุ้นอย่าง tshark:

tshark -r minictf_net3.pcapng -Y "dns && ip.dst == 8.8.8.8" -T fields -e dns.qry.name > export.txt

คำอธิบาย:

  • -Y เป็นการใส่ filter ตามข้างต้นที่กล่าว
  • -T เลือก fields
  • -e dns.query เพื่อเอาแค่ส่วนชื่อโดเมนจริง ๆ

Network3 Export

คราวนี้มันยังเหลือ .c2.sth.sh ซึ่งต้องกรองออก ผมก็เลยยัดใส่ VSCode เพื่อความง่าย (มั้ง) Network3 DNS Filter

แต่ถึง replace ออกไป ก็ต้องคลีนข้อมูลอีกนิด:

U0laRT04NTU0OTs = SIZE=85549;
MDovOWovNFEvK1JYaHBaZ0FBVFUwQUtnQUFBQWdBQmc=  0:/9j/4Q/+RXhpZgAATU0AKgAAAAgABg
MTpFU0FBTUFBQUFCQUFFQUFBRWFBQVVBQUFBQkFBQUE=  1:ESAAMAAAABAAEAAAEaAAUAAAABAAAA

สังเกตว่าจะมี 0: และ 1: นำหน้า ซึ่งเป็นตำแหน่งสำหรับการรวมแพ็กเก็ตที่ปลายทาง สำหรับให้ hacker ขโมยข้อมูลไปแล้วเรียงออกมาถูก

การใช้ RegEx

ผมก็เลยใส่ RegEx เพื่อเลือกเอาอะไรก็ตามที่อยู่หน้า : เป็นต้นไป:

^[^:]*:

คำอธิบาย:

  • ^ → เอาไว้บอกว่าหน้าสุด
  • [^:]* → เจ้า * หมายถึง match ตัวหน้า * อีกกี่ตัวก็ได้ เช่น a* คือได้ทั้ง a, aaa, aaaaa
  • [^:] คือเป็นการบอกนิเสธว่า match อะไรก็ได้ที่ไม่ใช่ :
  • ดังนั้น [^:]* หมายถึงจะ match อะไรก็ได้ที่ไม่ใช่ : และยาวจำนวนกี่ตัวก็ได้
  • : → และปิดท้ายเพื่อ match :

Network3 VSCode Replace

หลังคลีนเอาตัวหน้าออก ก็ดูดีขึ้นเยอะเลย

จับยัดเว็บ Base64 to JPG อันไหนก็ได้ แนะนำ Base64Guru รองรับการแปลงร่างหลายรูปแบบมาก ยิ่งกว่ามาสไรเดอร์ดีเคด

Network3 Result


โจทย์เพิ่มเติม

Section นี้ผมขอรวมโจทย์ที่น่าสนใจ นอกเหนือจากงานไว้นะ คือผมขี้เกียจเปิด writeup ใหม่ ก็เลยยัดไว้ในนี้ก่อน แต่มันจะไม่เกี่ยวกับ miniCTF ที่ไปมา

key.zip

Key.zip File

เปิดดูก็พบว่าเป็น key.zip เพียว ๆ คาดว่าเป็นหมวด Forensics นี่แหละ ผมเลยไล่ลอง tools ต่าง ๆ ก่อนดังนี้:

  • file
  • binwalk
  • exiftool
  • cat

พบว่าก็ปกติหมด ไอ้นี่มันไฟล์ zip ธรรมดา ๆ นี่หว่า

จากนั้นก็ unzip key.zip เอ๊ะ มันติด password

Key.zip Password

ด้วยความที่ผมเล่นด้วย Debian เป็นหลัก wordlists จึงไม่ได้เตรียมหยิบไวใกล้ตัวสุดก็นั่นแหละ rockyou.txt เจ้าเดิม (เอาน่าโจทย์ CTF มันคงไม่โหดร้าย ?) โดยใช้ tool ชื่อ fcrackzip

Key.zip fcrackzip

cd เข้าไปดูก็พบชายเดี่ยว เอ้ย ไฟล์เดี่ยว ๆ key.jpg ทำไมมันถึงชื่อ key นะ น่าสนใจมาก อาจจะเป็นการยัด encrypt + key ไว้ในไฟล์ .jpg ? หรืออาจจะคิดมากไปเอง

ก็ตามสเต็ปครับ exiftool, binwalk, cat, strings ล้วนไม่เจออะไร ลักษณะของมันก็ดูเป็นไฟล์ jpg ธรรมดา ๆ ยกเว้นว่า:

  • exiftool: “Error: File format error” หืมมมมม
  • เลย file key.jpg แล้วขึ้นว่า “key.jpg: data” อื้มมมมม
  • binwalk: ไม่เจออะไรเลย

Key.jpg Hex Editor 1

ผมก็เลยใช้บริการเว็บไซต์ดู hex file ชื่อ https://hexed.it/ โยนไฟล์ลงไป

Key.jpg Hex Editor 2

เท่าที่ดูไฟล์นี้เป็น JFIF ครับ (JPEG File Interchange Format) ดูจาก ASCII ด้านขวามี JFIF และส่วนประกอบทั่วไป แต่ว่า header ไฟล์มันแปลก ๆ เนื่องจากไฟล์ sample JFIF ที่ผมโหลดมามันควรเริ่มด้วย:

FF D8 FF E0 00 10 4A 46 49 46 00

Key.jpg Fixed Header

แสดงว่าอาจจะเป็น header นี่แหละ ที่เสีย ก็เลยทำการแก้กลับคืนแล้ว export

Key.jpg Exiftool

$exiftool key.jpg
ExifTool Version Number         : 12.57
File Name                       : key.jpg
Directory                       : .
File Size                       : 13 kB
File Modification Date/Time     : 2025:08:02 19:06:23+07:00
File Access Date/Time           : 2025:08:02 19:06:25+07:00
File Inode Change Date/Time     : 2025:08:02 19:06:23+07:00
File Permissions                : -rw-r--r--
File Type                       : JPEG
File Type Extension             : jpg
MIME Type                       : image/jpeg
JFIF Version                    : 1.01
Resolution Unit                 : inches
X Resolution                    : 72
Y Resolution                    : 72
Profile CMM Type                : 
Profile Version                 : 2.1.0
Profile Class                   : Display Device Profile
Color Space Data                : RGB
Profile Connection Space        : XYZ
Profile Date Time               : 0000:00:00 00:00:00
Profile File Signature          : acsp
Primary Platform                : Unknown ()
CMM Flags                       : Not Embedded, Independent
Device Manufacturer             : 
Device Model                    : 
Device Attributes               : Reflective, Glossy, Positive, Color
Rendering Intent                : Media-Relative Colorimetric
Connection Space Illuminant     : 0.9642 1 0.82491
Profile Creator                 : 
Profile ID                      : 0
Profile Description             : sRGB
Red Matrix Column               : 0.43607 0.22249 0.01392
Green Matrix Column             : 0.38515 0.71687 0.09708
Blue Matrix Column              : 0.14307 0.06061 0.7141
Red Tone Reproduction Curve     : (Binary data 40 bytes, use -b option to extract)
Green Tone Reproduction Curve   : (Binary data 40 bytes, use -b option to extract)
Blue Tone Reproduction Curve    : (Binary data 40 bytes, use -b option to extract)
Media White Point               : 0.9642 1 0.82491
Profile Copyright               : Google Inc. 2016
Image Width                     : 491
Image Height                    : 184
Encoding Process                : Baseline DCT, Huffman coding
Bits Per Sample                 : 8
Color Components                : 3
Y Cb Cr Sub Sampling            : YCbCr4:2:0 (2 2)
Image Size                      : 491x184
Megapixels                      : 0.090

เช็คอีกรอบ กันเหนียว เผื่อ flag ปลอม lol

Your_Mailing.pcap

ข้อนี้ผมได้มาจากอบรม สกมช เป็นไฟล์แปะไว้ให้ในไดรฟ์ น่าจะเป็น Network Hard จากรายการ WCTF ปี 2023

หลักการอันนี้ไม่ได้มีอะไรมากครับ มันเหมือนกับข้อ Network3 ด้านบนแหละ แค่เปลี่ยนจากเล่น DNS มาเล่น SMTP แทน

อันนี้ผมเดาได้จากชื่อไฟล์นะ แต่ถ้าไม่มีชื่อผมก็เช็คจาก Protocol Hierarchy ก่อนหาว่าอะไรเล่นได้บ้าง มันก็มี SMTP, DNS, TLS ที่น่าลุ้น สำหรับข้อนี้ ก็เป็น SMTP ครับ

Your Mailing Protocol Hierarchy

หลังจากกรองเอา filter: smtp แล้วกด follow TCP stream มา ก็ได้เป็นดังนี้ครับ เป็นเลขฐาน 16 (hex) จากฝั่ง client ซ่อนไว้ในทั้งหมด 32 แพ็กเก็ตนั้นแหละ

Your Mailing SMTP Stream

T shark เพื่อเอามันออกมาเร็ว ๆ ครับ

payload ที่ได้ออกมาจะเป็น hex เลยต้อง xxd -r -p เพื่อกลับมันเป็น binary data อีกที ที่โปรแกรมอื่นอ่านออกได้ แล้วก็ output ไว้ที่ output.txt ก็ได้:

tshark -r Your_Mailing.pcap -Y "smtp" -T fields -e tcp.payload | xxd -r -p > output.txt

Your Mailing Hex Data

ลบ response จาก server ออกครับ

คราวนี้จะได้เป็นแบบนี้ มันก็คงรวมกันเป็นไฟล์อะไรซักอย่าง:

504b03041400010808001d2e8c5730af6187360000002800000008002400666c61672e7478740a00200000000000010018000029ed39842cda0100803ed5deb19d0100803ed5deb19d01223dea64bc8cbe24be34c401db66995e90e265caa5e3cde3a5b518e2397f790357aed7298be222a51a895419f543dbdebfc667166235504b010214001400010808001d2e8c5730af61873600000028000000080024000000000001002000000000000000666c61672e7478740a00200000000000010018000029ed39842cda0100803ed5deb19d0100803ed5deb19d01504b050600000000010001005a000000800000000000

ซึ่งเป็น hex อะไรซักอย่าง ซึ่งส่วนแรก ๆ มี magic number ตรงกับ pkzip

Your Mailing PKZip

chatgpt ก็ช่วยนะอันนี้ มันระบุ header ไวมากเลย
xxd -r -p output.txt output.zip

ยัดมันกลับเป็น .zip อีกรอบครับ ชั้นตอนนี้จะใช้ tool ออนไลน์ทำก็ได้ หลังจากนั้นพอ unzip output.zip ดันติดรหัสซะงั้น ผมเลยใช้ john the ripper ช่วย ซึ่งผมก็ใช้ไม่ค่อยเป็น 😅

zip2john output.zip > hash.txt
john --wordlist="path" hash.txt

Your Mailing John the Ripper

ได้ว่ารหัสคือ iloveyou2 นะครับ ก็ unzip ได้เป็น flag.txt

Flag: WCTF23{b7ceb75620bb61fc062702c197d4004c}