How to review vulnerable codes – A1: SQli (2013)

บทนำ (Overview)

บทความนี้กล่าวถึงวิธีทดสอบช่องโหว่ของ SQL injection และชี้ให้เห็นถึง Sourcecode ที่เป็นช่องโหว่ รวมถึงแนวทางในการป้องกันสำหรับผู้พัฒนาระบบ

ขั้นตอน (Steps)

ติดตั้งใช้งาน DVNA

  1. ติดตั้งได้จากบทความ How to install DVNA (Damn Vulnerable NodeJS Application) on MacOS
  2. สามารถเรียกใช้งานครั้งต่อไปโดยใช้คำสั่ง
    docker ps -a
    sudo docker start dbcf5b9227c4
    sudo docker start f284553da237
    

  3. ไปที่หน้า UserSearch http://127.0.0.1:9090/app/usersearch

การโจมตี SQL injection

  1. สามารถติดตามวิธีโจมตีรูปแบบต่าง ๆ ได้จากบทความ
  2. จากตัวอย่างการโจมตีแบบ Manual
    root' union select null, concat(name,0x0a,password) from Users order by 1#
    

  3. โดยใช้ Tools
    sqlmap -r /root/Desktop/sql.txt --dump User
    


การหาช่องโหว่บน Sourcecodes

  1. พยายามค้นหาหน้าจอสำหรับกรอกข้อมูลจากผู้ใช้ จากตัวอย่างเป็นรูปแบบการเขียนโปรแกรมแบบ MVC (Model View Conroller) ส่วนติดต่อผู้ใช้คือ Views จะพบว่าหน้าจอ User Search มีส่วนติดต่อผู้ใช้ใน File ชื่อ usersearch.ejs และในส่วนของ Form สำหรับการ Submit  ข้อมูลโดย Method แบบ Post
  2. ไปที่โฟลเดอร์ Routes เพื่อหา Function ที่ Server ใช้ในการประมวลผลฟังก์ชัน usersearch พบฟังก์ชันชื่อ appHandler.userSearch
  3. ไปที่โฟลเดอร์ core (เป็นส่วนเชื่อมต่อ models ที่ติดต่อกับฐานข้อมูล) เพื่อหาฟังก์ชัน appHandler.userSearch พบว่าอยู่ในไฟล์ appHandler.js พบฟังก์ชัน userSearch ดังนี้
  4. จาก Sourcecode เราพบว่า โปรแกรมรับค่า {login} จากผู้ใช้ req.body.login ซึ่งผ่านหน้า Web browser แล้วนำไปต่อกับคำสั่ง SQL ที่ใช้. Query ข้อมูลจากฐานข้อมูลทันที ซึ่งทำให้ผู้ใช้สามารถเพิ่มคำสั่ง SQL ที่เป็นอันตรายได้
    module.exports.userSearch = function (req, res) {
    	var query = "SELECT name,id FROM Users WHERE login='" + req.body.login + "'";
    	db.sequelize.query(query, {
    		model: db.User
    	})
    

การป้องกันและแก้ไขปัญหา

  1. ใช้งาน Prepared Statements เช่น
    function findItems(req, resp)
    {
      try {
        // Find the relevant items
        sequelize.query(
          "SELECT Desc FROM Items WHERE Desc like ?",
          { replacements: ['%'+req.params.snippet+'%'],
            type: sequelize.QueryTypes.SELECT }
        ) // Retrieve results
        .spread(function(results, metadata) {
            // Add results to response
         });
      } catch {
        // Handle error
      }
    }
    
  2. การตรวจสอบข้อมูลนำเข้าผู้ใช้ สามารถใช้ Libary เช่น https://www.npmjs.com/package/validator ดังนี้
    • การตรวจสอบรูปแบบ Field ก่อนนำไปประมวลผล
      • การจัดรูปแบบของ Field รูปแบบ E-mail โทรศัพท์ วันที่ รหัสบัตรประชาชน
      • รูปแบบของ Field เช่น ตัวเลขอย่างเดียว
      • ขนาดของ Field เช่น ไม่เกิน 13 ตัวอักษรเป็นต้น
        var validator = require('validator');
        validator.isEmail('foo@bar.com'); true
        
    •  การกรองอักขระพิเศษก่อนนำไปจัดเก็บ
      • การกรองอักขระพิเศษ เช่น ;
        sanitizer description
        whitelist(input, chars) remove characters that do not appear in the whitelist. The characters are used in a RegExp and so you will need to escape some chars, e.g. whitelist(input, '\\[\\]').
        blacklist(input, chars) remove characters that appear in the blacklist. The characters are used in a RegExp and so you will need to escape some chars, e.g. blacklist(input, '\\[\\]').

อ้างอิง

ใส่ความเห็น