Reversing a router for fun and profit.

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

 

เรื่องมันก็มีอยู่ว่า เมื่อสองวันก่อนบังเอิญผมได้ไปอ่านเจอในกระทู้ ๆ หนึ่งใน 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) หากใครมีข้อสงสัย สอบถามได้ฮะ

เมื่อถูกท้าทาย

หลังจากที่ไม่ได้เปิด Facebook มานาน วันนี้ลองเข้าไปดูเล่น ๆ ปรากฎว่ามี Invitation มาให้เล่นเกมส์ word challenge
ไอ้เราก็ลองเล่นไปเล่นมา รู้สึกสนุกดีนะ แต่คิดศัพย์ไม่ค่อยออกเลย ก็เลยเขียน script มาช่วยค้นหาศัพย์ ซึ่งเขียนด้วย perl

ก่อนอื่นก็ไปหา dictionary ก่อนเลยไม่ค่อยมีที่ถูกใจ จนมาพบกับ web นึงซึ่งค่อนข้างดูแปลก (รึเปล่า)

นั่นคือ http://zyzzyva.net/ ตรงข้างล่างมีรวบรวมศัพย์หลาย ๆ แบบ เราก็เลยจับเอามายำกันซะ ให้เหลือศัพย์ที่มีความยาว 3 – 6 ตัวอักษร

จากนั้นก็เขียน perl เพื่อมา search ศัพย์จากตัวอักษรที่มีอยู่ ซึ่ง algorithm ไม่มีอะไรมาก คืออ่าน file เข้ามาแล้วก็ก็จัดการเรียงตัวอักษรซะใหม่ แล้วจึงค่อยจัดเก็บเข้า mem แบบ hash จะได้ไม่ต้องมาวน loop เพื่อ search หลาย ๆ รอบ จากนั้นก็ส่วนของการรับ input ก็เขียนให้เอาตัวอักษรมา 3 – 6 ตัวทุก combination มา search ใน hash ที่เตรียมไว้

ตอนแรกก็พิมพ์ตาม ศัพย์ที่มีใน dictionary นั่นแหละ แต่ทำไปทำมาชักไม่สะดวก โชคดีที่ perl มี Module ชื่แ Win32::GuiTest ซึ่งมีคำสั่ง Sendkey ของ windows… เสร็จโจรเลยหล่ะ ทีนี้ ผลลัพธ์ที่ได้คือ… ดัง VDO


ส่วน code นั้นก็เขียนแบบง่ายๆ มีเนื้อหาดังนี้

use Win32::GuiTest qw(FindWindowLike GetWindowText
SetForegroundWindow SendKeys);
use Win32::Clipboard;

load_word();
$min = 3;
$max = 6;

while(1)
{
	print "Input : ";
	$input = ;
	chomp($input);

	SetForegroundWindow(658262);
	doit($input);
}

sub doit
{
	my $set = shift;
	@answer = "";
	@list2 = "";
	for(my $i=$max;$i >= $min;$i--)
	{
		@list = "";
		find_com($set,"",0,$i);
		@list = sort(@list);
		foreach $l (@list)
		{
			push @list2,$l;
		}
	}

	my %ww = "";

	foreach $l (@list2)
	{

		if($word{$l})
		{
			for(my $i = 0;$i < $word{$l}; $i++)
			{
				if(!$ww{$words{$l}[$i]})
				{
					#print "$l = $words{$l}[$i]\n";
					push @answer, $words{$l}[$i];
					$ww{$words{$l}[$i]} = 1;
				}
			}
		}
	}
	print "\n\n";

	@answer = sort {length $a <=> length $b || $a cmp $b} @answer;
	foreach $ans (@answer)
	{
		if($ans eq "")
		{
			next;
		}
		if(length($ans) == 6)
		{
			print ">>> $ans\n";
			next;
		}
		SendKeys("$ans~");
		print "Trying $ans\n";
	}

	print "\n\n";
}

sub find_com
{
	my $set = shift;
	my $this_text = shift;
	my $count = shift;
	my $max = shift;
	for(my $i = $count;$i < length($set) ; $i++)
	{
		my $the_text = $this_text . substr($set,$i,1);
		if(length($the_text) == $max)
		{
			my $x = rearrange($the_text);
			push @list,$x;

		}
		elsif(length($set) - $i < $max - $count)
		{
			return;
		}
		else
		{
			find_com($set,$the_text,$i+1,$max);
		}
	}
}

sub rearrange
{
	my $text = shift;
	my @tmp;
	for(my $i = 0 ; $i < length($text) ; $i++)
	{
		my $sub = substr($text,$i,1);
		push @tmp, $sub;
	}
	@tmp = sort(@tmp);
	return join("",@tmp);
}

sub load_word
{

	open(READ,"enable1.txt");
	@data = ;
	close(READ);
	chomp(@data);

	my $set = shift;
	my $min = 3;
	my $max = 6;

	foreach $line (@data)
	{
		if(length($line) < 3 || length($line) > 6)
		{
			next;
		}
		$re = rearrange($line);
		if(!$word{$re})
		{
			$words{$re}[0] = $line;
			$word{$re} = 1;
		}
		else
		{
			$words{$re}[$word{$re}] = $line;
			$word{$re}++;
		}
	}
}

Rard Nah in London (ราดหน้า ใน ลอนดอน)

IMG_0916.JPG

Hi, Long time no see.
After never update the blog for quite a long time (actually, it’s really a long time). I’ve decided to update the blog again! (Applause !!). I’ve been living in UK for about 5 months. The weather was terrible when I had just arrived but it’s better now (I hope so).

The thing is ‘Living Cost’ here is quite expensive, especially for accommodations, transportations and food. I had to live unambitiously everyday since then. So, I’ve improved my cooking skill a lot ! I’ll show you what i’ve done today !

I just have finished cooking Ba-Mee Rard Nah (บะหมี่ราดหน้า) and have taken 4 – 5 photos. It’s not so bad. Actually, I think it’s perfect and lovely. Let see how I made this !

 

IMG_0909.JPG

First of all, I’ve got chicken breast, asparagus, shiitake mushroom, garlic, spinach (you might not see, it’s on the top right corner of the picture) and chinese fresh noodle. I prepared garlic oil (กระเทียมจียว) by putting sliced chopped garlic in hot oil and stir-fried it until the garlic turned yellow.

IMG_0912.JPG

After I had finished preparing garlic oil. I scalded the noodle by pouring boiling water into it, make sure you do not take this too long because the noodle will be softer than you want. Then I put a little amount of garlic oil into to ensure it’s going to be too dry.  

 

IMG_0913.JPG

Heat the pan again with garlic oil left in the pan. After the oil is hot enough, Put chicken and stir fry it ! After chicken had been cooked, I put asparagus first and then mushroom, Try to add some sauces like, Oyster sauce(น้ำมันหอย), Fish sauce(น้ำปลา), Knor(คนอร์ผง), Soya sauce(ซอสแม็กกี้) and Sugar.

IMG_0914.JPG

I poured hot water into it, In my taste I like a lot of water, so I use a bit more water. Taste it again, added more ingredients. 

IMG_0915.JPG

After it had been boiling for a short period, I just added watered tapioca flour to make it a bit thick and tough. Bring it to boil again, put spinach and pour it on top of the noodle.

IMG_0916.JPG

Finally, I’ve got Ba-mee Rard Nah (บะหมี่ราดหน้า) like a picture above. I’m sure, It will make you mouth-watered. 

The Better Wireless Signal

 จู่ ๆ ก็นึกสนใจในเรื่อง Wireless Lan ขึ้นมา ลองเล่นดูสักพัก..

ไม่พอใจ ทำไมสัญญาณห่วยแบบนี้.. อย่างนี้ต้อง Modify เพื่อสัญญาณที่ดีกว่า

IMG_0085

เริ่มต้นด้วย D-Link DWL G122 รุ่น Rev C1. (ใช้ Chip ของ Ralink) คอ Wireless คงรู้กันดีว่าทำไมต้องใช้รุ่นนี้
ตามมาด้วย Antenna ใช้ของ pci (จีนแดง) เขียนไว้ว่า 8 dBi ซึ่งมากเกินพอสำหรับ Client เสารุ่นที่ใช้เป็นแบบ Omni ซึ่งจะมีลักษณะรัศมีเป็นวงคล้ายโดนัท
เนื่องจากไม่สามารถหาหัวต่อ Antenna ได้จึงลงทุนซื้อหัวแปลง Antenna เป็นแบบ Linksys ในราคาค่อนข้างจะไม่สมเหตุสมผล

IMG_0086 

ทำการแงะตัว D-Link DWL G122 ออกมาแล้วก็

. . . X X X . . .

จนได้ตัวนี้

IMG_0102 

พออยู่ในฐานที่แถมมากับ D-Link ก็ดูดีเหมือนกันนะ

IMG_0098 

จากนั้นก็ทดสอบปรากฎว่าใช้งานได้ และมีสัญญาณที่แรงกว่าแบบเก่ามาก

สังเกตุจำนวนข้อมูลที่ดักได้ และ Access Point ที่หาเจอในรัศมี เทียบให้ดูกันจะ ๆ

IMG_0101

แบบเดิม ๆ เจอเพียง 3 APs และไม่เจอ Connection เลย

IMG_0100 

พอใส่เสาเข้าไปเท่านั้นแหละ เจอตรึม และข้อมูลสิ่งเยอะกว่ามาก

. . . 

ซื้อของเข้าห้อง

เงินเดือนออกทั้งที ซื้อของเข้าห้องดีกว่า

IMG_0051  

IMG_0056 

IMG_0058 

IMG_0060 

IMG_0059 

Return top