การโจมตีและช่องโหว่ประเภท SQL Injection

SQL Injection

SQL Injection เป็นหนึ่งในช่องโหว่ที่ร้ายแรงและพบได้มากเป็นอันดับต้น ๆ ของช่องโหว่ในเว็บแอปพลิเคชันจนถูกจัดให้เป็นช่องโหว่อันดับ 1 ใน OWASP TOP 10 ทั้งในปี 2010 และ 2013 ในบทนี้เราจะมาอธิบายถึงรูปแบบการโจมตีด้วย SQL Injection รวมถึงลักษณะของ SQL Injection ประเภทต่าง ๆ เช่น Blind SQL Injection และ Piggy-backed Queries พร้อมทั้งวิธีที่นักพัฒนาเว็บสามารถนำไปประยุกต์ใช้ในการป้องกันการโจมตีประเภทนี้

รู้จักกับ SQL

ต้องยอมรับว่าในปัจจุบัน ฐานข้อมูล นับว่าเป็นส่วนประกอบสำคัญในเว็บแอปพลิเคชันเกือบทุกเว็บ เนื่องด้วยฐานข้อมูลเป็นแหล่งที่ใช้ในการเก็บข้อมูลของเว็บแอปพลิเคชัน ไม่ว่าจะเป็นข้อมูลผู้ใช้งาน ข้อมูลกระดานสนทนา หรือข้อมูลอื่น ๆที่แตกต่างกันไปตามชนิดของเว็บ เรียกได้ว่าการทำงานระหว่างเว็บแอปพลิเคชันและฐานข้อมูลนั้นมีความสัมพันธ์กันอย่างใกล้ชิด โดยปกติเมื่อเว็บแอปพลิเคชันต้องการเรียกดู แก้ไข เพิ่ม หรือลบข้อมูลในฐานข้อมูลก็จะส่งสิ่งที่เรียกว่า SQL statement หรือเรียกอีกชื่อ SQL query ไปให้กับฐานข้อมูล ดังนั้นเราสามารถเรียกได้ว่า SQL เป็นภาษาที่ใช้ในการสั่งการฐานข้อมูลนั่นเอง

ชนิดของฐานข้อมูลและ SQL statement

ปัจจุบันมีฐานข้อมูล (Database Management System) อยู่หลายชนิดด้วยกัน ทั้งที่เป็น opensource หรือมี license โดยฐานข้อมูลที่เป็นที่รู้จักในวงกว้างได้แก่ MySQL PostgreSQL MSSQL Oracle DB2 เป็นต้น โดยฐานข้อมูลเหล่านี้ใช้ภาษา SQL ในสั่งการด้วยกันทั้งนั้น โดยรูปแบบของ SQL statement อาจมีการแตกต่างกันในรายละเอียด แต่รูปแบบโดยรวมมีความคล้ายกันมาก

ประเภทของฐานข้อมูล

ฐานข้อมูลในปัจจุบันแบ่งออกเป็น 2 ประเภทใหญ่ ๆ นั่นคือ relational database และ NoSQL database โดย relational database นั้นเป็นฐานข้อมูลที่ได้รับความนิยมมาก่อนเนื่องและใช้ภาษา SQL ในการควบคุม ส่วน NoSQL database เช่น MongoDB นั้นเป็นฐานข้อมูลที่เกิดขึ้นมาในภายหลังและไม่ได้ใช้ภาษา SQL ในการควบคุม ดังนั้นจะเห็นได้ว่าฐานข้อมูลประเภท relational database เท่านั้นที่มีโอกาสเกิดช่องโหว่ประเภท SQL Injection

โครงสร้าง SQL statement อย่างง่าย

SQL statement ที่นิยมใช้กันบ่อยประกอบไปด้วย 4 ฟังก์ชันนั่นคือ การเรียกดูข้อมูล (SELECT) การเพิ่มข้อมูล (INSERT) การแก้ไขข้อมูล (UPDATE) และการลบข้อมูล (DELETE) ในฐานข้อมูล โครงสร้างของ SQL statement อย่างง่ายดังตัวอย่างด้านล่าง

SELECT column_name,column_name
FROM table_name;


INSERT INTO table_name column1,column2,column3,...
VALUES value1,value2,value3,...;


UPDATE table_name
SET column1=value1,column2=value2,...
WHERE some_column=some_value;


DELETE FROM table_name
WHERE some_column=some_value;

MySQL และ PHP

MySQL และ PHP เป็น 2 เทคโนโลยีที่ใช้ในการสร้างเว็บแอปพลิเคชันที่ได้รับความนิยมเนื่องด้วยความง่ายในการพัฒนาและเป็น opensource เพื่อให้การอธิบาย SQL injection เป็นไปอย่างง่ายในบทความนี้จะขอใช้ซอร์สโค้ดที่เขียนอยู่ในภาษา PHP ที่ใช้ติดต่อกับ MySQL เป็นหลักในการอธิบาย

 

SQL Injection Example

ให้ลองพิจารณาซอร์สโค้ดในเว็บแอปพลิเคชันซึ่งประกอบไปด้วย 2 ไฟล์ คือ login_check.php และ login_form.php ด้านล่าง

login_check.php

<?php
$servername = "localhost";
$username = "root";
$password = "toor";
$dbname = "owasp";
// Create connection
$conn = mysql_connect($servername, $username, $password);
// Check connection
$select = mysql_select_db($dbname, $conn);

$username = $_POST['user_username'];
$password = $_POST['user_password'];
$sql = "SELECT * FROM users WHERE username = '$username' AND password = '$password'";

echo $sql;
echo "<br/>";

$result = mysql_query($sql);
echo "<br/>";

if(mysql_num_rows($result) > 0){
 echo "login success";
 setcookie("username", $username);
}else{
 echo "login fail";
}

?>

login_form.php

User Login Here
<form action="user_login.php" method="post">
        <input type="text" name="user_username"><br/>
        <input type="text" name="user_password"><br/>
        <button type="submit" value="submit" name="login">submit</button>
</form>

อธิบายการทำงาน

ไฟล์ PHP สองไฟล์ด้านบนเป็นตัวอย่างเว็บแอปพลิเคชันที่มีช่องโหว่ SQL Injection อยู่ โดยไฟล์ login_form.php ทำหน้าที่แสดงแบบฟอร์มให้ผู้ใช้งานทำการกรอก username และ password เพื่อยืนยันตัวบุคคล เมื่อผู้ใช้งานทำการกรอกข้อมูลลงใน login_form.php และกด submit แล้วข้อมูล username และ password จะถูกส่งต่อไปที่ไฟล์ login_check.php เพื่อทำการตรวจสอบว่า username และ password ที่ส่งมาตรงกับข้อมูลในฐานข้อมูลหรือไม่ จะเห็นได้ว่าไฟล์ login_check.php จะทำการส่ง SQL query ชนิด SELECT ไปยังฐานข้อมูลโดยนำ username และ password มาประกอบให้เป็น SQL query ที่สมบูรณ์ หากฐานข้อมูลตรวจสอบว่า username และ password ตรงกับข้อมูลที่เก็บอยู๋ในฐานข้อมูลก็จะทำการส่งข้อมูลกลับมาให้ login_check.php แต่หากพบว่าไม่ตรงก็จะไม่ส่งข้อมูลกลับมาให้ login_check.php จะเห็นได้ว่า login_check.php จะทำการแสดงผลว่า login success หาก username และ password นั้นถูกต้องและ login fail ในทางกลับกัน

*เพื่อให้เป็นการง่ายแก่การอธิบาย login_check.php จะทำการแสดงผล SQL statement ที่สร้างขึ้นมาด้วย

แบบฟอร์มสำหรับกรอก username และ password

Screen Shot 2559-01-06 at 3.07.02 PM


 

เมื่อ Login ด้วย username และ password ที่ถูกต้อง

Screen Shot 2559-01-06 at 3.04.16 PM


 

เมื่อ Login ด้วย username และ password ที่ผิด

Screen Shot 2559-01-06 at 3.16.05 PM


 

Bypassing Authentication

ช่องโหว่ SQL Injection ของการตรวจสอบการ login ดังกล่าวเกิดจากการที่ login_check.php นำ ข้อมูลที่ได้รับมาจากผู้ใช้งาน มาสร้างเป็น SQL statement โดยไม่ได้ตรวจสอบก่อนว่าข้อมูลที่ส่งมานั้นถูกต้องและไม่เป็นอันตรายต่อเว็บหรือไม่ จากข้อผิดพลาดดังกล่าวทำให้ผู้ไม่หวังดีสามารถส่งข้อมูลเพื่อเปลี่ยนแปลง SQL statement ให้ทำงานผิดพลาดได้

จะเห็นได้ว่า SQL statement ที่ถูกสร้างขึ้นจะประกอบไปด้วย

SELECT * FROM users WHERE username = '$username' AND password = '$password'

ซึ่ง $username และ $password เป็นข้อมูลที่ได้รับมาจากผู้ใช้งานโดยตรง

หากผู้ใช้งานหรอกข้อมูล user1′ AND 1=1# เข้ามาใน field ของ username ก็จะทำให้เกิด SQL statement ดังตัวอย่างด้านล่างนี้

Screen Shot 2559-01-06 at 3.33.59 PM

Screen Shot 2559-01-06 at 3.34.06 PM

ซึ่งจะเห็นได้ว่าเครื่องหมาย # เป็นเครื่องหมายที่ใช้ในการ commend ของ SQL statement ทำให้ SQL statement ด้านบนมีค่าเท่ากับ

SELECT * FROM users WHERE username = 'user1' AND 1=1

ดังนั้นฐานข้อมูลจะไม่ทำการตรวจสอบ password ที่ส่งมาเลย จึงทำให้ผู้ไม่หวังดีสามารถ login ด้วย username ไหนก็ได้ในฐานข้อมูล

 

SQL Injection รูปแบบอื่น

Bypassing Authentication นับว่าเป็น 1 ในรูปแบบของ SQL Injection ที่พบได้บ่อย แต่ในความเป็นจริงแล้วยังมีรูปแบบการโจมตีด้วย SQL Injection อีกหลายชนิด แบ่งตามจุดมุ่งหมายและวิธีการ ตัวอย่าง SQL Injection อื่น ๆ ที่เป็นที่รู้จักได้แก่

  1. Piggy-backed Queries เป็นการส่ง SQL query คำสั่งที่ 2 แนบไปกับ SQL query อันแรก
  2. Blind SQL Injection เป็นการทำ SQL injection ที่ไม่สนใจข้อมูลที่ได้รับกลับมาจากฐานข้อมูล

Piggy-backed Queries

Piggy-Backed Queries เป็นอีกหนึ่งรูปแบบของ SQL Injection ที่มีความร้ายแรงต่อความปลอดภัยและข้อมูลของเว็บแอปพลิเคชันอย่างมาก เนื่องจาก Piggy-Backed Queires อนุญาตให้ผู้ไม่หวังดีส่ง SQL query ได้อย่างอิสระโดยไม่มีข้อจำกัดหลักการของ Piggy-backed queries คือ ผู้ไม่หวังดีจะทำการใส่ SQL statement แนบมากับข้อมูลที่ส่งมาให้กับเก็บแอปพลิเคชัน

ตัวอย่าง Piggy-backed Queries

Screen Shot 2559-01-07 at 10.08.36 AM

SQL statement ที่ได้จะเป็น

SELECT * FROM users WHERE username = 'user1'; DROP TABLE users;#' AND password = ''

จะเห็นได้ว่าฐานข้อมูลจะได้รับ SQL query สองคำสั่งคือ คำสั่ง SELECT และ คำสั่ง DROP หากฐานข้อมูลทำการประมวลผลทั้งสองคำสั่งข้อมูลผู้ใช้งานทั้งหมดก็จะถูกลบไปจากฐานข้อมูล

อย่างไรก็ตาม Piggy-backed Query ไม่สามารถใช้งานได้กับฟังก์ชัน mysql_query เนื่องจาก mysql_query รับ query ได้เพียง 1 คำสั่งต่อฟังก์ชัน แต่ว่าหากเป็นภาษาอื่น เช่น Java ที่ใช้ฟังก์ชัน executeQuery ในการส่ง SQL query การโจมตีด้านบนก็มีโอกาสที่จะประสบผลสำเร็จ

ตัวอย่างซอร์สโค้ด Java ที่เชื่อมต่อกับ MySQL ที่มีช่องโหว่ในการทำ piggy-backed queries

Connection conn.createConnection("owasp");
username = getParameter("user_username");
password = getParameter("user_password");
query = "SELECT * FROM users WHERE username = " + username + " AND password = " + password";
ResultSet result = conn.executeQuery(query);

 

Blind SQL Injection

Blind SQL Injection Attack เป็นอีกหนึ่งประเภทของ SQL Injection Attack โดยผู้โจมตีจะใช้วิธีการในการส่งคำถาม true false เพื่อเก็บรวบรวมข้อมูล เหมือนกับการเล่นตอบคำถาม ใช่ หรือ ไม่ กับฐานข้อมูล

ตัวอย่างเช่น หากเว็บไซต์ขายของออนไลน์แห่งหนึ่ง มีหน้าที่ใช้ในการแสดงรายละเอียดสินค้าโดยการรับข้อมูลเป็น id ของสินค้าดังตัวอย่างด้านล่าง

http://www.someweb.com/view_item.php?item_id=10

ในกรณีผู้ไม่หวังดีอาจจะพอเดาได้ว่าเว็บแอบพลิเคชันจะทำการรับ item_id แล้วนำไปสร้าง SQL query ในการส่งไปยังฐานข้อมูลเพื่อดึงข้อมูลสินค้าออกมาแสดง

ตัวอย่างซอร์สโค้ด

<?php

$item_id = $_GET['item_id'];
$sql = "SELECT * FROM items WHERE item_id = $item_id";
$result = mysql_query($sql);
display($result);

?>

ดังนั้นหากผู้ไม่หวังดีทำการส่ง

http://www.someweb.com/view_item.php?item_id=10 AND 1=1
http://www.someweb.com/view_item.php?item_id=10 AND 2=1

SQL statement ที่ได้ก็จะเป็น

SELECT * FROM items WHERE item_id = 10 AND 1=1
SELECT * FROM items WHERE item_id = 10 AND 2=1

ดังนั้น หากเว็บแอปพลิเคชันยังแสดงผลสินค้าได้เหมือนปกติในครั้งที่ 1 และไม่แสดงผลสินค้าในครั้งที่ 2 ผู้ไม่หวังดีก็สามารถที่จะคาดเดาได้ว่าเว็บแอปพลิเคชันนี้น่าจะมีช่องโหว่ SQL Injection

Advanced Blind Injection

Blind Injection ยังสามารถถูกใช้งานในการเก็บรวบรวมข้อมูลอื่น ๆ ตัวอย่างเช่น หากเราต้องการทราบว่า MySQL ที่ใช้เป็นเวอร์ชันเท่าไร ก็สามารถทดสอบใส่

http://www.someweb.com/view_item.php?item_id=10 AND substring(version(),1,1)=2;#
http://www.someweb.com/view_item.php?item_id=10 AND substring(version(),1,1)=3;#
http://www.someweb.com/view_item.php?item_id=10 AND substring(version(),1,1)=4;#
http://www.someweb.com/view_item.php?item_id=10 AND substring(version(),1,1)=5;#

SQL statement ที่ได้ก็จะเป็น

SELECT * FROM items WHERE item_id = 10 AND substring(version(),1,1)=2;#
SELECT * FROM items WHERE item_id = 10 AND substring(version(),1,1)=3;#
SELECT * FROM items WHERE item_id = 10 AND substring(version(),1,1)=4;#
SELECT * FROM items WHERE item_id = 10 AND substring(version(),1,1)=5;#

substring(version(),1,1)=2 เป็นการตัดเอาเลขตัวแรกของ version มาเปรียบเทียบกับเลข 2 เช่น MySQL version 5.1.2 ก็จะได้เป็น 5=2 ซึ่งมีค่าเป็น false ทำให้เว็บไซต์ไม่แสดงผลข้อมูลสินค้า แต่หากค่าเป็น true และเว็บไซต์แสดงสินค้าปกติ  ก็จะทำให้เรารู้ทันทีว่าฐานข้อมูลที่ใช้เป็นเวอร์ชั่น 5

สรุป

ในความจริงแล้ว SQL Injection ยังสามารถนำไปประยุกต์ได้อีกหลายรูปแบบ ไม่ว่าจะเป็นการพยายามใส่ข้อมูล SQL ให้ผิดพลาดเพื่อให้ฐานข้อมูลแสดง error ออกมา โดย error นั้นก็จะให้ข้อมูลเกี่ยวกับ table และ column ใน SQL statement เพื่อให้ผู้โจมตีนำไปวิเคราะห์และสร้าง SQL statement ในการโจมตีได้ดียิ่งขึ้น ในบทความต่อไปผมจะมาพูดถึงการป้องกัน SQL Injection ให้ได้ผลและข้อควรปฏิบัติในการพัมนาเว็บไซต์ให้มีความปลอดภัยต่อการโจมตี

อ่านต่อ วิธีการป้องกัน SQL Injection

อ้างอิง

1. A Classification of SQL Injection Attacks and Countermeasures


Leave a Reply