ataque de inyección de Active Directory

0

¿Existe alguna forma de inyectar código para extraer datos de Active Directory?

He escrito una página PHP que ejecuta Powershell y puede cambiar las contraseñas a un grupo controlado de personas. Sin embargo, sigo sin saber si puedo o no inyectar código en mi script.

Actualmente, no se necesita escapar de todo, desde el espacio y todos los caracteres especiales.

PHP

<?php setlocale(LC_CTYPE, "en_US.UTF-8"); ?>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>Pw Changer</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<?php
/*
* Note: Errorstate var is changeable client side and should not be trusted
*/

$psScriptPath = ".\Bin\Non-Auth\adpwchange2014.ps1";// Path to the PowerShell script.
$logfile = './Logging/Phpruntime.txt';
$date = date('D, d M Y H:i:s');
$rand = mt_rand();

if(!empty($_GET["successstate"])){//Achievement Get: PW Changer
        echo '<div class="successstate">'. $_GET["successstate"] .'</div>';
        exit(header('refresh:5; ../index.php'));
        }

if(!isset($_POST["submit"])){
        if(!empty($_GET["errorstate"])){echo '<div class="errorstate">' . $_GET["errorstate"] . '</div><br /><br />';}
        // if there was no submit variable passed to the
        // script (i.e. user has visited the page without clicking submit), display the form:
        echo '<form name="testForm" class="formbox" id="testForm" action="index.php" method="post" />
        Username: <input type="text" name="username" id="username"/><br />
        Old Password: <input type="password" name="old_password"><br />
        New Password: <input type="password" name="new_password"><br />
        Confirm New Password: <input type="password" name="confirm"><br />
        <input type="submit" name="submit" id="submit" value="submit" />
        </form>';

}elseif(!empty($_POST["username"]) && !empty($_POST["old_password"]) && !empty($_POST["new_password"]) && !empty($_POST["confirm"])){// Else if submit was pressed, check if all of the required variables have a value and then Use PHP to check for risks such as Username in password or useing old password
        $errorstate = '';
        if($_POST["new_password"] != $_POST["confirm"]){
                $errorstate .= 'New Password and Confirm do not match</br>';
                }

        $username = utf8_decode($_POST["username"]);
        $old_password = utf8_decode($_POST["old_password"]);
        $new_password = utf8_decode($_POST["new_password"]);
        $confirm = utf8_decode($_POST["confirm"]);

        if(strlen($new_password) <= 8){//Length Check equal or greater then
                $errorstate .= 'Eight or more charictors needed</br>';
                }

        if(strpos($new_password,$old_password) !== false){//New Password Matches username or old password
                $errorstate .= 'Can not contain your old password</br>';
                }

        if(strpos($new_password, $username) !== false){
                $errorstate .= 'Can not contain your Username</br>';
                }

        $operator = array('\','#','+','<','>',';','\"','=',',');//Operators that need to be escaped with
        $replace = array('\\','\#','\+','\<','\>','\;','\"','\=','\,');//replacement

        //$username = str_replace ($operator, $replace, $username);
        //$new_password = str_replace ($operator, $replace, $new_password);
        //$old_password = str_replace ($operator, $replace, $old_password);

        $check_upper = 0;
        $check_lower = 0;
        $check_digit = 0;
        $check_punct = 0;

        foreach(count_chars($new_password, 1) as $key => $value){//Strength Test Results can be derived from $value
                if(!ctype_upper(chr($key))){$check_upper=1;}//if Upper-case
                if(!ctype_lower(chr($key))){$check_lower=1;}//if Lower-case
                if(!ctype_digit(chr($key))){$check_digit=1;}//if Numeric
                if(!ctype_punct(chr($key))){$check_punct=1;}//if Symbol
                if($check_upper + $check_lower + $check_digit + $check_punct>= 3){}//Save us from checking the entire string
                }

        if($check_upper + $check_lower + $check_digit + $check_punct<= 2){
                $errorstate .= 'Password needs to contain at least 3 of the following criteria: Upper-case, Lower-case, Numeric and/or Symbol</br>';
                }

        if(!empty($errorstate)){//EXIT if error state is set. Do not pass go, do not collect $200.
                exit(header('Location: .?errorstate='.$errorstate));
                }

        $user = $username;
        $username = base64_encode($username); //Transport Layer Base64
        $new_password = base64_encode($new_password); //Transport Layer Base64
        $old_password = base64_encode($old_password); //Transport Layer Base64

        /*
        * The danger happens here as it is sent to powershell.
        */
        $query = shell_exec('powershell.exe -ExecutionPolicy ByPass -command "' . $psScriptPath . '" < NUL -base64_username "' . $username . '" < NUL -base64_oldpassword "' . $old_password . '" < NUL -base64_newpassword "' . $new_password . '" < NUL');// Execute the PowerShell script, passing the parameters
        /*
        *Log the query result
        */

        if(stristr($query, 'Success'.$rand.':') !== false){ //Return True
                $logstr = '========================================'."\r\n";
                $logstr .= '                            ' . $date . ' - Success'."\r\n";
                $logstr .= '========================================'."\r\n";
                $logstr .= $_SERVER['REQUEST_TIME_FLOAT'] . "\r\n";
                $logstr .= $_SERVER['REMOTE_ADDR'] . ' - ' . $user .": Attempted Password Change result \r\n";
                $logstr .= $query;
                file_put_contents($logfile, $logstr, FILE_APPEND | LOCK_EX);
                $errorstate = '</br>Success: Password was changed</br>';
                exit(header('Location: ./index.php?successstate='.$errorstate));

        }elseif(stristr($query, 'Failed'.$rand.':') !== false){ //Return False
                $logstr = '========================================'."\r\n";
                $logstr .= '                            ' . $date . ' - Failed'."\r\n";
                $logstr .= '========================================'."\r\n";
                $logstr .= $_SERVER['REQUEST_TIME_FLOAT'] . "\r\n";
                $logstr .= $_SERVER['REMOTE_ADDR'] . ' - ' . $user .": Attempted Password Change result \r\n";
                $logstr .= $query;
                file_put_contents($logfile, $logstr, FILE_APPEND | LOCK_EX);
                $errorstate = '</br>Failed: Password was not changed</br>';
                exit(header('Location: .?errorstate='.$errorstate));

        }else{//someone broke something not that we tell them but we log the entry
                $logstr = '========================================'."\r\n";
                $logstr .= '                    ' . $date . ' - Error Warning'."\r\n";
                $logstr .= '========================================'."\r\n";
                $logstr .= $_SERVER['REQUEST_TIME_FLOAT'] . "\r\n";
                $logstr .= $_SERVER['REMOTE_ADDR'] . ' - ' . $user .": Attempted Password Change result \r\n";
                $logstr .= 'powershell.exe -ExecutionPolicy ByPass -command "' . $psScriptPath . '" < NUL -rand "' . $rand . '" < NUL -username "' . $username . '" < NUL -oldpassword "' . $old_password . '" < NUL -newpassword "' . $new_password . '" < NUL' . "\r\n";
                $logstr .= $query;
                $logstr .= 'Username: ' .$username . "\r\n";
                $logstr .= 'Old Password: ' .$old_password . "\r\n";
                $logstr .= 'New Password: ' .$new_password . "\r\n";
                file_put_contents($logfile, $logstr, FILE_APPEND | LOCK_EX);
                //You could go one step further and ban IP for X time // you could also send an email to yourself
                $headers = 'From: [email protected]' . "\r\n" .
                'Reply-To: [email protected]' . "\r\n" .
                'X-Mailer: PHP/' . phpversion();
                imap_mail('[email protected]', 'PHP/Powershell AD - Error Warning', $logstr, $headers);
                $errorstate = '</br>Failed: Password was not changed</br>';
                exit(header('Location: .?errorstate='.$errorstate));
                }

}else{// Else the user hit submit without all required fields being filled out:
        $errorstate = 'Please Complete all fields</br>';
        exit(header('Location: .?errorstate='.$errorstate));
        }
?>

</body>
</html>

Powershell

#*=============================================================================
#* Script Name: adpwchange2014.ps1
#* Created: 2014-10-07
#* Author:
#* Purpose: This is a simple script that queries AD users.
#* Reference Website: http://theboywonder.co.uk/2012/07/29/executing-powershell-using-php-and-iis/
#* 
#*=============================================================================

#*=============================================================================
#* PARAMETER DECLARATION
#*=============================================================================
param(
[string]$base64_username,
[string]$base64_newpassword,
[string]$base64_oldpassword,
[string]$rand
)

#*=============================================================================
#* IMPORT LIBRARIES
#*=============================================================================

if ((Get-Module | where {$_.Name -match "ActiveDirectory"}) -eq $null){
    #Loading module
    Write-Host "Loading module AcitveDirectory..."
    Import-Module ActiveDirectory
    }else{
    write-output "Error: Please install ActiveDirectory Module"
    EXIT
    NUL
    Stop-Process -processname powershell*
    }
#*=============================================================================
#* PARAMETERS
#*=============================================================================
$username = [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($base64_username))
$newpassword = [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($base64_newpassword))
$oldpassword = [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($base64_oldpassword))

#*=============================================================================
#* INITIALISE VARIABLES
#*=============================================================================
# Increase buffer width/height to avoid PowerShell from wrapping the text before
# sending it back to PHP (this results in weird spaces).
$pshost = Get-Host
$pswindow = $pshost.ui.rawui
$newsize = $pswindow.buffersize
$newsize.height = 1000
$newsize.width = 300
$pswindow.buffersize = $newsize

#*=============================================================================
#* EXCEPTION HANDLER
#*=============================================================================

#*=============================================================================
#* FUNCTION LISTINGS
#*=============================================================================

    Function Test-ADAuthentication  {
        Param($Auth_User, $Auth_Pass)
        $domain = $env:USERDOMAIN

        Add-Type -AssemblyName System.DirectoryServices.AccountManagement
        $ct = [System.DirectoryServices.AccountManagement.ContextType]::Domain
        $pc = New-Object System.DirectoryServices.AccountManagement.PrincipalContext($ct, $domain)
        $pc.ValidateCredentials($Auth_User, $Auth_Pass).ToString()
        }

    Function Set-ADAuthentication{
        Param($Auth_User,$Auth_OldPass, $Auth_NewPass)
        $domain = $env:USERDOMAIN
        $Auth_NewPass = ConvertTo-SecureString $Auth_NewPass -AsPlainText -Force
        $Auth_OldPass = ConvertTo-SecureString $Auth_OldPass -AsPlainText -Force
        #Running -whatif to simulate results
        #Therefore we expect "Failed: Password change" as it was not changed
        Set-ADAccountPassword -Identity $Auth_User -NewPassword $Auth_NewPass -OldPassword $Auth_OldPass -PassThru
        $authentication = Test-ADAuthentication $username $newpassword
        if ($authentication -eq $TRUE) {
            Write-Output "Success:$rand Password Changed"
            }elseif ($authentication -eq $FALSE) {
            Write-Output "Failed$rand: Password Change"
            }else{
                Write-Output "Error: EOS"
                EXIT
                NUL
                Stop-Process -processname powershell*
                }
        }

#*=============================================================================
#* Function: function1
#* Purpose: This function does X Y Z
#* =============================================================================

#*=============================================================================
#* END OF FUNCTION LISTINGS
#*=============================================================================

#*=============================================================================
#* SCRIPT BODY
#*=============================================================================
Write-Output $PSVersionTable
Write-Output "  "
$authentication = Test-ADAuthentication "$username" "$oldpassword"
if ($authentication -eq $TRUE) {
    Set-ADAuthentication $username $oldpassword $newpassword
    }elseif ($authentication -eq $FALSE) {
    Write-Output "Failed$rand: Validation"
    }else {Write-Output "Error: EOS"
    EXIT
    NUL
    Stop-Process -processname powershell*
    }

#*=============================================================================
#* SCRIPT Exit
#*=============================================================================
Write-Output "End Of Script"
EXIT
NUL
Stop-Process -processname powershell*

Notas:

  • Me doy cuenta de que base64 es solo encapsulación
  • Soy nuevo en Powershell y en el módulo de Active Directory.
  • Explicación de $ Rand - mientras php busca "Success:" o "Failure:" alguien podría ingresar Success: como nombre de usuario y devolverlo Success (aunque puede que no sea así). Ahora busco Success $ Rand: o Failure $ Rand:
pregunta Werezwolf 24.11.2014 - 05:19
fuente

0 respuestas

Lea otras preguntas en las etiquetas