[Write-up] War is so dangerous Reverse 250 Thailand CTF 2019

กราบสวัสดีผู้อ่านทุกท่าน บทความนี้เราจะมาชำแหละโจทย์ข้อ Reverse 250 War is so dangerous กันอย่างละเอียด โดยเราจะเฉลยวิธีแก้โจทย์นี้ทั้งหมด 3 แบบ จากยากไปง่าย เพื่อให้ผู้อ่านได้เรียนรู้กระบวนการทำ reverse engineering เพิ่มเติมจากโจทย์ข้อนี้ไปด้วยกัน ก่อนอื่นต้องขอแสดงความยินดีกับสมาชิกทีม MAYASEVEN ที่ได้เข้าร่วมแข่งขันงาน Thailand CTF 2019 และได้อันดับที่ 1 ตบมือ…

มาเริ่มกันครับ

เริ่มต้นโจทย์นี้ให้ไฟล์ชื่อว่า ezrev มา เรามาวิเคราะห์กันก่อนว่ามันคือไฟล์ประเภทไหนโดยใช้คำสั่ง file ได้ ผลลัพธ์ตามด้านล่าง

จะเห็นว่าเป็นไฟล์ ELF 64-bit ก็คือไฟล์ executable เหมือนไฟล์ exe บน windows แต่ที่ต่างกันคือไฟล์นี้เป็นไฟล์ ที่ทำงานได้บน linux 64-bit นั้นเอง เราเริ่มจากลอง run โปรแกรมนี้
คำเตือน: ไม่ควร run executable ไฟล์ ที่เราได้มาจากแหล่งที่ไม่น่าเชื่อถือ ในเคสนี้เรา run ใน vmware เพื่อวิเคราะห์โจทย์

หลังจาก เราได้เปิดโปรแกรมแล้วจะเห็นว่าโปรแกรมให้ใส่ key ถ้าใส่ key ไม่ถูกจะขึ้นบอกว่า Bro… please_try again 😐

เริ่ม disassembly โปรแกรมนี้ด้วย IDA กัน

จาก assembly code ด้านบน ทำให้เราเข้าใจ logic ของโปรแกรมได้ดังนี้
1. โปรแกรมทำการรับ input เข้ามาผ่าน scanf function
2. call validate function เพื่อ validate key
3. ถ้า key ถูกต้อง จะมาทำงานต่อกล่องด้านซ้ายแสดงข้อความว่า Key valid 😀 และ call process function เพื่อดึง flag มาให้เรา
4. ถ้า call validate function แล้ว key ไม่ถูก จะทำงานกล่องด้านขวาคือแสดงข้อความว่า  Bro… please_try again 😐 แล้วจบโปรแกรม

จากการทำงานด้านบน ผมคิดวิธีแก้โจทย์นี้ได้ 3 แบบ ผมจะเรียงจากยากไปง่ายเพราะทีมเราชอบทำอะไรยากๆ 😀
1. วิเคราะห์ validate function algorithm ว่า key ที่ถูกต้อง ต้องประกอบไปด้วยอะไรบ้าง อารมณ์เหมือนวิเคราะห์ algorithm และสร้างโปรแกรม keygen
2. วิเคราะห์ process function ว่าดึง flag มาได้อย่างไร
3. ทำ binary patching คือแก้ logic ในการ validate ว่าถ้า key ผิดให้เป็นไปทำงานกล่องซ้ายแทน

วิธีที่ 1 วิเคราะห์ validate function algorithm หารูปแบบ key ที่ถูกต้อง

รูปด้านบนเป็นการทำ decompile ไฟล์ ezrev ด้วย IDA กลับมาเป็นภาษา C แต่ก็ยังอ่านเข้าใจยากอยู่เหมือนกัน เราจะมาทำความเข้าใจกันแบบ step by step ครับ
1. บรรทัดที่ 21 ทำการตรวจสอบว่า key ยาว 19 ตัวหรือไม่
2. บรรทัดที่ 23 – 29 ทำการลูป 19 รอบ ในบรรทัดที่ 26 มีการตรวจสอบ key 11 ตัวแรก ตรงนี้จะยากนิดนึงเพราะ IDA ติด bug ในการ decompile บรรทัดที่ 27 JUMPOUT บลาๆๆ เลยไม่รู้ว่าเอาไปเช็คกับอะไร เราเลยได้ทำการ manual ถอดจาก assembly ได้ความว่า 11 ตัวแรกของ key ต้องประกอบด้วย Th@i|andCTF
3. บรรทัดที่ 30 มีการตรวจสอบว่าตัวสุดท้ายของ key ต้อง = 35 หรือ # นั้นเองตอนนี้เราได้ key บางส่วนแล้วคือ Th@i|andCTFXXXXXXX# เหลือตรง X ที่เราต้องแกะกันต่อ
4. บรรทัดที่ 34 – 40  มีการกำหนดค่าให้ตัวแปรหลายตัว แต่ตัวที่ถูกเอาไปใช้จริงๆคือตัวแปร v10 ตัวเดียว ก่อนที่เราจะเข้าใจได้ว่าค่าตัวแปร v10 คือเท่าไหร่ให้เรามาทำความเข้าใจ tm struct ของภาษา C กันก่อนตามรูปด้านล่าง

v10 = (*(_QWORD *)&v2->tm_mon >> 32) + 1900;
// (*(_QWORD *)&v2->tm_mon >> 32) คือการเอาค่าใน tm_mon ทำ right shift 32 bits หรือ 4 bytes 
// ตามโครงสร้างของ tm struct ด้านบน ทำให้เราได้ค่า v2->tm_year มาแทน v2->tm_mon 
// เป็น v10 = v2->tm_year + 1900; // v10 = 2019

5. บรรทัดที่ 43-47 เป็นการอ่าน key ที่เรากรอกใส่โปรแกรมตัวที่ 15 – 18 มาแปลงเป็น int
(เกล็ดความรู้เราสามารถแปลงตัวเลขที่เป็น char ให้เป็น int ได้ด้วยการเอา decimal ascii ของตัวเลขนั้น – 48)
6. บรรทัดที่ 48 ทำการตรวจสอบว่า key ที่กรอกมา = v10 หรือ 2019 หรือไม่ ถึงตรงนี้เราได้ส่วนหนึ่งของ key เป็น Th@i|andCTFXXX2019# เหลือ X อีกแค่ 3 ตัวเท่านั้นที่เราต้องแกะต่อ
7. บรรทัดที่ 49 คือการเช็คว่า v14 == 1557 หรือไม่ ถ้าเท่ากัน คือ return 1 คือ key ถูกต้อง แล้ว v14 คืออะไร ? ย้อนกลับไปดูบรรทัดที่ 23-25 คือ

while ( a1[v15] )
{
v14 += a1[v15];
...
}

จากโค้ดด้านบนคือการเอาค่า ascii ของ key ที่เรากรอกทั้งหมดมาบวกกันนั้นเอง
(เกล็ดความรู้การเอา ascii ของ key ทั้งหมดไปบวกกัน เป็นการทำ checksum แบบหนึ่งที่ไม่ปลอดภัย)
8. ตอนนี้สิ่งที่เรามีคือ Th@i|andCTFXXX2019# เราจะใส่ XXX เป็นอะไรก็ได้ที่ทำให้ ascii ทั้งหมดของ key นี้บวกกันได้ 1557 เช่น Th@i|andCTFdZw2019#

คนที่สร้าง enigma คือ Arthur Scherbius
Flag คือ THCTF{arthurscherbius}

วิธีที่ 2 วิเคราะห์ process function ว่าดึง flag มาได้อย่างไร

ภายในฟังก์ชั่น process เราเห็นว่ามีการเรียกใช้ฟังก์ชั่น launch โดยระบุ IP จำนวน 6 ชุดดังนี้
192.0.32.53, 213.208.154.7, 193.60.92.244, 202.7.59.24, 8.8.8.8, 128.125.82.80
ในบรรทัดที่ 22, 27, 29, 32, 37, 39

เมื่อเราวิเคราะห์ฟังก์ชั่น launch ทำให้เรารู้ว่ามีการดึง hostname โดยใช้ฟังก์ชั่น gethostbyaddr ของ IP ทั้ง 6 ชุด

และค่า hostname ที่เราได้จากฟังก์ชั่น launch จะถูกนำมาต่อกัน ในบรรทัดที่ 31, 41, 44
ดังรูปด้านบน ในบรรทัดที่ 31 มีการเรียกค่าจากตัวแปร dest มาแสดง ซึ่งค่า dest ก็คือ hostname ของ IP 192.0.32.53 (บรรทัด 22)
เราก็ลอง manual โดยใช้คำสั่ง host 192.0.32.53 ได้ผลลัพธ์ดังรูปด้านล่าง

ค่า hostname ที่ได้คือ whois.icann.org ถูกใส่ลงไปในฟังก์ชั่น cut ในบรรทัดที่ 23 โดยในฟังก์ชั่น cut มีการวนลูปเพื่อเอาค่าจาก hostname โดยเอาเฉพาะค่าที่อยู่ก่อน “.” แรก
หมายความว่าโปรแกรมจะแสดงข้อความว่า “Hi whois” เราเริ่มจับทางได้แล้ว ทีนี้เราก็ทำแบบเดียวกันกับ IP ที่เหลือครับ

ในบรรทัดที่ 41 ก็มีการเรียกค่าจากตัวแปร dest มาแสดง ซึ่งค่า dest ในบรรทัดนี้ถูกแทนที่ด้วย hostname ของ IP 202.7.59.24 (บรรทัด 32) และผ่านฟังก์ชั่น cut ก็จะได้คำว่า inventor ดังนั้นโปรแกรมจะแสดงข้อความว่า “ the inventor”

สุดท้ายในบรรทัดที่ 44 ใช้ hostname ที่ได้จาก IP 128.125.82.80 (บรรทัด 39) เมื่อผ่านฟังก์ชั่น cut เราจะได้คำว่า enigma ข้อความก็คือ “ of enigma ???”

รวมข้อความทั้งหมดที่ได้ก็คือ “Hi whois the inventor of enigma ???”
คนที่สร้าง enigma คือ Arthur Scherbius
Flag คือ THCTF{arthurscherbius}

วิธีที่ 3 ทำ binary patching คือแก้ logic ในการ validate

วิธีนี้ง่ายที่สุดคือการแก้ logic จากกรอก key ที่ผิดให้โปรแกรมเข้าใจว่า key นั้นถูกต้อง

จากรูปด้านบนให้เราสังเกตที่บรรทัดดังนี้
call validate // เรียกใช้ validate function จากการวิเคราะห์ด้วยวิธีที่ 1 ถ้า key ถูกจะ return 1 ถ้าผิด return 0
cmp eax, 1 // การ return ค่าจาก function โดยทั่วไปจะอยู่ใน register eax ในที่นี้ถ้า validate แล้ว key ถูก eax จะเท่ากับ 1 ถ้าไม่ถูกเท่ากับ 0
(เกล็ดความรู้ การ compare หรือเปรียบเทียบค่าตัวเลขในทางคอมพิวเตอร์
คือการเอาตัวเลข 2 ตัวมาลบกัน
ถ้าลบกันได้ 0 คือค่าเท่ากัน
ถ้าลบกันแล้วได้เลขบวกคือค่าที่ 1 มากกว่า
ถ้าลบกันแล้วติดลบแสดงว่าค่าที่ 1 น้อยกว่า)
(เกล็ดความรู้เพิ่มเติม การกระทำระหว่างค่า 2 ค่า ถ้าได้ผลลัพท์เป็น 0 zero flag จะถูก set เป็น 1 โดยทั่วไป zero flag จะถูกใช้เป็นเงื่อนไขในการ jump)

jnz short loc_17c8 //  jnz เป็นการ jump แบบมีเงื่อนไขคือ ถ้า zero flag เป็น 0 จะ jump ไปที่ loc_17c8 หรือกล่องด้านขวา

สิ่งที่เราต้องทำคือแก้ค่าจาก
cmp eax, 1
เป็น
cmp eax, 0
จากนั้นเราใส่ key อะไรก็ได้ที่ไม่ใช่ key ที่ถูกต้อง โปรแกรมจะเข้าใจว่าเป็น key ที่ถูกต้องทั้งหมด

คนที่สร้าง enigma คือ Arthur Scherbius
Flag คือ THCTF{arthurscherbius}

Download ezrev : https://drive.google.com/file/d/1yJdjeARqvgUgSl0IuR-_bK-X4zqsT8PG
md5sum (ezrev.zip): 1a96c6626fe910eb89448a1842cb0ad5

Previous Post
Third-Party Software Help or Harm
Next Post
[Write-up] Covert Channel 4 TH Capture the Packet

Related Posts

No results found.

Leave a Reply

Your email address will not be published. Required fields are marked *

Fill out this field
Fill out this field
Please enter a valid email address.
You need to agree with the terms to proceed