Hola a todos, en esta oportunidad quiero compartirles un tema el cual constituye una vulnerabilidad en un sistema de gestión de datos, usando en este caso SQL Server cómo motor de bases de datos.

Muchas veces por comodidad y facilidad solemos usar SQL Dinámico, el cual básicamente consiste en flexibilizar una consulta sobre la base de datos, ¿por qué razón?, por ejemplo  imaginemos un formulario de ASP.NET en el cual tengamos filtros tales cómo podrían ser  fechas, descripción de un dato u otro valor que se desea filtrar, digamos que tenemos un control  el cual permita una funcionalidad similar a la que podemos encontrar en el buscador google (Control tipo AJAX para encontrar coincidencias por ejemplo en una BD para nuestro caso).

Ejemplo Formulario:

ASPX AJAX xon JQUERY ver post anterior

<pre><%@ Page Title="Home Page" Language="C#" MasterPageFile="~/Site.master" AutoEventWireup="true"
    CodeBehind="Default.aspx.cs" Inherits="WebApplication1._Default" %>

<asp:Content ID="HeaderContent" runat="server" ContentPlaceHolderID="HeadContent">
    <script type="text/javascript" language="javascript" src="Scripts/jquery-1.4.1.min.js"></script>
    <script type="text/javascript" language="javascript">
        $(document).ready(function () {
            $("#<%=TxtBusqueda.ClientID%>").keyup(function () {
                $.ajax({
                    type: "POST",
                    url: "Default.aspx/GetData",
                    dataType: "json",
                    contentType: "application/json; chartset=utf-8",
                    data: '{ "filter":"' + $(this).val() + '"}',
                    success: function (result) {
                        if (!result)
                            return;
                        if (!result.d)
                            return;
                        $("#DivResults").html("");
                        var table = $('<table></table>');
                        table.append($("<tr><td>Id</td><td>Nombre</td><td>Apellido</td></tr>"));
                        $(result.d).each(function () {
                            table.append($('<tr>' +
                                '<td>' + this.ContactID + '</td>' +
                                '<td>' + this.FirstName + '</td>' +
                                '<td>' + this.LastName + '</td>' +
                            '</tr>'));
                        });
                        $("#DivResults").append(table);
                    },
                    error: function (XmlError, error, desc) { },
                    async: true
                });
            });
        });
    </script>
</asp:Content>
<asp:Content ID="BodyContent" runat="server" ContentPlaceHolderID="MainContent">

    <br />
    <table>
        <tr>
            <td>
                Descripción Producto
            </td>
            <td>
                <asp:TextBox ID="TxtBusqueda" Width="500px" runat="server"></asp:TextBox>
            </td>
        </tr>
    </table>
    <br />
    <div style="background:black; width:50%;">
        <span style="color:White">Resultados : </span>
        <br />
        <div id="DivResults">

        </div>
    </div>
</asp:Content></pre>

CodeBehind: Podemos ver cómo creamos una conexión a la base de datos, y como devolvemos los datos transformados a un objeto List<T>

<pre>using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.Services;
using System.Data;
using System.Data.SqlClient;
namespace WebApplication1
{
    public partial class _Default : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {

        }
        [WebMethod]
        public static List<Result> GetData(string filter)
        {
            DataTable dt = new DataTable();
            List<Result> listResults = new List<Result>();
            using (SqlConnection connection = new SqlConnection(System.Web.Configuration.WebConfigurationManager.ConnectionStrings["AdventureWorksConnectionString"].ConnectionString))
            {
                using (SqlCommand cmd = new SqlCommand("Person.AWProcDinamico", connection))
                {
                    cmd.CommandType = CommandType.StoredProcedure;
                    cmd.Parameters.AddWithValue("@Descripcion", filter);
                    SqlDataAdapter da = new SqlDataAdapter(cmd);
                    try
                    {
                        connection.Open();
                        da.Fill(dt);
                    }
                    catch (SqlException ex)
                    {
                        throw ex;
                    }
                }
            }
            //Para ver una mejor forma de hacer esta parte: https://ingphillip.wordpress.com/2011/04/09/generics-t-anonymous-types-system-reflection-y-metodos-extensores-en-net/
            foreach (DataRow dRow in dt.Rows)
            {
                listResults.Add(
                    new Result
                    {
                        ContactID = dRow["ContactID"].ToString(),
                        FirstName = dRow["FirstName"].ToString(),
                        LastName = dRow["LastName"].ToString()
                    }
                );
            }
            return listResults;
        }
        public class Result
        {
            public string ContactID { get; set; }
            public string FirstName { get; set; }
            public string LastName { get; set; }
        }
    }
}</pre>

AHORA SUPONGAMOS:

En la base de datos AdventureWork (que en realidad puede ser una base de datos en producción con datos sensibles) creamos un “StoreProcedure dinámico para hacer un select,  en este caso un select like ” así:

	USE AdventureWorks
	GO
	ALTER PROC Person.AWProcDinamico
		@Descripcion varchar(100)
	AS
	BEGIN
		DECLARE @SQL VARCHAR(MAX)
		SET @SQL = ''
		SET @SQL = @SQL + 'SELECT Person.Contact.ContactID, Person.Contact.FirstName, Person.Contact.LastName '
		SET @SQL = @SQL + 'FROM Person.Contact WHERE FirstName Like ''%'+ @Descripcion + '%''  '
		SET @SQL = @SQL + 'ORDER BY Person.Contact.ContactID, Person.Contact.FirstName, Person.Contact.LastName'
		PRINT (@SQL)
		EXEC (@SQL)
	END
	GO

Hasta acá sólo se intentó un caso probable en el mundo real. Ahora bien si sabes que es un store procedure y cómo poderlo ejecutar desde .NET entonces entenderás que allí hemos abierto una muy sensible puerta  a los datos residentes en la base de datos.

Veamos este video de lo que es un hacking muy simple pero instructivo acerca de lo que no debemos hacer en la base con nuestra presida base de datos.

Como vimos en el video, aunque no evidente la base de datos está vulnerable, por tal razón luego de conocer el nombre de las tablas, podemos pasar a hacer cualquier tipo de consultas o updates o más grave aun deletes sobre los registros.

Cosas a tener en cuenta.

– No quemes cadenas de conexión en el Web Config,  Encriptalas!. (Te gustaría ver el artículo ?)

– No dejes abierto determinado usuario ‘sa’ u otro con permisos para manipular tablas como en nuestro caso sys.Tables

– Trata de no usar SQL dinámico en lo posible, si lo requieres, asegúrate de tener un filtro de cráteres especiales y además puedes seguir esta guía: http://msdn.microsoft.com/es-es/library/bb669091.aspx.

– Valida tanto en el cliente, cómo en el Servidor!

Saludos, espero sea de utilidad!!!

Anuncios