Archive for September, 2009


Some Asp.net Controls support you customize the layout within LayoutTemplate tag, and you can even add new controls with it. e.g., add a VerifyCode feature for ASP:Login control. However, you will found you cannot get the customized control directly as other common ones, such as the customized VerifyCode textbox in login control in below,

The issue

Following code will encounter “The name ‘tbVerifyCode’ does not exist in the current context” error in Page_Load Method,
protected void Page_Load(object sender, EventArgs e)
{

///


/// Update Key and Value of AppSettings configuration.The value of the current key will be update if the key is exist,
/// or a new key with corresponding value will be created in application configuration file.
///


/// The key of the configuration entry.
/// The value of the configuration entry.
public static void UpdateAppSettings(string key, string value)
{
bool isModify = false; // Indicate if given config entry exist or not.

// If given config entry already existed.
if (!String.IsNullOrEmpty(ConfigurationManager.AppSettings.Get(key)))
isModify = true;

Configuration config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);

if (isModify)
config.AppSettings.Settings.Remove(key); // Remove the existing config entry.

// Add an entry to appSettings.
config.AppSettings.Settings.Add(key, value);

// Save the configuration file.
config.Save(ConfigurationSaveMode.Modified);

// Force a reload of the changed section.
ConfigurationManager.RefreshSection(“appSettings”);
}

Problem space

Sad, but true, “Forms authentication in ASP.NET does not directly support role based authorization”. If you have ended up implementing Forms authentication along with configuring authorization rules for “users” and “roles” in the web.config, you are going to see the access rules working fine for “users”, but, not working at all for “roles”. You might have thought, there must be some way to specify user roles in the famous FormsAuthentication.RedirectFromLoginPage(), or, any other method. But, there isn’t!

Background

This is really surprising because, in real life, most applications (if not all) actually require authorization of system resources based upon user roles, not user names. So, if you are going to use Forms authentication in your upcoming ASP.NET application, and you need to implement role based authorization in your system, you have a problem.

Wait, this is not entirely true, because of two reasons:

Reason 1: Since ASP.NET 2.0, we have Membership. It includes Membership (User) service, Role service, and Profile (User properties) service. And, using Membership, you can easily implement Role based authorization in your ASP.NET application.

Reason 2: Even if you don’t use Membership, you can write some code to implement Role based authorization in Forms authentication. Basically, you need to create the authentication ticket yourself and push the user roles in the “UserData” property after authenticating the user. Also, you need to retrieve user roles from the same “UserData” property in the authentication ticket and set it in the current User property in the subsequent requests. This trick works, and many have done this already.

So, what is this article about?

Well, this article assumes that you did use Forms authentication directly instead of ASP.NET Membership in your application for some good reasons. Consequently, you implemented Role based authorization as suggested by lots of articles on the web (like this one). But I tell you, you probably ended up doing an incorrect and incomplete implementation, and you may be going to have problems in near future.

This article is going to address the problems with the suggested implementation approaches, and provide you a correct, smart, and quick way of implementing Role based authorization in case you are not using ASP.NET Membership in your system. All you’ll need is 5 minutes to implement this!

Please take a look at this article before you proceed, in case you are new to ASP.NET and wondering about Forms Authentication.

OK, so what is the problem with the suggested approaches?

As was said already, the suggested approaches for implementing Role based authorization have some problems, and I realized those while trying to implement them in one of my ASP.NET applications. I did what was suggested in one of those articles, and found that the authorization was working fine. But, in order to fulfill a client request, I had to increase the cookie timeout property in the <forms> element and set it to “120” (120 minutes), and found that, the timeout value change didn’t have any impact on the application. Exploring this, I was surprised to see that the system was never reading the increased value; rather, it was always reading “30”, the default value.

I was curious to investigate this issue and found another problem. I specified cookieless="UseUri" in the <forms> element, to test whether the Forms authentication worked (by writing authentication ticket in the request URL) if cookies are disabled in the client’s browser. Surprise again, now the system stopped authenticating the user!

Besides, I had a quick look at the authentication/authorization code (that were written to implement Role based authorization as suggested), and thought, why do I have to write all these codes? It should be fairly easy for anybody to implement it just by changing one or two lines of code.

So, I decided to write my own code, and share it with you!

How easy is it for you to use my implementation?

Well, I assume that you already have implemented Forms authentication in your application and configured stuff in the web.config. So, to implement Role based authorization, now you just need to do following three easy things, requiring a maximum of five minutes in total to implement.

  • Add a reference to RoleBasedFormAuthentication.dll (which you can download from this article, along with the source code) in your web site/project.
  • Instead of calling the following method after authenticating the user:
    FormsAuthentication.RedirectFromLoginPage(userName,createPersistantCookie);

    Call the following method:

    FormsAuthenticationUtil.RedirectFromLoginPage(userName,
                            commaSeperatedRoles, createPersistantCookie);
  • Add the following code in the Global.asax file, or, change the code if it is already there:
    protected void Application_AuthenticateRequest(Object sender,EventArgs e)
    {
        FormsAuthenticationUtil.AttachRolesToUser();
    }

That’s it, you are done.

Curious? Here are the details

I created my version of the authentication/authorization code and had overcome the three mentioned issues, as follows:

Solving the “timeout” problem

While creating the FormsAuthenticationTicket object, we need to provide five parameters. Take a look at the following method which creates the authentication ticket:

/// <summary> 
/// Creates and returns the Forms authentication ticket
/// </summary>
/// <param name="userName">User name</param>
/// <param name="commaSeperatedRoles">Comma seperated roles for the users</param>
/// <param name="createPersistentCookie">True or false
///        whether to create persistant cookie</param>
/// <param name="strCookiePath">Path for which the authentication ticket is valid</param>
private static FormsAuthenticationTicket CreateAuthenticationTicket(string userName,
        string commaSeperatedRoles, bool createPersistentCookie, string strCookiePath)
{
    string cookiePath = strCookiePath == null ?
      FormsAuthentication.FormsCookiePath : strCookiePath;
    //Determine the cookie timeout value from web.config if specified
    int expirationMinutes = GetCookieTimeoutValue();
    //Create the authentication ticket
    FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(
    1, //A dummy ticket version
    userName, //User name for whome the ticket is issued
    DateTime.Now, //Current date and time
    DateTime.Now.AddMinutes(expirationMinutes), //Expiration date and time
    createPersistentCookie, //Whether to persist coolkie on client side. If true,
    //The authentication ticket will be issued for new sessions from the same client
    //PC
    commaSeperatedRoles, //Comma seperated user roles
    cookiePath); //Path cookie valid for
    return ticket;
}

Note the third parameter DateTime.Now.AddMinutes(expirationMinutes). Here, we expect the expirationMinutes variable’s value to be read from the timeout property in the <forms> section. But, unfortunately, like the FormsAuthentication.FormsCookiePath property (that reads the path configuration value specified in the <forms> section), FormsAuthentication or any other class does not give you any way to read the timeout property value. I don’t know why.

So, I had to implement and use the following method to read the timeout property from web.config (if it is specified) and set the value while creating the FormsAuthenticationTicket object.

/// <summary>
/// Retrieves cookie timeout value in the <forms></forms>
/// section in the web.config file as this
/// value is not accessable via the FormsAuthentication or any other built in class
/// </summary>
/// <returns></returns>
private static int GetCookieTimeoutValue()
{
    int timeout = 30; //Default timeout is 30 minutes
    XmlDocument webConfig = new XmlDocument();
    webConfig.Load(HttpContext.Current.Server.MapPath("web.config"));
    XmlNode node = webConfig.SelectSingleNode("/configuration/" +
                             "system.web/authentication/forms");
    if (node != null && node.Attributes["timeout"] != null)
    {
        timeout = int.Parse(node.Attributes["timeout"].Value);
    }
    return timeout;
}

After doing this, the system was able to read the “timeout” value from the web.config properly and set it in the authentication ticket object.

Solving the “cookieless” problem

If the “cookieless” property in the web.config is set to “UseUri“, or if for any reason the browser doesn’t support cookies, or, if the browser has cookie support but disabled in the settings, the Forms authentication writes the authentication ticket in the URL and reads the ticket back on subsequent requests.

So, while we create the authentication ticket ourselves in order to implement Role based authorization, we need to implement the same logic, otherwise we will have problems. So, we need to determine whether we have to embed the ticket within a Cookie, or, we have to write the ticket to the URL based on the situation described above. The following code does this:

/// <summary>
/// Creates Forms authentication ticket and writes it in URL or embeds it within Cookie
/// </summary>
/// <param name="userName">User name</param>
/// <param name="commaSeperatedRoles">Comma seperated roles for the users</param>
/// <param name="createPersistentCookie">True or false whether
///          to create persistant cookie</param>
/// <param name="strCookiePath">Path for which
///         the authentication ticket is valid</param>
private static void SetAuthCookieMain(string userName, string commaSeperatedRoles,
        bool createPersistentCookie, string strCookiePath)
{
    FormsAuthenticationTicket ticket =
      CreateAuthenticationTicket(userName, commaSeperatedRoles,
    createPersistentCookie, strCookiePath);
    //Encrypt the authentication ticket
    string encrypetedTicket = FormsAuthentication.Encrypt(ticket);
    if (!FormsAuthentication.CookiesSupported)
    {
        //If the authentication ticket is specified not to use cookie, set it in the URL
        FormsAuthentication.SetAuthCookie(encrypetedTicket, false);
    }
    else
    {
        //If the authentication ticket is specified to use a cookie,
        //wrap it within a cookie.
        //The default cookie name is .ASPXAUTH if not specified
        //in the
 element in web.config
        HttpCookie authCookie = new HttpCookie(FormsAuthentication.FormsCookieName,
        encrypetedTicket);
        //Set the cookie's expiration time to the tickets expiration time
        authCookie.Expires = ticket.Expiration;
        //Set the cookie in the Response
        HttpContext.Current.Response.Cookies.Add(authCookie);
    }
}

The following piece of code does the main trick here:

if (!FormsAuthentication.CookiesSupported)
{
    //If the authentication ticket is specified not to use cookie, set it in the URL
    FormsAuthentication.SetAuthCookie(encrypetedTicket, false);
}

The FormsAuthentication.SetAuthCookie() method may be a misleading one. As the name suggests, it seems to create the Forms authentication cookie with the authentication ticket. Yes, it does. But, if cookies are not supported in the browser, it sets the encrypted authorization ticket content into the URL. So now, if the browser doesn’t support cookies, Forms authentication and Role based authorization will work fine for us.

Please note that after changing the code as above, we also need to modify the code where user roles are set on subsequent requests (in the Application_AuthenticateRequest() event in Global.asax).

/// <summary>
/// Adds roles to the current User in HttpContext
/// after forms authentication authenticates the user
/// so that, the authorization mechanism can authorize
/// user based on the groups/roles of the user
/// </summary>if (HttpContext.Current.User != null)
{
    if (HttpContext.Current.User.Identity.IsAuthenticated)
    {
        if (HttpContext.Current.User.Identity is FormsIdentity)
        {
            FormsIdentity id = (FormsIdentity)HttpContext.Current.User.Identity;
            FormsAuthenticationTicket ticket = (id.Ticket);
            if (!FormsAuthentication.CookiesSupported)
            {
                //If cookie is not supported for forms authentication, then the
                //authentication ticket is stored in the URL, which is encrypted.
                //So, decrypt it
                ticket = FormsAuthentication.Decrypt(id.Ticket.Name);
            }
            // Get the stored user-data, in this case, user roles
            if (!string.IsNullOrEmpty(ticket.UserData))
            {
                string userData = ticket.UserData;
                string[] roles = userData.Split(',');
                //Roles were put in the UserData property in the authentication ticket
                //while creating it
                HttpContext.Current.User =
                  new System.Security.Principal.GenericPrincipal(id, roles);
            }
        }
    }
}

I just added the following piece of code after FormsAuthenticationTicket ticket = (id.Ticket);.

if (!FormsAuthentication.CookiesSupported)
{
    //If cookie is not supported for forms authentication, then the
    //authentication ticket is stored in the URL, which is encrypted.
    //So, decrypt it
    ticket = FormsAuthentication.Decrypt(id.Ticket.Name);
}

So, this was the solution to the “cookieless” problem.

Decoupling the codes in a reusable DLL

The golden principle of “Encapsulation” says that you should encapsulate your complexities to the outside world. So, why don’t we encapsulate all this dirty nonsense code into a box? Why don’t we stay clean?

Being inspired to follow this principle, I created a Class Library (“RoleBasedFormAuthentication”) and moved the entire authentication and authorization related code there. I created a FormsAuthenticationUtil class inside the class library, and implemented the following core reusable private methods inside it:

Private methods

/// <summary> 
/// Creates and returns the Forms authentication ticket
/// </summary>
private static FormsAuthenticationTicket CreateAuthenticationTicket(…)

/// <summary>
/// Creates a Forms authentication ticket using the private
/// method CreateAuthenticationTicket() and writes
/// it in URL or embeds it within Cookie
/// </summary> 
private static void SetAuthCookieMain(…)

/// <summary>
/// Creates a Forms authentication ticket and sets it within URL or Cookie
/// using the SetAuthCookieMain() private method, and redirects
/// to the originally requested page
/// </summary>
private static void RedirectFromLoginPageMain(…) 

The above three are the core methods that are being used by the public methods exposed to the outside world. The following are the public methods (with their overloaded versions) implemented inside the class:

Public methods

/// <summary>
/// Creates Forms authentication ticket and redirects
/// to the originally requested page. Uses the
/// RedirectFromLoginPageMain() private method
/// </summary>
public static void RedirectFromLoginPage(…)

/// <summary>
/// Creates a Forms authentication ticket and writes it
/// in URL or embeds it within Cookie. Uses the 
/// SetAuthCookieMain() private method
/// </summary>
public static void SetAuthCookie(…)

/// <summary>
/// Adds roles to the current User in HttpContext
/// after forms authentication authenticates the user
/// so that, the authorization mechanism can authorize
/// user based on the groups/roles of the user
/// </summary>
public static void AttachRolesToUser()

These public methods are being called by the client web application to implement Forms authentication and Role based authorization. Decoupling and implementing all authorization and authorization related logic inside the class library allows us to implement Role based authorization in our ASP.NET applications:

  • In a small amount of time.
  • In the correct way.
  • In a cleaner and smarter way.

The sample project

Download the sample ASP.NET web site application (created using Visual Studio 2008, Framework 3.5) and unzip it (FormsAuthorization.zip) into a convenient location. Open the web site using Visual Studio, or, create an IIS site/virtual directory pointing to the web root folder of the sample web site. Assuming that you have created the IIS site/virtual directory, do the followings to verify the authentication and Role based authorization along with the mentioned issues.

Testing authorization

  • Hit the following URL in the browser: http://localhost/FormsAuthorization/Admin/Default.aspx. The system will redirect you to the login page. Provide “Administrator/123” as the login credential and press “Login”. You will get a page where the “Hello Admin” message is displayed.

    Hit the same URL again by logging out, or, opening a new browser window/tab. But, this time, provide “John/123” as the credential. The system will not let you access the page; rather, the login screen will remain there intact.

    Looking at the web.config file of the web site, you will see that only the “Admin” role is allowed to access this URL and all other users are denied access. That is why John’s credential (who is a member of the “User” role) cannot access the URL that belongs to only the “Admin” role.

    <location path="Admin">
        <system.web>
            <authorization>
                <allow roles="Admin"/>
                <deny users="*"/>
            </authorization>
        </system.web>
    </location>
  • Hit the following URL in the browser: http://localhost/FormsAuthorization/User/Default.aspx. The system will redirect you to the login page. Provide “John/123” as the login credential and press “Login”. You will get a page where a “Hello John” message is displayed.

    Hit the same URL again by logging out, or, opening a new browser window/tab. But, this time provide “Administrator /123” as the credential. The system will not let you access the page; rather, the login screen will remain there intact.

    Looking at the web.config file of the web site, you will see that only the “User” role is allowed to access this URL and all other users are denied access. That is why Admin’s credential (who is a member of the “Admin” role) cannot access the URL that belongs to only the “User” role.

    <location path="User">
        <system.web>
            <authorization>
                <allow roles="User"/>
                <deny users="*"/>
            </authorization>
        </system.web>
    </location>
  • Hit the following URL in the browser: http://localhost/FormsAuthorization/Public/Default.aspx. The system will display “Hello, this is a public page”. As you can understand, this is a public page and no credential is required to access this page.

    Looking at the web.config file of the web site, you will see that all users are allowed to access this URL. So, no login credential is required to access it.

    <location path="Public">
        <system.web>
            <authorization>
                <allow users="*"/>
            </authorization>
        </system.web>
    </location>

Testing the “timeout” property

  • Change the “timeout” property value and set it to “1” in the web.config file.
    <forms name="login" timeout="1" loginUrl="Login.aspx"></forms>
  • Hit the following URL in the browser: http://localhost/FormsAuthorization/Admin/Default.aspx and login using “Administrator/123” as the login credential.
  • Don’t do anything for the next 1+ minute, and when a minute has passed, refresh the page. The system will redirect you to the login page, because, the authentication cookie has expired in the mean time. This indicates that the system can read and apply the “timeout” property correctly from the web.config.

Testing the “cookieless” property

  • Change the “cookieless” property value and set it to “UseUri” in the web.config.
    <forms name="login" timeout="120"
           loginUrl="Login.aspx" cookieless="UseUri"></forms>
  • Hit the following URL in the browser: http://localhost/FormsAuthorization/Admin/Default.aspx and login using “Administrator/123” as the login credential. The system will log you in successfully.
  • Take a look at the URL in the address bar. This should look something like the following:
    http://localhost/FormsAuthorization/(F(Oz5JC7onSkVsmb6....))/Admin/Default.aspx

    You can see that the authentication ticket has been encrypted and included in the URL (the actual URL should be a large one, and to save space, the remaining parts of the encrypted ticket in the URL has been omitted using some dots). This indicates that the system was able to write the authentication ticket in the URL and perform authentication and authorization correctly.

The sample web site “FormsAuthorization” uses the class library “RoleBasedFormsAuthentication.dll” to implement the authentication and Role based authorization. The source code for the class library is also available for download (RoleBasedFormsAuthentication.zip) in this article.

Conclusion

Despite the fact that Membership is a rocking stuff implemented in ASP.NET, the basic Forms authentication is not going to be eliminated at all and is going to be used over and over again. This article does not discuss about any “Rocket Science” here, and I just hope my effort would help you to implement a robust Forms authentication/authorization system and would save some of your precious time. I wish the commaSeperatedRoles parameter (or something like it) will be included in the FormsAuthentication.RedirectFromLoginPage() and other related methods in the future versions of the ASP.NET framework.

Happy programming!

FormsAuthorization.zip (12.74 kb)

RoleBasedFormsAuthentication.zip (7.54 kb)

web.config信息及RSA加密方式

我们都知道web.config可以保存连接字符串,我们在程序中也都是这么做的,web.config是XML,所

以它有清晰的结构,是我们很容易可以读懂它,但是这也出现一个问题,我们数据库完全暴露给浏览该文

件的人,这是我们所不希望的。我们可以使用一个简单有效的加密算法来加密这段连接字符,使直接浏览

该文件的人不能清楚地看到这些信息。

MSIL Disassembler (ildasm.exe)

Entry:
Start -> Programs ->Microsoft Visual Studio 2008(2005)->Visual Studio Tools->Visual Studio 2008(2005)

The Issue:

Get following issue while uploading a file to Server via FCKeditor or CKFinder

“It was not possible to complete the request due to file system permission restrictions.”

And the issue mostly repros in Linux servers

Issue:

Warning: session_start() [function.session-start]: Cannot send session cache limiter – headers already sent (output started at E:\php\code\admin.php:1) in E:\php\code\logolist\adminlogo.php on line 2

The Issue:

After installed CKFinder 1.4, I always get following error while trying to upload a file

“The file browser is disabled for security reasons. Please contact your system administrator and check the CKFinder configuration file.”

Or in Chinese

“因为安全原因,文件不可浏览. 请联系系统管理员并检查CKFinder配置文件.”

FCKeditor漏洞(版本2.4.2以下)

FCKeditor介绍
FCKeditor是一款功能强大的开源在线文本编辑器(DHTML editor),它使你在web上可以使用类似微软Word 的桌面文本编辑器的许多强大功能。它是轻量级且不必在客户端进行任何方式的安装。 FCKeditor兼容Firefox, Mozilla, Netscape 和IE。
FCKeditor官司方网址:http://www.fckeditor.net/
FCKeditor在线DEMO:http://www.fckeditor.net/demo
FCKeditor下载直址:http://www.fckeditor.net/download
确认程序为FCKeditor
要对漏洞进行测试,首先我们要确认网站中使用的编辑功能是不是由FCKeditor进行支持的。确认的方法很简单,打开网站带有编辑功能的页面,通常是发表文章或帖子的页面。单击IE菜单栏上的“查看”按钮,选择“源文件”,以“FCKeditor”为关键 字进行搜索,如果能搜索到,那么基本上可以确认该编辑功能使用的是FCKeditor。例如著名的博客程序Pjblog就可以通过这种方法得知其使用的就是FCKeditor。不过确认是FCKeditor并不代表其就有漏洞,因为这个漏洞只存在于之前的版本中,但是目前存在漏洞的 FCKeditor还是比较多的。
Google搜索:inurl:Fckeditor/editor
上传asp木马
确定网站中使用的是FCKeditor后,可以直接在IE地址栏中输入:http://www.***.com/FCKeditor /_samples/default.html。默认情况下可以打开一个FCKeditor编辑页面,有些精简版的FCKeditor会将 _samples文件夹删除,因此可能出现“找不到网页”的情况。在出现的页面中点击“插入/编辑图像”图标,打开“图像属性”窗口,点击其中的“浏览服 务器”服务器按钮,将出现一个文件上传页面。我们在这个页面上单击鼠标右键,选择“属性”,在“地址”一项中将找到这个页面的真实地址:
http://www.***.com/FCKeditor/editor/filemanager/browser/default/browser.html?Type=Image&Connector=connectors/asp/connector.asp。
将 找到的地址复制到IE地址栏中打开,出现一个上传文件管理页面,此时我们就可以上传我们的asp木马了,不过在上传之前我们需要将asp木马的后缀名改为 asa,因为FCKeditor限制了asp文件的上传,却没有限制asa文件的上传,而asp文件和asa文件的执行效果是一样的,这就是 FCKeditor的漏洞所在——上传文件的过滤不严。
上传asp木马完成后,就可以在浏览器中执行木马,此时我们得到的是一个webshell,可以对网站中任意文件进行操作,如果想黑掉网站,也是轻而易举的事。可见,虽然FCKeditor功能做得很强大,在安全性方面却很薄弱。

如果通过上面的步骤进行测试没有成功,可能有以下几方面的原因:
1.FCKeditor没有开启文件上传功能,这项功能在安装FCKeditor时默认是关闭的。如果想上传文件,FCKeditor会给出错误提示。
2.网站采用了精简版的FCKeditor,精简版的FCKeditor很多功能丢失,包括文件上传功能。
3.FCKeditor的这个漏洞已经被修复。
FCKeditor上传路径
比如输入:
http://[target]/[path]/FCKeditor/editor/filemanager/browser/default/browser.html?Type=all&Connector=connectors/asp/connector.asp
上传文件地址是UserFiles/all/1.asa
“Type=all” 这个变量是自己定义的,在这里创建了all这个目录,而且新的目录没有上传文件格式的限制.
type=xxx
所传的文件就到了http://[target]/[path]/UserFiles/xxx/下了
type=../
所传文件就到网站根目录了.
FCKeditor的JSP版漏洞
查看配置和列出目录下的文件:
http://www.xxx.com/fckeditor/editor/filemanager/browser/default/connectors/jsp/connector?Command=FileUpload&Type=Image&CurrentFolder=%2F

上传shell的地址:
http://www.xxx.com/fckeditor/editor/filemanager/browser/default/browser.html?Type=Image&Connector=connectors/jsp/connector
跟版本有关系.并不是百分百成功.
FCKeditor的PHP版漏洞
1. 上传文件漏洞,适用版本2.4.2以下:
fckeditor/editor/filemanager/upload/php/upload.php 61行未对Media类型进行上传文件类型的控制,导致用户上传任意文件。修补办法:更新到最新的2.5版本。或者在config.php文件中,添加对Media类型的文件类型限制。
2. 被动过滤:
config.php:

$Config['AllowedExtensions']['File'] = array() ;
$Config['DeniedExtensions']['File'] = array(’html’,’htm’,’php’,’php2′,’php3′,’php4′,’php5′,’phtml’,’pwml’,’inc’,’asp’,’aspx’,’ascx’,’jsp’,’cfm’,’cfc’,’pl’,’bat’,’exe’,’com’,’dll’,’vbs’,’js’,’reg’,’cgi’,’htaccess’,’asis’) ;

字典越来越大啊 :) 。我们先测试先以前的exp,上穿aa.php. 这样的文件结果变成了 aa_php. 看来还有其他变化啊:

function FileUpload( $resourceType, $currentFolder )
{
$sErrorNumber = ‘0′ ;
$sFileName = ” ;

……….
// Replace dots in the name with underscores (only one dot can be there… security issue).
if ( $Config['ForceSingleExtension'] ) //多了个$Config['ForceSingleExtension']的配置 默认是ture
$sFileName = preg_replace( ‘/\\.(?![^.]*$)/’, ‘_’, $sFileName ) ; //这里替换了文件名里多余的. 即:1.1.php–>1_1.php

$sOriginalFileName = $sFileName ;

// Get the extension.
$sExtension = substr( $sFileName, ( strrpos($sFileName, ‘.’) + 1 ) ) ;
$sExtension = strtolower( $sExtension ) ; //替换后取后缀,因为上面的替换所以保证了文件名里只有一个. 即:1_1.php—>php

$arAllowed = $Config['AllowedExtensions'][$resourceType] ;
$arDenied = $Config['DeniedExtensions'][$resourceType] ;

if ( ( count($arAllowed) == 0 || in_array( $sExtension, $arAllowed ) ) && ( count($arDenied) == 0 || !in_array( $sExtension, $arDenied ) ) )//判断
{
………….

if ( is_file( $sFilePath ) )

{
$iCounter++ ;
$sFileName = RemoveExtension( $sOriginalFileName ) . ‘(’ . $iCounter . ‘).’ . $sExtension ;

/*
这里判断有没有相同的文件名,如果有这改为在后缀前加一个(n). 如:_phs–>(1)._phs
那么我们可以利用产生的这个(n).不呢?答案是:NO 因为我们提交_php 经过
// Get the extension.
$sExtension = substr( $sFileName, ( strrpos($sFileName, ‘.’) + 1 ) ) ;
$sExtension = strtolower( $sExtension ) ;
这里时strrpos($sFileName, ‘.’)为空所以 还是:_php–>php 这个是没有办法通过上面的判断语句的
*/

$sErrorNumber = ‘201′ ;

}
else
{
move_uploaded_file( $oFile['tmp_name'], $sFilePath ) ;

通过上面的分析,好象没办法了?。呵呵 我们可以不用.嘛,在win下还有一个空格呢 :) 提交1.php+空格 就可以过去所有的。不过空格只支持win系统 *nix是不支持的[1.php和1.php+空格是2个不同的文件]

最后说明下,默认fckeditor是不让上传文件的:config.php:
// SECURITY: You must explicitelly enable this “connector”. (Set it to “true”).
$Config['Enabled'] = false ;

漏洞的修复
FCKeditor的漏洞因上传功能而起,因此只要我们将上传功能彻底关闭就可以了。打开位于FCKeditor安装目录 editor/filemanager/browser/default/connectors/asp/文件夹中的config.asp文件,将其中的 ConfigIsEnabled参数后面的值改为False,这样做的目的是将FCKeditor的文件上传功能关闭,漏洞当然也就无法被黑客利用了。
其实最简单的方法就是升级FCKeditor的版本,升级后漏洞就不存在了。如果FCKeditor是嵌入在网站程序中的,那么可能升级后会比较麻烦,这时采用第一种方法即可。

XML Reserved Characters

In XML, some characters are reserved for internal use and you must replace them by entity references when they are used in data. Additionally, the Notification Services XML vocabulary reserves the percent sign for use in denoting parameters.

The following table shows the reserved characters and the entity references that must replace them in all ADF data.

Character Meaning Entity reference
> Greater than >
< Less than <
Apostrophe (single quote) '
Quotation mark (double quote) "
& Ampersand &
% Percent %
Powered by WordPress | Theme: Motion by 85ideas.