API testing (phần 1) - viblo learning:
I. Giới thiệu
API (Application Programming Interfaces) là một giao diện lập trình ứng dụng. Có thể hiểu API là một tập hợp các quy tắc và giao thức cho phép các ứng dụng hoặc dịch vụ khác nhau giao tiếp với nhau, giống như một cầu nối giúp các phần mềm khác nhau có thể tương tác mà không cần hiểu toàn bộ cấu trúc nội bộ của nhau.
Một ví dụ thường được sử dụng giúp dễ dàng hình dung về API: Giả sử bạn đi ăn ở một nhà hàng. Bạn gọi món ăn từ thực đơn, và người phục vụ (API) là người trung gian nhận yêu cầu của bạn, gửi yêu cầu đến bếp (hệ thống nội bộ) để chế biến, sau đó mang món ăn từ bếp trở lại cho bạn. Bạn không cần vào bếp để nấu ăn, và đầu bếp không cần gặp bạn trực tiếp. Chỉ cần người phục vụ chuyển yêu cầu và mang món ăn đến đúng yêu cầu.
Xét về góc nhìn trong lĩnh vực phần mềm:
- Khi bạn sử dụng ứng dụng thời tiết trên điện thoại, ứng dụng sẽ gọi API của một dịch vụ thời tiết để lấy thông tin như nhiệt độ và điều kiện thời tiết từ máy chủ của dịch vụ thời tiết đó.
- Hoặc khi bạn đăng nhập vào một trang web bằng tài khoản Google, trang web sẽ sử dụng API của Google để xác minh thông tin đăng nhập mà không cần tự mình xây dựng toàn bộ hệ thống xác thực.
API testing bao gồm việc kiểm thử toàn bộ lỗ hổng chúng ta đã biết trên các API. (Tham khảo thêm tại link)
II. API reconnaissance
1. Một số lý thuyết
API reconnaissance là quá trình thu thập thông tin về các API cần kiểm thử. API recon thường bước đầu tiên trong API testing. Mục tiêu là nắm bắt các đặc điểm của API như cấu trúc, cách thức hoạt động và các endpoints có sẵn. Hiểu rõ về API sẽ giúp xác định cách thức kiểm tra và phát hiện các điểm yếu tiềm ẩn.
Chúng ta quan tâm đến một số tính chất của API trong quá trình thu thập thông tin:
- Thông tin công khai về API
- Tài liệu về API (API document)
- Thông tin xác thực hoặc mã thông báo bị lộ
- Thông tin phiên bản
- Mục đích kinh doanh của API để hiểu rõ hơn về chức năng mong đợi
Xem xét một số đặc điểm của API và cách thu thập API thông qua các cú pháp tìm kiếm dorking.
API của một ứng dụng thường:
- Bắt đầu bằng đường dẫn
/api/v1
,/api/v2
, ... - Sử dụng định dạng dữ liệu JSON
- Xác thực thông qua header Authorization
- Sử dụng công cụ document RESTfull APIs Swagger
- Sử dụng
content-type: application/json
Google dorking ví dụ:
inurl:"/api/v1" site:microsoft.com
intitle:json site:ebay.com
...
Github dorking ví dụ:
Authorization: Bearer
filename:swagger.json
...
Shodan dorking ví dụ:
content-type: application/json
...
2. Lab demo
Phân tích bài lab Exploiting an API endpoint using documentation
Mục tiêu của bài lab là tìm ra endpoint API document bị exposed. Ý tưởng là sử dụng tấn công brute force với một API document wordlist. Bạn đọc có thể tìm kiếm các API wordlist trong Github, chẳng hạn list.
Sử dụng chức năng Intruder của BurpSuite thực hiện brute force, tìm thấy API document tại /api/openapi.json
Quan sát API document nhận thấy API /user/[username: String]
với phương thức DELETE có thể sử dụng để xóa người dùng bất kỳ:
Xây dựng lại gói tin có nội dung như sau:
DELETE /api/user/carlos HTTP/2
Host: 0a4f00270351b3d380e0585a004a001f.web-security-academy.net
Cookie: session=YghfxI4Jgt6v29s9DEOlUUPp7SeGBBkN
Content-Type: application/json
Content-Length: 2
{}
API này yêu cầu quyền xác thực, đăng nhập với tài khoản người dùng thường wiener
thay giá trị session
vào request này, response trả về cho thấy hành động xóa người dùng carlos
thành công:
Bạn đọc có thể luyện tập thêm tại lab Finding and exploiting an unused API endpoint
III. Tham số ẩn trong API
Tham số ẩn (hidden parameters) có thể hiểu là các tham số chúng ta chưa biết, không được đính kèm trong gói tin khi gửi tới server. Tuy nhiên nếu gói tin chứa các tham số này thì cũng sẽ được xử lý hoặc sử dụng khi server nhận request. Đây có thể là yếu tố giúp lập trình viên kiểm tra website của họ (debug) hoặc do logic hoạt động của chương trình chưa chặt chẽ dẫn tới lỗ hổng.
Xem xét chức năng cập nhật thông tin cá nhân bao gồm tên và email cho người dùng. Request chỉ gửi đi hai tham số là name
và email
. Dưới đây là đoạn code minh họa cho quá trình xử lý ở server:
from flask import Flask, request, jsonify
app = Flask(__name__)
users = {
123: {
"id": 123,
"name": "John Doe",
"email": "john@viblo.com",
"isAdmin": False
},
124: {
"id": 124,
"name": "Alice Smith",
"email": "alice@viblo.com",
"isAdmin": False
}
}
@app.route('/api/users/<int:user_id>', methods=['PATCH'])
def update_user(user_id):
user = users.get(user_id)
if not user:
return jsonify({"error": "User not found"}), 404
data = request.get_json()
for key, value in data.items():
user[key] = value
users[user_id] = user
return jsonify(user), 200
if __name__ == '__main__':
app.run(debug=True)
Route /api/users/<int:user_id>
nhận tham số từ request dưới dạng JSON và cập nhật và cơ sở dữ liệu. Chú ý rằng cách xử lý cập nhật dữ liệu:
for key, value in data.items():
user[key] = value
Việc lấy tất cả tham số và giá trị trong request và cập nhật dẫn đến lỗ hổng mass assignment. Attacker có thể tìm kiếm các param ẩn trong bộ dữ liệu người dùng, ví dụ thêm cặp giá trị "isAdmin": true
vào request, server xử lý như trên sẽ cập nhật cả thuộc tính isAdmin
cho người dùng, attacker đã leo thang đặc quyền thành công từ người thường lên admin.
{
"name": "wiener",
"email": "wiener@viblo.com",
"isAdmin": true,
}
Đến đây, một số bạn đọc có thể thắc mắc rằng làm sao attacker có thể biết chính xác trong bộ dữ liệu người dùng tồn tại tham số isAdmin
. Có thể có nhiều cách để attacker có được giá trị này. Thường thấy nhất là trong quá trình sử dụng ứng dụng, khi cập nhật thông tin người dùng, gói tin response có thể trả về bộ dữ liệu bao gồm cả thuộc tính isAdmin
này:
Một cách làm khác là thực hiện brute force tất cả tham số có thể với parameters wordlist.
Bạn đọc có thể luyện tập thêm khai thác lỗ hổng mass assignment trong API testing qua bài lab Exploiting a mass assignment vulnerability.
Tài liệu tham khảo
All rights reserved