Thứ Hai, 20 tháng 6, 2011

Sử dụng ISA Server 2006 hạn chế tấn công SQL Injection (P2)

Phần 2: Thực hiện khai thác lỗi SQL Injection và dùng ISA Server 2006 hạn chế việc khai thác lỗi này.

>>> Phần 1 

Trong Phần 1, tôi đã giới thiệu đôi nét về cơ sở dữ liệu MSDE và cách thức tạo database trong MSDE. Trong Phần 2, ta sẽ tiến hành xây dựng web site được thiết kế trên nền tảng công nghệ web .NET , dùng ISA Server 2006 để publish website này. Khách hàng truy cập website và attacker khai thác lỗi SQL Injection. Cuối cùng dùng ISA Server 2006 để lọc cách thức tấn công này.

II. Các bước thực hiện

B1. Tạo trang web.
B2. Cấu hình Web Server
B3. Kiểm tra web site trong cục bộ.
B4. Publish web site
B5. Kiểm tra web site từ bên ngoài.
B6. Khai thác lỗi SQL Injection.
B7. Ngăn chặn khai thác lỗi SQL Injection.
B8. Kiểm tra kết quả sau khi cấu hình filter SQL Injection

III. Thực hiện
 
B1. Tạo trang web 


a. Copy đoạn code sau lưu thành file SQLLoginUnsafe.aspx hoặc tải về tại: http://thuc.nhatnghe.vn/sqlinjection/part1/softs/websample.rar

This is the Unsafe SQL Login Page.  Username:
Password:
Result:
Text="Login" />
Visible="False">
Text="Logout" Visible="False" />

b. Copy đoạn code sau lưu thành file SQLLoginUnsafe.aspx.cs
/*
* SQLLoginUnsafe.aspx.cs
* Author: Nazim Lala
*
*/
using System;
using System.Web;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Text;
using System.Data;
using System.Data.SqlClient;
public partial class SQLLoginUnsafe : System.Web.UI.Page
{
private string _username;
private string _password;
private bool _loggedIn = false;


private string _connString =
@"Data Source=localhost\Bank;"+
"Initial Catalog=CreditCardDB;"+
"Integrated Security=False;"+
"uid=sa;"+
"pwd=P@ssword";


private SqlConnection _sqlConn = null;

protected void ButtonLogin_Click(object sender, EventArgs e)
{
_username = Request["TextBoxUsername"];
_password = Request["TextBoxPassword"];


if (!IsNonEmptyCredentials())
{
LabelResult.Text = "ERROR: Cannot have empty credentials.";
return;
}


if (AttemptSQLLogin())
{
// Login succeeded

// Fill order data
FillOrderData();


EnableLoggedInVisuals();

}
else
{
DisableLoggedInVisuals();
}


}

protected bool IsNonEmptyCredentials()
{
if (_username == null ||
_username.Length == 0 ||
_password == null ||
_password.Length == 0)
{
return false;
}
else return true;

}


protected bool AttemptSQLLogin()
{
try
{
_sqlConn = new SqlConnection(_connString);
_sqlConn.Open();
}
catch (Exception ex)
{
LabelResult.Text = String.Format(
"ERROR: Failed to open SQL Connection: {0}", ex.Message);
return false;
}


SqlDataReader dataReader = null;

string SQLQuery = String.Format(
"SELECT * FROM Users WHERE Username='{0}' AND Password='{1}'",
_username, _password);


SqlCommand command = new SqlCommand(SQLQuery, _sqlConn);

try
{
dataReader = command.ExecuteReader(CommandBehavior.SingleResult);


if (dataReader.HasRows)
{
LabelResult.Text = String.Format("Login success");
dataReader.Close();
_loggedIn = true;
return true;
}
else
{
LabelResult.Text = String.Format(
"Login failed: Invalid credentials");
dataReader.Close();
return false;
}


}
catch (Exception ex)
{
LabelResult.Text = String.Format(
"ERROR: Failed to execute SQL command: {0}", ex.Message);
return false;
}


//return true;
}


protected bool FillOrderData()
{
SqlDataReader dataReader = null;


if (!_loggedIn)
{
LabelResult.Text = "No user logged it";
return false;
}


string SQLQuery = String.Format(
"SELECT Orders.OrderId, Orders.Amount, Orders.CreditCard "+
"FROM Users, Orders WHERE Users.Username='{0}' "+
"AND Users.UserId=Orders.UserId", _username);


SqlCommand command = new SqlCommand(SQLQuery, _sqlConn);

try
{
dataReader = command.ExecuteReader(CommandBehavior.Default);


GridView1.DataSource = dataReader;
GridView1.DataBind();


dataReader.Close();

return true;
}
catch (Exception ex)
{
LabelResult.Text = String.Format(
"ERROR: Failed to execute SQL command: {0}", ex.Message);
return false;
}
}


protected void ButtonLogout_Click(object sender, EventArgs e)
{
LabelResult.Text = "Logged Out";
_loggedIn = false;
_username = "";
_password = "";
DisableLoggedInVisuals();
}


protected void EnableLoggedInVisuals()
{
ButtonLogin.Enabled = false;
ButtonLogin.Visible = false;
LabelData.Visible = true;
GridView1.Enabled = true;
GridView1.Visible = true;
ButtonLogout.Enabled = true;
ButtonLogout.Visible = true;
}


protected void DisableLoggedInVisuals()
{
ButtonLogin.Enabled = true;
ButtonLogin.Visible = true;
LabelData.Visible = false;
GridView1.Enabled = false;
GridView1.Visible = false;
ButtonLogout.Enabled = false;
ButtonLogout.Visible = false;
}
}

Lưu ý đoạn code màu vàng
private string _connString =
@"Data Source=localhost\Bank;"+ //--> database cài chung với web server, Bank là instance name đã tạo phần 1
"Initial Catalog=CreditCardDB;"+ //-->CreditCardDB là tên database
"Integrated Security=False;"+
"uid=sa;"+ //--> dùng user sa
"pwd=P@ssword"; //--> password của user sa

Cả 2 file trên lưu vào C:\Web

B2. Cấu hình web server

Lưu ý: Web server đã cài ASP.NET, IIS và .NET Framework 2.0

Mở Administrative Tools > Internet Information Services, chuột phải Default Web Site chọn Properties


Chọn tab Home Directory, cấu hình như hình >OK


Chọn tab ASP.NET, chọn như hình > OK


Tab Documents, chọn Add


Gõ tên SQLLoginUnsafe.aspx > OK


Chọn file sqlLoginUnsafe.aspx và nhấn nút move up để đưa lên đầu danh sách > OK 





B3. Kiểm tra web site trong cục bộ
 
Mở Internet Explorer gõ http://localhost và đăng nhập với username và password đã tạo ở phần 1, kết quả login thành công, truy cập được tài khoản Credit Card. 



Chọn Logout và đăng nhập với user teo, password Nh@tnghe thì login không thành công vì không có tài khoản này trong cơ sở dữ liệu


 
B4. Publish Website



Đặt IP như hình trên

Máy ISA thực hiện publish web server

Chuột phải Firewall Policy > New > Web Site Publishing Rule


Đặt tên cho rule > Next


Chọn Allow > Next


Chọn như hình > Next


Chọn như hình > Next



Trỏ về địa chỉ IP của Web Server > Next 



Chọn Next 



Chọn như hình > Next



Chọn New để tạo Web Listener 



Đặt tên cho Web Listener > Next 



Chọn như hình > Next



Chọn như hình > Next



Chọn như hình > Next


Chọn Next 



Chọn Finish



Chọn như hình > Next


Chọn như hình > Next



Chọn Next 



Chọn Finish



Chọn Apply



B5. Kiểm tra web site từ bên ngoài

Tại Client truy cập địa chỉ http://192.168.1.1 , và đăng nhập hợp lệ


Chọn Logout và đăng nhập không hợp lệ 



B6. Khai thác lỗi SQL Injection.

Chiêu thứ nhất: Đăng nhập với username ' OR 1=1-- , password tùy ý, như vậy tuy không biết username và password nhưng bạn cũng đã có thể xem được toàn bộ cơ sở dữ liệu của ngân hàng.


Chiêu thứ hai : Đăng nhập với username ';INSERT INTO Users VALUES (105,'HackerTeo','NhatNghe')-- ,password tùy ý. Với chiêu này bạn đã có thể tạo mới 1 user HackerTeo, password NhatNghe với UserID thứ 105



Tuy rằng hình trên báo lỗi login failed, nhưng bạn đăng nhập với username HackerTeo, password NhatNghe thì vẫn đăng nhập thành công.


Nếu kiểm tra trên Database Server thì thấy user HackerTeo đã được cập nhật.



Chiêu thứ ba: Đăng nhập với username ';UPDATE Orders Set Amount=100-- ,password tùy ý. Với chiêu này bạn đã có thể thay đổi số tiền của các tài khoản CreditCard là 100.



Kết quả như hình



 
B7. Ngăn chặn khai thác lỗi SQL Injection

Thực hiện tại ISA server 

Chuột phải rule Publish Web Server chọn Configure HTTP


Chọn Tab Signature > Add 



Nhận xét: cả 3 chiêu trên đều sử dụng có ký tự ' nhập trong form, do đó ta sẽ filter ký tự ' trong phần request body. Ký tự ' khi truyền trên đường mạng là %27 và trong bài lab này ký tự ' nằm trong 200 byte đầu tiên. Bạn đặt như hình > OK >Apply .



B8. Kiểm tra kết quả sau khi cấu hình filter SQL Injection

Tại client truy cập http://192.168.1.1 và đăng nhập thử 3 chiêu khai thác lỗi SQL Injection thì không thực hiện được và nhận thông báo lỗi.



Nhưng nếu đăng nhập hợp lệ thì kết quả bình thường 





Kết luận

Để khai thác lỗi SQL Injection có rất nhiều cách, tại bài viết này chỉ khai thác lỗi trong phần nhập liệu của form thì bạn phải filter phần request body. 

Một số cách khác khai thác lỗi SQL Injection tại URL thì bạn phải filter phần Request URL. 

Một số ký tự mà bạn cần filter trong Request URL là : " .. ", " ./ " , " \ " , " : " , " % " , " & " theo sách MOC 70-351 (trang 33 of 54)

Một số ký tự khác cũng cần khai báo để filter như " select%20 " ," delete%20 "," sp_ "," xp_ "," create table "," drop table "," ;- "," | " ,"^",.. ," char( "," syscolumns " hay "hkey", "c:", "d:", "regedit" (theo http://forums.isaserver.org/m_2002069616/mpage_1/key_/tm.htm#2002069759)

Một số firewall có khả năng filter tới tầng 7 (Application) tăng cường khả năng filter tự động và performance

Editor: Vương L. Kiều (Baomathethong.blogspot.com)
Author & Source: Nhatnghe.com

Không có nhận xét nào:

Đăng nhận xét