Bảo mật cơ bản – Giới thiệu về SQL Injection

Mình thấy một số bạn vẫn thường gặp phải một số lỗi bảo mật cơ bản. Điều này một phần do các bạn thường xuyên được nhắc nhở về các lỗ hổng bảo mật, tuy nhiên các bạn cũng chỉ được nghe từ những người khác, mà bản thân lại mông lung không biết làm cách nào mà Hacker có thể tấn công được, dẫn đến việc các bạn không thực sự nhìn nhận vấn đề một cách nghiêm túc. Vì vậy mình quyết định sẽ làm một series về bảo mật cơ bản, trong series mình sẽ trình bày cách làm sao để mà một Hacker có thể thâm nhập vào hệ thống của bạn bằng việc lợi dụng các sơ hở trong lúc lập trình ứng dụng. Bản thân mình chỉ là một Web Developer chứ không phải là chuyên gia bảo mật, kiến thức về bảo mật không thực sự phong phú, nên mình sẽ chỉ trình bày các kỹ thuật mình hiểu, sử dụng được và biết cách khắc phục. Trong quá trình tiếp cận, viết bài chắc chắn sẽ có một số thiếu sót, rất mong các bạn có kiến thức chuyên sâu về an ninh mạng, chia sẻ, góp ý thêm để mình và những bạn không chuyên có thể biết và phòng tránh hiệu quả.

Trong bài đầu tiên của Series này mình sẽ giới thiệu về lỗ hổng SQL Injection, một lỗ hổng nghiêm trọng, mặc dù là các phòng tránh cực kỳ đơn giản nhưng vẫn có rất nhiều bạn vẫn khá thờ ơ với lỗ hổng này.

Trong series này mình sử dụng DVWA (Damn Vulnerable Web Application) – đây là một bộ mã nguồn mở có chứa những lỗ hổng cơ bản, được tạo ra với mục đích giúp các Web Developer hiểu về các kỹ thuật tấn công thông qua những lỗ hổng này.

Các bạn có thể tải mã nguồn về từ: http://www.dvwa.co.uk/

Việc tiến hành cài đặt cũng được hướng dẫn một cách khá chi tiết và đơn giản, các bạn vui lòng tham khảo cách cài đặt tại: https://github.com/ethicalhack3r/DVWA

SQL Injection là gì?

SQL Injection là một kỹ thuật lợi dụng những lỗ hổng về câu truy vấn của các phần mềm, thực hiện bằng cách chèn thêm một đoạn SQL để làm sai lệnh đi câu truy vấn ban đầu, từ đó có thể khai thác dữ liệu từ database.

<?php

if( isset( $_REQUEST[ 'Submit' ] ) ) {
    // Get input
    $id = $_REQUEST[ 'id' ];

    // Check database
    $query  = "SELECT first_name, last_name FROM users WHERE user_id = '$id';";
    $result = mysql_query( $query ) or die( '<pre>' . mysql_error() . '</pre>' );

    // Get results
    $num = mysql_numrows( $result );
    $i   = 0;
    while( $i < $num ) {
        // Get values
        $first = mysql_result( $result, $i, "first_name" );
        $last  = mysql_result( $result, $i, "last_name" );

        // Feedback for end user
        $html .= "<pre>ID: {$id}<br />First name: {$first}<br />Surname: {$last}</pre>";

        // Increase loop count
        $i++;
    }

    mysql_close();
}

?>

đây là code trong của trang demo các bạn có thể tìm thấy trong file vulnerabilities/sqli/source/low.php

đoạn code trên thực hiện lấy user_id từ url hoặc form data của người dùng gửi lên và lấy trong database với dữ liệu tương ứng.

Giờ mình thử nhập giá trị 1 vào trong input và submit form thử.

alt text

OK, vậy là mình đã lấy được dữ liệu của user có id là 1.

Giờ theo code ở trên nếu ta nhập vào form ' OR 1=1 # lập tức câu truy vấn

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

sẽ thành:

$query = "SELECT first_name, last_name FROM users WHERE user_id = '' OR 1=1 #;";

khiến câu truy vấn bị sai đi, dấu ‘ đầu tiên trở thành dấu đóng chuỗi và điều kiện user_id = '' sẽ kết hợp với OR 1=1 và điều này luôn luôn đúng, nên chúng ta có thể show được toàn bộ dữ liệu của người dùng.

alt text

đến đây thì mình đã giới thiệu với các bạn thế nào là SQL Injetion rồi, tuy nhiên nếu thấy ở trên thì các bạn vẫn chưa thấy nó thực sự nguy hiểm.

Vậy chúng ta sẽ tiếp tục xem còn khai thác được gì khác không.

Mình sẽ dùng lệnh select union để kết hợp câu select với bộ dữ liệu khác, dưới đây là lệnh mình sử dụng để nhập vào input.

' UNION SELECT 1,2  #

và đây là kết quả: giá trị 1 sẽ được chương trình hiểu là first name và hiển thị bình thường.

alt text

Tiếp theo mình sẽ thực hiện lấy thông về về Database và hiển thị vào cột first name


' UNION SELECT CONCAT_WS(CHAR(32,58,32),user(),database(),version()),2 #

alt text

Và đây chúng ta có tên user là root, host sử dụng là localhost, tên của db là dvwa, sử dụng MariaDB phiên bản 10.1.9.

Tiếp theo mình sẽ xem thử xem cơ sở dữ liệu có bao nhiêu bảng.

' UNION SELECT table_schema,table_name FROM information_schema.tables WHERE table_schema = database() #

alt text

Ola, chúng ta có được 2 bảng là guestbookusers,

Giờ mình sẽ xem cấu trúc của bảng 2 bảng xem có gì hot.

' UNION SELECT table_name, column_name FROM information_schema.columns WHERE table_schema = database() #

alt text

Xem nào, chúng ta có bảng guestbook với comment_id, comment . Bảng users với các trường user_id, first_name, last_name, user, password, avatar, last_login, failed_login.

Giờ mình sẽ thử lấy user và passord xem sao:

' UNION SELECT user, password FROM users #

alt text

Đến đây thì chấm hết. Hacker đã có được tên tài khoản và chuỗi hash của password, Việc tiếp theo là tìm password gốc dựa vào chuỗi hash ở trên, điều này không phải là bất khả thi, nên các bạn cũng đừng quá tin tưởng vào mấy thuật toán mã hóa một chiều kiểu như sha1, hay md5.

Như các bạn đã thấy, thông qua bất kỳ một lỗ hổng SQL Injection nào, hacker cũng có được toàn bộ dữ liệu trong cơ sở dữ liệu của bạn.

Làm sao để tránh SQL Injection

Để điều trị SQL Injection khá đơn giản, và đều dựa trên nguyên tắc chung là escape giá trị đầu vào trước khi thực hiện truy vấn.

Với php có thể dùng các hàm. mysql_real_escape_string(), addslashes() để escape các ký tự này.

Hầu hết các thư viện trong các ngôn ngữ như PHP có PDO, MySQLi, NodeJS có mysql đều có các cung cấp các cơ chế bind params vào truy vấn.

// Pdo: 
$stmt = $pdo->prepare("SELECT * FROM users WHERE id = ?");

// mysqli
$stmt = $mysqli->prepare("INSERT INTO CountryLanguage VALUES (?, ?, ?, ?)");

$stmt->bind_param('sssd', $code, $language, $official, $percent);

Khi sử dụng bind params các thư viện này sẽ tự động escape giá trị đầu vào giúp tránh nguy cơ bị lỗ hổng SQL Injection, đây cũng là kỹ được được khuyến khích sử dụng nhiều nhất trong thời điểm hiện tại.

Hiện tại cũng có rất nhiều tài liệu hướng dẫn về bind param khá chi tiết và đơn giản. Nên mình sẽ không tập trung vào phần này.

Trong bài này mình chỉ muốn chia sẻ với các bạn một cách tổng quát cách thức mà một hacker sẽ khai thác dữ liệu thông qua lỗ hổng này như thế nào. Giúp các bạn có cái nhìn khách quan, chính xác hơn về độ nguy hiểm của lỗ hổng phổ biến này. Trên đây chỉ là một cách thức tấn công, cơ bản nhất, tùy vào từng trường hợp mà hacker sẽ kết hợp thêm một số kỹ thuật khác để có thể khai thác được dữ liệu.

Bài viết nhằm hướng các bạn đến tư duy của Hacker để các bạn bảo mật ứng dụng của mình, không khuyến khích các bạn sử dụng vào mục đích bất chính, hoặc phá làng, phá xóm.

Bình luận


White
{{ comment.user.name }}
Bỏ hay Hay
{{comment.like_count}}
Male avatar
{{ comment_error }}
Hủy
   

Hiển thị thử

Chỉnh sửa

White

Ôm Boom

10 bài viết.
31 người follow
Kipalog
{{userFollowed ? 'Following' : 'Follow'}}
Cùng một tác giả
White
13 5
Quên mật khẩu là một tính năng mà hấu hết các ứng dụng đều có. Đôi khi nó cũng vô cùng hữu ích. Nhưng đây cũng chính là một backdoor để chiếm tài...
Ôm Boom viết 6 tháng trước
13 5
White
11 2
Nhiều khi chúng ta cần một start một project nhỏ gọn, không cần phải quá cầu kỳ, nhưng lại quá quen thuộc với Eloquent của Laravel. Vậy làm sao để ...
Ôm Boom viết 1 năm trước
11 2
White
9 6
Virtual Host Virtual Host là một cấu hình trong Apache để cho phép nhiều domain cùng chạy trên một máy chủ. Có một khái niệm khác được đề cập tới ...
Ôm Boom viết hơn 2 năm trước
9 6
Bài viết liên quan
White
11 2
Mở bài Chào các thành viên Kipalog :D Mình không biết viết văn, nên câu chữ lủng củng, mong mọi người hiểu được =)) Mục đích bài viết này là chi...
Nguyễn Văn Mạnh viết 1 năm trước
11 2
{{like_count}}

kipalog

{{ comment_count }}

bình luận

{{liked ? "Đã kipalog" : "Kipalog"}}


White
{{userFollowed ? 'Following' : 'Follow'}}
10 bài viết.
31 người follow

 Đầu mục bài viết

Vẫn còn nữa! x

Kipalog vẫn còn rất nhiều bài viết hay và chủ đề thú vị chờ bạn khám phá!