CVE-2019-7164: Lỗ hổng trong SQLALchemy (version 1.2.17 và 1.3.x đến 1.3.0b2) cho phép SQL injection thông qua tham số order_by.

Lời mở đầu

Câu chuyện nó không có gì thú vị lắm nếu như tối không ngồi rảnh tay bấm vào xem source code của từng project cũ tôi từng viết trên github.

Một ngày trời mưa ( theo tôi thì Hà Nội nắng nóng lâu rồi nên hôm nào mưa chính là ngày đẹp trời ), tôi vào xem lại từng project đã từng viết trong github của mình và nhận được một alert từ github: We found potential security vulnerabilities in your dependencies. Rồi github cho mình tên là CVE-2019-7164: Lỗ hổng trong SQLALchemy (version 1.2.17 and 1.3.x đến 1.3.0b2) cho phép SQL injection thông qua tham số order_by.

Mình đã ngâm cứu CVE này rất kỹ, dựng lên mỗi trường và tìm cách khai thác và hôm nay mình viết lại cho các bạn đọc được biết cũng như không nên quá tin tưởng vào ORM nha.

Vì phạm vi viết về ORM rất là rộng, mỗi ngôn ngữ sẽ dùng 1 loại cho ngôn ngữ đó. Nên để ví dụ chi tiết, cụ thể thì mình tập trung đi vào làm ví dụ demo bằng SQLALchemy trong python.

Một số khái niệm sẽ gặp: ORM, SQLALchemy

Có rất nhiều bài viết nói về các khái niệm này trên mạng rồi, nhưng mình xin tóm lại cho bạn hiểu sơ qua.

ORM là gì? ORM là tên viết tắt của cụm từ “Object Relational Mapping” đây là tên gọi chỉ việc ánh xạ các record dữ liệu trong hệ quản trị cơ sở dữ liệu sang dạng đối tượng mà mã nguồn đang định nghĩa trong class. Là một khái niệm phổ biến, được cài đặt trong tất cả các loại ngôn ngữ hiện đại ngày nay như: java, php, node.js, swift … Bạn dễ dàng có thể cài đặt ORM hoặc sử dụng các thư viện mã nguồn mở về ORM trong bất cứ dự án nào bạn thích. Vậy ORM đem lại ích lợi gì cho các lập trình viên.

ORM là gì

SQLALchemy là gì? SQLAlchemy là một công cụ mã nguồn mở của SQL và O R M , được phát hành theo giấy phép MIT. Nó được phát hành ban đầu vào tháng Hai năm 2006, và được viết bởi Michael Bayer. Nó cung cấp đầy đủ các phương thức, ở level cao, đảm bảo cho việc truy cập cơ sở dữ liệu hiệu suất cao, là một chuyển thể đơn giản của Pythonic language. , nó hoạt đông theo data mapper pattern ( như Hibernate trong Java), chứ không phải là record pattern như trong Ruby and Rails.

Xây dựng môi trường

  • Dùng framework flask của python
  • SQLALchemy version < 1.3.0 ( từ bản >=1.3.0 đã đã được cập nhật sử lỗi nhé)

file requirements.txt:

Flask==1.1.1
Flask-SQLAlchemy==2.3.2
SQLAlchemy==1.2.14
mysqlclient==1.4.2.post1

File app.py:

import os
import json
from flask import Flask,request
from flask_sqlalchemy import SQLAlchemy

app = Flask(__name__, instance_relative_config=True)
app.config.from_mapping(
    SECRET_KEY='manhnv.com',
    SQLALCHEMY_TRACK_MODIFICATIONS=False,
    SQLALCHEMY_DATABASE_URI='mysql+mysqldb://username:password@localhost:3306/cve_2019_7164',
)
db = SQLAlchemy(app)
db.create_all()

class User(db.Model):
    __tablename__ = 'user'

    id = db.Column(db.String(20), primary_key=True)
    username = db.Column(db.String(255))
    created_at = db.Column(db.String(255))

@app.route('/api/list')
def hello():
    # Đoạn code sẽ bị sql injection
    order_by = request.args.get('order_by')
    result=User.query.order_by(order_by).all()

    return json.dumps([row.username for row in result] or [])
  • Đoạn code trên sẽ dùng SQLALchemy để truy vấn dữ liệu, và mình tạo ra một trang lấy list user và nhận tham số order_by từ param.

Run cve

=> Như vậy môi trường đã dựng xong

Cách khai thác

Run cve

  • Đáng lý ra nếu lọc hết đầu vào thì ở ảnh trên mình thêm ‘;’ thì chắc chắn sẽ bị raise lỗi ra, nhưng lạ thay chương trình vẫn chạy, vì nó dính SQL injection mà.
  • Vậy tiếp theo mình thử một đoạn SQL injection khắc thử username, (select sleep(10) from dual where database() like database())-- thì thấy trang web sẽ delay 10s mới trả về kết quả. Thì khẳng định luôn là có thể dùng SQL injection để khai thác triệt để qua tham số order_by này.

Điều muốn nói

  • Những thư viện ORM thật sự giúp ích cho lập trình viên rất nhiều, vì nó giúp cho lập trình viên tập trung vào phát triển ý tưởng mà không cần quan tâm câu lệnh truy vấn. Nhưng nếu lập trình viên quá phụ thuộc vào ORM mà không tìm hiểu kỹ nó hoạt động như thế nào, có những lỗi gì thì sẽ rất nguy hiểm cho project của bạn.
  • Nếu đã dùng ORM hay bất cứ thư viện nào trong project của bạn thì cũng nên kiểm tra cập nhật thường xuyên để đảm bảo rằng ORM vẫn hoạt động không lỗi nào.
  • Hãy nhớ, thư viện cũng là do lập trình viên tạo ra và chắc chắn sẽ không kiểm soát hết lỗi, nên đừng tin tưởng một cái gì đó quá.