เนื่องจากเรื่องที่จะเขียนต่อไปนี้ มีความละเอียดอ่อนด้านจริยธรรมและกฏหมาย จึงจะขอเขียนเป็นภาษาไทย

เรื่องมันก็มีอยู่ว่า เมื่อสองวันก่อนบังเอิญผมได้ไปอ่านเจอในกระทู้ ๆ หนึ่งใน web remote-exploit.org แต่ก็เป็นกระทู้ที่นานมาแล้วแหละ สักประมาณเดือน เม.ย. 2008 ซึ่งเขียนไว้ว่า router ที่ให้ลูกค้า broadband นำไปใช้ของบริษัทใหญ่แห่งหนึ่งในประเทศที่ผมอยู่ตอนนี้ ซึ่งดังในด้านให้บริการดู TV ผ่านดาวเทียมแบบเสียรายเดือน โดยที่ตัว router ที่ให้มานั้น จะถูก SET Password เป็นแบบ WPA อยู่แล้ว โดยมี Password เป็นตัวอักษร 10 หลัก
ซึ่งฟังดูก็ปกติดี ใช้ WPA ปลอดภัยจากการโจมตี อย่างดีก็ต้องใช้เวลาถอดรหัส ไม่น่ามีอะไรผิดปกติ แต่ที่ผิดปกติมันอยู่ที่
ตัว software ของ router ยี่ห้อ NETGEAR ซึ่ง Firmware จะเป็น Firmware ที่ทาง Netgear ทำเป็นพิเศษเพื่อให้บริษัทที่แปลเป็นไทยว่า “ท้องฟ้า” นี้ โดยที่ username, password และ wpa passkey ของตัว router นั้นจะถูก set มาจากโรงงาน ซึ่งสามารถคำนวณได้จาก mac address ซึ่งเพียงแค่รันโปรแกรม net stumbler, airodump ก็สามารถเห็นได้โดยง่าย
จากนั้นผมก็เริ่มค้นหาจาก Google ว่าพอมีเบาะแสอะไรบ้างเกี่ยวกับเรื่องนี้ เพราะคนที่ใช้ router ตัวนี้อยู่ที่ประเทศนี้ ไม่น่าจะมีต่ำกว่าครึ่งล้านคน ปรากฏว่าไปพบ web นึง ซึ่งเป็นไปแล้วจริง ๆ ที่เพียงแค่กรอก mac address ลงไป ก็ได้ username, password และ wpa passkey โอ้ว ยังไงกันเนี่ย แต่ทางคนเขียน web ไม่ได้มีจุดประสงค์ให้คนนำไปใช้ในทางที่ผิด จึงกำหนดให้เข้าไปใช้ได้ วันละ 3 ครั้งเท่านั้น
เอาหล่ะ ค้นหาใน google อยู่หลายชั่วโมง ไม่มีเบาะแสอะไรเพิ่มเติม ก็เลยต้องลองเล่นกันมันสักหน่อย
โชคดีที่ทราบมาว่าตัว NETGEAR DG834G นี้ใช้ OS Linux เป็นระบบปฏิบัติการ ซึ่งแน่นอนมี License เป็นแบบ GPL คือหากมีการนำไปพัฒนา ต้องเปิดเผย Source code ด้วย ทาง Web netgear จึงมีให้โหลด firmware ของเจ้า router ทุกตัวที่ออกสู่ท้องตลาด รวมถึงตัวที่เจ้าบริษัท “ท้องฟ้า” นำมาขายให้ลูกค้าด้วย
โชคก็ไม่ดีเสมอไป ตัว firmware ที่โหลดมามี Source code ก็จริง แต่เฉพาะส่วนที่เป็น Linux ส่วนโปรแกรมอื่นที่ทาง Netgear พัฒนาขึ้นมาเอง ไม่ได้อยู่ในเงื่อนไข GPL แต่ก็ยังดีที่มีเป็น binary file เราจึงต้องมาแกะ กัน
หลังจากที่โหลดมาและแตก fileแล้ว ผมก็ได้ลองเล่นกับ binary file ต่าง ๆ ปรากฏว่าไปเจอ file นึงมีเบาะแส น่าจะเป็น file ที่เราต้องการ เพราะดูจากคำสั่งพวก plain text ภายใน file แล้วเหมือนกับทำหน้าที่หลายอย่าง file นั้นคือ /usr/sbin/rc นั่นเอง
kengz:sbin kittikan$ strings rc | grep iwconfig
iwconfig ath0 essid "%s"
iwconfig ath0 channel %d
iwconfig ath0 key %s [%d]
kengz:sbin kittikan$ file rc
rc: ELF 32-bit MSB executable, MIPS, version 1 (SYSV), dynamically linked (uses shared libs), stripped
kengz:sbin kittikan$
ตอนแรกผมก็ไม่รู้หรอกนะครับว่าเจ้า router เนี่ยมันใช้ cpu ตระกูลไหน แต่พอลองใช้คำสั่ง file ดูก็พบว่ามันเป็น CPU MIPS ซึ่งทำงานแบบ MSB Mode
MSB หรือ Most Significant Bit คือประเภทของการเรียงข้อมูลใน memory ซึ่งมีอีกชื่อนึงว่า Big Endian ซึ่งคนละแบบกับตระกูล Intel ที่เราใช้กันจะเป็น LSB หรือ Little Endian ซึ่งสองแบบนี้จะเรียงข้อมูลสลับลำดับกัน (เฉพาะตอนเก็บลง mem ข้อมูลใน register ไม่เกี่ยว)
จากนั้นผมก็ไม่รอช้า เปิดโปรแกรม ida pro ที่มีให้ disassemble ออกมาเลยซึ่งหน้าตาที่ได้ ก็คล้าย ๆ แบบนี้
.text:0040E0BC li $gp, 0xFBFA214
.text:0040E0C4 addu $gp, $t9
.text:0040E0C8 addiu $sp, -0xD0
.text:0040E0CC sw $ra, 0xD0+var_8($sp)
.text:0040E0D0 sw $s3, 0xD0+var_C($sp)
.text:0040E0D4 sw $s2, 0xD0+var_10($sp)
.text:0040E0D8 sw $s1, 0xD0+var_14($sp)
.text:0040E0DC sw $s0, 0xD0+var_18($sp)
.text:0040E0E0 sw $gp, 0xD0+var_C0($sp)
.text:0040E0E4 lw $v0, (off_100002F4 - 0x100082D0)($gp)
.text:0040E0E8 lw $t9, (off_100003E4 - 0x100082D0)($gp)
.text:0040E0EC addiu $a0, $sp, 0xD0+var_2F
.text:0040E0F0 lbu $v0, 0x7330($v0)
.text:0040E0F4 move $a1, $0
.text:0040E0F8 li $a2, 9
.text:0040E0FC jalr $t9
.text:0040E100 sb $v0, 0xD0+var_30($sp)
.text:0040E104 lw $gp, 0xD0+var_C0($sp)
.text:0040E108 addiu $a0, $sp, 0xD0+var_B8
.text:0040E10C move $a1, $0
.text:0040E110 lw $t9, (off_100003E4 - 0x100082D0)($gp)
.text:0040E114 li $a2, 0x80
.text:0040E118 jalr $t9
.text:0040E11C addiu $s3, $sp, 0xD0+var_30
.text:0040E120 lw $gp, 0xD0+var_C0($sp)
.text:0040E124 move $a0, $s3
.text:0040E128 move $a1, $0
.text:0040E12C lw $t9, (off_100003E4 - 0x100082D0)($gp)
.text:0040E130 li $a2, 0xA
.text:0040E134 sh $0, 0xD0+var_38($sp)
.text:0040E138 jalr $t9
.text:0040E13C sb $0, 0xD0+var_36($sp)
.text:0040E140 lw $gp, 0xD0+var_C0($sp)
.text:0040E144 addiu $a1, $sp, 0xD0+var_20
.text:0040E148 move $s1, $0
.text:0040E14C lw $a0, (off_100002F4 - 0x100082D0)($gp)
.text:0040E150 lw $t9, (myPipe_ptr - 0x100082D0)($gp)
.text:0040E154 move $s2, $0
.text:0040E158 jalr $t9
.text:0040E15C addiu $a0, 0x72D4
.text:0040E160 lw $gp, 0xD0+var_C0($sp)
.text:0040E164 addiu $v0, $s1, 1
งง เลย ใช่ไหมหล่ะครับ ไม่ต้องแปลกใจครับ ผมก็งง ผมไม่เคย reverse MIPS มาก่อน ซึ่ง Instruction set ก็ไม่เหมือนกับ Intel และ register ก็ชื่อแปลก ๆ มากมาย ตั้งแต่ s0, s1, s2… a0, a1, a2… v0, v1,… โอยจำได้ไม่หมด คำสั่งก็งง ๆ ยิ่งไปกว่านั้นในการเรียก function ยังทำให้งงไปใหญ่ ส่วนโปรแกรม IDA Pro ที่ผมใช้ disassemble มันออกก็ยังทำได้ไม่ดี ไม่ resolve พวก symbol และ reference ให้ บอกตามตรง อ่านแทบไม่รู้เรื่อง
จึงต้องหามาพึ่งพี่ google เพื่อดูคู่มี Instruction set ของ MIPS ว่าตัวไหนทำอะไรได้บ้าง (ผมไม่ได้อ่านหมดนะครับ ไล่โปรแกรมไป แล้วสงสัยตัวไหนแบบละเอียดค่อยดู) และพยายามหาเทคนิคการ Reverse engineer สำหรับ MIPS ปรากฏว่าในโลกนี้แทบไม่มีใคร reverse MIPS เท่าไรนัก ที่เจอมีแค่คนเดียวคือคุณ Julian http://www.cr0.org/paper/mips.elf.external.resolution.txt เขียนไว้คร่าว ๆ ว่าการเรียก function ของ MIPS แบบ ELF เป็นลักษณะไหน
จากพิจารณาตามที่คุณ julian บอกไว้แล้ว ผมจึงต้องความหา uclibc toolchian มาเพิ่มใช้ objdump สำหรับ MIPS รวมถึง readelf ด้วย ผมลองมาแกะข้อมูลต่าง ๆ และยัดค่าต่าง ๆ ลงใน file ที่ได้จากมา IDA โดยใช้ perl script และ tool ตามที่ตา Julian บอกไว้ จึงทำให้ code ที่แกะได้มา ดูดีขึ้นมาก แทบจะเริ่มอ่านรู้เรื่องแล้ว ดังเช่นแบบนี็
.text:0040D924 li $v0, 0x62
.text:0040D928 beq $v1, $v0, loc_40D998
.text:0040D92C lw $t9, (create_upnp_cfg_ptr - 0x100082D0)($gp) # create_upnp_cfg -> $t9
.text:0040D930 jalr $t9
.text:0040D934 nop
.text:0040D938 lw $gp, 0xA8+var_98($sp)
.text:0040D93C move $a2, $s0
.text:0040D940 addiu $a0, $sp, 0xA8+var_90
.text:0040D944 lw $a1, (off_100002F4 - 0x100082D0)($gp) # aTmpNvram -> $a1
.text:0040D948 lw $t9, (off_100003A4 - 0x100082D0)($gp) # sprintf -> $t9 (sub_40FEE0)
.text:0040D94C jalr $t9
.text:0040D950 addiu $a1, 0x724C # "route add -net 239.0.0.0 netmask 255.0.0.0 %s"
.text:0040D954 lw $gp, 0xA8+var_98($sp)
.text:0040D958 lw $t9, (off_10000500 - 0x100082D0)($gp) # system -> $t9 (sub_40FC30)
.text:0040D95C jalr $t9
.text:0040D960 addiu $a0, $sp, 0xA8+var_90
.text:0040D964 lw $gp, 0xA8+var_98($sp)
.text:0040D968 addiu $a0, $sp, 0xA8+var_90
.text:0040D96C lw $a1, (off_100002F4 - 0x100082D0)($gp) # aTmpNvram -> $a1
.text:0040D970 lw $a2, (off_100002F4 - 0x100082D0)($gp) # aTmpNvram -> $a2
.text:0040D974 lw $t9, (off_100003A4 - 0x100082D0)($gp) # sprintf -> $t9 (sub_40FEE0)
.text:0040D978 addiu $a1, 0x727C # "%s&"
ทำให้ดูคร่าว ๆ ออกว่า มีการเรียกอะไรตรงไหนเกิดขึ้นบ้าง แต่ปัญหาต่อไปที่เจอก็คือ ไม่เข้าใจ step การทำงานลึก ๆ เพราะในการทำ reverse engineering นั้นต้องสามารถไล่ step การทำงานได้จึงจะสามารถ เขียน algorithm ตามนั้นได้ ซึ่งผมต้องเสียเวลาถึงครึ่งวันในการเข้าใจการทำงานของมัน ซึ่งผมก็ได้เขียนโปรแกรมที่แกะ algorithm ออกมาเป็นภาษา perl (อีกแล้ว) และทดลองดูปรากฏว่าได้ output เหมือนกับ web ของนาย julian
ตัวอย่างโดยการใส่ mac address เป็น 11:22:33:44:55:66 อันบนเป็นของนาย Julian อันล่างเป็นของผม


แฮะ ๆ มี bug นิดหน่อยเนื่องจากใน algorithm มีคำสั่งคุณด้วย ผมลัพธ์ที่ได้ของ MIPS จะมีขนาด 64bit
จากการที่ได้ลองทำครั้งนี้ ทำให้รู้ถึงคำสั่งของ MIPS และเทคนิคเกี่ยวกับ MSB รวมถึงการเรียก function ของ ELF ดีขึ้นมาก ซึ่งผมคิดว่ามีหลายประเทศไม่น้อย ที่มีการใช้เทคนิคนี้ในการ generator wifi password ให้กับลูกค้า…
ผมไม่สามารถเปิดเผย algorithm และ code ส่วนนั้นได้ เนื่องจากเหตุผลด้านจริยธรรมและกฏหมาย (ethical and legal issue) หากใครมีข้อสงสัย สอบถามได้ฮะ
Reversing